From 7fe21291bad93458100fbbf0078d40cdb529a646 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 14 Jan 2015 15:15:57 +0000 Subject: [PATCH 01/64] MPILIB: Deobfuscate mpi_cmp The condition preceding 'return 1;' makes my head hurt. At this point, we know that u and v have the same sign; if they are negative, they compare opposite to how their absolute values compare (which mpihelp_cmp found for us), otherwise cmp itself is the answer. Negating cmp is ok since mpihelp_cmp returns {-1,0,1}; -INT_MIN==INT_MIN won't bite us. Signed-off-by: Rasmus Villemoes Signed-off-by: David Howells Acked-by: Dmitry Kasatkin --- lib/mpi/mpi-cmp.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c index 1871e7b61ca0..8ed36b8cbe02 100644 --- a/lib/mpi/mpi-cmp.c +++ b/lib/mpi/mpi-cmp.c @@ -61,10 +61,8 @@ int mpi_cmp(MPI u, MPI v) if (!usize) return 0; cmp = mpihelp_cmp(u->d, v->d, usize); - if (!cmp) - return 0; - if ((cmp < 0 ? 1 : 0) == (u->sign ? 1 : 0)) - return 1; - return -1; + if (u->sign) + return -cmp; + return cmp; } EXPORT_SYMBOL_GPL(mpi_cmp); From 98dbbcba1b0c1874b9faf9c77b83f9729360aa2c Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 14 Jan 2015 15:16:00 +0000 Subject: [PATCH 02/64] MPILIB: Fix obvious but harmless typo The macro MPN_COPY_INCR this occurs in isn't used anywhere. Signed-off-by: Rasmus Villemoes Signed-off-by: David Howells --- lib/mpi/mpi-internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpi/mpi-internal.h b/lib/mpi/mpi-internal.h index 60cf765628e9..c65dd1bff45a 100644 --- a/lib/mpi/mpi-internal.h +++ b/lib/mpi/mpi-internal.h @@ -84,7 +84,7 @@ static inline int RESIZE_IF_NEEDED(MPI a, unsigned b) do { \ mpi_size_t _i; \ for (_i = 0; _i < (n); _i++) \ - (d)[_i] = (d)[_i]; \ + (d)[_i] = (s)[_i]; \ } while (0) #define MPN_COPY_DECR(d, s, n) \ From b9f918a31d629e99c9ca3d6ac2a2d7a905715c69 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 14 Jan 2015 16:10:12 +0000 Subject: [PATCH 03/64] MPILIB: Fix comparison of negative MPIs If u and v both represent negative integers and their limb counts happen to differ, mpi_cmp will always return a positive value - this is obviously bogus. u is smaller than v if and only if it is larger in absolute value. Signed-off-by: Rasmus Villemoes Signed-off-by: David Howells Acked-by: Dmitry Kasatkin --- lib/mpi/mpi-cmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c index 8ed36b8cbe02..d25e9e96c310 100644 --- a/lib/mpi/mpi-cmp.c +++ b/lib/mpi/mpi-cmp.c @@ -57,7 +57,7 @@ int mpi_cmp(MPI u, MPI v) if (usize != vsize && !u->sign && !v->sign) return usize - vsize; if (usize != vsize && u->sign && v->sign) - return vsize + usize; + return vsize - usize; if (!usize) return 0; cmp = mpihelp_cmp(u->d, v->d, usize); From 398a1e71dc827b994b7f2f56c7c2186fea7f8d75 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 29 Aug 2014 10:33:02 +0100 Subject: [PATCH 04/64] TPM: Add new TPMs to the tail of the list to prevent inadvertent change of dev Add newly registered TPMs to the tail of the list, not the beginning, so that things that are specifying TPM_ANY_NUM don't find that the device they're using has inadvertently changed. Adding a second device would break IMA, for instance. Cc: stable@vger.kernel.org Signed-off-by: David Howells Reviewed-by: Jason Gunthorpe Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm-interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 6af17002a115..cfb9089887bd 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -1122,7 +1122,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, /* Make chip available */ spin_lock(&driver_lock); - list_add_rcu(&chip->list, &tpm_chip_list); + list_add_tail_rcu(&chip->list, &tpm_chip_list); spin_unlock(&driver_lock); return chip; From bb95cd34ba4c9467114acc78eeddd53ab1c10085 Mon Sep 17 00:00:00 2001 From: Kiran Padwal Date: Fri, 19 Sep 2014 12:44:39 +0530 Subject: [PATCH 05/64] char: tpm: Add missing error check for devm_kzalloc Currently these driver are missing a check on the return value of devm_kzalloc, which would cause a NULL pointer dereference in a OOM situation. This patch adds a missing check for tpm_i2c_atmel.c and tpm_i2c_nuvoton.c Cc: stable@vger.kernel.org Signed-off-by: Kiran Padwal Reviewed-By: Jason Gunthorpe Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_atmel.c | 4 ++++ drivers/char/tpm/tpm_i2c_nuvoton.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index 77272925dee6..503a85ae176c 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -168,6 +168,10 @@ static int i2c_atmel_probe(struct i2c_client *client, chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL); + if (!chip->vendor.priv) { + rc = -ENOMEM; + goto out_err; + } /* Default timeouts */ chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index 7b158efd49f7..23c7b137a7fd 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -538,6 +538,11 @@ static int i2c_nuvoton_probe(struct i2c_client *client, chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL); + if (!chip->vendor.priv) { + rc = -ENOMEM; + goto out_err; + } + init_waitqueue_head(&chip->vendor.read_queue); init_waitqueue_head(&chip->vendor.int_queue); From 448e9c55c12d6bd4fa90a7e31d802e045666d7c8 Mon Sep 17 00:00:00 2001 From: Scot Doyle Date: Wed, 24 Sep 2014 22:41:10 +0000 Subject: [PATCH 06/64] tpm_tis: verify interrupt during init Some machines, such as the Acer C720 and Toshiba CB35, have TPMs that do not send IRQs while also having an ACPI TPM entry indicating that they will be sent. These machines freeze on resume while the tpm_tis module waits for an IRQ, eventually timing out. When in interrupt mode, the tpm_tis module should receive an IRQ during module init. Fall back to polling mode if none is received when expected. Cc: Signed-off-by: Scot Doyle Tested-by: Michael Mullin Reviewed-by: Jason Gunthorpe [phuewe: minor checkpatch fixed] Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_tis.c | 76 +++++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 6f1985496112..ccb140d60532 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -75,6 +75,10 @@ enum tis_defaults { #define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) #define TPM_RID(l) (0x0F04 | ((l) << 12)) +struct priv_data { + bool irq_tested; +}; + static LIST_HEAD(tis_chips); static DEFINE_MUTEX(tis_lock); @@ -338,12 +342,27 @@ out_err: return rc; } +static void disable_interrupts(struct tpm_chip *chip) +{ + u32 intmask; + + intmask = + ioread32(chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + intmask &= ~TPM_GLOBAL_INT_ENABLE; + iowrite32(intmask, + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + free_irq(chip->vendor.irq, chip); + chip->vendor.irq = 0; +} + /* * If interrupts are used (signaled by an irq set in the vendor structure) * tpm.c can skip polling for the data to be available as the interrupt is * waited for here */ -static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) +static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len) { int rc; u32 ordinal; @@ -373,6 +392,30 @@ out_err: return rc; } +static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) +{ + int rc, irq; + struct priv_data *priv = chip->vendor.priv; + + if (!chip->vendor.irq || priv->irq_tested) + return tpm_tis_send_main(chip, buf, len); + + /* Verify receipt of the expected IRQ */ + irq = chip->vendor.irq; + chip->vendor.irq = 0; + rc = tpm_tis_send_main(chip, buf, len); + chip->vendor.irq = irq; + if (!priv->irq_tested) + msleep(1); + if (!priv->irq_tested) { + disable_interrupts(chip); + dev_err(chip->dev, + FW_BUG "TPM interrupt not working, polling instead\n"); + } + priv->irq_tested = true; + return rc; +} + struct tis_vendor_timeout_override { u32 did_vid; unsigned long timeout_us[4]; @@ -505,6 +548,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) if (interrupt == 0) return IRQ_NONE; + ((struct priv_data *)chip->vendor.priv)->irq_tested = true; if (interrupt & TPM_INTF_DATA_AVAIL_INT) wake_up_interruptible(&chip->vendor.read_queue); if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT) @@ -534,9 +578,14 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, u32 vendor, intfcaps, intmask; int rc, i, irq_s, irq_e, probe; struct tpm_chip *chip; + struct priv_data *priv; + priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; if (!(chip = tpm_register_hardware(dev, &tpm_tis))) return -ENODEV; + chip->vendor.priv = priv; chip->vendor.iobase = ioremap(start, len); if (!chip->vendor.iobase) { @@ -605,19 +654,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, if (intfcaps & TPM_INTF_DATA_AVAIL_INT) dev_dbg(dev, "\tData Avail Int Support\n"); - /* get the timeouts before testing for irqs */ - if (tpm_get_timeouts(chip)) { - dev_err(dev, "Could not get TPM timeouts and durations\n"); - rc = -ENODEV; - goto out_err; - } - - if (tpm_do_selftest(chip)) { - dev_err(dev, "TPM self test failed\n"); - rc = -ENODEV; - goto out_err; - } - /* INTERRUPT Setup */ init_waitqueue_head(&chip->vendor.read_queue); init_waitqueue_head(&chip->vendor.int_queue); @@ -719,6 +755,18 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, } } + if (tpm_get_timeouts(chip)) { + dev_err(dev, "Could not get TPM timeouts and durations\n"); + rc = -ENODEV; + goto out_err; + } + + if (tpm_do_selftest(chip)) { + dev_err(dev, "TPM self test failed\n"); + rc = -ENODEV; + goto out_err; + } + INIT_LIST_HEAD(&chip->vendor.list); mutex_lock(&tis_lock); list_add(&chip->vendor.list, &tis_chips); From 84eb186bc37c0900b53077ca21cf6dd15823a232 Mon Sep 17 00:00:00 2001 From: "Hon Ching (Vicky) Lo" Date: Sun, 30 Nov 2014 15:01:28 +0100 Subject: [PATCH 07/64] tpm: Fix NULL return in tpm_ibmvtpm_get_desired_dma There was an oops in tpm_ibmvtpm_get_desired_dma, which caused kernel panic during boot when vTPM is enabled in Power partition configured in AMS mode. vio_bus_probe calls vio_cmo_bus_probe which calls tpm_ibmvtpm_get_desired_dma to get the size needed for DMA allocation. The problem is, vio_cmo_bus_probe is called before calling probe, which for vtpm is tpm_ibmvtpm_probe and it's this function that initializes and sets up vtpm's CRQ and gets required data values. Therefore, since this has not yet been done, NULL is returned in attempt to get the size for DMA allocation. We added a NULL check. In addition, a default buffer size will be set when NULL is returned. Cc: Signed-off-by: Hon Ching (Vicky) Lo Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_ibmvtpm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index af74c57e5090..4109222f2878 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -307,6 +307,14 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev) { struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); + + /* ibmvtpm initializes at probe time, so the data we are + * asking for may not be set yet. Estimate that 4K required + * for TCE-mapped buffer in addition to CRQ. + */ + if (!ibmvtpm) + return CRQ_RES_BUF_SIZE + PAGE_SIZE; + return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size; } From 9fd8e5a25ecb0febfad321c04478a9d8b8b247f7 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 16 Nov 2014 11:03:24 +0100 Subject: [PATCH 08/64] tpm: remove unnecessary sizeof(u8) sizeof(u8) is always 1. Signed-off-by: Fabian Frederick Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 4669e3713428..5271b75d7661 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -635,13 +635,13 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) } platform_data->tpm_i2c_buffer[0] = - kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); + kmalloc(TPM_BUFSIZE, GFP_KERNEL); if (platform_data->tpm_i2c_buffer[0] == NULL) { err = -ENOMEM; goto _tpm_clean_answer; } platform_data->tpm_i2c_buffer[1] = - kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); + kmalloc(TPM_BUFSIZE, GFP_KERNEL); if (platform_data->tpm_i2c_buffer[1] == NULL) { err = -ENOMEM; goto _tpm_clean_response1; From 2dfc2deda2c9b1def7dc9399623479b69cd9f7ff Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 19 Nov 2014 14:44:15 +0100 Subject: [PATCH 09/64] char: tpm: Deletion of unnecessary checks before the function call "tpm_dev_vendor_release" The tpm_dev_vendor_release() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_atmel.c | 3 +-- drivers/char/tpm/tpm_i2c_nuvoton.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index 503a85ae176c..5f448886417f 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -206,8 +206,7 @@ static int i2c_atmel_remove(struct i2c_client *client) struct device *dev = &(client->dev); struct tpm_chip *chip = dev_get_drvdata(dev); - if (chip) - tpm_dev_vendor_release(chip); + tpm_dev_vendor_release(chip); tpm_remove_hardware(dev); kfree(chip); return 0; diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index 23c7b137a7fd..bbb4997438c3 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -630,8 +630,7 @@ static int i2c_nuvoton_remove(struct i2c_client *client) struct device *dev = &(client->dev); struct tpm_chip *chip = dev_get_drvdata(dev); - if (chip) - tpm_dev_vendor_release(chip); + tpm_dev_vendor_release(chip); tpm_remove_hardware(dev); kfree(chip); return 0; From 1ba3b0b6f218072afe8372d12f1b6bf26a26008e Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:46 +0100 Subject: [PATCH 10/64] tpm/tpm_i2c_stm_st33: Fix potential bug in tpm_stm_i2c_send When sending data in tpm_stm_i2c_send, each loop iteration send buf. Send buf + i instead as the goal of this for loop is to send a number of byte from buf that fit in burstcnt. Once those byte are sent, we are supposed to send the next ones. The driver was working because the burstcount value returns always the maximum size for a TPM command or response. (0x800 for a command and 0x400 for a response). Cc: stable@vger.kernel.org Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 5271b75d7661..d2031c43caa1 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -487,7 +487,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, if (burstcnt < 0) return burstcnt; size = min_t(int, len - i - 1, burstcnt); - ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size); + ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf + i, size); if (ret < 0) goto out_err; From 578aa13eb796ce3f20523504424e973f351e4870 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:47 +0100 Subject: [PATCH 11/64] tpm/tpm_i2c_stm_st33: Update Kconfig in order to be inline to other similar product STMicroelectronics i2c tpm is the only one to have a different tristate label. Rename it "TPM Interface Specification 1.2 Interface (I2C - STMicroelectronics)" Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard [phuewe: corrected module name in the helptext] Signed-off-by: Peter Huewe --- drivers/char/tpm/Kconfig | 6 +++--- drivers/char/tpm/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index c54cac3f8bc8..3d0873b1ab5b 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -100,15 +100,15 @@ config TCG_IBMVTPM will be accessible from within Linux. To compile this driver as a module, choose M here; the module will be called tpm_ibmvtpm. -config TCG_ST33_I2C - tristate "STMicroelectronics ST33 I2C TPM" +config TCG_TIS_I2C_ST33 + tristate "TPM Interface Specification 1.2 Interface (I2C - STMicroelectronics)" depends on I2C depends on GPIOLIB ---help--- If you have a TPM security chip from STMicroelectronics working with an I2C bus say Yes and it will be accessible from within Linux. To compile this driver as a module, choose M here; the module will be - called tpm_stm_st33_i2c. + called tpm_i2c_stm_st33. config TCG_XEN tristate "XEN TPM Interface" diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 4d85dd681b81..7f54dae847e4 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -20,5 +20,5 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o -obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o +obj-$(CONFIG_TCG_TIS_I2C_ST33) += tpm_i2c_stm_st33.o obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o From 642d2be22a746ba756e0273e19977f1794fe080c Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:48 +0100 Subject: [PATCH 12/64] tpm/tpm_i2c_stm_st33: Change License header to have up to date address information The Free Software Foundation may have mail address change. In order to be sure to have up to date mail address give an url to the license which includes accurate informations. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index d2031c43caa1..bf1e53093873 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -12,9 +12,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . * * STMicroelectronics version 1.2.0, Copyright (C) 2010 * STMicroelectronics comes with ABSOLUTELY NO WARRANTY. From 7500c4b99bddf1b01440bb430d7e38e7652817bf Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:49 +0100 Subject: [PATCH 13/64] tpm/tpm_i2c_stm_st33: Fix few coding style error reported by scripts/checkpatch.pl Fix: - WARNING: Missing a blank line after declarations - WARNING: braces {} are not necessary for any arm of this statement Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index bf1e53093873..c4925a03d7ab 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -156,6 +156,7 @@ static int read8_reg(struct i2c_client *client, u8 tpm_register, static void clear_interruption(struct i2c_client *client) { u8 interrupt; + I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1); I2C_WRITE_DATA(client, TPM_INT_STATUS, &interrupt, 1); I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1); @@ -232,6 +233,7 @@ static u8 tpm_stm_i2c_status(struct tpm_chip *chip) { struct i2c_client *client; u8 data; + client = (struct i2c_client *)TPM_VPRIV(chip); I2C_READ_DATA(client, TPM_STS, &data, 1); @@ -783,11 +785,11 @@ static int tpm_st33_i2c_pm_suspend(struct device *dev) struct st33zp24_platform_data *pin_infos = dev->platform_data; int ret = 0; - if (power_mgt) { + if (power_mgt) gpio_set_value(pin_infos->io_lpcpd, 0); - } else { + else ret = tpm_pm_suspend(dev); - } + return ret; } /* tpm_st33_i2c_suspend() */ From 2dbca7508f99618fc6cf964134403dccb63968bd Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:50 +0100 Subject: [PATCH 14/64] tpm/tpm_i2c_stm_st33: Move tpm registers to tpm_i2c_stm_st33.c Move tpm registers to tpm_i2c_stm_st33.c. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 17 +++++++++++++++++ drivers/char/tpm/tpm_i2c_stm_st33.h | 17 ----------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index c4925a03d7ab..44a02103ad49 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -49,6 +49,23 @@ #include #include "tpm.h" + +#define TPM_ACCESS 0x0 +#define TPM_STS 0x18 +#define TPM_HASH_END 0x20 +#define TPM_DATA_FIFO 0x24 +#define TPM_HASH_DATA 0x24 +#define TPM_HASH_START 0x28 +#define TPM_INTF_CAPABILITY 0x14 +#define TPM_INT_STATUS 0x10 +#define TPM_INT_ENABLE 0x08 + +#define TPM_DUMMY_BYTE 0xAA +#define TPM_WRITE_DIRECTION 0x80 +#define TPM_HEADER_SIZE 10 +#define TPM_BUFSIZE 2048 + +#define LOCALITY0 0 #include "tpm_i2c_stm_st33.h" enum stm33zp24_access { diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.h b/drivers/char/tpm/tpm_i2c_stm_st33.h index 439a43249aa6..3041271342eb 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.h +++ b/drivers/char/tpm/tpm_i2c_stm_st33.h @@ -30,23 +30,6 @@ #ifndef __STM_ST33_TPM_I2C_MAIN_H__ #define __STM_ST33_TPM_I2C_MAIN_H__ -#define TPM_ACCESS (0x0) -#define TPM_STS (0x18) -#define TPM_HASH_END (0x20) -#define TPM_DATA_FIFO (0x24) -#define TPM_HASH_DATA (0x24) -#define TPM_HASH_START (0x28) -#define TPM_INTF_CAPABILITY (0x14) -#define TPM_INT_STATUS (0x10) -#define TPM_INT_ENABLE (0x08) - -#define TPM_DUMMY_BYTE 0xAA -#define TPM_WRITE_DIRECTION 0x80 -#define TPM_HEADER_SIZE 10 -#define TPM_BUFSIZE 2048 - -#define LOCALITY0 0 - #define TPM_ST33_I2C "st33zp24_i2c" struct st33zp24_platform_data { From b9626f32876debc356fadb6e19aebcfe9d70c5ff Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:51 +0100 Subject: [PATCH 15/64] tpm/tpm_i2c_stm_st33: Add new tpm_stm_dev structure and remove tpm_i2c_buffer[0], [1] buffer. In order to clean big buffers in st33zp24_platform_data structure, replace with tpm_stm_dev for driver internal usage. As only one buffer is really necessary replace with buf field. In the mean time move tpm_i2c_stm_st33.h to include/linux/platform_data. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 204 ++++++++---------- .../linux/platform_data}/tpm_i2c_stm_st33.h | 10 +- 2 files changed, 95 insertions(+), 119 deletions(-) rename {drivers/char/tpm => include/linux/platform_data}/tpm_i2c_stm_st33.h (81%) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 44a02103ad49..4f725386385f 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -48,6 +47,7 @@ #include #include +#include #include "tpm.h" #define TPM_ACCESS 0x0 @@ -66,7 +66,7 @@ #define TPM_BUFSIZE 2048 #define LOCALITY0 0 -#include "tpm_i2c_stm_st33.h" + enum stm33zp24_access { TPM_ACCESS_VALID = 0x80, @@ -98,6 +98,15 @@ enum tis_defaults { TIS_LONG_TIMEOUT = 2000, }; +struct tpm_stm_dev { + struct i2c_client *client; + struct completion irq_detection; + struct tpm_chip *chip; + u8 buf[TPM_BUFSIZE + 1]; + int io_serirq; + int io_lpcpd; +}; + /* * write8_reg * Send byte to the TIS register according to the ST33ZP24 I2C protocol. @@ -106,17 +115,12 @@ enum tis_defaults { * @param: tpm_size, The length of the data * @return: Returns negative errno, or else the number of bytes written. */ -static int write8_reg(struct i2c_client *client, u8 tpm_register, +static int write8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register, u8 *tpm_data, u16 tpm_size) { - struct st33zp24_platform_data *pin_infos; - - pin_infos = client->dev.platform_data; - - pin_infos->tpm_i2c_buffer[0][0] = tpm_register; - memcpy(&pin_infos->tpm_i2c_buffer[0][1], tpm_data, tpm_size); - return i2c_master_send(client, pin_infos->tpm_i2c_buffer[0], - tpm_size + 1); + tpm_dev->buf[0] = tpm_register; + memcpy(tpm_dev->buf + 1, tpm_data, tpm_size); + return i2c_master_send(tpm_dev->client, tpm_dev->buf, tpm_size + 1); } /* write8_reg() */ /* @@ -127,56 +131,56 @@ static int write8_reg(struct i2c_client *client, u8 tpm_register, * @param: tpm_size, tpm TPM response size to read. * @return: number of byte read successfully: should be one if success. */ -static int read8_reg(struct i2c_client *client, u8 tpm_register, +static int read8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register, u8 *tpm_data, int tpm_size) { u8 status = 0; u8 data; data = TPM_DUMMY_BYTE; - status = write8_reg(client, tpm_register, &data, 1); + status = write8_reg(tpm_dev, tpm_register, &data, 1); if (status == 2) - status = i2c_master_recv(client, tpm_data, tpm_size); + status = i2c_master_recv(tpm_dev->client, tpm_data, tpm_size); return status; } /* read8_reg() */ /* * I2C_WRITE_DATA * Send byte to the TIS register according to the ST33ZP24 I2C protocol. - * @param: client, the chip description + * @param: tpm_dev, the chip description * @param: tpm_register, the tpm tis register where the data should be written * @param: tpm_data, the tpm_data to write inside the tpm_register * @param: tpm_size, The length of the data * @return: number of byte written successfully: should be one if success. */ -#define I2C_WRITE_DATA(client, tpm_register, tpm_data, tpm_size) \ - (write8_reg(client, tpm_register | \ +#define I2C_WRITE_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \ + (write8_reg(tpm_dev, tpm_register | \ TPM_WRITE_DIRECTION, tpm_data, tpm_size)) /* * I2C_READ_DATA * Recv byte from the TIS register according to the ST33ZP24 I2C protocol. - * @param: tpm, the chip description + * @param: tpm_dev, the chip description * @param: tpm_register, the tpm tis register where the data should be read * @param: tpm_data, the TPM response * @param: tpm_size, tpm TPM response size to read. * @return: number of byte read successfully: should be one if success. */ -#define I2C_READ_DATA(client, tpm_register, tpm_data, tpm_size) \ - (read8_reg(client, tpm_register, tpm_data, tpm_size)) +#define I2C_READ_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \ + (read8_reg(tpm_dev, tpm_register, tpm_data, tpm_size)) /* * clear_interruption * clear the TPM interrupt register. * @param: tpm, the chip description */ -static void clear_interruption(struct i2c_client *client) +static void clear_interruption(struct tpm_stm_dev *tpm_dev) { u8 interrupt; - I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1); - I2C_WRITE_DATA(client, TPM_INT_STATUS, &interrupt, 1); - I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1); + I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); + I2C_WRITE_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); + I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); } /* clear_interruption() */ /* @@ -190,17 +194,16 @@ static long _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip, { long status; struct i2c_client *client; - struct st33zp24_platform_data *pin_infos; + struct tpm_stm_dev *tpm_dev; - client = (struct i2c_client *)TPM_VPRIV(chip); - pin_infos = client->dev.platform_data; + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + client = tpm_dev->client; status = wait_for_completion_interruptible_timeout( - &pin_infos->irq_detection, - timeout); + &tpm_dev->irq_detection, + timeout); if (status > 0) - enable_irq(gpio_to_irq(pin_infos->io_serirq)); - gpio_direction_input(pin_infos->io_serirq); + enable_irq(client->irq); return status; } /* wait_for_interrupt_serirq_timeout() */ @@ -209,15 +212,15 @@ static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition, unsigned long timeout) { int status = 2; - struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); status = _wait_for_interrupt_serirq_timeout(chip, timeout); if (!status) { status = -EBUSY; } else { - clear_interruption(client); + clear_interruption(tpm_dev); if (condition) status = 1; } @@ -230,13 +233,13 @@ static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition, */ static void tpm_stm_i2c_cancel(struct tpm_chip *chip) { - struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; u8 data; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); data = TPM_STS_COMMAND_READY; - I2C_WRITE_DATA(client, TPM_STS, &data, 1); + I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); if (chip->vendor.irq) wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a); } /* tpm_stm_i2c_cancel() */ @@ -248,12 +251,12 @@ static void tpm_stm_i2c_cancel(struct tpm_chip *chip) */ static u8 tpm_stm_i2c_status(struct tpm_chip *chip) { - struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; u8 data; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - I2C_READ_DATA(client, TPM_STS, &data, 1); + I2C_READ_DATA(tpm_dev, TPM_STS, &data, 1); return data; } /* tpm_stm_i2c_status() */ @@ -265,13 +268,13 @@ static u8 tpm_stm_i2c_status(struct tpm_chip *chip) */ static int check_locality(struct tpm_chip *chip) { - struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; u8 data; u8 status; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - status = I2C_READ_DATA(client, TPM_ACCESS, &data, 1); + status = I2C_READ_DATA(tpm_dev, TPM_ACCESS, &data, 1); if (status && (data & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) @@ -290,16 +293,16 @@ static int request_locality(struct tpm_chip *chip) { unsigned long stop; long rc; - struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; u8 data; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); if (check_locality(chip) == chip->vendor.locality) return chip->vendor.locality; data = TPM_ACCESS_REQUEST_USE; - rc = I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1); + rc = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); if (rc < 0) goto end; @@ -328,13 +331,13 @@ end: */ static void release_locality(struct tpm_chip *chip) { - struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; u8 data; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); data = TPM_ACCESS_ACTIVE_LOCALITY; - I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1); + I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); } /* @@ -347,19 +350,20 @@ static int get_burstcount(struct tpm_chip *chip) unsigned long stop; int burstcnt, status; u8 tpm_reg, temp; + struct tpm_stm_dev *tpm_dev; - struct i2c_client *client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); stop = jiffies + chip->vendor.timeout_d; do { tpm_reg = TPM_STS + 1; - status = I2C_READ_DATA(client, tpm_reg, &temp, 1); + status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1); if (status < 0) goto end; tpm_reg = tpm_reg + 1; burstcnt = temp; - status = I2C_READ_DATA(client, tpm_reg, &temp, 1); + status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1); if (status < 0) goto end; @@ -416,9 +420,9 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) { int size = 0, burstcnt, len; - struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); while (size < count && wait_for_stat(chip, @@ -430,7 +434,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) if (burstcnt < 0) return burstcnt; len = min_t(int, burstcnt, count - size); - I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len); + I2C_READ_DATA(tpm_dev, TPM_DATA_FIFO, buf + size, len); size += len; } return size; @@ -446,14 +450,14 @@ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) { struct tpm_chip *chip = dev_id; struct i2c_client *client; - struct st33zp24_platform_data *pin_infos; + struct tpm_stm_dev *tpm_dev; disable_irq_nosync(irq); - client = (struct i2c_client *)TPM_VPRIV(chip); - pin_infos = client->dev.platform_data; + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + client = tpm_dev->client; - complete(&pin_infos->irq_detection); + complete(&tpm_dev->irq_detection); return IRQ_HANDLED; } /* tpm_ioserirq_handler() */ @@ -475,13 +479,15 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, int ret; u8 data; struct i2c_client *client; + struct tpm_stm_dev *tpm_dev; if (chip == NULL) return -EBUSY; if (len < TPM_HEADER_SIZE) return -EBUSY; - client = (struct i2c_client *)TPM_VPRIV(chip); + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + client = tpm_dev->client; client->flags = 0; @@ -505,7 +511,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, if (burstcnt < 0) return burstcnt; size = min_t(int, len - i - 1, burstcnt); - ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf + i, size); + ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + i, size); if (ret < 0) goto out_err; @@ -518,7 +524,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, goto out_err; } - ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf + len - 1, 1); + ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + len - 1, 1); if (ret < 0) goto out_err; @@ -529,7 +535,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, } data = TPM_STS_GO; - I2C_WRITE_DATA(client, TPM_STS, &data, 1); + I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); return len; out_err: @@ -623,6 +629,7 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) u8 intmask; struct tpm_chip *chip; struct st33zp24_platform_data *platform_data; + struct tpm_stm_dev *tpm_dev; if (client == NULL) { pr_info("%s: i2c client is NULL. Device not accessible.\n", @@ -637,11 +644,11 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) goto end; } - chip = tpm_register_hardware(&client->dev, &st_i2c_tpm); - if (!chip) { - dev_info(&client->dev, "fail chip\n"); - err = -ENODEV; - goto end; + tpm_dev = devm_kzalloc(&client->dev, sizeof(struct tpm_stm_dev), + GFP_KERNEL); + if (!tpm_dev) { + err = -ENOMEM; + goto _tpm_clean_answer; } platform_data = client->dev.platform_data; @@ -652,20 +659,14 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) goto _tpm_clean_answer; } - platform_data->tpm_i2c_buffer[0] = - kmalloc(TPM_BUFSIZE, GFP_KERNEL); - if (platform_data->tpm_i2c_buffer[0] == NULL) { - err = -ENOMEM; - goto _tpm_clean_answer; - } - platform_data->tpm_i2c_buffer[1] = - kmalloc(TPM_BUFSIZE, GFP_KERNEL); - if (platform_data->tpm_i2c_buffer[1] == NULL) { - err = -ENOMEM; - goto _tpm_clean_response1; + chip = tpm_register_hardware(&client->dev, &st_i2c_tpm); + if (!chip) { + dev_info(&client->dev, "fail chip\n"); + return -ENODEV; } - TPM_VPRIV(chip) = client; + TPM_VPRIV(chip) = tpm_dev; + tpm_dev->client = client; chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); @@ -682,16 +683,16 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) } if (interrupts) { - init_completion(&platform_data->irq_detection); + init_completion(&tpm_dev->irq_detection); if (request_locality(chip) != LOCALITY0) { err = -ENODEV; - goto _tpm_clean_response2; + goto _tpm_clean_answer; } err = gpio_request(platform_data->io_serirq, "TPM IO_SERIRQ"); if (err) goto _gpio_init2; - clear_interruption(client); + clear_interruption(tpm_dev); err = request_irq(gpio_to_irq(platform_data->io_serirq), &tpm_ioserirq_handler, IRQF_TRIGGER_HIGH, @@ -702,7 +703,7 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) goto _irq_set; } - err = I2C_READ_DATA(client, TPM_INT_ENABLE, &intmask, 1); + err = I2C_READ_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); if (err < 0) goto _irq_set; @@ -713,16 +714,17 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) | TPM_INTF_STS_VALID_INT | TPM_INTF_DATA_AVAIL_INT; - err = I2C_WRITE_DATA(client, TPM_INT_ENABLE, &intmask, 1); + err = I2C_WRITE_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); if (err < 0) goto _irq_set; intmask = TPM_GLOBAL_INT_ENABLE; - err = I2C_WRITE_DATA(client, (TPM_INT_ENABLE + 3), &intmask, 1); + err = I2C_WRITE_DATA(tpm_dev, (TPM_INT_ENABLE + 3), + &intmask, 1); if (err < 0) goto _irq_set; - err = I2C_READ_DATA(client, TPM_INT_STATUS, &intmask, 1); + err = I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &intmask, 1); if (err < 0) goto _irq_set; @@ -744,12 +746,6 @@ _gpio_init2: _gpio_init1: if (power_mgt) gpio_free(platform_data->io_lpcpd); -_tpm_clean_response2: - kzfree(platform_data->tpm_i2c_buffer[1]); - platform_data->tpm_i2c_buffer[1] = NULL; -_tpm_clean_response1: - kzfree(platform_data->tpm_i2c_buffer[0]); - platform_data->tpm_i2c_buffer[0] = NULL; _tpm_clean_answer: tpm_remove_hardware(chip->dev); end: @@ -765,28 +761,12 @@ end: */ static int tpm_st33_i2c_remove(struct i2c_client *client) { - struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client); - struct st33zp24_platform_data *pin_infos = - ((struct i2c_client *)TPM_VPRIV(chip))->dev.platform_data; - - if (pin_infos != NULL) { - free_irq(pin_infos->io_serirq, chip); - - gpio_free(pin_infos->io_serirq); - gpio_free(pin_infos->io_lpcpd); + struct tpm_chip *chip = + (struct tpm_chip *) i2c_get_clientdata(client); + if (chip) tpm_remove_hardware(chip->dev); - if (pin_infos->tpm_i2c_buffer[1] != NULL) { - kzfree(pin_infos->tpm_i2c_buffer[1]); - pin_infos->tpm_i2c_buffer[1] = NULL; - } - if (pin_infos->tpm_i2c_buffer[0] != NULL) { - kzfree(pin_infos->tpm_i2c_buffer[0]); - pin_infos->tpm_i2c_buffer[0] = NULL; - } - } - return 0; } diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.h b/include/linux/platform_data/tpm_i2c_stm_st33.h similarity index 81% rename from drivers/char/tpm/tpm_i2c_stm_st33.h rename to include/linux/platform_data/tpm_i2c_stm_st33.h index 3041271342eb..88f9cb18113a 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.h +++ b/include/linux/platform_data/tpm_i2c_stm_st33.h @@ -12,9 +12,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . * * STMicroelectronics version 1.2.0, Copyright (C) 2010 * STMicroelectronics comes with ABSOLUTELY NO WARRANTY. @@ -30,15 +29,12 @@ #ifndef __STM_ST33_TPM_I2C_MAIN_H__ #define __STM_ST33_TPM_I2C_MAIN_H__ + #define TPM_ST33_I2C "st33zp24_i2c" struct st33zp24_platform_data { int io_serirq; int io_lpcpd; - struct i2c_client *client; - u8 *tpm_i2c_buffer[2]; /* 0 Request 1 Response */ - struct completion irq_detection; - struct mutex lock; }; #endif /* __STM_ST33_TPM_I2C_MAIN_H__ */ From 76182b6b008b694d095aec1e2eb6c07fae787128 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:52 +0100 Subject: [PATCH 16/64] tpm/tpm_i2c_stm_st33: Remove reference to io_serirq The serirq gpio pin is used only as interrupt. After driver initialization, the serirq signal is always used through interrupt and never with gpio kernel API. The irq can then be initialized during the platform_data definition within the client->irq pin. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 13 +++---------- include/linux/platform_data/tpm_i2c_stm_st33.h | 1 - 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 4f725386385f..728611638d1c 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -103,7 +103,6 @@ struct tpm_stm_dev { struct completion irq_detection; struct tpm_chip *chip; u8 buf[TPM_BUFSIZE + 1]; - int io_serirq; int io_lpcpd; }; @@ -688,18 +687,15 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) err = -ENODEV; goto _tpm_clean_answer; } - err = gpio_request(platform_data->io_serirq, "TPM IO_SERIRQ"); - if (err) - goto _gpio_init2; clear_interruption(tpm_dev); - err = request_irq(gpio_to_irq(platform_data->io_serirq), + err = request_irq(client->irq, &tpm_ioserirq_handler, IRQF_TRIGGER_HIGH, "TPM SERIRQ management", chip); if (err < 0) { dev_err(chip->dev , "TPM SERIRQ signals %d not available\n", - gpio_to_irq(platform_data->io_serirq)); + client->irq); goto _irq_set; } @@ -739,10 +735,7 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) dev_info(chip->dev, "TPM I2C Initialized\n"); return 0; _irq_set: - free_irq(gpio_to_irq(platform_data->io_serirq), (void *)chip); -_gpio_init2: - if (interrupts) - gpio_free(platform_data->io_serirq); + free_irq(client->irq, (void *)chip); _gpio_init1: if (power_mgt) gpio_free(platform_data->io_lpcpd); diff --git a/include/linux/platform_data/tpm_i2c_stm_st33.h b/include/linux/platform_data/tpm_i2c_stm_st33.h index 88f9cb18113a..85775cf5f9a5 100644 --- a/include/linux/platform_data/tpm_i2c_stm_st33.h +++ b/include/linux/platform_data/tpm_i2c_stm_st33.h @@ -33,7 +33,6 @@ #define TPM_ST33_I2C "st33zp24_i2c" struct st33zp24_platform_data { - int io_serirq; int io_lpcpd; }; From ca16b7671365d71f29973ca6931be821780f592e Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:53 +0100 Subject: [PATCH 17/64] tpm/tpm_i2c_stm_st33: Replace err/rc/ret by ret for a function return code Some functions return err, rc or ret for a status code. Return ret instead for all of them. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 61 ++++++++++++++--------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 728611638d1c..d425fa1a25bc 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -291,7 +291,7 @@ static int check_locality(struct tpm_chip *chip) static int request_locality(struct tpm_chip *chip) { unsigned long stop; - long rc; + long ret; struct tpm_stm_dev *tpm_dev; u8 data; @@ -301,15 +301,15 @@ static int request_locality(struct tpm_chip *chip) return chip->vendor.locality; data = TPM_ACCESS_REQUEST_USE; - rc = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); - if (rc < 0) + ret = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); + if (ret < 0) goto end; if (chip->vendor.irq) { - rc = wait_for_serirq_timeout(chip, (check_locality + ret = wait_for_serirq_timeout(chip, (check_locality (chip) >= 0), chip->vendor.timeout_a); - if (rc > 0) + if (ret > 0) return chip->vendor.locality; } else { stop = jiffies + chip->vendor.timeout_a; @@ -319,9 +319,9 @@ static int request_locality(struct tpm_chip *chip) msleep(TPM_TIMEOUT); } while (time_before(jiffies, stop)); } - rc = -EACCES; + ret = -EACCES; end: - return rc; + return ret; } /* request_locality() */ /* @@ -388,14 +388,14 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, wait_queue_head_t *queue) { unsigned long stop; - long rc; + long ret; u8 status; if (chip->vendor.irq) { - rc = wait_for_serirq_timeout(chip, ((tpm_stm_i2c_status + ret = wait_for_serirq_timeout(chip, ((tpm_stm_i2c_status (chip) & mask) == mask), timeout); - if (rc > 0) + if (ret > 0) return 0; } else { stop = jiffies + timeout; @@ -624,7 +624,7 @@ MODULE_PARM_DESC(power_mgt, "Power Management"); static int tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int err; + int ret; u8 intmask; struct tpm_chip *chip; struct st33zp24_platform_data *platform_data; @@ -633,20 +633,20 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) if (client == NULL) { pr_info("%s: i2c client is NULL. Device not accessible.\n", __func__); - err = -ENODEV; + ret = -ENODEV; goto end; } if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_info(&client->dev, "client not i2c capable\n"); - err = -ENODEV; + ret = -ENODEV; goto end; } tpm_dev = devm_kzalloc(&client->dev, sizeof(struct tpm_stm_dev), GFP_KERNEL); if (!tpm_dev) { - err = -ENOMEM; + ret = -ENOMEM; goto _tpm_clean_answer; } @@ -654,7 +654,7 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) if (!platform_data) { dev_info(&client->dev, "chip not available\n"); - err = -ENODEV; + ret = -ENODEV; goto _tpm_clean_answer; } @@ -675,8 +675,8 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) chip->vendor.locality = LOCALITY0; if (power_mgt) { - err = gpio_request(platform_data->io_lpcpd, "TPM IO_LPCPD"); - if (err) + ret = gpio_request(platform_data->io_lpcpd, "TPM IO_LPCPD"); + if (ret) goto _gpio_init1; gpio_set_value(platform_data->io_lpcpd, 1); } @@ -684,23 +684,23 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) if (interrupts) { init_completion(&tpm_dev->irq_detection); if (request_locality(chip) != LOCALITY0) { - err = -ENODEV; + ret = -ENODEV; goto _tpm_clean_answer; } clear_interruption(tpm_dev); - err = request_irq(client->irq, + ret = request_irq(client->irq, &tpm_ioserirq_handler, IRQF_TRIGGER_HIGH, "TPM SERIRQ management", chip); - if (err < 0) { + if (ret < 0) { dev_err(chip->dev , "TPM SERIRQ signals %d not available\n", client->irq); goto _irq_set; } - err = I2C_READ_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); - if (err < 0) + ret = I2C_READ_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); + if (ret < 0) goto _irq_set; intmask |= TPM_INTF_CMD_READY_INT @@ -710,18 +710,18 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) | TPM_INTF_STS_VALID_INT | TPM_INTF_DATA_AVAIL_INT; - err = I2C_WRITE_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); - if (err < 0) + ret = I2C_WRITE_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); + if (ret < 0) goto _irq_set; intmask = TPM_GLOBAL_INT_ENABLE; - err = I2C_WRITE_DATA(tpm_dev, (TPM_INT_ENABLE + 3), + ret = I2C_WRITE_DATA(tpm_dev, (TPM_INT_ENABLE + 3), &intmask, 1); - if (err < 0) + if (ret < 0) goto _irq_set; - err = I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &intmask, 1); - if (err < 0) + ret = I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &intmask, 1); + if (ret < 0) goto _irq_set; chip->vendor.irq = interrupts; @@ -743,7 +743,7 @@ _tpm_clean_answer: tpm_remove_hardware(chip->dev); end: pr_info("TPM I2C initialisation fail\n"); - return err; + return ret; } /* @@ -779,7 +779,6 @@ static int tpm_st33_i2c_pm_suspend(struct device *dev) gpio_set_value(pin_infos->io_lpcpd, 0); else ret = tpm_pm_suspend(dev); - return ret; } /* tpm_st33_i2c_suspend() */ @@ -807,7 +806,7 @@ static int tpm_st33_i2c_pm_resume(struct device *dev) tpm_do_selftest(chip); } return ret; -} /* tpm_st33_i2c_pm_resume() */ +} /* tpm_st33_i2c_pm_resume() */ #endif static const struct i2c_device_id tpm_st33_i2c_id[] = { From 875edad528cf29b382e82837e652e997aec16c49 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:54 +0100 Subject: [PATCH 18/64] tpm/tpm_i2c_stm_st33: Replace tpm_st33_* function with tpm_stm_* For sanity, replace every tpm_st33_* with tpm_stm_* Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 50 ++++++++++++++--------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index d425fa1a25bc..7f036630e87a 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -224,7 +224,7 @@ static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition, status = 1; } return status; -} +} /* wait_for_serirq_timeout() */ /* * tpm_stm_i2c_cancel, cancel is not implemented. @@ -241,7 +241,7 @@ static void tpm_stm_i2c_cancel(struct tpm_chip *chip) I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); if (chip->vendor.irq) wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a); -} /* tpm_stm_i2c_cancel() */ +} /* tpm_stm_i2c_cancel() */ /* * tpm_stm_spi_status return the TPM_STS register @@ -257,7 +257,7 @@ static u8 tpm_stm_i2c_status(struct tpm_chip *chip) I2C_READ_DATA(tpm_dev, TPM_STS, &data, 1); return data; -} /* tpm_stm_i2c_status() */ +} /* tpm_stm_i2c_status() */ /* @@ -591,7 +591,7 @@ out: return size; } -static bool tpm_st33_i2c_req_canceled(struct tpm_chip *chip, u8 status) +static bool tpm_stm_i2c_req_canceled(struct tpm_chip *chip, u8 status) { return (status == TPM_STS_COMMAND_READY); } @@ -603,7 +603,7 @@ static const struct tpm_class_ops st_i2c_tpm = { .status = tpm_stm_i2c_status, .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, - .req_canceled = tpm_st33_i2c_req_canceled, + .req_canceled = tpm_stm_i2c_req_canceled, }; static int interrupts; @@ -615,14 +615,14 @@ module_param(power_mgt, int, 0444); MODULE_PARM_DESC(power_mgt, "Power Management"); /* - * tpm_st33_i2c_probe initialize the TPM device + * tpm_stm_i2c_probe initialize the TPM device * @param: client, the i2c_client drescription (TPM I2C description). * @param: id, the i2c_device_id struct. * @return: 0 in case of success. * -1 in other case. */ static int -tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; u8 intmask; @@ -747,12 +747,12 @@ end: } /* - * tpm_st33_i2c_remove remove the TPM device + * tpm_stm_i2c_remove remove the TPM device * @param: client, the i2c_client drescription (TPM I2C description). clear_bit(0, &chip->is_open); * @return: 0 in case of success. */ -static int tpm_st33_i2c_remove(struct i2c_client *client) +static int tpm_stm_i2c_remove(struct i2c_client *client) { struct tpm_chip *chip = (struct tpm_chip *) i2c_get_clientdata(client); @@ -765,12 +765,12 @@ static int tpm_st33_i2c_remove(struct i2c_client *client) #ifdef CONFIG_PM_SLEEP /* - * tpm_st33_i2c_pm_suspend suspend the TPM device + * tpm_stm_i2c_pm_suspend suspend the TPM device * @param: client, the i2c_client drescription (TPM I2C description). * @param: mesg, the power management message. * @return: 0 in case of success. */ -static int tpm_st33_i2c_pm_suspend(struct device *dev) +static int tpm_stm_i2c_pm_suspend(struct device *dev) { struct st33zp24_platform_data *pin_infos = dev->platform_data; int ret = 0; @@ -780,14 +780,14 @@ static int tpm_st33_i2c_pm_suspend(struct device *dev) else ret = tpm_pm_suspend(dev); return ret; -} /* tpm_st33_i2c_suspend() */ +} /* tpm_stm_i2c_suspend() */ /* - * tpm_st33_i2c_pm_resume resume the TPM device + * tpm_stm_i2c_pm_resume resume the TPM device * @param: client, the i2c_client drescription (TPM I2C description). * @return: 0 in case of success. */ -static int tpm_st33_i2c_pm_resume(struct device *dev) +static int tpm_stm_i2c_pm_resume(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); struct st33zp24_platform_data *pin_infos = dev->platform_data; @@ -806,28 +806,28 @@ static int tpm_st33_i2c_pm_resume(struct device *dev) tpm_do_selftest(chip); } return ret; -} /* tpm_st33_i2c_pm_resume() */ +} /* tpm_stm_i2c_pm_resume() */ #endif -static const struct i2c_device_id tpm_st33_i2c_id[] = { +static const struct i2c_device_id tpm_stm_i2c_id[] = { {TPM_ST33_I2C, 0}, {} }; -MODULE_DEVICE_TABLE(i2c, tpm_st33_i2c_id); -static SIMPLE_DEV_PM_OPS(tpm_st33_i2c_ops, tpm_st33_i2c_pm_suspend, - tpm_st33_i2c_pm_resume); -static struct i2c_driver tpm_st33_i2c_driver = { +MODULE_DEVICE_TABLE(i2c, tpm_stm_i2c_id); +static SIMPLE_DEV_PM_OPS(tpm_stm_i2c_ops, tpm_stm_i2c_pm_suspend, + tpm_stm_i2c_pm_resume); +static struct i2c_driver tpm_stm_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = TPM_ST33_I2C, - .pm = &tpm_st33_i2c_ops, + .pm = &tpm_stm_i2c_ops, }, - .probe = tpm_st33_i2c_probe, - .remove = tpm_st33_i2c_remove, - .id_table = tpm_st33_i2c_id + .probe = tpm_stm_i2c_probe, + .remove = tpm_stm_i2c_remove, + .id_table = tpm_stm_i2c_id }; -module_i2c_driver(tpm_st33_i2c_driver); +module_i2c_driver(tpm_stm_i2c_driver); MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)"); MODULE_DESCRIPTION("STM TPM I2C ST33 Driver"); From c36b1b2d1fa5b24e21482f33694a8ca0c653ecd9 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:55 +0100 Subject: [PATCH 19/64] tpm/tpm_i2c_stm_st33: Add devicetree structure Add tpm_stm_st33_i2c dts structure keeping backward compatibility with static platform_data support as well. In the mean time to easy this update and to make it much simpler, we: - Moved all gpio_request to devm_gpio_request_one primitive - Moved request_irq to devm_request_irq Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 166 +++++++++++++++++++--------- 1 file changed, 116 insertions(+), 50 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 7f036630e87a..3f722630ff92 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include #include "tpm.h" @@ -606,13 +608,81 @@ static const struct tpm_class_ops st_i2c_tpm = { .req_canceled = tpm_stm_i2c_req_canceled, }; -static int interrupts; -module_param(interrupts, int, 0444); -MODULE_PARM_DESC(interrupts, "Enable interrupts"); +#ifdef CONFIG_OF +static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip) +{ + struct device_node *pp; + struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + struct i2c_client *client = tpm_dev->client; -static int power_mgt = 1; -module_param(power_mgt, int, 0444); -MODULE_PARM_DESC(power_mgt, "Power Management"); + int gpio; + int ret; + + pp = client->dev.of_node; + if (!pp) { + dev_err(chip->dev, "No platform data\n"); + return -ENODEV; + } + + /* Get GPIO from device tree */ + gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0); + if (gpio < 0) { + dev_err(chip->dev, "Failed to retrieve lpcpd-gpios from dts.\n"); + tpm_dev->io_lpcpd = -1; + /* + * lpcpd pin is not specified. This is not an issue as + * power management can be also managed by TPM specific + * commands. So leave with a success status code. + */ + return 0; + } + /* GPIO request and configuration */ + ret = devm_gpio_request_one(&client->dev, gpio, + GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD"); + if (ret) { + dev_err(chip->dev, "Failed to request lpcpd pin\n"); + return -ENODEV; + } + tpm_dev->io_lpcpd = gpio; + + return 0; +} +#else +static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip) +{ + return -ENODEV; +} +#endif + +static int tpm_stm_i2c_request_resources(struct i2c_client *client, + struct tpm_chip *chip) +{ + struct st33zp24_platform_data *pdata; + struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + int ret; + + pdata = client->dev.platform_data; + if (pdata == NULL) { + pr_err("No platform data\n"); + return -EINVAL; + } + + /* store for late use */ + tpm_dev->io_lpcpd = pdata->io_lpcpd; + + if (gpio_is_valid(pdata->io_lpcpd)) { + ret = devm_gpio_request_one(&client->dev, + pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH, + "TPM IO_LPCPD"); + if (ret) { + dev_err(chip->dev, "%s : reset gpio_request failed\n", + __FILE__); + return ret; + } + } + + return 0; +} /* * tpm_stm_i2c_probe initialize the TPM device @@ -633,30 +703,18 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) if (client == NULL) { pr_info("%s: i2c client is NULL. Device not accessible.\n", __func__); - ret = -ENODEV; - goto end; + return -ENODEV; } if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_info(&client->dev, "client not i2c capable\n"); - ret = -ENODEV; - goto end; + return -ENODEV; } tpm_dev = devm_kzalloc(&client->dev, sizeof(struct tpm_stm_dev), GFP_KERNEL); - if (!tpm_dev) { - ret = -ENOMEM; - goto _tpm_clean_answer; - } - - platform_data = client->dev.platform_data; - - if (!platform_data) { - dev_info(&client->dev, "chip not available\n"); - ret = -ENODEV; - goto _tpm_clean_answer; - } + if (!tpm_dev) + return -ENOMEM; chip = tpm_register_hardware(&client->dev, &st_i2c_tpm); if (!chip) { @@ -667,6 +725,17 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) TPM_VPRIV(chip) = tpm_dev; tpm_dev->client = client; + platform_data = client->dev.platform_data; + if (!platform_data && client->dev.of_node) { + ret = tpm_stm_i2c_of_request_resources(chip); + if (ret) + goto _tpm_clean_answer; + } else if (platform_data) { + ret = tpm_stm_i2c_request_resources(client, chip); + if (ret) + goto _tpm_clean_answer; + } + chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); @@ -674,14 +743,7 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) chip->vendor.locality = LOCALITY0; - if (power_mgt) { - ret = gpio_request(platform_data->io_lpcpd, "TPM IO_LPCPD"); - if (ret) - goto _gpio_init1; - gpio_set_value(platform_data->io_lpcpd, 1); - } - - if (interrupts) { + if (client->irq) { init_completion(&tpm_dev->irq_detection); if (request_locality(chip) != LOCALITY0) { ret = -ENODEV; @@ -689,19 +751,19 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) } clear_interruption(tpm_dev); - ret = request_irq(client->irq, - &tpm_ioserirq_handler, + ret = devm_request_irq(&client->dev, client->irq, + tpm_ioserirq_handler, IRQF_TRIGGER_HIGH, "TPM SERIRQ management", chip); if (ret < 0) { dev_err(chip->dev , "TPM SERIRQ signals %d not available\n", client->irq); - goto _irq_set; + goto _tpm_clean_answer; } ret = I2C_READ_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); if (ret < 0) - goto _irq_set; + goto _tpm_clean_answer; intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_FIFO_AVALAIBLE_INT @@ -712,19 +774,19 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) ret = I2C_WRITE_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); if (ret < 0) - goto _irq_set; + goto _tpm_clean_answer; intmask = TPM_GLOBAL_INT_ENABLE; ret = I2C_WRITE_DATA(tpm_dev, (TPM_INT_ENABLE + 3), &intmask, 1); if (ret < 0) - goto _irq_set; + goto _tpm_clean_answer; ret = I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &intmask, 1); if (ret < 0) - goto _irq_set; + goto _tpm_clean_answer; - chip->vendor.irq = interrupts; + chip->vendor.irq = client->irq; tpm_gen_interrupt(chip); } @@ -734,15 +796,9 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) dev_info(chip->dev, "TPM I2C Initialized\n"); return 0; -_irq_set: - free_irq(client->irq, (void *)chip); -_gpio_init1: - if (power_mgt) - gpio_free(platform_data->io_lpcpd); _tpm_clean_answer: tpm_remove_hardware(chip->dev); -end: - pr_info("TPM I2C initialisation fail\n"); + dev_info(chip->dev, "TPM I2C initialisation fail\n"); return ret; } @@ -775,7 +831,7 @@ static int tpm_stm_i2c_pm_suspend(struct device *dev) struct st33zp24_platform_data *pin_infos = dev->platform_data; int ret = 0; - if (power_mgt) + if (gpio_is_valid(pin_infos->io_lpcpd)) gpio_set_value(pin_infos->io_lpcpd, 0); else ret = tpm_pm_suspend(dev); @@ -794,7 +850,7 @@ static int tpm_stm_i2c_pm_resume(struct device *dev) int ret = 0; - if (power_mgt) { + if (gpio_is_valid(pin_infos->io_lpcpd)) { gpio_set_value(pin_infos->io_lpcpd, 1); ret = wait_for_serirq_timeout(chip, (chip->ops->status(chip) & @@ -813,14 +869,24 @@ static const struct i2c_device_id tpm_stm_i2c_id[] = { {TPM_ST33_I2C, 0}, {} }; + +#ifdef CONFIG_OF +static const struct of_device_id of_st33zp24_i2c_match[] = { + { .compatible = "st,st33zp24-i2c", }, + {} +}; +MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match); +#endif + MODULE_DEVICE_TABLE(i2c, tpm_stm_i2c_id); static SIMPLE_DEV_PM_OPS(tpm_stm_i2c_ops, tpm_stm_i2c_pm_suspend, tpm_stm_i2c_pm_resume); static struct i2c_driver tpm_stm_i2c_driver = { .driver = { - .owner = THIS_MODULE, - .name = TPM_ST33_I2C, - .pm = &tpm_stm_i2c_ops, + .owner = THIS_MODULE, + .name = TPM_ST33_I2C, + .pm = &tpm_stm_i2c_ops, + .of_match_table = of_match_ptr(of_st33zp24_i2c_match), }, .probe = tpm_stm_i2c_probe, .remove = tpm_stm_i2c_remove, From e8f6f3b4d69956f66bba14a4d33aadf1fb209050 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:56 +0100 Subject: [PATCH 20/64] tpm/tpm_i2c_stm_st33/dts/st33zp24_i2c: Add DTS Documentation st33zp24 tpm can be seen as a trivial i2c device as other i2c tpm. However several other properties needs to be documented such as lpcpd. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- .../bindings/security/tpm/st33zp24.txt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/security/tpm/st33zp24.txt diff --git a/Documentation/devicetree/bindings/security/tpm/st33zp24.txt b/Documentation/devicetree/bindings/security/tpm/st33zp24.txt new file mode 100644 index 000000000000..0a7361dae65f --- /dev/null +++ b/Documentation/devicetree/bindings/security/tpm/st33zp24.txt @@ -0,0 +1,36 @@ +* STMicroelectronics SAS. ST33ZP24 TPM SoC + +Required properties: +- compatible: Should be "st,st33zp24-i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus + +Optional ST33ZP24 Properties: +- interrupt-parent: phandle for the interrupt gpio controller +- interrupts: GPIO interrupt to which the chip is connected +- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state. +If set, power must be present when the platform is going into sleep/hibernate mode. + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBoard xM with ST33ZP24 on I2C2): + +&i2c2 { + + status = "okay"; + + st33zp24: st33zp24@13 { + + compatible = "st,st33zp24-i2c"; + + reg = <0x013>; + clock-frequency = <400000>; + + interrupt-parent = <&gpio5>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + + lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>; + }; +}; From 8dcd19874f31b7a806a2a2b129e94882918c3aaf Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:57 +0100 Subject: [PATCH 21/64] tpm/tpm_i2c_stm_st33: Few code cleanup Cleanup code indentation, braces, test variable when NULL. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 3f722630ff92..a444cd3cb17d 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -26,7 +26,7 @@ * * @Synopsis: * 09/15/2010: First shot driver tpm_tis driver for - lpc is used as model. + * lpc is used as model. */ #include @@ -393,7 +393,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, long ret; u8 status; - if (chip->vendor.irq) { + if (chip->vendor.irq) { ret = wait_for_serirq_timeout(chip, ((tpm_stm_i2c_status (chip) & mask) == mask), timeout); @@ -429,8 +429,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) wait_for_stat(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, chip->vendor.timeout_c, - &chip->vendor.read_queue) - == 0) { + &chip->vendor.read_queue) == 0) { burstcnt = get_burstcount(chip); if (burstcnt < 0) return burstcnt; @@ -482,7 +481,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, struct i2c_client *client; struct tpm_stm_dev *tpm_dev; - if (chip == NULL) + if (!chip) return -EBUSY; if (len < TPM_HEADER_SIZE) return -EBUSY; @@ -559,7 +558,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, int size = 0; int expected; - if (chip == NULL) + if (!chip) return -EBUSY; if (count < TPM_HEADER_SIZE) { @@ -580,7 +579,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, } size += recv_data(chip, &buf[TPM_HEADER_SIZE], - expected - TPM_HEADER_SIZE); + expected - TPM_HEADER_SIZE); if (size < expected) { dev_err(chip->dev, "Unable to read remainder of result\n"); size = -ETIME; @@ -662,9 +661,9 @@ static int tpm_stm_i2c_request_resources(struct i2c_client *client, int ret; pdata = client->dev.platform_data; - if (pdata == NULL) { - pr_err("No platform data\n"); - return -EINVAL; + if (!pdata) { + dev_err(chip->dev, "No platform data\n"); + return -ENODEV; } /* store for late use */ @@ -695,13 +694,13 @@ static int tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; - u8 intmask; + u8 intmask = 0; struct tpm_chip *chip; struct st33zp24_platform_data *platform_data; struct tpm_stm_dev *tpm_dev; - if (client == NULL) { - pr_info("%s: i2c client is NULL. Device not accessible.\n", + if (!client) { + dev_info(&client->dev, "%s: i2c client is NULL. Device not accessible.\n", __func__); return -ENODEV; } @@ -805,7 +804,7 @@ _tpm_clean_answer: /* * tpm_stm_i2c_remove remove the TPM device * @param: client, the i2c_client drescription (TPM I2C description). - clear_bit(0, &chip->is_open); + * clear_bit(0, &chip->is_open); * @return: 0 in case of success. */ static int tpm_stm_i2c_remove(struct i2c_client *client) @@ -835,6 +834,7 @@ static int tpm_stm_i2c_pm_suspend(struct device *dev) gpio_set_value(pin_infos->io_lpcpd, 0); else ret = tpm_pm_suspend(dev); + return ret; } /* tpm_stm_i2c_suspend() */ @@ -869,6 +869,7 @@ static const struct i2c_device_id tpm_stm_i2c_id[] = { {TPM_ST33_I2C, 0}, {} }; +MODULE_DEVICE_TABLE(i2c, tpm_stm_i2c_id); #ifdef CONFIG_OF static const struct of_device_id of_st33zp24_i2c_match[] = { @@ -878,7 +879,6 @@ static const struct of_device_id of_st33zp24_i2c_match[] = { MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match); #endif -MODULE_DEVICE_TABLE(i2c, tpm_stm_i2c_id); static SIMPLE_DEV_PM_OPS(tpm_stm_i2c_ops, tpm_stm_i2c_pm_suspend, tpm_stm_i2c_pm_resume); static struct i2c_driver tpm_stm_i2c_driver = { @@ -887,7 +887,7 @@ static struct i2c_driver tpm_stm_i2c_driver = { .name = TPM_ST33_I2C, .pm = &tpm_stm_i2c_ops, .of_match_table = of_match_ptr(of_st33zp24_i2c_match), - }, + }, .probe = tpm_stm_i2c_probe, .remove = tpm_stm_i2c_remove, .id_table = tpm_stm_i2c_id From c3804b8cdbd2abb50cf87318b13660dff46b7fe8 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:58 +0100 Subject: [PATCH 22/64] tpm/tpm_i2c_stm_st33: Interrupt management improvement Improve the irq management by using a new function wait_for_stat. Instead of using a completion struct, we rely on the waitqueue read_queue and int_queue from chip->vendor field. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 197 +++++++++++++++------------- 1 file changed, 109 insertions(+), 88 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index a444cd3cb17d..eb0244a2ec9d 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -102,9 +103,9 @@ enum tis_defaults { struct tpm_stm_dev { struct i2c_client *client; - struct completion irq_detection; struct tpm_chip *chip; u8 buf[TPM_BUFSIZE + 1]; + u32 intrs; int io_lpcpd; }; @@ -174,60 +175,17 @@ static int read8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register, * clear_interruption * clear the TPM interrupt register. * @param: tpm, the chip description + * @return: the TPM_INT_STATUS value */ -static void clear_interruption(struct tpm_stm_dev *tpm_dev) +static u8 clear_interruption(struct tpm_stm_dev *tpm_dev) { u8 interrupt; I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); I2C_WRITE_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); - I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1); + return interrupt; } /* clear_interruption() */ -/* - * _wait_for_interrupt_serirq_timeout - * @param: tpm, the chip description - * @param: timeout, the timeout of the interrupt - * @return: the status of the interruption. - */ -static long _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip, - unsigned long timeout) -{ - long status; - struct i2c_client *client; - struct tpm_stm_dev *tpm_dev; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - client = tpm_dev->client; - - status = wait_for_completion_interruptible_timeout( - &tpm_dev->irq_detection, - timeout); - if (status > 0) - enable_irq(client->irq); - - return status; -} /* wait_for_interrupt_serirq_timeout() */ - -static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition, - unsigned long timeout) -{ - int status = 2; - struct tpm_stm_dev *tpm_dev; - - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - - status = _wait_for_interrupt_serirq_timeout(chip, timeout); - if (!status) { - status = -EBUSY; - } else { - clear_interruption(tpm_dev); - if (condition) - status = 1; - } - return status; -} /* wait_for_serirq_timeout() */ - /* * tpm_stm_i2c_cancel, cancel is not implemented. * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h @@ -241,8 +199,6 @@ static void tpm_stm_i2c_cancel(struct tpm_chip *chip) data = TPM_STS_COMMAND_READY; I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1); - if (chip->vendor.irq) - wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a); } /* tpm_stm_i2c_cancel() */ /* @@ -297,30 +253,24 @@ static int request_locality(struct tpm_chip *chip) struct tpm_stm_dev *tpm_dev; u8 data; - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - if (check_locality(chip) == chip->vendor.locality) return chip->vendor.locality; + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + data = TPM_ACCESS_REQUEST_USE; ret = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1); if (ret < 0) goto end; - if (chip->vendor.irq) { - ret = wait_for_serirq_timeout(chip, (check_locality - (chip) >= 0), - chip->vendor.timeout_a); - if (ret > 0) + stop = jiffies + chip->vendor.timeout_a; + + /* Request locality is usually effective after the request */ + do { + if (check_locality(chip) >= 0) return chip->vendor.locality; - } else { - stop = jiffies + chip->vendor.timeout_a; - do { - if (check_locality(chip) >= 0) - return chip->vendor.locality; - msleep(TPM_TIMEOUT); - } while (time_before(jiffies, stop)); - } + msleep(TPM_TIMEOUT); + } while (time_before(jiffies, stop)); ret = -EACCES; end: return ret; @@ -378,36 +328,107 @@ end: return -EBUSY; } /* get_burstcount() */ +static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, + bool check_cancel, bool *canceled) +{ + u8 status = chip->ops->status(chip); + + *canceled = false; + if ((status & mask) == mask) + return true; + if (check_cancel && chip->ops->req_canceled(chip, status)) { + *canceled = true; + return true; + } + return false; +} + +/* + * interrupt_to_status + * @param: irq_mask, the irq mask value to wait + * @return: the corresponding tpm_sts value + */ +static u8 interrupt_to_status(u8 irq_mask) +{ + u8 status = 0; + + if ((irq_mask & TPM_INTF_STS_VALID_INT) == TPM_INTF_STS_VALID_INT) + status |= TPM_STS_VALID; + if ((irq_mask & TPM_INTF_DATA_AVAIL_INT) == TPM_INTF_DATA_AVAIL_INT) + status |= TPM_STS_DATA_AVAIL; + if ((irq_mask & TPM_INTF_CMD_READY_INT) == TPM_INTF_CMD_READY_INT) + status |= TPM_STS_COMMAND_READY; + + return status; +} /* status_to_interrupt() */ + /* * wait_for_stat wait for a TPM_STS value * @param: chip, the tpm chip description * @param: mask, the value mask to wait * @param: timeout, the timeout * @param: queue, the wait queue. + * @param: check_cancel, does the command can be cancelled ? * @return: the tpm status, 0 if success, -ETIME if timeout is reached. */ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, - wait_queue_head_t *queue) + wait_queue_head_t *queue, bool check_cancel) { unsigned long stop; - long ret; - u8 status; + int r; + bool canceled = false; + bool condition; + u32 cur_intrs; + u8 interrupt, status; + struct tpm_stm_dev *tpm_dev; + + tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); + + /* check current status */ + status = tpm_stm_i2c_status(chip); + if ((status & mask) == mask) + return 0; + + stop = jiffies + timeout; if (chip->vendor.irq) { - ret = wait_for_serirq_timeout(chip, ((tpm_stm_i2c_status - (chip) & mask) == - mask), timeout); - if (ret > 0) + cur_intrs = tpm_dev->intrs; + interrupt = clear_interruption(tpm_dev); + enable_irq(chip->vendor.irq); + +again: + timeout = stop - jiffies; + if ((long) timeout <= 0) + return -1; + + r = wait_event_interruptible_timeout(*queue, + cur_intrs != tpm_dev->intrs, timeout); + + interrupt |= clear_interruption(tpm_dev); + status = interrupt_to_status(interrupt); + condition = wait_for_tpm_stat_cond(chip, mask, + check_cancel, &canceled); + + if (r >= 0 && condition) { + if (canceled) + return -ECANCELED; return 0; + } + if (r == -ERESTARTSYS && freezing(current)) { + clear_thread_flag(TIF_SIGPENDING); + goto again; + } + disable_irq_nosync(chip->vendor.irq); + } else { - stop = jiffies + timeout; do { msleep(TPM_TIMEOUT); - status = tpm_stm_i2c_status(chip); + status = chip->ops->status(chip); if ((status & mask) == mask) return 0; } while (time_before(jiffies, stop)); } + return -ETIME; } /* wait_for_stat() */ @@ -429,7 +450,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) wait_for_stat(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, chip->vendor.timeout_c, - &chip->vendor.read_queue) == 0) { + &chip->vendor.read_queue, true) == 0) { burstcnt = get_burstcount(chip); if (burstcnt < 0) return burstcnt; @@ -449,15 +470,14 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) { struct tpm_chip *chip = dev_id; - struct i2c_client *client; struct tpm_stm_dev *tpm_dev; - disable_irq_nosync(irq); - tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); - client = tpm_dev->client; - complete(&tpm_dev->irq_detection); + tpm_dev->intrs++; + wake_up_interruptible(&chip->vendor.read_queue); + disable_irq_nosync(chip->vendor.irq); + return IRQ_HANDLED; } /* tpm_ioserirq_handler() */ @@ -500,7 +520,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf, tpm_stm_i2c_cancel(chip); if (wait_for_stat (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, - &chip->vendor.int_queue) < 0) { + &chip->vendor.read_queue, false) < 0) { ret = -ETIME; goto out_err; } @@ -743,7 +763,10 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) chip->vendor.locality = LOCALITY0; if (client->irq) { - init_completion(&tpm_dev->irq_detection); + /* INTERRUPT Setup */ + init_waitqueue_head(&chip->vendor.read_queue); + tpm_dev->intrs = 0; + if (request_locality(chip) != LOCALITY0) { ret = -ENODEV; goto _tpm_clean_answer; @@ -765,9 +788,6 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) goto _tpm_clean_answer; intmask |= TPM_INTF_CMD_READY_INT - | TPM_INTF_FIFO_AVALAIBLE_INT - | TPM_INTF_WAKE_UP_READY_INT - | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT | TPM_INTF_DATA_AVAIL_INT; @@ -787,6 +807,8 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) chip->vendor.irq = client->irq; + disable_irq_nosync(chip->vendor.irq); + tpm_gen_interrupt(chip); } @@ -852,10 +874,9 @@ static int tpm_stm_i2c_pm_resume(struct device *dev) if (gpio_is_valid(pin_infos->io_lpcpd)) { gpio_set_value(pin_infos->io_lpcpd, 1); - ret = wait_for_serirq_timeout(chip, - (chip->ops->status(chip) & - TPM_STS_VALID) == TPM_STS_VALID, - chip->vendor.timeout_b); + ret = wait_for_stat(chip, + TPM_STS_VALID, chip->vendor.timeout_b, + &chip->vendor.read_queue, false); } else { ret = tpm_pm_resume(dev); if (!ret) From 00820e8207b9b87fe0e34062876696dd6d326b2d Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:32:59 +0100 Subject: [PATCH 23/64] tpm/tpm_i2c_stm_st33: Remove useless i2c read on interrupt registers Remove useless i2c read on TPM_INT_ENABLE and TPM_INT_STATUS Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index eb0244a2ec9d..1d589e06e0dd 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -783,10 +783,6 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) goto _tpm_clean_answer; } - ret = I2C_READ_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1); - if (ret < 0) - goto _tpm_clean_answer; - intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_STS_VALID_INT | TPM_INTF_DATA_AVAIL_INT; @@ -801,10 +797,6 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) if (ret < 0) goto _tpm_clean_answer; - ret = I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &intmask, 1); - if (ret < 0) - goto _tpm_clean_answer; - chip->vendor.irq = client->irq; disable_irq_nosync(chip->vendor.irq); From f2f083b5d478d409e6658392088e7e594f748c04 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Mon, 1 Dec 2014 19:33:00 +0100 Subject: [PATCH 24/64] tpm/tpm_i2c_stm_st33: Increment driver version to 1.2.1. Many changes were added to the driver so increment the version. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 1d589e06e0dd..e643c8627b7d 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -1,6 +1,6 @@ /* * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24 - * Copyright (C) 2009, 2010 STMicroelectronics + * Copyright (C) 2009, 2010, 2014 STMicroelectronics * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see . * - * STMicroelectronics version 1.2.0, Copyright (C) 2010 + * STMicroelectronics version 1.2.1, Copyright (C) 2014 * STMicroelectronics comes with ABSOLUTELY NO WARRANTY. * This is free software, and you are welcome to redistribute it * under certain conditions. @@ -910,5 +910,5 @@ module_i2c_driver(tpm_stm_i2c_driver); MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)"); MODULE_DESCRIPTION("STM TPM I2C ST33 Driver"); -MODULE_VERSION("1.2.0"); +MODULE_VERSION("1.2.1"); MODULE_LICENSE("GPL"); From 67fe94175a3e2da2bb0897f644ed856b8528c633 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 2 Dec 2014 21:06:03 +0100 Subject: [PATCH 25/64] tpm/tpm_i2c_stm_st33: Fix coccinelle warnings. Possible NULL pointer dereference If !client the kernel mays oops in dev_info when doing client->dev. Reported-by: Peter Huewe Signed-off-by: Christophe Ricard Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index e643c8627b7d..86203b022d13 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -720,7 +720,7 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) struct tpm_stm_dev *tpm_dev; if (!client) { - dev_info(&client->dev, "%s: i2c client is NULL. Device not accessible.\n", + pr_info("%s: i2c client is NULL. Device not accessible.\n", __func__); return -ENODEV; } From 1a0f1b279c2c4e5747a682b055d27d88e35bb632 Mon Sep 17 00:00:00 2001 From: Ashley Lai Date: Thu, 4 Dec 2014 21:01:51 -0600 Subject: [PATCH 26/64] tpm_ibmvtpm: Update email address in maintainers list and ibmvtpm driver Added myself as a maintainer for the IBM vtpm driver and removed myself from the tpm maintainer list. Also, updated the tpm_ibmvtpm driver with my current email address. Signed-off-by: Ashley Lai Signed-off-by: Peter Huewe --- MAINTAINERS | 8 +++++++- drivers/char/tpm/tpm_ibmvtpm.c | 2 +- drivers/char/tpm/tpm_ibmvtpm.h | 2 +- drivers/char/tpm/tpm_of.c | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 600d2aad8276..e18aef54b4b2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9720,13 +9720,19 @@ F: drivers/media/pci/tw68/ TPM DEVICE DRIVER M: Peter Huewe -M: Ashley Lai M: Marcel Selhorst W: http://tpmdd.sourceforge.net L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers) S: Maintained F: drivers/char/tpm/ +TPM IBM_VTPM DEVICE DRIVER +M: Ashley Lai +W: http://tpmdd.sourceforge.net +L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers) +S: Maintained +F: drivers/char/tpm/tpm_ibmvtpm* + TRACING M: Steven Rostedt M: Ingo Molnar diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 4109222f2878..96f5d448b84c 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 IBM Corporation * - * Author: Ashley Lai + * Author: Ashley Lai * * Maintained by: * diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h index bd82a791f995..f595f14426bf 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.h +++ b/drivers/char/tpm/tpm_ibmvtpm.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2012 IBM Corporation * - * Author: Ashley Lai + * Author: Ashley Lai * * Maintained by: * diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 98ba2bd1a355..c002d1bd9caf 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -1,7 +1,7 @@ /* * Copyright 2012 IBM Corporation * - * Author: Ashley Lai + * Author: Ashley Lai * * Maintained by: * From 87155b7311bfec75b590b823b11f77adf2a16412 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 12 Dec 2014 11:46:33 -0800 Subject: [PATCH 27/64] tpm: merge duplicate transmit_cmd() functions Merged transmit_cmd() functions in tpm-interface.c and tpm-sysfs.c. Added "tpm_" prefix for consistency sake. Changed cmd parameter as opaque. This enables to use separate command structures for TPM1 and TPM2 commands in future. Loose coupling works fine here. Signed-off-by: Jarkko Sakkinen Reviewed-by: Jasob Gunthorpe Reviewed-by: Stefan Berger Reviewed-by: Peter Huewe Tested-by: Scot Doyle Tested-by: Peter Huewe Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm-interface.c | 49 +++++++++++++++++--------------- drivers/char/tpm/tpm-sysfs.c | 23 ++------------- drivers/char/tpm/tpm.h | 3 +- 3 files changed, 30 insertions(+), 45 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index cfb9089887bd..c17aa45024aa 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -398,9 +398,10 @@ out: #define TPM_DIGEST_SIZE 20 #define TPM_RET_CODE_IDX 6 -static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, - int len, const char *desc) +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, + int len, const char *desc) { + struct tpm_output_header *header; int err; len = tpm_transmit(chip, (u8 *) cmd, len); @@ -409,7 +410,9 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, else if (len < TPM_HEADER_SIZE) return -EFAULT; - err = be32_to_cpu(cmd->header.out.return_code); + header = cmd; + + err = be32_to_cpu(header->return_code); if (err != 0 && desc) dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); @@ -448,7 +451,7 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap, tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = subcap_id; } - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); if (!rc) *cap = tpm_cmd.params.getcap_out.cap; return rc; @@ -464,8 +467,8 @@ void tpm_gen_interrupt(struct tpm_chip *chip) tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the timeouts"); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to determine the timeouts"); } EXPORT_SYMBOL_GPL(tpm_gen_interrupt); @@ -484,8 +487,8 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) struct tpm_cmd_t start_cmd; start_cmd.header.in = tpm_startup_header; start_cmd.params.startup_in.startup_type = startup_type; - return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to start the TPM"); + return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to start the TPM"); } int tpm_get_timeouts(struct tpm_chip *chip) @@ -500,7 +503,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL); if (rc == TPM_ERR_INVALID_POSTINIT) { /* The TPM is not started, we are the first to talk to it. @@ -513,7 +516,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL); } if (rc) { @@ -575,8 +578,8 @@ duration: tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the durations"); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to determine the durations"); if (rc) return rc; @@ -631,8 +634,8 @@ static int tpm_continue_selftest(struct tpm_chip *chip) struct tpm_cmd_t cmd; cmd.header.in = continue_selftest_header; - rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, - "continue selftest"); + rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, + "continue selftest"); return rc; } @@ -672,8 +675,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) cmd.header.in = pcrread_header; cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); - rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, - "attempting to read a pcr value"); + rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, + "attempting to read a pcr value"); if (rc == 0) memcpy(res_buf, cmd.params.pcrread_out.pcr_result, @@ -737,8 +740,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); - rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, - "attempting extend a PCR value"); + rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + "attempting extend a PCR value"); tpm_chip_put(chip); return rc; @@ -817,7 +820,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen) if (chip == NULL) return -ENODEV; - rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); + rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); tpm_chip_put(chip); return rc; @@ -938,14 +941,14 @@ int tpm_pm_suspend(struct device *dev) cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr); memcpy(cmd.params.pcrextend_in.hash, dummy_hash, TPM_DIGEST_SIZE); - rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, - "extending dummy pcr before suspend"); + rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + "extending dummy pcr before suspend"); } /* now do the actual savestate */ for (try = 0; try < TPM_RETRY; try++) { cmd.header.in = savestate_header; - rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL); + rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL); /* * If the TPM indicates that it is too busy to respond to @@ -1022,7 +1025,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) tpm_cmd.header.in = tpm_getrandom_header; tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); - err = transmit_cmd(chip, &tpm_cmd, + err = tpm_transmit_cmd(chip, &tpm_cmd, TPM_GETRANDOM_RESULT_SIZE + num_bytes, "attempting get random"); if (err) diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 01730a27ae07..8ecb052e290d 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -20,25 +20,6 @@ #include #include "tpm.h" -/* XXX for now this helper is duplicated in tpm-interface.c */ -static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, - int len, const char *desc) -{ - int err; - - len = tpm_transmit(chip, (u8 *) cmd, len); - if (len < 0) - return len; - else if (len < TPM_HEADER_SIZE) - return -EFAULT; - - err = be32_to_cpu(cmd->header.out.return_code); - if (err != 0 && desc) - dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); - - return err; -} - #define READ_PUBEK_RESULT_SIZE 314 #define TPM_ORD_READPUBEK cpu_to_be32(124) static struct tpm_input_header tpm_readpubek_header = { @@ -58,8 +39,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, struct tpm_chip *chip = dev_get_drvdata(dev); tpm_cmd.header.in = tpm_readpubek_header; - err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, - "attempting to read the PUBEK"); + err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, + "attempting to read the PUBEK"); if (err) goto out; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index e4d0888d2eab..e638eb016b90 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -314,9 +314,10 @@ struct tpm_cmd_t { } __packed; ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); - ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, size_t bufsiz); +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len, + const char *desc); extern int tpm_get_timeouts(struct tpm_chip *); extern void tpm_gen_interrupt(struct tpm_chip *); extern int tpm_do_selftest(struct tpm_chip *); From afb5abc262e962089ef2d7c2bbf71bb6f53a2a78 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 12 Dec 2014 11:46:34 -0800 Subject: [PATCH 28/64] tpm: two-phase chip management functions tpm_register_hardware() and tpm_remove_hardware() are called often before initializing the device. The problem is that the device might not be fully initialized when it comes visible to the user space. This patch resolves the issue by diving initialization into two parts: - tpmm_chip_alloc() creates struct tpm_chip. - tpm_chip_register() sets up the character device and sysfs attributes. The framework takes care of freeing struct tpm_chip by using the devres API. The broken release callback has been wiped. ACPI drivers do not ever get this callback. Regards to Jason Gunthorpe for carefully reviewing this part of the code. Signed-off-by: Jarkko Sakkinen Reviewed-by: Jasob Gunthorpe Reviewed-by: Stefan Berger Tested-by: Scot Doyle Tested-by: Peter Huewe [phuewe: update to upstream changes] Signed-off-by: Peter Huewe --- drivers/char/tpm/Makefile | 2 +- drivers/char/tpm/tpm-chip.c | 199 ++++++++++++++++++++++++++++ drivers/char/tpm/tpm-interface.c | 148 +-------------------- drivers/char/tpm/tpm.h | 16 ++- drivers/char/tpm/tpm_atmel.c | 11 +- drivers/char/tpm/tpm_i2c_atmel.c | 39 ++---- drivers/char/tpm/tpm_i2c_infineon.c | 37 +----- drivers/char/tpm/tpm_i2c_nuvoton.c | 47 ++----- drivers/char/tpm/tpm_i2c_stm_st33.c | 14 +- drivers/char/tpm/tpm_ibmvtpm.c | 17 +-- drivers/char/tpm/tpm_infineon.c | 29 ++-- drivers/char/tpm/tpm_nsc.c | 14 +- drivers/char/tpm/tpm_tis.c | 80 +++++------ drivers/char/tpm/xen-tpmfront.c | 14 +- 14 files changed, 329 insertions(+), 338 deletions(-) create mode 100644 drivers/char/tpm/tpm-chip.c diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 7f54dae847e4..c715596acb7c 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -2,7 +2,7 @@ # Makefile for the kernel tpm device drivers. # obj-$(CONFIG_TCG_TPM) += tpm.o -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm-$(CONFIG_ACPI) += tpm_ppi.o ifdef CONFIG_ACPI diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c new file mode 100644 index 000000000000..7dc9999e2d54 --- /dev/null +++ b/drivers/char/tpm/tpm-chip.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2004 IBM Corporation + * Copyright (C) 2014 Intel Corporation + * + * Authors: + * Jarkko Sakkinen + * Leendert van Doorn + * Dave Safford + * Reiner Sailer + * Kylene Hall + * + * Maintained by: + * + * TPM chip management routines. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + */ + +#include +#include +#include +#include +#include +#include "tpm.h" +#include "tpm_eventlog.h" + +static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); +static LIST_HEAD(tpm_chip_list); +static DEFINE_SPINLOCK(driver_lock); + +/* + * tpm_chip_find_get - return tpm_chip for a given chip number + * @chip_num the device number for the chip + */ +struct tpm_chip *tpm_chip_find_get(int chip_num) +{ + struct tpm_chip *pos, *chip = NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(pos, &tpm_chip_list, list) { + if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) + continue; + + if (try_module_get(pos->dev->driver->owner)) { + chip = pos; + break; + } + } + rcu_read_unlock(); + return chip; +} + +/** + * tpmm_chip_remove() - free chip memory and device number + * @data: points to struct tpm_chip instance + * + * This is used internally by tpmm_chip_alloc() and called by devres + * when the device is released. This function does the opposite of + * tpmm_chip_alloc() freeing memory and the device number. + */ +static void tpmm_chip_remove(void *data) +{ + struct tpm_chip *chip = (struct tpm_chip *) data; + + spin_lock(&driver_lock); + clear_bit(chip->dev_num, dev_mask); + spin_unlock(&driver_lock); + kfree(chip); +} + +/** + * tpmm_chip_alloc() - allocate a new struct tpm_chip instance + * @dev: device to which the chip is associated + * @ops: struct tpm_class_ops instance + * + * Allocates a new struct tpm_chip instance and assigns a free + * device number for it. Caller does not have to worry about + * freeing the allocated resources. When the devices is removed + * devres calls tpmm_chip_remove() to do the job. + */ +struct tpm_chip *tpmm_chip_alloc(struct device *dev, + const struct tpm_class_ops *ops) +{ + struct tpm_chip *chip; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) + return ERR_PTR(-ENOMEM); + + mutex_init(&chip->tpm_mutex); + INIT_LIST_HEAD(&chip->list); + + chip->ops = ops; + + spin_lock(&driver_lock); + chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); + spin_unlock(&driver_lock); + + if (chip->dev_num >= TPM_NUM_DEVICES) { + dev_err(dev, "No available tpm device numbers\n"); + kfree(chip); + return ERR_PTR(-ENOMEM); + } + + set_bit(chip->dev_num, dev_mask); + + scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num); + + chip->dev = dev; + devm_add_action(dev, tpmm_chip_remove, chip); + dev_set_drvdata(dev, chip); + + return chip; +} +EXPORT_SYMBOL_GPL(tpmm_chip_alloc); + +/* + * tpm_chip_register() - create a misc driver for the TPM chip + * @chip: TPM chip to use. + * + * Creates a misc driver for the TPM chip and adds sysfs interfaces for + * the device, PPI and TCPA. As the last step this function adds the + * chip to the list of TPM chips available for use. + * + * NOTE: This function should be only called after the chip initialization + * is complete. + * + * Called from tpm_.c probe function only for devices + * the driver has determined it should claim. Prior to calling + * this function the specific probe function has called pci_enable_device + * upon errant exit from this function specific probe function should call + * pci_disable_device + */ +int tpm_chip_register(struct tpm_chip *chip) +{ + int rc; + + rc = tpm_dev_add_device(chip); + if (rc) + return rc; + + rc = tpm_sysfs_add_device(chip); + if (rc) + goto del_misc; + + rc = tpm_add_ppi(&chip->dev->kobj); + if (rc) + goto del_sysfs; + + chip->bios_dir = tpm_bios_log_setup(chip->devname); + + /* Make the chip available. */ + spin_lock(&driver_lock); + list_add_rcu(&chip->list, &tpm_chip_list); + spin_unlock(&driver_lock); + + chip->flags |= TPM_CHIP_FLAG_REGISTERED; + + return 0; +del_sysfs: + tpm_sysfs_del_device(chip); +del_misc: + tpm_dev_del_device(chip); + return rc; +} +EXPORT_SYMBOL_GPL(tpm_chip_register); + +/* + * tpm_chip_unregister() - release the TPM driver + * @chip: TPM chip to use. + * + * Takes the chip first away from the list of available TPM chips and then + * cleans up all the resources reserved by tpm_chip_register(). + * + * NOTE: This function should be only called before deinitializing chip + * resources. + */ +void tpm_chip_unregister(struct tpm_chip *chip) +{ + if (!(chip->flags & TPM_CHIP_FLAG_REGISTERED)) + return; + + spin_lock(&driver_lock); + list_del_rcu(&chip->list); + spin_unlock(&driver_lock); + synchronize_rcu(); + + if (chip->bios_dir) + tpm_bios_log_teardown(chip->bios_dir); + tpm_remove_ppi(&chip->dev->kobj); + tpm_sysfs_del_device(chip); + + tpm_dev_del_device(chip); +} +EXPORT_SYMBOL_GPL(tpm_chip_unregister); diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index c17aa45024aa..4dbed1e45abd 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2004 IBM Corporation + * Copyright (C) 2014 Intel Corporation * * Authors: * Leendert van Doorn @@ -47,10 +48,6 @@ module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644); MODULE_PARM_DESC(suspend_pcr, "PCR to use for dummy writes to faciltate flush on suspend."); -static LIST_HEAD(tpm_chip_list); -static DEFINE_SPINLOCK(driver_lock); -static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); - /* * Array with one entry per ordinal defining the maximum amount * of time the chip could take to return the result. The ordinal @@ -639,27 +636,6 @@ static int tpm_continue_selftest(struct tpm_chip *chip) return rc; } -/* - * tpm_chip_find_get - return tpm_chip for given chip number - */ -static struct tpm_chip *tpm_chip_find_get(int chip_num) -{ - struct tpm_chip *pos, *chip = NULL; - - rcu_read_lock(); - list_for_each_entry_rcu(pos, &tpm_chip_list, list) { - if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) - continue; - - if (try_module_get(pos->dev->driver->owner)) { - chip = pos; - break; - } - } - rcu_read_unlock(); - return chip; -} - #define TPM_ORDINAL_PCRREAD cpu_to_be32(21) #define READ_PCR_RESULT_SIZE 30 static struct tpm_input_header pcrread_header = { @@ -887,30 +863,6 @@ again: } EXPORT_SYMBOL_GPL(wait_for_tpm_stat); -void tpm_remove_hardware(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - - if (chip == NULL) { - dev_err(dev, "No device data found\n"); - return; - } - - spin_lock(&driver_lock); - list_del_rcu(&chip->list); - spin_unlock(&driver_lock); - synchronize_rcu(); - - tpm_dev_del_device(chip); - tpm_sysfs_del_device(chip); - tpm_remove_ppi(&dev->kobj); - tpm_bios_log_teardown(chip->bios_dir); - - /* write it this way to be explicit (chip->dev == dev) */ - put_device(chip->dev); -} -EXPORT_SYMBOL_GPL(tpm_remove_hardware); - #define TPM_ORD_SAVESTATE cpu_to_be32(152) #define SAVESTATE_RESULT_SIZE 10 @@ -1044,104 +996,6 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) } EXPORT_SYMBOL_GPL(tpm_get_random); -/* In case vendor provided release function, call it too.*/ - -void tpm_dev_vendor_release(struct tpm_chip *chip) -{ - if (!chip) - return; - - clear_bit(chip->dev_num, dev_mask); -} -EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); - - -/* - * Once all references to platform device are down to 0, - * release all allocated structures. - */ -static void tpm_dev_release(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - - if (!chip) - return; - - tpm_dev_vendor_release(chip); - - chip->release(dev); - kfree(chip); -} - -/* - * Called from tpm_.c probe function only for devices - * the driver has determined it should claim. Prior to calling - * this function the specific probe function has called pci_enable_device - * upon errant exit from this function specific probe function should call - * pci_disable_device - */ -struct tpm_chip *tpm_register_hardware(struct device *dev, - const struct tpm_class_ops *ops) -{ - struct tpm_chip *chip; - - /* Driver specific per-device data */ - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - - if (chip == NULL) - return NULL; - - mutex_init(&chip->tpm_mutex); - INIT_LIST_HEAD(&chip->list); - - chip->ops = ops; - chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); - - if (chip->dev_num >= TPM_NUM_DEVICES) { - dev_err(dev, "No available tpm device numbers\n"); - goto out_free; - } - - set_bit(chip->dev_num, dev_mask); - - scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm", - chip->dev_num); - - chip->dev = get_device(dev); - chip->release = dev->release; - dev->release = tpm_dev_release; - dev_set_drvdata(dev, chip); - - if (tpm_dev_add_device(chip)) - goto put_device; - - if (tpm_sysfs_add_device(chip)) - goto del_misc; - - if (tpm_add_ppi(&dev->kobj)) - goto del_sysfs; - - chip->bios_dir = tpm_bios_log_setup(chip->devname); - - /* Make chip available */ - spin_lock(&driver_lock); - list_add_tail_rcu(&chip->list, &tpm_chip_list); - spin_unlock(&driver_lock); - - return chip; - -del_sysfs: - tpm_sysfs_del_device(chip); -del_misc: - tpm_dev_del_device(chip); -put_device: - put_device(chip->dev); -out_free: - kfree(chip); - return NULL; -} -EXPORT_SYMBOL_GPL(tpm_register_hardware); - MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); MODULE_DESCRIPTION("TPM Driver"); MODULE_VERSION("2.0"); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index e638eb016b90..72ff18c872d3 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -94,9 +94,14 @@ struct tpm_vendor_specific { #define TPM_VID_WINBOND 0x1050 #define TPM_VID_STM 0x104A +enum tpm_chip_flags { + TPM_CHIP_FLAG_REGISTERED = BIT(0), +}; + struct tpm_chip { struct device *dev; /* Device stuff */ const struct tpm_class_ops *ops; + unsigned int flags; int dev_num; /* /dev/tpm# */ char devname[7]; @@ -110,7 +115,6 @@ struct tpm_chip { struct dentry **bios_dir; struct list_head list; - void (*release) (struct device *); }; #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor) @@ -322,15 +326,17 @@ extern int tpm_get_timeouts(struct tpm_chip *); extern void tpm_gen_interrupt(struct tpm_chip *); extern int tpm_do_selftest(struct tpm_chip *); extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); -extern struct tpm_chip* tpm_register_hardware(struct device *, - const struct tpm_class_ops *ops); -extern void tpm_dev_vendor_release(struct tpm_chip *); -extern void tpm_remove_hardware(struct device *); extern int tpm_pm_suspend(struct device *); extern int tpm_pm_resume(struct device *); extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, wait_queue_head_t *, bool); +struct tpm_chip *tpm_chip_find_get(int chip_num); +extern struct tpm_chip *tpmm_chip_alloc(struct device *dev, + const struct tpm_class_ops *ops); +extern int tpm_chip_register(struct tpm_chip *chip); +extern void tpm_chip_unregister(struct tpm_chip *chip); + int tpm_dev_add_device(struct tpm_chip *chip); void tpm_dev_del_device(struct tpm_chip *chip); int tpm_sysfs_add_device(struct tpm_chip *chip); diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 435c8b9dd2f8..3d4c6c3b0433 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -138,11 +138,11 @@ static void atml_plat_remove(void) struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); if (chip) { + tpm_chip_unregister(chip); if (chip->vendor.have_region) atmel_release_region(chip->vendor.base, chip->vendor.region_size); atmel_put_base_addr(chip->vendor.iobase); - tpm_remove_hardware(chip->dev); platform_device_unregister(pdev); } } @@ -183,8 +183,9 @@ static int __init init_atmel(void) goto err_rel_reg; } - if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) { - rc = -ENODEV; + chip = tpmm_chip_alloc(&pdev->dev, &tpm_atmel); + if (IS_ERR(chip)) { + rc = PTR_ERR(chip); goto err_unreg_dev; } @@ -193,6 +194,10 @@ static int __init init_atmel(void) chip->vendor.have_region = have_region; chip->vendor.region_size = region_size; + rc = tpm_chip_register(chip); + if (rc) + goto err_unreg_dev; + return 0; err_unreg_dev: diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index 5f448886417f..643a9402e911 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -153,25 +153,20 @@ static const struct tpm_class_ops i2c_atmel = { static int i2c_atmel_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int rc; struct tpm_chip *chip; struct device *dev = &client->dev; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; - chip = tpm_register_hardware(dev, &i2c_atmel); - if (!chip) { - dev_err(dev, "%s() error in tpm_register_hardware\n", __func__); - return -ENODEV; - } + chip = tpmm_chip_alloc(dev, &i2c_atmel); + if (IS_ERR(chip)) + return PTR_ERR(chip); chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL); - if (!chip->vendor.priv) { - rc = -ENOMEM; - goto out_err; - } + if (!chip->vendor.priv) + return -ENOMEM; /* Default timeouts */ chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT); @@ -183,32 +178,20 @@ static int i2c_atmel_probe(struct i2c_client *client, /* There is no known way to probe for this device, and all version * information seems to be read via TPM commands. Thus we rely on the * TPM startup process in the common code to detect the device. */ - if (tpm_get_timeouts(chip)) { - rc = -ENODEV; - goto out_err; - } + if (tpm_get_timeouts(chip)) + return -ENODEV; - if (tpm_do_selftest(chip)) { - rc = -ENODEV; - goto out_err; - } + if (tpm_do_selftest(chip)) + return -ENODEV; - return 0; - -out_err: - tpm_dev_vendor_release(chip); - tpm_remove_hardware(chip->dev); - return rc; + return tpm_chip_register(chip); } static int i2c_atmel_remove(struct i2c_client *client) { struct device *dev = &(client->dev); struct tpm_chip *chip = dev_get_drvdata(dev); - - tpm_dev_vendor_release(chip); - tpm_remove_hardware(dev); - kfree(chip); + tpm_chip_unregister(chip); return 0; } diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index 472af4bb1b61..03708e6b309a 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -581,12 +581,9 @@ static int tpm_tis_i2c_init(struct device *dev) int rc = 0; struct tpm_chip *chip; - chip = tpm_register_hardware(dev, &tpm_tis_i2c); - if (!chip) { - dev_err(dev, "could not register hardware\n"); - rc = -ENODEV; - goto out_err; - } + chip = tpmm_chip_alloc(dev, &tpm_tis_i2c); + if (IS_ERR(chip)) + return PTR_ERR(chip); /* Disable interrupts */ chip->vendor.irq = 0; @@ -600,7 +597,7 @@ static int tpm_tis_i2c_init(struct device *dev) if (request_locality(chip, 0) != 0) { dev_err(dev, "could not request locality\n"); rc = -ENODEV; - goto out_vendor; + goto out_err; } /* read four bytes from DID_VID register */ @@ -628,21 +625,9 @@ static int tpm_tis_i2c_init(struct device *dev) tpm_get_timeouts(chip); tpm_do_selftest(chip); - return 0; - + return tpm_chip_register(chip); out_release: release_locality(chip, chip->vendor.locality, 1); - -out_vendor: - /* close file handles */ - tpm_dev_vendor_release(chip); - - /* remove hardware */ - tpm_remove_hardware(chip->dev); - - /* reset these pointers, otherwise we oops */ - chip->dev->release = NULL; - chip->release = NULL; tpm_dev.client = NULL; out_err: return rc; @@ -712,17 +697,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client, static int tpm_tis_i2c_remove(struct i2c_client *client) { struct tpm_chip *chip = tpm_dev.chip; + + tpm_chip_unregister(chip); release_locality(chip, chip->vendor.locality, 1); - - /* close file handles */ - tpm_dev_vendor_release(chip); - - /* remove hardware */ - tpm_remove_hardware(chip->dev); - - /* reset these pointers, otherwise we oops */ - chip->dev->release = NULL; - chip->release = NULL; tpm_dev.client = NULL; return 0; diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index bbb4997438c3..8c23088d99ef 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -530,18 +530,14 @@ static int i2c_nuvoton_probe(struct i2c_client *client, dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid, (u8) (vid >> 16), (u8) (vid >> 24)); - chip = tpm_register_hardware(dev, &tpm_i2c); - if (!chip) { - dev_err(dev, "%s() error in tpm_register_hardware\n", __func__); - return -ENODEV; - } + chip = tpmm_chip_alloc(dev, &tpm_i2c); + if (IS_ERR(chip)) + return PTR_ERR(chip); chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL); - if (!chip->vendor.priv) { - rc = -ENOMEM; - goto out_err; - } + if (!chip->vendor.priv) + return -ENOMEM; init_waitqueue_head(&chip->vendor.read_queue); init_waitqueue_head(&chip->vendor.int_queue); @@ -589,7 +585,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client, TPM_DATA_FIFO_W, 1, (u8 *) (&rc)); if (rc < 0) - goto out_err; + return rc; /* TPM_STS <- 0x40 (commandReady) */ i2c_nuvoton_ready(chip); } else { @@ -599,44 +595,29 @@ static int i2c_nuvoton_probe(struct i2c_client *client, * only TPM_STS_VALID should be set */ if (i2c_nuvoton_read_status(chip) != - TPM_STS_VALID) { - rc = -EIO; - goto out_err; - } + TPM_STS_VALID) + return -EIO; } } } - if (tpm_get_timeouts(chip)) { - rc = -ENODEV; - goto out_err; - } + if (tpm_get_timeouts(chip)) + return -ENODEV; - if (tpm_do_selftest(chip)) { - rc = -ENODEV; - goto out_err; - } + if (tpm_do_selftest(chip)) + return -ENODEV; - return 0; - -out_err: - tpm_dev_vendor_release(chip); - tpm_remove_hardware(chip->dev); - return rc; + return tpm_chip_register(chip); } static int i2c_nuvoton_remove(struct i2c_client *client) { struct device *dev = &(client->dev); struct tpm_chip *chip = dev_get_drvdata(dev); - - tpm_dev_vendor_release(chip); - tpm_remove_hardware(dev); - kfree(chip); + tpm_chip_unregister(chip); return 0; } - static const struct i2c_device_id i2c_nuvoton_id[] = { {I2C_DRIVER_NAME, 0}, {} diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 86203b022d13..9a96d3704fe5 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -735,11 +735,9 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) if (!tpm_dev) return -ENOMEM; - chip = tpm_register_hardware(&client->dev, &st_i2c_tpm); - if (!chip) { - dev_info(&client->dev, "fail chip\n"); - return -ENODEV; - } + chip = tpmm_chip_alloc(&client->dev, &st_i2c_tpm); + if (IS_ERR(chip)) + return PTR_ERR(chip); TPM_VPRIV(chip) = tpm_dev; tpm_dev->client = client; @@ -807,10 +805,8 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) tpm_get_timeouts(chip); tpm_do_selftest(chip); - dev_info(chip->dev, "TPM I2C Initialized\n"); - return 0; + return tpm_chip_register(chip); _tpm_clean_answer: - tpm_remove_hardware(chip->dev); dev_info(chip->dev, "TPM I2C initialisation fail\n"); return ret; } @@ -827,7 +823,7 @@ static int tpm_stm_i2c_remove(struct i2c_client *client) (struct tpm_chip *) i2c_get_clientdata(client); if (chip) - tpm_remove_hardware(chip->dev); + tpm_chip_unregister(chip); return 0; } diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 96f5d448b84c..0840347e251c 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -270,8 +270,11 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) static int tpm_ibmvtpm_remove(struct vio_dev *vdev) { struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); + struct tpm_chip *chip = dev_get_drvdata(ibmvtpm->dev); int rc = 0; + tpm_chip_unregister(chip); + free_irq(vdev->irq, ibmvtpm); do { @@ -290,8 +293,6 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) kfree(ibmvtpm->rtce_buf); } - tpm_remove_hardware(ibmvtpm->dev); - kfree(ibmvtpm); return 0; @@ -563,11 +564,9 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, struct tpm_chip *chip; int rc = -ENOMEM, rc1; - chip = tpm_register_hardware(dev, &tpm_ibmvtpm); - if (!chip) { - dev_err(dev, "tpm_register_hardware failed\n"); - return -ENODEV; - } + chip = tpmm_chip_alloc(dev, &tpm_ibmvtpm); + if (IS_ERR(chip)) + return PTR_ERR(chip); ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL); if (!ibmvtpm) { @@ -637,7 +636,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, if (rc) goto init_irq_cleanup; - return rc; + return tpm_chip_register(chip); init_irq_cleanup: do { rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address); @@ -652,8 +651,6 @@ cleanup: kfree(ibmvtpm); } - tpm_remove_hardware(dev); - return rc; } diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index dc0a2554034e..dcdb671b2a5d 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -546,7 +546,14 @@ static int tpm_inf_pnp_probe(struct pnp_dev *dev, vendorid[0], vendorid[1], productid[0], productid[1], chipname); - if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) + chip = tpmm_chip_alloc(&dev->dev, &tpm_inf); + if (IS_ERR(chip)) { + rc = PTR_ERR(chip); + goto err_release_region; + } + + rc = tpm_chip_register(chip); + if (rc) goto err_release_region; return 0; @@ -572,17 +579,15 @@ static void tpm_inf_pnp_remove(struct pnp_dev *dev) { struct tpm_chip *chip = pnp_get_drvdata(dev); - if (chip) { - if (tpm_dev.iotype == TPM_INF_IO_PORT) { - release_region(tpm_dev.data_regs, tpm_dev.data_size); - release_region(tpm_dev.config_port, - tpm_dev.config_size); - } else { - iounmap(tpm_dev.mem_base); - release_mem_region(tpm_dev.map_base, tpm_dev.map_size); - } - tpm_dev_vendor_release(chip); - tpm_remove_hardware(chip->dev); + tpm_chip_unregister(chip); + + if (tpm_dev.iotype == TPM_INF_IO_PORT) { + release_region(tpm_dev.data_regs, tpm_dev.data_size); + release_region(tpm_dev.config_port, + tpm_dev.config_size); + } else { + iounmap(tpm_dev.mem_base); + release_mem_region(tpm_dev.map_base, tpm_dev.map_size); } } diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 4d0a17ea8cde..6e2c2e64b292 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -247,10 +247,9 @@ static struct platform_device *pdev = NULL; static void tpm_nsc_remove(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); - if ( chip ) { - release_region(chip->vendor.base, 2); - tpm_remove_hardware(chip->dev); - } + + tpm_chip_unregister(chip); + release_region(chip->vendor.base, 2); } static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume); @@ -307,11 +306,16 @@ static int __init init_nsc(void) goto err_del_dev; } - if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) { + chip = tpmm_chip_alloc(&pdev->dev, &tpm_nsc); + if (IS_ERR(chip)) { rc = -ENODEV; goto err_rel_reg; } + rc = tpm_chip_register(chip); + if (rc) + goto err_rel_reg; + dev_dbg(&pdev->dev, "NSC TPM detected\n"); dev_dbg(&pdev->dev, "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n", diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index ccb140d60532..36f4fec11c2a 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -79,9 +79,6 @@ struct priv_data { bool irq_tested; }; -static LIST_HEAD(tis_chips); -static DEFINE_MUTEX(tis_lock); - #if defined(CONFIG_PNP) && defined(CONFIG_ACPI) static int is_itpm(struct pnp_dev *dev) { @@ -572,6 +569,17 @@ static bool interrupts = true; module_param(interrupts, bool, 0444); MODULE_PARM_DESC(interrupts, "Enable interrupts"); +static void tpm_tis_remove(struct tpm_chip *chip) +{ + iowrite32(~TPM_GLOBAL_INT_ENABLE & + ioread32(chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor. + locality)), + chip->vendor.iobase + + TPM_INT_ENABLE(chip->vendor.locality)); + release_locality(chip, chip->vendor.locality, 1); +} + static int tpm_tis_init(struct device *dev, resource_size_t start, resource_size_t len, unsigned int irq) { @@ -583,15 +591,16 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL); if (priv == NULL) return -ENOMEM; - if (!(chip = tpm_register_hardware(dev, &tpm_tis))) - return -ENODEV; + + chip = tpmm_chip_alloc(dev, &tpm_tis); + if (IS_ERR(chip)) + return PTR_ERR(chip); + chip->vendor.priv = priv; - chip->vendor.iobase = ioremap(start, len); - if (!chip->vendor.iobase) { - rc = -EIO; - goto out_err; - } + chip->vendor.iobase = devm_ioremap(dev, start, len); + if (!chip->vendor.iobase) + return -EIO; /* Default timeouts */ chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); @@ -685,8 +694,8 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) { iowrite8(i, chip->vendor.iobase + TPM_INT_VECTOR(chip->vendor.locality)); - if (request_irq - (i, tis_int_probe, IRQF_SHARED, + if (devm_request_irq + (dev, i, tis_int_probe, IRQF_SHARED, chip->vendor.miscdev.name, chip) != 0) { dev_info(chip->dev, "Unable to request irq: %d for probe\n", @@ -726,15 +735,14 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, iowrite32(intmask, chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); - free_irq(i, chip); } } if (chip->vendor.irq) { iowrite8(chip->vendor.irq, chip->vendor.iobase + TPM_INT_VECTOR(chip->vendor.locality)); - if (request_irq - (chip->vendor.irq, tis_int_handler, IRQF_SHARED, + if (devm_request_irq + (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED, chip->vendor.miscdev.name, chip) != 0) { dev_info(chip->dev, "Unable to request irq: %d for use\n", @@ -767,17 +775,9 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, goto out_err; } - INIT_LIST_HEAD(&chip->vendor.list); - mutex_lock(&tis_lock); - list_add(&chip->vendor.list, &tis_chips); - mutex_unlock(&tis_lock); - - - return 0; + return tpm_chip_register(chip); out_err: - if (chip->vendor.iobase) - iounmap(chip->vendor.iobase); - tpm_remove_hardware(chip->dev); + tpm_tis_remove(chip); return rc; } @@ -859,13 +859,10 @@ MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); static void tpm_tis_pnp_remove(struct pnp_dev *dev) { struct tpm_chip *chip = pnp_get_drvdata(dev); - - tpm_dev_vendor_release(chip); - - kfree(chip); + tpm_chip_unregister(chip); + tpm_tis_remove(chip); } - static struct pnp_driver tis_pnp_driver = { .name = "tpm_tis", .id_table = tpm_pnp_tbl, @@ -884,7 +881,7 @@ MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe"); static struct platform_driver tis_drv = { .driver = { - .name = "tpm_tis", + .name = "tpm_tis", .pm = &tpm_tis_pm, }, }; @@ -923,31 +920,16 @@ err_dev: static void __exit cleanup_tis(void) { - struct tpm_vendor_specific *i, *j; struct tpm_chip *chip; - mutex_lock(&tis_lock); - list_for_each_entry_safe(i, j, &tis_chips, list) { - chip = to_tpm_chip(i); - tpm_remove_hardware(chip->dev); - iowrite32(~TPM_GLOBAL_INT_ENABLE & - ioread32(chip->vendor.iobase + - TPM_INT_ENABLE(chip->vendor. - locality)), - chip->vendor.iobase + - TPM_INT_ENABLE(chip->vendor.locality)); - release_locality(chip, chip->vendor.locality, 1); - if (chip->vendor.irq) - free_irq(chip->vendor.irq, chip); - iounmap(i->iobase); - list_del(&i->list); - } - mutex_unlock(&tis_lock); #ifdef CONFIG_PNP if (!force) { pnp_unregister_driver(&tis_pnp_driver); return; } #endif + chip = dev_get_drvdata(&pdev->dev); + tpm_chip_unregister(chip); + tpm_tis_remove(chip); platform_device_unregister(pdev); platform_driver_unregister(&tis_drv); } diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 441b44e54226..c3b4f5a5ac10 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -175,9 +175,9 @@ static int setup_chip(struct device *dev, struct tpm_private *priv) { struct tpm_chip *chip; - chip = tpm_register_hardware(dev, &tpm_vtpm); - if (!chip) - return -ENODEV; + chip = tpmm_chip_alloc(dev, &tpm_vtpm); + if (IS_ERR(chip)) + return PTR_ERR(chip); init_waitqueue_head(&chip->vendor.read_queue); @@ -286,6 +286,7 @@ static int tpmfront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { struct tpm_private *priv; + struct tpm_chip *chip; int rv; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -302,21 +303,22 @@ static int tpmfront_probe(struct xenbus_device *dev, rv = setup_ring(dev, priv); if (rv) { - tpm_remove_hardware(&dev->dev); + chip = dev_get_drvdata(&dev->dev); + tpm_chip_unregister(chip); ring_free(priv); return rv; } tpm_get_timeouts(priv->chip); - return rv; + return tpm_chip_register(priv->chip); } static int tpmfront_remove(struct xenbus_device *dev) { struct tpm_chip *chip = dev_get_drvdata(&dev->dev); struct tpm_private *priv = TPM_VPRIV(chip); - tpm_remove_hardware(&dev->dev); + tpm_chip_unregister(chip); ring_free(priv); TPM_VPRIV(chip) = NULL; return 0; From 0dc553652102c55a43eb1ab52e2049e478469f53 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 12 Dec 2014 11:46:35 -0800 Subject: [PATCH 29/64] tpm: fix raciness of PPI interface lookup Traversal of the ACPI device tree was not done right. PPI interface should be looked up only from the ACPI device that is the platform device for the TPM. This could cause problems with systems with two TPM chips such as 4th gen Intel systems. In addition, added the missing license and copyright platter to the tpm_ppi.c. Signed-off-by: Jarkko Sakkinen Reviewed-by: Jasob Gunthorpe Reviewed-by: Stefan Berger Tested-by: Scot Doyle Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm-chip.c | 4 +- drivers/char/tpm/tpm.h | 17 ++++- drivers/char/tpm/tpm_ppi.c | 141 ++++++++++++++++++++++-------------- drivers/char/tpm/tpm_tis.c | 14 +++- 4 files changed, 112 insertions(+), 64 deletions(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 7dc9999e2d54..64102de91ca3 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -147,7 +147,7 @@ int tpm_chip_register(struct tpm_chip *chip) if (rc) goto del_misc; - rc = tpm_add_ppi(&chip->dev->kobj); + rc = tpm_add_ppi(chip); if (rc) goto del_sysfs; @@ -191,7 +191,7 @@ void tpm_chip_unregister(struct tpm_chip *chip) if (chip->bios_dir) tpm_bios_log_teardown(chip->bios_dir); - tpm_remove_ppi(&chip->dev->kobj); + tpm_remove_ppi(chip); tpm_sysfs_del_device(chip); tpm_dev_del_device(chip); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 72ff18c872d3..3409acf953f3 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -27,6 +27,7 @@ #include #include #include +#include enum tpm_const { TPM_MINOR = 224, /* officially assigned */ @@ -94,8 +95,11 @@ struct tpm_vendor_specific { #define TPM_VID_WINBOND 0x1050 #define TPM_VID_STM 0x104A +#define TPM_PPI_VERSION_LEN 3 + enum tpm_chip_flags { TPM_CHIP_FLAG_REGISTERED = BIT(0), + TPM_CHIP_FLAG_PPI = BIT(1), }; struct tpm_chip { @@ -114,6 +118,11 @@ struct tpm_chip { struct dentry **bios_dir; +#ifdef CONFIG_ACPI + acpi_handle acpi_dev_handle; + char ppi_version[TPM_PPI_VERSION_LEN + 1]; +#endif /* CONFIG_ACPI */ + struct list_head list; }; @@ -345,15 +354,15 @@ void tpm_sysfs_del_device(struct tpm_chip *chip); int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); #ifdef CONFIG_ACPI -extern int tpm_add_ppi(struct kobject *); -extern void tpm_remove_ppi(struct kobject *); +extern int tpm_add_ppi(struct tpm_chip *chip); +extern void tpm_remove_ppi(struct tpm_chip *chip); #else -static inline int tpm_add_ppi(struct kobject *parent) +static inline int tpm_add_ppi(struct tpm_chip *chip) { return 0; } -static inline void tpm_remove_ppi(struct kobject *parent) +static inline void tpm_remove_ppi(struct tpm_chip *chip) { } #endif diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index 61dcc8011ec7..af48c56f642f 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2012-2014 Intel Corporation + * + * Authors: + * Xiaoyan Zhang + * Jiang Liu + * Jarkko Sakkinen + * + * Maintained by: + * + * This file contains implementation of the sysfs interface for PPI. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + + #include #include "tpm.h" @@ -12,7 +31,6 @@ #define PPI_TPM_REQ_MAX 22 #define PPI_VS_REQ_START 128 #define PPI_VS_REQ_END 255 -#define PPI_VERSION_LEN 3 static const u8 tpm_ppi_uuid[] = { 0xA6, 0xFA, 0xDD, 0x3D, @@ -22,45 +40,22 @@ static const u8 tpm_ppi_uuid[] = { 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 }; -static char tpm_ppi_version[PPI_VERSION_LEN + 1]; -static acpi_handle tpm_ppi_handle; - -static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, - void **return_value) -{ - union acpi_object *obj; - - if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, - 1 << TPM_PPI_FN_VERSION)) - return AE_OK; - - /* Cache version string */ - obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid, - TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, - NULL, ACPI_TYPE_STRING); - if (obj) { - strlcpy(tpm_ppi_version, obj->string.pointer, - PPI_VERSION_LEN + 1); - ACPI_FREE(obj); - } - - *return_value = handle; - - return AE_CTRL_TERMINATE; -} - static inline union acpi_object * -tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4) +tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type, + union acpi_object *argv4) { - BUG_ON(!tpm_ppi_handle); - return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid, - TPM_PPI_REVISION_ID, func, argv4, type); + BUG_ON(!ppi_handle); + return acpi_evaluate_dsm_typed(ppi_handle, tpm_ppi_uuid, + TPM_PPI_REVISION_ID, + func, argv4, type); } static ssize_t tpm_show_ppi_version(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version); + struct tpm_chip *chip = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version); } static ssize_t tpm_show_ppi_request(struct device *dev, @@ -68,8 +63,10 @@ static ssize_t tpm_show_ppi_request(struct device *dev, { ssize_t size = -EINVAL; union acpi_object *obj; + struct tpm_chip *chip = dev_get_drvdata(dev); - obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL); + obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ, + ACPI_TYPE_PACKAGE, NULL); if (!obj) return -ENXIO; @@ -103,14 +100,15 @@ static ssize_t tpm_store_ppi_request(struct device *dev, int func = TPM_PPI_FN_SUBREQ; union acpi_object *obj, tmp; union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp); + struct tpm_chip *chip = dev_get_drvdata(dev); /* * the function to submit TPM operation request to pre-os environment * is updated with function index from SUBREQ to SUBREQ2 since PPI * version 1.1 */ - if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, - 1 << TPM_PPI_FN_SUBREQ2)) + if (acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid, + TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2)) func = TPM_PPI_FN_SUBREQ2; /* @@ -119,7 +117,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev, * string/package type. For PPI version 1.0 and 1.1, use buffer type * for compatibility, and use package type since 1.2 according to spec. */ - if (strcmp(tpm_ppi_version, "1.2") < 0) { + if (strcmp(chip->ppi_version, "1.2") < 0) { if (sscanf(buf, "%d", &req) != 1) return -EINVAL; argv4.type = ACPI_TYPE_BUFFER; @@ -131,7 +129,8 @@ static ssize_t tpm_store_ppi_request(struct device *dev, return -EINVAL; } - obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4); + obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER, + &argv4); if (!obj) { return -ENXIO; } else { @@ -157,6 +156,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev, .buffer.length = 0, .buffer.pointer = NULL }; + struct tpm_chip *chip = dev_get_drvdata(dev); static char *info[] = { "None", @@ -171,9 +171,10 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev, * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for * compatibility, define params[3].type as buffer, if PPI version < 1.2 */ - if (strcmp(tpm_ppi_version, "1.2") < 0) + if (strcmp(chip->ppi_version, "1.2") < 0) obj = &tmp; - obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj); + obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT, + ACPI_TYPE_INTEGER, obj); if (!obj) { return -ENXIO; } else { @@ -196,8 +197,10 @@ static ssize_t tpm_show_ppi_response(struct device *dev, acpi_status status = -EINVAL; union acpi_object *obj, *ret_obj; u64 req, res; + struct tpm_chip *chip = dev_get_drvdata(dev); - obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL); + obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP, + ACPI_TYPE_PACKAGE, NULL); if (!obj) return -ENXIO; @@ -248,7 +251,8 @@ cleanup: return status; } -static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) +static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start, + u32 end) { int i; u32 ret; @@ -264,14 +268,15 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) "User not required", }; - if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, + if (!acpi_check_dsm(dev_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_GETOPR)) return -EPERM; tmp.integer.type = ACPI_TYPE_INTEGER; for (i = start; i <= end; i++) { tmp.integer.value = i; - obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv); + obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR, + ACPI_TYPE_INTEGER, &argv); if (!obj) { return -ENOMEM; } else { @@ -291,14 +296,20 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev, struct device_attribute *attr, char *buf) { - return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX); + struct tpm_chip *chip = dev_get_drvdata(dev); + + return show_ppi_operations(chip->acpi_dev_handle, buf, 0, + PPI_TPM_REQ_MAX); } static ssize_t tpm_show_ppi_vs_operations(struct device *dev, struct device_attribute *attr, char *buf) { - return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END); + struct tpm_chip *chip = dev_get_drvdata(dev); + + return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START, + PPI_VS_REQ_END); } static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL); @@ -323,16 +334,38 @@ static struct attribute_group ppi_attr_grp = { .attrs = ppi_attrs }; -int tpm_add_ppi(struct kobject *parent) +int tpm_add_ppi(struct tpm_chip *chip) { - /* Cache TPM ACPI handle and version string */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, - ppi_callback, NULL, NULL, &tpm_ppi_handle); - return tpm_ppi_handle ? sysfs_create_group(parent, &ppi_attr_grp) : 0; + union acpi_object *obj; + int rc; + + if (!chip->acpi_dev_handle) + return 0; + + if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid, + TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION)) + return 0; + + /* Cache PPI version string. */ + obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid, + TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION, + NULL, ACPI_TYPE_STRING); + if (obj) { + strlcpy(chip->ppi_version, obj->string.pointer, + sizeof(chip->ppi_version)); + ACPI_FREE(obj); + } + + rc = sysfs_create_group(&chip->dev->kobj, &ppi_attr_grp); + + if (!rc) + chip->flags |= TPM_CHIP_FLAG_PPI; + + return rc; } -void tpm_remove_ppi(struct kobject *parent) +void tpm_remove_ppi(struct tpm_chip *chip) { - if (tpm_ppi_handle) - sysfs_remove_group(parent, &ppi_attr_grp); + if (chip->flags & TPM_CHIP_FLAG_PPI) + sysfs_remove_group(&chip->dev->kobj, &ppi_attr_grp); } diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 36f4fec11c2a..9695850d2afa 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -580,8 +580,9 @@ static void tpm_tis_remove(struct tpm_chip *chip) release_locality(chip, chip->vendor.locality, 1); } -static int tpm_tis_init(struct device *dev, resource_size_t start, - resource_size_t len, unsigned int irq) +static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, + resource_size_t start, resource_size_t len, + unsigned int irq) { u32 vendor, intfcaps, intmask; int rc, i, irq_s, irq_e, probe; @@ -597,6 +598,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, return PTR_ERR(chip); chip->vendor.priv = priv; + chip->acpi_dev_handle = acpi_dev_handle; chip->vendor.iobase = devm_ioremap(dev, start, len); if (!chip->vendor.iobase) @@ -827,6 +829,7 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev, { resource_size_t start, len; unsigned int irq = 0; + acpi_handle acpi_dev_handle = NULL; start = pnp_mem_start(pnp_dev, 0); len = pnp_mem_len(pnp_dev, 0); @@ -839,7 +842,10 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev, if (is_itpm(pnp_dev)) itpm = true; - return tpm_tis_init(&pnp_dev->dev, start, len, irq); + if (pnp_acpi_device(pnp_dev)) + acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle; + + return tpm_tis_init(&pnp_dev->dev, acpi_dev_handle, start, len, irq); } static struct pnp_device_id tpm_pnp_tbl[] = { @@ -907,7 +913,7 @@ static int __init init_tis(void) rc = PTR_ERR(pdev); goto err_dev; } - rc = tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0); + rc = tpm_tis_init(&pdev->dev, NULL, TIS_MEM_BASE, TIS_MEM_LEN, 0); if (rc) goto err_init; return 0; From 71ed848fd791bc0b53a1b7a04f29eb9e994c7cbb Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 12 Dec 2014 11:46:36 -0800 Subject: [PATCH 30/64] tpm: rename chip->dev to chip->pdev Rename chip->dev to chip->pdev to make it explicit that this not the character device but actually represents the platform device. Signed-off-by: Jarkko Sakkinen Reviewed-by: Jasob Gunthorpe Reviewed-by: Stefan Berger Reviewed-by: Peter Huewe Tested-by: Scot Doyle Tested-by: Peter Huewe Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm-chip.c | 4 ++-- drivers/char/tpm/tpm-dev.c | 10 +++++----- drivers/char/tpm/tpm-interface.c | 29 +++++++++++++++-------------- drivers/char/tpm/tpm-sysfs.c | 6 +++--- drivers/char/tpm/tpm.h | 4 ++-- drivers/char/tpm/tpm_atmel.c | 14 +++++++------- drivers/char/tpm/tpm_i2c_atmel.c | 16 ++++++++-------- drivers/char/tpm/tpm_i2c_infineon.c | 6 +++--- drivers/char/tpm/tpm_i2c_nuvoton.c | 22 +++++++++++----------- drivers/char/tpm/tpm_i2c_stm_st33.c | 18 +++++++++--------- drivers/char/tpm/tpm_infineon.c | 22 +++++++++++----------- drivers/char/tpm/tpm_nsc.c | 20 ++++++++++---------- drivers/char/tpm/tpm_ppi.c | 4 ++-- drivers/char/tpm/tpm_tis.c | 14 +++++++------- 14 files changed, 95 insertions(+), 94 deletions(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 64102de91ca3..e72b042aa867 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -45,7 +45,7 @@ struct tpm_chip *tpm_chip_find_get(int chip_num) if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) continue; - if (try_module_get(pos->dev->driver->owner)) { + if (try_module_get(pos->pdev->driver->owner)) { chip = pos; break; } @@ -110,7 +110,7 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev, scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num); - chip->dev = dev; + chip->pdev = dev; devm_add_action(dev, tpmm_chip_remove, chip); dev_set_drvdata(dev, chip); diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index d9b774e02a1f..356832146788 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -63,7 +63,7 @@ static int tpm_open(struct inode *inode, struct file *file) * by the check of is_open variable, which is protected * by driver_lock. */ if (test_and_set_bit(0, &chip->is_open)) { - dev_dbg(chip->dev, "Another process owns this TPM\n"); + dev_dbg(chip->pdev, "Another process owns this TPM\n"); return -EBUSY; } @@ -81,7 +81,7 @@ static int tpm_open(struct inode *inode, struct file *file) INIT_WORK(&priv->work, timeout_work); file->private_data = priv; - get_device(chip->dev); + get_device(chip->pdev); return 0; } @@ -168,7 +168,7 @@ static int tpm_release(struct inode *inode, struct file *file) file->private_data = NULL; atomic_set(&priv->data_pending, 0); clear_bit(0, &priv->chip->is_open); - put_device(priv->chip->dev); + put_device(priv->chip->pdev); kfree(priv); return 0; } @@ -193,12 +193,12 @@ int tpm_dev_add_device(struct tpm_chip *chip) chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; chip->vendor.miscdev.name = chip->devname; - chip->vendor.miscdev.parent = chip->dev; + chip->vendor.miscdev.parent = chip->pdev; rc = misc_register(&chip->vendor.miscdev); if (rc) { chip->vendor.miscdev.name = NULL; - dev_err(chip->dev, + dev_err(chip->pdev, "unable to misc_register %s, minor %d err=%d\n", chip->vendor.miscdev.name, chip->vendor.miscdev.minor, rc); diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 4dbed1e45abd..e2af28fd63cb 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -343,7 +343,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, if (count == 0) return -ENODATA; if (count > bufsiz) { - dev_err(chip->dev, + dev_err(chip->pdev, "invalid count value %x %zx\n", count, bufsiz); return -E2BIG; } @@ -352,7 +352,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { - dev_err(chip->dev, + dev_err(chip->pdev, "tpm_transmit: tpm_send: error %zd\n", rc); goto out; } @@ -368,7 +368,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, goto out_recv; if (chip->ops->req_canceled(chip, status)) { - dev_err(chip->dev, "Operation Canceled\n"); + dev_err(chip->pdev, "Operation Canceled\n"); rc = -ECANCELED; goto out; } @@ -378,14 +378,14 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, } while (time_before(jiffies, stop)); chip->ops->cancel(chip); - dev_err(chip->dev, "Operation Timed out\n"); + dev_err(chip->pdev, "Operation Timed out\n"); rc = -ETIME; goto out; out_recv: rc = chip->ops->recv(chip, (u8 *) buf, bufsiz); if (rc < 0) - dev_err(chip->dev, + dev_err(chip->pdev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: mutex_unlock(&chip->tpm_mutex); @@ -411,7 +411,8 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, err = be32_to_cpu(header->return_code); if (err != 0 && desc) - dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); + dev_err(chip->pdev, "A TPM error (%d) occurred %s\n", err, + desc); return err; } @@ -505,7 +506,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) if (rc == TPM_ERR_INVALID_POSTINIT) { /* The TPM is not started, we are the first to talk to it. Execute a startup command. */ - dev_info(chip->dev, "Issuing TPM_STARTUP"); + dev_info(chip->pdev, "Issuing TPM_STARTUP"); if (tpm_startup(chip, TPM_ST_CLEAR)) return rc; @@ -517,7 +518,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) NULL); } if (rc) { - dev_err(chip->dev, + dev_err(chip->pdev, "A TPM error (%zd) occurred attempting to determine the timeouts\n", rc); goto duration; @@ -556,7 +557,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) /* Report adjusted timeouts */ if (chip->vendor.timeout_adjusted) { - dev_info(chip->dev, + dev_info(chip->pdev, HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n", old_timeout[0], new_timeout[0], old_timeout[1], new_timeout[1], @@ -603,7 +604,7 @@ duration: chip->vendor.duration[TPM_MEDIUM] *= 1000; chip->vendor.duration[TPM_LONG] *= 1000; chip->vendor.duration_adjusted = true; - dev_info(chip->dev, "Adjusting TPM timeout parameters."); + dev_info(chip->pdev, "Adjusting TPM timeout parameters."); } return 0; } @@ -760,7 +761,7 @@ int tpm_do_selftest(struct tpm_chip *chip) * around 300ms while the self test is ongoing, keep trying * until the self test duration expires. */ if (rc == -ETIME) { - dev_info(chip->dev, HW_ERR "TPM command timed out during continue self test"); + dev_info(chip->pdev, HW_ERR "TPM command timed out during continue self test"); msleep(delay_msec); continue; } @@ -770,7 +771,7 @@ int tpm_do_selftest(struct tpm_chip *chip) rc = be32_to_cpu(cmd.header.out.return_code); if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) { - dev_info(chip->dev, + dev_info(chip->pdev, "TPM is disabled/deactivated (0x%X)\n", rc); /* TPM is disabled and/or deactivated; driver can * proceed and TPM does handle commands for @@ -918,10 +919,10 @@ int tpm_pm_suspend(struct device *dev) } if (rc) - dev_err(chip->dev, + dev_err(chip->pdev, "Error (%d) sending savestate before suspend\n", rc); else if (try > 0) - dev_warn(chip->dev, "TPM savestate took %dms\n", + dev_warn(chip->pdev, "TPM savestate took %dms\n", try * TPM_TIMEOUT_RETRY); return rc; diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 8ecb052e290d..ee66fd4673f3 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -284,16 +284,16 @@ static const struct attribute_group tpm_dev_group = { int tpm_sysfs_add_device(struct tpm_chip *chip) { int err; - err = sysfs_create_group(&chip->dev->kobj, + err = sysfs_create_group(&chip->pdev->kobj, &tpm_dev_group); if (err) - dev_err(chip->dev, + dev_err(chip->pdev, "failed to create sysfs attributes, %d\n", err); return err; } void tpm_sysfs_del_device(struct tpm_chip *chip) { - sysfs_remove_group(&chip->dev->kobj, &tpm_dev_group); + sysfs_remove_group(&chip->pdev->kobj, &tpm_dev_group); } diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 3409acf953f3..adf6af835329 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -103,7 +103,7 @@ enum tpm_chip_flags { }; struct tpm_chip { - struct device *dev; /* Device stuff */ + struct device *pdev; /* Device stuff */ const struct tpm_class_ops *ops; unsigned int flags; @@ -130,7 +130,7 @@ struct tpm_chip { static inline void tpm_chip_put(struct tpm_chip *chip) { - module_put(chip->dev->driver->owner); + module_put(chip->pdev->driver->owner); } static inline int tpm_read_index(int base, int index) diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 3d4c6c3b0433..dfadad0916a1 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -49,7 +49,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) for (i = 0; i < 6; i++) { status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { - dev_err(chip->dev, "error reading header\n"); + dev_err(chip->pdev, "error reading header\n"); return -EIO; } *buf++ = ioread8(chip->vendor.iobase); @@ -60,12 +60,12 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) size = be32_to_cpu(*native_size); if (count < size) { - dev_err(chip->dev, + dev_err(chip->pdev, "Recv size(%d) less than available space\n", size); for (; i < size; i++) { /* clear the waiting data anyway */ status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { - dev_err(chip->dev, "error reading data\n"); + dev_err(chip->pdev, "error reading data\n"); return -EIO; } } @@ -76,7 +76,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) for (; i < size; i++) { status = ioread8(chip->vendor.iobase + 1); if ((status & ATML_STATUS_DATA_AVAIL) == 0) { - dev_err(chip->dev, "error reading data\n"); + dev_err(chip->pdev, "error reading data\n"); return -EIO; } *buf++ = ioread8(chip->vendor.iobase); @@ -86,7 +86,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) status = ioread8(chip->vendor.iobase + 1); if (status & ATML_STATUS_DATA_AVAIL) { - dev_err(chip->dev, "data available is stuck\n"); + dev_err(chip->pdev, "data available is stuck\n"); return -EIO; } @@ -97,9 +97,9 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) { int i; - dev_dbg(chip->dev, "tpm_atml_send:\n"); + dev_dbg(chip->pdev, "tpm_atml_send:\n"); for (i = 0; i < count; i++) { - dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); + dev_dbg(chip->pdev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); iowrite8(buf[i], chip->vendor.iobase); } diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c index 643a9402e911..7a0ca78ad3c6 100644 --- a/drivers/char/tpm/tpm_i2c_atmel.c +++ b/drivers/char/tpm/tpm_i2c_atmel.c @@ -52,7 +52,7 @@ struct priv_data { static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) { struct priv_data *priv = chip->vendor.priv; - struct i2c_client *client = to_i2c_client(chip->dev); + struct i2c_client *client = to_i2c_client(chip->pdev); s32 status; priv->len = 0; @@ -62,7 +62,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) status = i2c_master_send(client, buf, len); - dev_dbg(chip->dev, + dev_dbg(chip->pdev, "%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__, (int)min_t(size_t, 64, len), buf, len, status); return status; @@ -71,7 +71,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len) static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) { struct priv_data *priv = chip->vendor.priv; - struct i2c_client *client = to_i2c_client(chip->dev); + struct i2c_client *client = to_i2c_client(chip->pdev); struct tpm_output_header *hdr = (struct tpm_output_header *)priv->buffer; u32 expected_len; @@ -88,7 +88,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) return -ENOMEM; if (priv->len >= expected_len) { - dev_dbg(chip->dev, + dev_dbg(chip->pdev, "%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__, (int)min_t(size_t, 64, expected_len), buf, count, expected_len); @@ -97,7 +97,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) } rc = i2c_master_recv(client, buf, expected_len); - dev_dbg(chip->dev, + dev_dbg(chip->pdev, "%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__, (int)min_t(size_t, 64, expected_len), buf, count, expected_len); @@ -106,13 +106,13 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count) static void i2c_atmel_cancel(struct tpm_chip *chip) { - dev_err(chip->dev, "TPM operation cancellation was requested, but is not supported"); + dev_err(chip->pdev, "TPM operation cancellation was requested, but is not supported"); } static u8 i2c_atmel_read_status(struct tpm_chip *chip) { struct priv_data *priv = chip->vendor.priv; - struct i2c_client *client = to_i2c_client(chip->dev); + struct i2c_client *client = to_i2c_client(chip->pdev); int rc; /* The TPM fails the I2C read until it is ready, so we do the entire @@ -125,7 +125,7 @@ static u8 i2c_atmel_read_status(struct tpm_chip *chip) /* Once the TPM has completed the command the command remains readable * until another command is issued. */ rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer)); - dev_dbg(chip->dev, + dev_dbg(chip->pdev, "%s: sts=%d", __func__, rc); if (rc <= 0) return 0; diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index 03708e6b309a..33c5f360ab01 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -446,7 +446,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) /* read first 10 bytes, including tag, paramsize, and result */ size = recv_data(chip, buf, TPM_HEADER_SIZE); if (size < TPM_HEADER_SIZE) { - dev_err(chip->dev, "Unable to read header\n"); + dev_err(chip->pdev, "Unable to read header\n"); goto out; } @@ -459,14 +459,14 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) size += recv_data(chip, &buf[TPM_HEADER_SIZE], expected - TPM_HEADER_SIZE); if (size < expected) { - dev_err(chip->dev, "Unable to read remainder of result\n"); + dev_err(chip->pdev, "Unable to read remainder of result\n"); size = -ETIME; goto out; } wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); if (status & TPM_STS_DATA_AVAIL) { /* retry? */ - dev_err(chip->dev, "Error left over data\n"); + dev_err(chip->pdev, "Error left over data\n"); size = -EIO; goto out; } diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index 8c23088d99ef..e1eadb0c1568 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -96,13 +96,13 @@ static s32 i2c_nuvoton_write_buf(struct i2c_client *client, u8 offset, u8 size, /* read TPM_STS register */ static u8 i2c_nuvoton_read_status(struct tpm_chip *chip) { - struct i2c_client *client = to_i2c_client(chip->dev); + struct i2c_client *client = to_i2c_client(chip->pdev); s32 status; u8 data; status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data); if (status <= 0) { - dev_err(chip->dev, "%s() error return %d\n", __func__, + dev_err(chip->pdev, "%s() error return %d\n", __func__, status); data = TPM_STS_ERR_VAL; } @@ -127,13 +127,13 @@ static s32 i2c_nuvoton_write_status(struct i2c_client *client, u8 data) /* write commandReady to TPM_STS register */ static void i2c_nuvoton_ready(struct tpm_chip *chip) { - struct i2c_client *client = to_i2c_client(chip->dev); + struct i2c_client *client = to_i2c_client(chip->pdev); s32 status; /* this causes the current command to be aborted */ status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY); if (status < 0) - dev_err(chip->dev, + dev_err(chip->pdev, "%s() fail to write TPM_STS.commandReady\n", __func__); } @@ -212,7 +212,7 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value, return 0; } while (time_before(jiffies, stop)); } - dev_err(chip->dev, "%s(%02x, %02x) -> timeout\n", __func__, mask, + dev_err(chip->pdev, "%s(%02x, %02x) -> timeout\n", __func__, mask, value); return -ETIMEDOUT; } @@ -240,7 +240,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client, &chip->vendor.read_queue) == 0) { burst_count = i2c_nuvoton_get_burstcount(client, chip); if (burst_count < 0) { - dev_err(chip->dev, + dev_err(chip->pdev, "%s() fail to read burstCount=%d\n", __func__, burst_count); return -EIO; @@ -249,12 +249,12 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client, rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_R, bytes2read, &buf[size]); if (rc < 0) { - dev_err(chip->dev, + dev_err(chip->pdev, "%s() fail on i2c_nuvoton_read_buf()=%d\n", __func__, rc); return -EIO; } - dev_dbg(chip->dev, "%s(%d):", __func__, bytes2read); + dev_dbg(chip->pdev, "%s(%d):", __func__, bytes2read); size += bytes2read; } @@ -264,7 +264,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client, /* Read TPM command results */ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) { - struct device *dev = chip->dev; + struct device *dev = chip->pdev; struct i2c_client *client = to_i2c_client(dev); s32 rc; int expected, status, burst_count, retries, size = 0; @@ -334,7 +334,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) break; } i2c_nuvoton_ready(chip); - dev_dbg(chip->dev, "%s() -> %d\n", __func__, size); + dev_dbg(chip->pdev, "%s() -> %d\n", __func__, size); return size; } @@ -347,7 +347,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) */ static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len) { - struct device *dev = chip->dev; + struct device *dev = chip->pdev; struct i2c_client *client = to_i2c_client(dev); u32 ordinal; size_t count = 0; diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 9a96d3704fe5..48c4808d5a7a 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -588,7 +588,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, size = recv_data(chip, buf, TPM_HEADER_SIZE); if (size < TPM_HEADER_SIZE) { - dev_err(chip->dev, "Unable to read header\n"); + dev_err(chip->pdev, "Unable to read header\n"); goto out; } @@ -601,7 +601,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, size += recv_data(chip, &buf[TPM_HEADER_SIZE], expected - TPM_HEADER_SIZE); if (size < expected) { - dev_err(chip->dev, "Unable to read remainder of result\n"); + dev_err(chip->pdev, "Unable to read remainder of result\n"); size = -ETIME; goto out; } @@ -639,14 +639,14 @@ static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip) pp = client->dev.of_node; if (!pp) { - dev_err(chip->dev, "No platform data\n"); + dev_err(chip->pdev, "No platform data\n"); return -ENODEV; } /* Get GPIO from device tree */ gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0); if (gpio < 0) { - dev_err(chip->dev, "Failed to retrieve lpcpd-gpios from dts.\n"); + dev_err(chip->pdev, "Failed to retrieve lpcpd-gpios from dts.\n"); tpm_dev->io_lpcpd = -1; /* * lpcpd pin is not specified. This is not an issue as @@ -659,7 +659,7 @@ static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip) ret = devm_gpio_request_one(&client->dev, gpio, GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD"); if (ret) { - dev_err(chip->dev, "Failed to request lpcpd pin\n"); + dev_err(chip->pdev, "Failed to request lpcpd pin\n"); return -ENODEV; } tpm_dev->io_lpcpd = gpio; @@ -682,7 +682,7 @@ static int tpm_stm_i2c_request_resources(struct i2c_client *client, pdata = client->dev.platform_data; if (!pdata) { - dev_err(chip->dev, "No platform data\n"); + dev_err(chip->pdev, "No platform data\n"); return -ENODEV; } @@ -694,7 +694,7 @@ static int tpm_stm_i2c_request_resources(struct i2c_client *client, pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH, "TPM IO_LPCPD"); if (ret) { - dev_err(chip->dev, "%s : reset gpio_request failed\n", + dev_err(chip->pdev, "%s : reset gpio_request failed\n", __FILE__); return ret; } @@ -776,7 +776,7 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) IRQF_TRIGGER_HIGH, "TPM SERIRQ management", chip); if (ret < 0) { - dev_err(chip->dev , "TPM SERIRQ signals %d not available\n", + dev_err(chip->pdev , "TPM SERIRQ signals %d not available\n", client->irq); goto _tpm_clean_answer; } @@ -807,7 +807,7 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) return tpm_chip_register(chip); _tpm_clean_answer: - dev_info(chip->dev, "TPM I2C initialisation fail\n"); + dev_info(chip->pdev, "TPM I2C initialisation fail\n"); return ret; } diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index dcdb671b2a5d..6d492132ad2b 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -195,9 +195,9 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) } if (i == TPM_MAX_TRIES) { /* timeout occurs */ if (wait_for_bit == STAT_XFE) - dev_err(chip->dev, "Timeout in wait(STAT_XFE)\n"); + dev_err(chip->pdev, "Timeout in wait(STAT_XFE)\n"); if (wait_for_bit == STAT_RDA) - dev_err(chip->dev, "Timeout in wait(STAT_RDA)\n"); + dev_err(chip->pdev, "Timeout in wait(STAT_RDA)\n"); return -EIO; } return 0; @@ -220,7 +220,7 @@ static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) static void tpm_wtx(struct tpm_chip *chip) { number_of_wtx++; - dev_info(chip->dev, "Granting WTX (%02d / %02d)\n", + dev_info(chip->pdev, "Granting WTX (%02d / %02d)\n", number_of_wtx, TPM_MAX_WTX_PACKAGES); wait_and_send(chip, TPM_VL_VER); wait_and_send(chip, TPM_CTRL_WTX); @@ -231,7 +231,7 @@ static void tpm_wtx(struct tpm_chip *chip) static void tpm_wtx_abort(struct tpm_chip *chip) { - dev_info(chip->dev, "Aborting WTX\n"); + dev_info(chip->pdev, "Aborting WTX\n"); wait_and_send(chip, TPM_VL_VER); wait_and_send(chip, TPM_CTRL_WTX_ABORT); wait_and_send(chip, 0x00); @@ -257,7 +257,7 @@ recv_begin: } if (buf[0] != TPM_VL_VER) { - dev_err(chip->dev, + dev_err(chip->pdev, "Wrong transport protocol implementation!\n"); return -EIO; } @@ -272,7 +272,7 @@ recv_begin: } if ((size == 0x6D00) && (buf[1] == 0x80)) { - dev_err(chip->dev, "Error handling on vendor layer!\n"); + dev_err(chip->pdev, "Error handling on vendor layer!\n"); return -EIO; } @@ -284,7 +284,7 @@ recv_begin: } if (buf[1] == TPM_CTRL_WTX) { - dev_info(chip->dev, "WTX-package received\n"); + dev_info(chip->pdev, "WTX-package received\n"); if (number_of_wtx < TPM_MAX_WTX_PACKAGES) { tpm_wtx(chip); goto recv_begin; @@ -295,14 +295,14 @@ recv_begin: } if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) { - dev_info(chip->dev, "WTX-abort acknowledged\n"); + dev_info(chip->pdev, "WTX-abort acknowledged\n"); return size; } if (buf[1] == TPM_CTRL_ERROR) { - dev_err(chip->dev, "ERROR-package received:\n"); + dev_err(chip->pdev, "ERROR-package received:\n"); if (buf[4] == TPM_INF_NAK) - dev_err(chip->dev, + dev_err(chip->pdev, "-> Negative acknowledgement" " - retransmit command!\n"); return -EIO; @@ -321,7 +321,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count) ret = empty_fifo(chip, 1); if (ret) { - dev_err(chip->dev, "Timeout while clearing FIFO\n"); + dev_err(chip->pdev, "Timeout while clearing FIFO\n"); return -EIO; } diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 6e2c2e64b292..289389ecef84 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -113,7 +113,7 @@ static int nsc_wait_for_ready(struct tpm_chip *chip) } while (time_before(jiffies, stop)); - dev_info(chip->dev, "wait for ready failed\n"); + dev_info(chip->pdev, "wait for ready failed\n"); return -EBUSY; } @@ -129,12 +129,12 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) return -EIO; if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) { - dev_err(chip->dev, "F0 timeout\n"); + dev_err(chip->pdev, "F0 timeout\n"); return -EIO; } if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) { - dev_err(chip->dev, "not in normal mode (0x%x)\n", + dev_err(chip->pdev, "not in normal mode (0x%x)\n", data); return -EIO; } @@ -143,7 +143,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) for (p = buffer; p < &buffer[count]; p++) { if (wait_for_stat (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) { - dev_err(chip->dev, + dev_err(chip->pdev, "OBF timeout (while reading data)\n"); return -EIO; } @@ -154,11 +154,11 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) if ((data & NSC_STATUS_F0) == 0 && (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) { - dev_err(chip->dev, "F0 not set\n"); + dev_err(chip->pdev, "F0 not set\n"); return -EIO; } if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) { - dev_err(chip->dev, + dev_err(chip->pdev, "expected end of command(0x%x)\n", data); return -EIO; } @@ -189,19 +189,19 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) return -EIO; if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { - dev_err(chip->dev, "IBF timeout\n"); + dev_err(chip->pdev, "IBF timeout\n"); return -EIO; } outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND); if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) { - dev_err(chip->dev, "IBR timeout\n"); + dev_err(chip->pdev, "IBR timeout\n"); return -EIO; } for (i = 0; i < count; i++) { if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { - dev_err(chip->dev, + dev_err(chip->pdev, "IBF timeout (while writing data)\n"); return -EIO; } @@ -209,7 +209,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) } if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { - dev_err(chip->dev, "IBF timeout\n"); + dev_err(chip->pdev, "IBF timeout\n"); return -EIO; } outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND); diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index af48c56f642f..6ca9b5d78144 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -356,7 +356,7 @@ int tpm_add_ppi(struct tpm_chip *chip) ACPI_FREE(obj); } - rc = sysfs_create_group(&chip->dev->kobj, &ppi_attr_grp); + rc = sysfs_create_group(&chip->pdev->kobj, &ppi_attr_grp); if (!rc) chip->flags |= TPM_CHIP_FLAG_PPI; @@ -367,5 +367,5 @@ int tpm_add_ppi(struct tpm_chip *chip) void tpm_remove_ppi(struct tpm_chip *chip) { if (chip->flags & TPM_CHIP_FLAG_PPI) - sysfs_remove_group(&chip->dev->kobj, &ppi_attr_grp); + sysfs_remove_group(&chip->pdev->kobj, &ppi_attr_grp); } diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 9695850d2afa..9e02489a94f3 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -242,7 +242,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) /* read first 10 bytes, including tag, paramsize, and result */ if ((size = recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) { - dev_err(chip->dev, "Unable to read header\n"); + dev_err(chip->pdev, "Unable to read header\n"); goto out; } @@ -255,7 +255,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) if ((size += recv_data(chip, &buf[TPM_HEADER_SIZE], expected - TPM_HEADER_SIZE)) < expected) { - dev_err(chip->dev, "Unable to read remainder of result\n"); + dev_err(chip->pdev, "Unable to read remainder of result\n"); size = -ETIME; goto out; } @@ -264,7 +264,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) &chip->vendor.int_queue, false); status = tpm_tis_status(chip); if (status & TPM_STS_DATA_AVAIL) { /* retry? */ - dev_err(chip->dev, "Error left over data\n"); + dev_err(chip->pdev, "Error left over data\n"); size = -EIO; goto out; } @@ -406,7 +406,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) msleep(1); if (!priv->irq_tested) { disable_interrupts(chip); - dev_err(chip->dev, + dev_err(chip->pdev, FW_BUG "TPM interrupt not working, polling instead\n"); } priv->irq_tested = true; @@ -476,7 +476,7 @@ static int probe_itpm(struct tpm_chip *chip) rc = tpm_tis_send_data(chip, cmd_getticks, len); if (rc == 0) { - dev_info(chip->dev, "Detected an iTPM.\n"); + dev_info(chip->pdev, "Detected an iTPM.\n"); rc = 1; } else rc = -EFAULT; @@ -699,7 +699,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, if (devm_request_irq (dev, i, tis_int_probe, IRQF_SHARED, chip->vendor.miscdev.name, chip) != 0) { - dev_info(chip->dev, + dev_info(chip->pdev, "Unable to request irq: %d for probe\n", i); continue; @@ -746,7 +746,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, if (devm_request_irq (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED, chip->vendor.miscdev.name, chip) != 0) { - dev_info(chip->dev, + dev_info(chip->pdev, "Unable to request irq: %d for use\n", chip->vendor.irq); chip->vendor.irq = 0; From 313d21eeab9282e01fdcecd40e9ca87e0953627f Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 12 Dec 2014 11:46:37 -0800 Subject: [PATCH 31/64] tpm: device class for tpm Added own device class for TPM. Uses MISC_MAJOR:TPM_MINOR for the first character device in order to retain backwards compatibility. Added tpm_dev_release() back attached to the character device. I've been running this code now for a while on my laptop (Lenovo T430S) TrouSerS works perfectly without modifications. I don't believe it breaks anything significantly. The sysfs attributes that have been placed under the wrong place and are against sysfs-rules.txt should be probably left to stagnate under platform device directory and start defining new sysfs attributes to the char device directory. Guidelines for future TPM sysfs attributes should be probably along the lines of - Single flat set of mandatory sysfs attributes. For example, current PPI interface is way way too rich when you only want to use it to clear and activate the TPM. - Define sysfs attribute if and only if there's no way to get the value from ring-3. No attributes for TPM properties. It's just unnecessary maintenance hurdle that we don't want. Signed-off-by: Jarkko Sakkinen Reviewed-by: Jasob Gunthorpe Reviewed-by: Stefan Berger Tested-by: Scot Doyle Tested-by: Peter Huewe Signed-off-by: Peter Huewe --- Documentation/ABI/stable/sysfs-class-tpm | 22 ++++---- drivers/char/tpm/tpm-chip.c | 72 ++++++++++++++++++++---- drivers/char/tpm/tpm-dev.c | 36 +----------- drivers/char/tpm/tpm-interface.c | 29 ++++++++++ drivers/char/tpm/tpm.h | 12 ++-- drivers/char/tpm/tpm_i2c_nuvoton.c | 2 +- drivers/char/tpm/tpm_tis.c | 4 +- 7 files changed, 116 insertions(+), 61 deletions(-) diff --git a/Documentation/ABI/stable/sysfs-class-tpm b/Documentation/ABI/stable/sysfs-class-tpm index a60b45e2493b..9f790eebb5d2 100644 --- a/Documentation/ABI/stable/sysfs-class-tpm +++ b/Documentation/ABI/stable/sysfs-class-tpm @@ -1,4 +1,4 @@ -What: /sys/class/misc/tpmX/device/ +What: /sys/class/tpm/tpmX/device/ Date: April 2005 KernelVersion: 2.6.12 Contact: tpmdd-devel@lists.sf.net @@ -6,7 +6,7 @@ Description: The device/ directory under a specific TPM instance exposes the properties of that TPM chip -What: /sys/class/misc/tpmX/device/active +What: /sys/class/tpm/tpmX/device/active Date: April 2006 KernelVersion: 2.6.17 Contact: tpmdd-devel@lists.sf.net @@ -18,7 +18,7 @@ Description: The "active" property prints a '1' if the TPM chip is accepting section 17 for more information on which commands are available. -What: /sys/class/misc/tpmX/device/cancel +What: /sys/class/tpm/tpmX/device/cancel Date: June 2005 KernelVersion: 2.6.13 Contact: tpmdd-devel@lists.sf.net @@ -26,7 +26,7 @@ Description: The "cancel" property allows you to cancel the currently pending TPM command. Writing any value to cancel will call the TPM vendor specific cancel operation. -What: /sys/class/misc/tpmX/device/caps +What: /sys/class/tpm/tpmX/device/caps Date: April 2005 KernelVersion: 2.6.12 Contact: tpmdd-devel@lists.sf.net @@ -43,7 +43,7 @@ Description: The "caps" property contains TPM manufacturer and version info. the chip supports. Firmware version is that of the chip and is manufacturer specific. -What: /sys/class/misc/tpmX/device/durations +What: /sys/class/tpm/tpmX/device/durations Date: March 2011 KernelVersion: 3.1 Contact: tpmdd-devel@lists.sf.net @@ -66,7 +66,7 @@ Description: The "durations" property shows the 3 vendor-specific values scaled to be displayed in usecs. In this case "[adjusted]" will be displayed in place of "[original]". -What: /sys/class/misc/tpmX/device/enabled +What: /sys/class/tpm/tpmX/device/enabled Date: April 2006 KernelVersion: 2.6.17 Contact: tpmdd-devel@lists.sf.net @@ -75,7 +75,7 @@ Description: The "enabled" property prints a '1' if the TPM chip is enabled, may be visible but produce a '0' after some operation that disables the TPM. -What: /sys/class/misc/tpmX/device/owned +What: /sys/class/tpm/tpmX/device/owned Date: April 2006 KernelVersion: 2.6.17 Contact: tpmdd-devel@lists.sf.net @@ -83,7 +83,7 @@ Description: The "owned" property produces a '1' if the TPM_TakeOwnership ordinal has been executed successfully in the chip. A '0' indicates that ownership hasn't been taken. -What: /sys/class/misc/tpmX/device/pcrs +What: /sys/class/tpm/tpmX/device/pcrs Date: April 2005 KernelVersion: 2.6.12 Contact: tpmdd-devel@lists.sf.net @@ -106,7 +106,7 @@ Description: The "pcrs" property will dump the current value of all Platform 1.2 chips, PCRs represent SHA-1 hashes, which are 20 bytes long. Use the "caps" property to determine TPM version. -What: /sys/class/misc/tpmX/device/pubek +What: /sys/class/tpm/tpmX/device/pubek Date: April 2005 KernelVersion: 2.6.12 Contact: tpmdd-devel@lists.sf.net @@ -158,7 +158,7 @@ Description: The "pubek" property will return the TPM's public endorsement Modulus Length: 256 (bytes) Modulus: The 256 byte Endorsement Key modulus -What: /sys/class/misc/tpmX/device/temp_deactivated +What: /sys/class/tpm/tpmX/device/temp_deactivated Date: April 2006 KernelVersion: 2.6.17 Contact: tpmdd-devel@lists.sf.net @@ -167,7 +167,7 @@ Description: The "temp_deactivated" property returns a '1' if the chip has cycle. Whether a warm boot (reboot) will clear a TPM chip from a temp_deactivated state is platform specific. -What: /sys/class/misc/tpmX/device/timeouts +What: /sys/class/tpm/tpmX/device/timeouts Date: March 2011 KernelVersion: 3.1 Contact: tpmdd-devel@lists.sf.net diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index e72b042aa867..7596eef3bff9 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "tpm.h" #include "tpm_eventlog.h" @@ -32,6 +33,9 @@ static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); static LIST_HEAD(tpm_chip_list); static DEFINE_SPINLOCK(driver_lock); +struct class *tpm_class; +dev_t tpm_devt; + /* * tpm_chip_find_get - return tpm_chip for a given chip number * @chip_num the device number for the chip @@ -55,16 +59,14 @@ struct tpm_chip *tpm_chip_find_get(int chip_num) } /** - * tpmm_chip_remove() - free chip memory and device number - * @data: points to struct tpm_chip instance + * tpm_dev_release() - free chip memory and the device number + * @dev: the character device for the TPM chip * - * This is used internally by tpmm_chip_alloc() and called by devres - * when the device is released. This function does the opposite of - * tpmm_chip_alloc() freeing memory and the device number. + * This is used as the release function for the character device. */ -static void tpmm_chip_remove(void *data) +static void tpm_dev_release(struct device *dev) { - struct tpm_chip *chip = (struct tpm_chip *) data; + struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); spin_lock(&driver_lock); clear_bit(chip->dev_num, dev_mask); @@ -111,18 +113,68 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev, scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num); chip->pdev = dev; - devm_add_action(dev, tpmm_chip_remove, chip); + dev_set_drvdata(dev, chip); + chip->dev.class = tpm_class; + chip->dev.release = tpm_dev_release; + chip->dev.parent = chip->pdev; + + if (chip->dev_num == 0) + chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR); + else + chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num); + + dev_set_name(&chip->dev, chip->devname); + + device_initialize(&chip->dev); + + chip->cdev.owner = chip->pdev->driver->owner; + cdev_init(&chip->cdev, &tpm_fops); + return chip; } EXPORT_SYMBOL_GPL(tpmm_chip_alloc); +static int tpm_dev_add_device(struct tpm_chip *chip) +{ + int rc; + + rc = device_add(&chip->dev); + if (rc) { + dev_err(&chip->dev, + "unable to device_register() %s, major %d, minor %d, err=%d\n", + chip->devname, MAJOR(chip->dev.devt), + MINOR(chip->dev.devt), rc); + + return rc; + } + + rc = cdev_add(&chip->cdev, chip->dev.devt, 1); + if (rc) { + dev_err(&chip->dev, + "unable to cdev_add() %s, major %d, minor %d, err=%d\n", + chip->devname, MAJOR(chip->dev.devt), + MINOR(chip->dev.devt), rc); + + device_unregister(&chip->dev); + return rc; + } + + return rc; +} + +static void tpm_dev_del_device(struct tpm_chip *chip) +{ + cdev_del(&chip->cdev); + device_unregister(&chip->dev); +} + /* - * tpm_chip_register() - create a misc driver for the TPM chip + * tpm_chip_register() - create a character device for the TPM chip * @chip: TPM chip to use. * - * Creates a misc driver for the TPM chip and adds sysfs interfaces for + * Creates a character device for the TPM chip and adds sysfs interfaces for * the device, PPI and TCPA. As the last step this function adds the * chip to the list of TPM chips available for use. * diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index 356832146788..de0337ebd658 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -17,7 +17,6 @@ * License. * */ -#include #include #include #include "tpm.h" @@ -54,9 +53,8 @@ static void timeout_work(struct work_struct *work) static int tpm_open(struct inode *inode, struct file *file) { - struct miscdevice *misc = file->private_data; - struct tpm_chip *chip = container_of(misc, struct tpm_chip, - vendor.miscdev); + struct tpm_chip *chip = + container_of(inode->i_cdev, struct tpm_chip, cdev); struct file_priv *priv; /* It's assured that the chip will be opened just once, @@ -173,7 +171,7 @@ static int tpm_release(struct inode *inode, struct file *file) return 0; } -static const struct file_operations tpm_fops = { +const struct file_operations tpm_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .open = tpm_open, @@ -182,32 +180,4 @@ static const struct file_operations tpm_fops = { .release = tpm_release, }; -int tpm_dev_add_device(struct tpm_chip *chip) -{ - int rc; - chip->vendor.miscdev.fops = &tpm_fops; - if (chip->dev_num == 0) - chip->vendor.miscdev.minor = TPM_MINOR; - else - chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; - - chip->vendor.miscdev.name = chip->devname; - chip->vendor.miscdev.parent = chip->pdev; - - rc = misc_register(&chip->vendor.miscdev); - if (rc) { - chip->vendor.miscdev.name = NULL; - dev_err(chip->pdev, - "unable to misc_register %s, minor %d err=%d\n", - chip->vendor.miscdev.name, - chip->vendor.miscdev.minor, rc); - } - return rc; -} - -void tpm_dev_del_device(struct tpm_chip *chip) -{ - if (chip->vendor.miscdev.name) - misc_deregister(&chip->vendor.miscdev); -} diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index e2af28fd63cb..b6f6b17392fd 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -997,6 +997,35 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) } EXPORT_SYMBOL_GPL(tpm_get_random); +static int __init tpm_init(void) +{ + int rc; + + tpm_class = class_create(THIS_MODULE, "tpm"); + if (IS_ERR(tpm_class)) { + pr_err("couldn't create tpm class\n"); + return PTR_ERR(tpm_class); + } + + rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm"); + if (rc < 0) { + pr_err("tpm: failed to allocate char dev region\n"); + class_destroy(tpm_class); + return rc; + } + + return 0; +} + +static void __exit tpm_exit(void) +{ + class_destroy(tpm_class); + unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES); +} + +subsys_initcall(tpm_init); +module_exit(tpm_exit); + MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); MODULE_DESCRIPTION("TPM Driver"); MODULE_VERSION("2.0"); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index adf6af835329..d46765b4c97e 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -23,11 +23,11 @@ #include #include #include -#include #include #include #include #include +#include enum tpm_const { TPM_MINOR = 224, /* officially assigned */ @@ -74,7 +74,6 @@ struct tpm_vendor_specific { int region_size; int have_region; - struct miscdevice miscdev; struct list_head list; int locality; unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */ @@ -104,6 +103,9 @@ enum tpm_chip_flags { struct tpm_chip { struct device *pdev; /* Device stuff */ + struct device dev; + struct cdev cdev; + const struct tpm_class_ops *ops; unsigned int flags; @@ -326,6 +328,10 @@ struct tpm_cmd_t { tpm_cmd_params params; } __packed; +extern struct class *tpm_class; +extern dev_t tpm_devt; +extern const struct file_operations tpm_fops; + ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, size_t bufsiz); @@ -346,8 +352,6 @@ extern struct tpm_chip *tpmm_chip_alloc(struct device *dev, extern int tpm_chip_register(struct tpm_chip *chip); extern void tpm_chip_unregister(struct tpm_chip *chip); -int tpm_dev_add_device(struct tpm_chip *chip); -void tpm_dev_del_device(struct tpm_chip *chip); int tpm_sysfs_add_device(struct tpm_chip *chip); void tpm_sysfs_del_device(struct tpm_chip *chip); diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index e1eadb0c1568..9d42b7d78e50 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -560,7 +560,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client, rc = devm_request_irq(dev, chip->vendor.irq, i2c_nuvoton_int_handler, IRQF_TRIGGER_LOW, - chip->vendor.miscdev.name, + chip->devname, chip); if (rc) { dev_err(dev, "%s() Unable to request irq: %d for use\n", diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 9e02489a94f3..239cf0bbc1a1 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -698,7 +698,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, TPM_INT_VECTOR(chip->vendor.locality)); if (devm_request_irq (dev, i, tis_int_probe, IRQF_SHARED, - chip->vendor.miscdev.name, chip) != 0) { + chip->devname, chip) != 0) { dev_info(chip->pdev, "Unable to request irq: %d for probe\n", i); @@ -745,7 +745,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, TPM_INT_VECTOR(chip->vendor.locality)); if (devm_request_irq (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED, - chip->vendor.miscdev.name, chip) != 0) { + chip->devname, chip) != 0) { dev_info(chip->pdev, "Unable to request irq: %d for use\n", chip->vendor.irq); From 7a1d7e6dd76a2070e2d86826391468edc33bb6d6 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 12 Dec 2014 11:46:38 -0800 Subject: [PATCH 32/64] tpm: TPM 2.0 baseline support TPM 2.0 devices are separated by adding a field 'flags' to struct tpm_chip and defining a flag TPM_CHIP_FLAG_TPM2 for tagging them. This patch adds the following internal functions: - tpm2_get_random() - tpm2_get_tpm_pt() - tpm2_pcr_extend() - tpm2_pcr_read() - tpm2_startup() Additionally, the following exported functions are implemented for implementing TPM 2.0 device drivers: - tpm2_do_selftest() - tpm2_calc_ordinal_durations() - tpm2_gen_interrupt() The existing functions that are exported for the use for existing subsystems have been changed to check the flags field in struct tpm_chip and use appropriate TPM 2.0 counterpart if TPM_CHIP_FLAG_TPM2 is est. The code for tpm2_calc_ordinal_duration() and tpm2_startup() were originally written by Will Arthur. Signed-off-by: Jarkko Sakkinen Signed-off-by: Will Arthur Reviewed-by: Jasob Gunthorpe Reviewed-by: Stefan Berger Reviewed-by: Peter Huewe Tested-by: Peter Huewe [phuewe: Fixed copy paste error * 2] Signed-off-by: Peter Huewe --- drivers/char/tpm/Makefile | 2 +- drivers/char/tpm/tpm-chip.c | 27 +- drivers/char/tpm/tpm-interface.c | 23 +- drivers/char/tpm/tpm.h | 66 ++++ drivers/char/tpm/tpm2-cmd.c | 617 +++++++++++++++++++++++++++++++ 5 files changed, 721 insertions(+), 14 deletions(-) create mode 100644 drivers/char/tpm/tpm2-cmd.c diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index c715596acb7c..88848edb081c 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -2,7 +2,7 @@ # Makefile for the kernel tpm device drivers. # obj-$(CONFIG_TCG_TPM) += tpm.o -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o tpm-$(CONFIG_ACPI) += tpm_ppi.o ifdef CONFIG_ACPI diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 7596eef3bff9..6459af7c1646 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -195,15 +195,18 @@ int tpm_chip_register(struct tpm_chip *chip) if (rc) return rc; - rc = tpm_sysfs_add_device(chip); - if (rc) - goto del_misc; + /* Populate sysfs for TPM1 devices. */ + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { + rc = tpm_sysfs_add_device(chip); + if (rc) + goto del_misc; - rc = tpm_add_ppi(chip); - if (rc) - goto del_sysfs; + rc = tpm_add_ppi(chip); + if (rc) + goto del_sysfs; - chip->bios_dir = tpm_bios_log_setup(chip->devname); + chip->bios_dir = tpm_bios_log_setup(chip->devname); + } /* Make the chip available. */ spin_lock(&driver_lock); @@ -241,10 +244,12 @@ void tpm_chip_unregister(struct tpm_chip *chip) spin_unlock(&driver_lock); synchronize_rcu(); - if (chip->bios_dir) - tpm_bios_log_teardown(chip->bios_dir); - tpm_remove_ppi(chip); - tpm_sysfs_del_device(chip); + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { + if (chip->bios_dir) + tpm_bios_log_teardown(chip->bios_dir); + tpm_remove_ppi(chip); + tpm_sysfs_del_device(chip); + } tpm_dev_del_device(chip); } diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index b6f6b17392fd..20cf94d31386 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -360,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, if (chip->vendor.irq) goto out_recv; - stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); + if (chip->flags & TPM_CHIP_FLAG_TPM2) + stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal); + else + stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); do { u8 status = chip->ops->status(chip); if ((status & chip->ops->req_complete_mask) == @@ -484,6 +487,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) { struct tpm_cmd_t start_cmd; start_cmd.header.in = tpm_startup_header; + start_cmd.params.startup_in.startup_type = startup_type; return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, "attempting to start the TPM"); @@ -680,7 +684,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) chip = tpm_chip_find_get(chip_num); if (chip == NULL) return -ENODEV; - rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); + if (chip->flags & TPM_CHIP_FLAG_TPM2) + rc = tpm2_pcr_read(chip, pcr_idx, res_buf); + else + rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); tpm_chip_put(chip); return rc; } @@ -714,6 +721,12 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + rc = tpm2_pcr_extend(chip, pcr_idx, hash); + tpm_chip_put(chip); + return rc; + } + cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); @@ -974,6 +987,12 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + err = tpm2_get_random(chip, out, max); + tpm_chip_put(chip); + return err; + } + do { tpm_cmd.header.in = tpm_getrandom_header; tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index d46765b4c97e..cc421cfde389 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -62,6 +62,59 @@ enum tpm_duration { #define TPM_ERR_INVALID_POSTINIT 38 #define TPM_HEADER_SIZE 10 + +enum tpm2_const { + TPM2_PLATFORM_PCR = 24, + TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8), + TPM2_TIMEOUT_A = 750, + TPM2_TIMEOUT_B = 2000, + TPM2_TIMEOUT_C = 200, + TPM2_TIMEOUT_D = 30, + TPM2_DURATION_SHORT = 20, + TPM2_DURATION_MEDIUM = 750, + TPM2_DURATION_LONG = 2000, +}; + +enum tpm2_structures { + TPM2_ST_NO_SESSIONS = 0x8001, + TPM2_ST_SESSIONS = 0x8002, +}; + +enum tpm2_return_codes { + TPM2_RC_INITIALIZE = 0x0100, + TPM2_RC_TESTING = 0x090A, + TPM2_RC_DISABLED = 0x0120, +}; + +enum tpm2_algorithms { + TPM2_ALG_SHA1 = 0x0004, +}; + +enum tpm2_command_codes { + TPM2_CC_FIRST = 0x011F, + TPM2_CC_SELF_TEST = 0x0143, + TPM2_CC_STARTUP = 0x0144, + TPM2_CC_SHUTDOWN = 0x0145, + TPM2_CC_GET_CAPABILITY = 0x017A, + TPM2_CC_GET_RANDOM = 0x017B, + TPM2_CC_PCR_READ = 0x017E, + TPM2_CC_PCR_EXTEND = 0x0182, + TPM2_CC_LAST = 0x018F, +}; + +enum tpm2_permanent_handles { + TPM2_RS_PW = 0x40000009, +}; + +enum tpm2_capabilities { + TPM2_CAP_TPM_PROPERTIES = 6, +}; + +enum tpm2_startup_types { + TPM2_SU_CLEAR = 0x0000, + TPM2_SU_STATE = 0x0001, +}; + struct tpm_chip; struct tpm_vendor_specific { @@ -99,6 +152,7 @@ struct tpm_vendor_specific { enum tpm_chip_flags { TPM_CHIP_FLAG_REGISTERED = BIT(0), TPM_CHIP_FLAG_PPI = BIT(1), + TPM_CHIP_FLAG_TPM2 = BIT(2), }; struct tpm_chip { @@ -370,3 +424,15 @@ static inline void tpm_remove_ppi(struct tpm_chip *chip) { } #endif + +int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); +int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash); +int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max); +ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, + u32 *value, const char *desc); + +extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type); +extern int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type); +extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32); +extern int tpm2_do_selftest(struct tpm_chip *chip); +extern int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet); diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c new file mode 100644 index 000000000000..1abe6502219f --- /dev/null +++ b/drivers/char/tpm/tpm2-cmd.c @@ -0,0 +1,617 @@ +/* + * Copyright (C) 2014 Intel Corporation + * + * Authors: + * Jarkko Sakkinen + * + * Maintained by: + * + * This file contains TPM2 protocol implementations of the commands + * used by the kernel internally. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + +#include "tpm.h" + +struct tpm2_startup_in { + __be16 startup_type; +} __packed; + +struct tpm2_self_test_in { + u8 full_test; +} __packed; + +struct tpm2_pcr_read_in { + __be32 pcr_selects_cnt; + __be16 hash_alg; + u8 pcr_select_size; + u8 pcr_select[TPM2_PCR_SELECT_MIN]; +} __packed; + +struct tpm2_pcr_read_out { + __be32 update_cnt; + __be32 pcr_selects_cnt; + __be16 hash_alg; + u8 pcr_select_size; + u8 pcr_select[TPM2_PCR_SELECT_MIN]; + __be32 digests_cnt; + __be16 digest_size; + u8 digest[TPM_DIGEST_SIZE]; +} __packed; + +struct tpm2_null_auth_area { + __be32 handle; + __be16 nonce_size; + u8 attributes; + __be16 auth_size; +} __packed; + +struct tpm2_pcr_extend_in { + __be32 pcr_idx; + __be32 auth_area_size; + struct tpm2_null_auth_area auth_area; + __be32 digest_cnt; + __be16 hash_alg; + u8 digest[TPM_DIGEST_SIZE]; +} __packed; + +struct tpm2_get_tpm_pt_in { + __be32 cap_id; + __be32 property_id; + __be32 property_cnt; +} __packed; + +struct tpm2_get_tpm_pt_out { + u8 more_data; + __be32 subcap_id; + __be32 property_cnt; + __be32 property_id; + __be32 value; +} __packed; + +struct tpm2_get_random_in { + __be16 size; +} __packed; + +struct tpm2_get_random_out { + __be16 size; + u8 buffer[TPM_MAX_RNG_DATA]; +} __packed; + +union tpm2_cmd_params { + struct tpm2_startup_in startup_in; + struct tpm2_self_test_in selftest_in; + struct tpm2_pcr_read_in pcrread_in; + struct tpm2_pcr_read_out pcrread_out; + struct tpm2_pcr_extend_in pcrextend_in; + struct tpm2_get_tpm_pt_in get_tpm_pt_in; + struct tpm2_get_tpm_pt_out get_tpm_pt_out; + struct tpm2_get_random_in getrandom_in; + struct tpm2_get_random_out getrandom_out; +}; + +struct tpm2_cmd { + tpm_cmd_header header; + union tpm2_cmd_params params; +} __packed; + +/* + * Array with one entry per ordinal defining the maximum amount + * of time the chip could take to return the result. The values + * of the SHORT, MEDIUM, and LONG durations are taken from the + * PC Client Profile (PTP) specification. + */ +static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = { + TPM_UNDEFINED, /* 11F */ + TPM_UNDEFINED, /* 120 */ + TPM_LONG, /* 121 */ + TPM_UNDEFINED, /* 122 */ + TPM_UNDEFINED, /* 123 */ + TPM_UNDEFINED, /* 124 */ + TPM_UNDEFINED, /* 125 */ + TPM_UNDEFINED, /* 126 */ + TPM_UNDEFINED, /* 127 */ + TPM_UNDEFINED, /* 128 */ + TPM_LONG, /* 129 */ + TPM_UNDEFINED, /* 12a */ + TPM_UNDEFINED, /* 12b */ + TPM_UNDEFINED, /* 12c */ + TPM_UNDEFINED, /* 12d */ + TPM_UNDEFINED, /* 12e */ + TPM_UNDEFINED, /* 12f */ + TPM_UNDEFINED, /* 130 */ + TPM_UNDEFINED, /* 131 */ + TPM_UNDEFINED, /* 132 */ + TPM_UNDEFINED, /* 133 */ + TPM_UNDEFINED, /* 134 */ + TPM_UNDEFINED, /* 135 */ + TPM_UNDEFINED, /* 136 */ + TPM_UNDEFINED, /* 137 */ + TPM_UNDEFINED, /* 138 */ + TPM_UNDEFINED, /* 139 */ + TPM_UNDEFINED, /* 13a */ + TPM_UNDEFINED, /* 13b */ + TPM_UNDEFINED, /* 13c */ + TPM_UNDEFINED, /* 13d */ + TPM_MEDIUM, /* 13e */ + TPM_UNDEFINED, /* 13f */ + TPM_UNDEFINED, /* 140 */ + TPM_UNDEFINED, /* 141 */ + TPM_UNDEFINED, /* 142 */ + TPM_LONG, /* 143 */ + TPM_MEDIUM, /* 144 */ + TPM_UNDEFINED, /* 145 */ + TPM_UNDEFINED, /* 146 */ + TPM_UNDEFINED, /* 147 */ + TPM_UNDEFINED, /* 148 */ + TPM_UNDEFINED, /* 149 */ + TPM_UNDEFINED, /* 14a */ + TPM_UNDEFINED, /* 14b */ + TPM_UNDEFINED, /* 14c */ + TPM_UNDEFINED, /* 14d */ + TPM_LONG, /* 14e */ + TPM_UNDEFINED, /* 14f */ + TPM_UNDEFINED, /* 150 */ + TPM_UNDEFINED, /* 151 */ + TPM_UNDEFINED, /* 152 */ + TPM_UNDEFINED, /* 153 */ + TPM_UNDEFINED, /* 154 */ + TPM_UNDEFINED, /* 155 */ + TPM_UNDEFINED, /* 156 */ + TPM_UNDEFINED, /* 157 */ + TPM_UNDEFINED, /* 158 */ + TPM_UNDEFINED, /* 159 */ + TPM_UNDEFINED, /* 15a */ + TPM_UNDEFINED, /* 15b */ + TPM_MEDIUM, /* 15c */ + TPM_UNDEFINED, /* 15d */ + TPM_UNDEFINED, /* 15e */ + TPM_UNDEFINED, /* 15f */ + TPM_UNDEFINED, /* 160 */ + TPM_UNDEFINED, /* 161 */ + TPM_UNDEFINED, /* 162 */ + TPM_UNDEFINED, /* 163 */ + TPM_UNDEFINED, /* 164 */ + TPM_UNDEFINED, /* 165 */ + TPM_UNDEFINED, /* 166 */ + TPM_UNDEFINED, /* 167 */ + TPM_UNDEFINED, /* 168 */ + TPM_UNDEFINED, /* 169 */ + TPM_UNDEFINED, /* 16a */ + TPM_UNDEFINED, /* 16b */ + TPM_UNDEFINED, /* 16c */ + TPM_UNDEFINED, /* 16d */ + TPM_UNDEFINED, /* 16e */ + TPM_UNDEFINED, /* 16f */ + TPM_UNDEFINED, /* 170 */ + TPM_UNDEFINED, /* 171 */ + TPM_UNDEFINED, /* 172 */ + TPM_UNDEFINED, /* 173 */ + TPM_UNDEFINED, /* 174 */ + TPM_UNDEFINED, /* 175 */ + TPM_UNDEFINED, /* 176 */ + TPM_LONG, /* 177 */ + TPM_UNDEFINED, /* 178 */ + TPM_UNDEFINED, /* 179 */ + TPM_MEDIUM, /* 17a */ + TPM_LONG, /* 17b */ + TPM_UNDEFINED, /* 17c */ + TPM_UNDEFINED, /* 17d */ + TPM_UNDEFINED, /* 17e */ + TPM_UNDEFINED, /* 17f */ + TPM_UNDEFINED, /* 180 */ + TPM_UNDEFINED, /* 181 */ + TPM_MEDIUM, /* 182 */ + TPM_UNDEFINED, /* 183 */ + TPM_UNDEFINED, /* 184 */ + TPM_MEDIUM, /* 185 */ + TPM_MEDIUM, /* 186 */ + TPM_UNDEFINED, /* 187 */ + TPM_UNDEFINED, /* 188 */ + TPM_UNDEFINED, /* 189 */ + TPM_UNDEFINED, /* 18a */ + TPM_UNDEFINED, /* 18b */ + TPM_UNDEFINED, /* 18c */ + TPM_UNDEFINED, /* 18d */ + TPM_UNDEFINED, /* 18e */ + TPM_UNDEFINED /* 18f */ +}; + +#define TPM2_PCR_READ_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_pcr_read_in)) + +static const struct tpm_input_header tpm2_pcrread_header = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_PCR_READ) +}; + +/** + * tpm2_pcr_read() - read a PCR value + * @chip: TPM chip to use. + * @pcr_idx: index of the PCR to read. + * @ref_buf: buffer to store the resulting hash, + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) +{ + int rc; + struct tpm2_cmd cmd; + u8 *buf; + + if (pcr_idx >= TPM2_PLATFORM_PCR) + return -EINVAL; + + cmd.header.in = tpm2_pcrread_header; + cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1); + cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); + cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN; + + memset(cmd.params.pcrread_in.pcr_select, 0, + sizeof(cmd.params.pcrread_in.pcr_select)); + cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); + + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + "attempting to read a pcr value"); + if (rc == 0) { + buf = cmd.params.pcrread_out.digest; + memcpy(res_buf, buf, TPM_DIGEST_SIZE); + } + + return rc; +} + +#define TPM2_GET_PCREXTEND_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_pcr_extend_in)) + +static const struct tpm_input_header tpm2_pcrextend_header = { + .tag = cpu_to_be16(TPM2_ST_SESSIONS), + .length = cpu_to_be32(TPM2_GET_PCREXTEND_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND) +}; + +/** + * tpm2_pcr_extend() - extend a PCR value + * @chip: TPM chip to use. + * @pcr_idx: index of the PCR. + * @hash: hash value to use for the extend operation. + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) +{ + struct tpm2_cmd cmd; + int rc; + + cmd.header.in = tpm2_pcrextend_header; + cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); + cmd.params.pcrextend_in.auth_area_size = + cpu_to_be32(sizeof(struct tpm2_null_auth_area)); + cmd.params.pcrextend_in.auth_area.handle = + cpu_to_be32(TPM2_RS_PW); + cmd.params.pcrextend_in.auth_area.nonce_size = 0; + cmd.params.pcrextend_in.auth_area.attributes = 0; + cmd.params.pcrextend_in.auth_area.auth_size = 0; + cmd.params.pcrextend_in.digest_cnt = cpu_to_be32(1); + cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); + memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE); + + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + "attempting extend a PCR value"); + + return rc; +} + +#define TPM2_GETRANDOM_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_get_random_in)) + +static const struct tpm_input_header tpm2_getrandom_header = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .length = cpu_to_be32(TPM2_GETRANDOM_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_GET_RANDOM) +}; + +/** + * tpm2_get_random() - get random bytes from the TPM RNG + * @chip: TPM chip to use + * @out: destination buffer for the random bytes + * @max: the max number of bytes to write to @out + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) +{ + struct tpm2_cmd cmd; + u32 recd; + u32 num_bytes; + int err; + int total = 0; + int retries = 5; + u8 *dest = out; + + num_bytes = min_t(u32, max, sizeof(cmd.params.getrandom_out.buffer)); + + if (!out || !num_bytes || + max > sizeof(cmd.params.getrandom_out.buffer)) + return -EINVAL; + + do { + cmd.header.in = tpm2_getrandom_header; + cmd.params.getrandom_in.size = cpu_to_be16(num_bytes); + + err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + "attempting get random"); + if (err) + break; + + recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size), + num_bytes); + memcpy(dest, cmd.params.getrandom_out.buffer, recd); + + dest += recd; + total += recd; + num_bytes -= recd; + } while (retries-- && total < max); + + return total ? total : -EIO; +} + +#define TPM2_GET_TPM_PT_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_get_tpm_pt_in)) + +static const struct tpm_input_header tpm2_get_tpm_pt_header = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY) +}; + +/** + * tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property + * @chip: TPM chip to use. + * @property_id: property ID. + * @value: output variable. + * @desc: passed to tpm_transmit_cmd() + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, + const char *desc) +{ + struct tpm2_cmd cmd; + int rc; + + cmd.header.in = tpm2_get_tpm_pt_header; + cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES); + cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id); + cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); + + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), desc); + if (!rc) + *value = cmd.params.get_tpm_pt_out.value; + + return rc; +} + +#define TPM2_STARTUP_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_startup_in)) + +static const struct tpm_input_header tpm2_startup_header = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .length = cpu_to_be32(TPM2_STARTUP_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_STARTUP) +}; + +/** + * tpm2_startup() - send startup command to the TPM chip + * @chip: TPM chip to use. + * @startup_type startup type. The value is either + * TPM_SU_CLEAR or TPM_SU_STATE. + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_startup(struct tpm_chip *chip, u16 startup_type) +{ + struct tpm2_cmd cmd; + + cmd.header.in = tpm2_startup_header; + + cmd.params.startup_in.startup_type = cpu_to_be16(startup_type); + return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + "attempting to start the TPM"); +} +EXPORT_SYMBOL_GPL(tpm2_startup); + +#define TPM2_SHUTDOWN_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_startup_in)) + +static const struct tpm_input_header tpm2_shutdown_header = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .length = cpu_to_be32(TPM2_SHUTDOWN_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_SHUTDOWN) +}; + +/** + * tpm2_shutdown() - send shutdown command to the TPM chip + * @chip: TPM chip to use. + * @shutdown_type shutdown type. The value is either + * TPM_SU_CLEAR or TPM_SU_STATE. + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) +{ + struct tpm2_cmd cmd; + + cmd.header.in = tpm2_shutdown_header; + + cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type); + return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + "stopping the TPM"); +} +EXPORT_SYMBOL_GPL(tpm2_shutdown); + +/* + * tpm2_calc_ordinal_duration() - maximum duration for a command + * @chip: TPM chip to use. + * @ordinal: command code number. + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) +{ + int index = TPM_UNDEFINED; + int duration = 0; + + if (ordinal >= TPM2_CC_FIRST && ordinal <= TPM2_CC_LAST) + index = tpm2_ordinal_duration[ordinal - TPM2_CC_FIRST]; + + if (index != TPM_UNDEFINED) + duration = chip->vendor.duration[index]; + + if (duration <= 0) + duration = 2 * 60 * HZ; + + return duration; +} +EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration); + +#define TPM2_SELF_TEST_IN_SIZE \ + (sizeof(struct tpm_input_header) + \ + sizeof(struct tpm2_self_test_in)) + +static const struct tpm_input_header tpm2_selftest_header = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .length = cpu_to_be32(TPM2_SELF_TEST_IN_SIZE), + .ordinal = cpu_to_be32(TPM2_CC_SELF_TEST) +}; + +/** + * tpm2_continue_selftest() - start a self test + * @chip: TPM chip to use + * @full: test all commands instead of testing only those that were not + * previously tested. + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +static int tpm2_start_selftest(struct tpm_chip *chip, bool full) +{ + int rc; + struct tpm2_cmd cmd; + + cmd.header.in = tpm2_selftest_header; + cmd.params.selftest_in.full_test = full; + + rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, + "continue selftest"); + + /* At least some prototype chips seem to give RC_TESTING error + * immediately. This is a workaround for that. + */ + if (rc == TPM2_RC_TESTING) { + dev_warn(chip->pdev, "Got RC_TESTING, ignoring\n"); + rc = 0; + } + + return rc; +} + +/** + * tpm2_do_selftest() - run a full self test + * @chip: TPM chip to use + * + * During the self test TPM2 commands return with the error code RC_TESTING. + * Waiting is done by issuing PCR read until it executes successfully. + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_do_selftest(struct tpm_chip *chip) +{ + int rc; + unsigned int loops; + unsigned int delay_msec = 100; + unsigned long duration; + struct tpm2_cmd cmd; + int i; + + duration = tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST); + + loops = jiffies_to_msecs(duration) / delay_msec; + + rc = tpm2_start_selftest(chip, true); + if (rc) + return rc; + + for (i = 0; i < loops; i++) { + /* Attempt to read a PCR value */ + cmd.header.in = tpm2_pcrread_header; + cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1); + cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); + cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN; + cmd.params.pcrread_in.pcr_select[0] = 0x01; + cmd.params.pcrread_in.pcr_select[1] = 0x00; + cmd.params.pcrread_in.pcr_select[2] = 0x00; + + rc = tpm_transmit_cmd(chip, (u8 *) &cmd, sizeof(cmd), NULL); + if (rc < 0) + break; + + rc = be32_to_cpu(cmd.header.out.return_code); + if (rc != TPM2_RC_TESTING) + break; + + msleep(delay_msec); + } + + return rc; +} +EXPORT_SYMBOL_GPL(tpm2_do_selftest); + +/** + * tpm2_gen_interrupt() - generate an interrupt + * @chip: TPM chip to use + * @quiet: surpress the error message + * + * 0 is returned when the operation is successful. If a negative number is + * returned it remarks a POSIX error code. If a positive number is returned + * it remarks a TPM error. + */ +int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet) +{ + const char *desc = NULL; + u32 dummy; + + if (!quiet) + desc = "attempting to generate an interrupt"; + + return tpm2_get_tpm_pt(chip, TPM2_CAP_TPM_PROPERTIES, &dummy, desc); +} +EXPORT_SYMBOL_GPL(tpm2_gen_interrupt); From 30fc8d138e9123f374a3c3867e7c7c5cd4004941 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 12 Dec 2014 11:46:39 -0800 Subject: [PATCH 33/64] tpm: TPM 2.0 CRB Interface tpm_crb is a driver for TPM 2.0 Command Response Buffer (CRB) Interface as defined in PC Client Platform TPM Profile (PTP) Specification. Only polling and single locality is supported as these are the limitations of the available hardware, Platform Trust Techonlogy (PTT) in Haswell CPUs. The driver always applies CRB with ACPI start because PTT reports using only ACPI start as start method but as a result of my testing it requires also CRB start. Signed-off-by: Jarkko Sakkinen Reviewed-by: Jasob Gunthorpe Reviewed-by: Stefan Berger Signed-off-by: Peter Huewe --- drivers/char/tpm/Kconfig | 9 + drivers/char/tpm/Makefile | 1 + drivers/char/tpm/tpm-interface.c | 3 + drivers/char/tpm/tpm_crb.c | 354 +++++++++++++++++++++++++++++++ 4 files changed, 367 insertions(+) create mode 100644 drivers/char/tpm/tpm_crb.c diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 3d0873b1ab5b..9d4e37549eb2 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -122,4 +122,13 @@ config TCG_XEN To compile this driver as a module, choose M here; the module will be called xen-tpmfront. +config TCG_CRB + tristate "TPM 2.0 CRB Interface" + depends on X86 && ACPI + ---help--- + If you have a TPM security chip that is compliant with the + TCG CRB 2.0 TPM specification say Yes and it will be accessible + from within Linux. To compile this driver as a module, choose + M here; the module will be called tpm_crb. + endif # TCG_TPM diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 88848edb081c..990cf183931d 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o obj-$(CONFIG_TCG_TIS_I2C_ST33) += tpm_i2c_stm_st33.o obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o +obj-$(CONFIG_TCG_CRB) += tpm_crb.o diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 20cf94d31386..bf53a3771da5 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -901,6 +901,9 @@ int tpm_pm_suspend(struct device *dev) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_TPM2) + return tpm2_shutdown(chip, TPM2_SU_CLEAR); + /* for buggy tpm, flush pcrs with extend to selected dummy */ if (tpm_suspend_pcr) { cmd.header.in = pcrextend_header; diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c new file mode 100644 index 000000000000..c248a356d5c9 --- /dev/null +++ b/drivers/char/tpm/tpm_crb.c @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2014 Intel Corporation + * + * Authors: + * Jarkko Sakkinen + * + * Maintained by: + * + * This device driver implements the TPM interface as defined in + * the TCG CRB 2.0 TPM specification. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + +#include +#include +#include +#include +#include +#include "tpm.h" + +#define ACPI_SIG_TPM2 "TPM2" + +static const u8 CRB_ACPI_START_UUID[] = { + /* 0000 */ 0xAB, 0x6C, 0xBF, 0x6B, 0x63, 0x54, 0x14, 0x47, + /* 0008 */ 0xB7, 0xCD, 0xF0, 0x20, 0x3C, 0x03, 0x68, 0xD4 +}; + +enum crb_defaults { + CRB_ACPI_START_REVISION_ID = 1, + CRB_ACPI_START_INDEX = 1, +}; + +enum crb_start_method { + CRB_SM_ACPI_START = 2, + CRB_SM_CRB = 7, + CRB_SM_CRB_WITH_ACPI_START = 8, +}; + +struct acpi_tpm2 { + struct acpi_table_header hdr; + u16 platform_class; + u16 reserved; + u64 control_area_pa; + u32 start_method; +} __packed; + +enum crb_ca_request { + CRB_CA_REQ_GO_IDLE = BIT(0), + CRB_CA_REQ_CMD_READY = BIT(1), +}; + +enum crb_ca_status { + CRB_CA_STS_ERROR = BIT(0), + CRB_CA_STS_TPM_IDLE = BIT(1), +}; + +enum crb_start { + CRB_START_INVOKE = BIT(0), +}; + +enum crb_cancel { + CRB_CANCEL_INVOKE = BIT(0), +}; + +struct crb_control_area { + u32 req; + u32 sts; + u32 cancel; + u32 start; + u32 int_enable; + u32 int_sts; + u32 cmd_size; + u64 cmd_pa; + u32 rsp_size; + u64 rsp_pa; +} __packed; + +enum crb_status { + CRB_STS_COMPLETE = BIT(0), +}; + +enum crb_flags { + CRB_FL_ACPI_START = BIT(0), + CRB_FL_CRB_START = BIT(1), +}; + +struct crb_priv { + unsigned int flags; + struct crb_control_area __iomem *cca; + u8 __iomem *cmd; + u8 __iomem *rsp; +}; + +#ifdef CONFIG_PM_SLEEP +static int crb_resume(struct device *dev) +{ + int rc; + struct tpm_chip *chip = dev_get_drvdata(dev); + + rc = tpm2_shutdown(chip, TPM2_SU_STATE); + if (!rc) + rc = tpm2_do_selftest(chip); + + return rc; +} + +static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, crb_resume); +#endif + +static u8 crb_status(struct tpm_chip *chip) +{ + struct crb_priv *priv = chip->vendor.priv; + u8 sts = 0; + + if ((le32_to_cpu(ioread32(&priv->cca->start)) & CRB_START_INVOKE) != + CRB_START_INVOKE) + sts |= CRB_STS_COMPLETE; + + return sts; +} + +static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count) +{ + struct crb_priv *priv = chip->vendor.priv; + unsigned int expected; + + /* sanity check */ + if (count < 6) + return -EIO; + + if (le32_to_cpu(ioread32(&priv->cca->sts)) & CRB_CA_STS_ERROR) + return -EIO; + + memcpy_fromio(buf, priv->rsp, 6); + expected = be32_to_cpup((__be32 *) &buf[2]); + + if (expected > count) + return -EIO; + + memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6); + + return expected; +} + +static int crb_do_acpi_start(struct tpm_chip *chip) +{ + union acpi_object *obj; + int rc; + + obj = acpi_evaluate_dsm(chip->acpi_dev_handle, + CRB_ACPI_START_UUID, + CRB_ACPI_START_REVISION_ID, + CRB_ACPI_START_INDEX, + NULL); + if (!obj) + return -ENXIO; + rc = obj->integer.value == 0 ? 0 : -ENXIO; + ACPI_FREE(obj); + return rc; +} + +static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len) +{ + struct crb_priv *priv = chip->vendor.priv; + int rc = 0; + + if (len > le32_to_cpu(ioread32(&priv->cca->cmd_size))) { + dev_err(&chip->dev, + "invalid command count value %x %zx\n", + (unsigned int) len, + (size_t) le32_to_cpu(ioread32(&priv->cca->cmd_size))); + return -E2BIG; + } + + memcpy_toio(priv->cmd, buf, len); + + /* Make sure that cmd is populated before issuing start. */ + wmb(); + + if (priv->flags & CRB_FL_CRB_START) + iowrite32(cpu_to_le32(CRB_START_INVOKE), &priv->cca->start); + + if (priv->flags & CRB_FL_ACPI_START) + rc = crb_do_acpi_start(chip); + + return rc; +} + +static void crb_cancel(struct tpm_chip *chip) +{ + struct crb_priv *priv = chip->vendor.priv; + + iowrite32(cpu_to_le32(CRB_CANCEL_INVOKE), &priv->cca->cancel); + + /* Make sure that cmd is populated before issuing cancel. */ + wmb(); + + if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip)) + dev_err(&chip->dev, "ACPI Start failed\n"); + + iowrite32(0, &priv->cca->cancel); +} + +static bool crb_req_canceled(struct tpm_chip *chip, u8 status) +{ + struct crb_priv *priv = chip->vendor.priv; + u32 cancel = le32_to_cpu(ioread32(&priv->cca->cancel)); + + return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE; +} + +static const struct tpm_class_ops tpm_crb = { + .status = crb_status, + .recv = crb_recv, + .send = crb_send, + .cancel = crb_cancel, + .req_canceled = crb_req_canceled, + .req_complete_mask = CRB_STS_COMPLETE, + .req_complete_val = CRB_STS_COMPLETE, +}; + +static int crb_acpi_add(struct acpi_device *device) +{ + struct tpm_chip *chip; + struct acpi_tpm2 *buf; + struct crb_priv *priv; + struct device *dev = &device->dev; + acpi_status status; + u32 sm; + u64 pa; + int rc; + + chip = tpmm_chip_alloc(dev, &tpm_crb); + if (IS_ERR(chip)) + return PTR_ERR(chip); + + chip->flags = TPM_CHIP_FLAG_TPM2; + + status = acpi_get_table(ACPI_SIG_TPM2, 1, + (struct acpi_table_header **) &buf); + if (ACPI_FAILURE(status)) { + dev_err(dev, "failed to get TPM2 ACPI table\n"); + return -ENODEV; + } + + if (buf->hdr.length < sizeof(struct acpi_tpm2)) { + dev_err(dev, "TPM2 ACPI table has wrong size"); + return -EINVAL; + } + + priv = (struct crb_priv *) devm_kzalloc(dev, sizeof(struct crb_priv), + GFP_KERNEL); + if (!priv) { + dev_err(dev, "failed to devm_kzalloc for private data\n"); + return -ENOMEM; + } + + sm = le32_to_cpu(buf->start_method); + + /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs + * report only ACPI start but in practice seems to require both + * ACPI start and CRB start. + */ + if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START || + !strcmp(acpi_device_hid(device), "MSFT0101")) + priv->flags |= CRB_FL_CRB_START; + + if (sm == CRB_SM_ACPI_START || sm == CRB_SM_CRB_WITH_ACPI_START) + priv->flags |= CRB_FL_ACPI_START; + + priv->cca = (struct crb_control_area __iomem *) + devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000); + if (!priv->cca) { + dev_err(dev, "ioremap of the control area failed\n"); + return -ENOMEM; + } + + memcpy_fromio(&pa, &priv->cca->cmd_pa, 8); + pa = le64_to_cpu(pa); + priv->cmd = devm_ioremap_nocache(dev, le64_to_cpu(pa), + ioread32(&priv->cca->cmd_size)); + if (!priv->cmd) { + dev_err(dev, "ioremap of the command buffer failed\n"); + return -ENOMEM; + } + + memcpy_fromio(&pa, &priv->cca->rsp_pa, 8); + pa = le64_to_cpu(pa); + priv->rsp = devm_ioremap_nocache(dev, le64_to_cpu(pa), + ioread32(&priv->cca->rsp_size)); + if (!priv->rsp) { + dev_err(dev, "ioremap of the response buffer failed\n"); + return -ENOMEM; + } + + chip->vendor.priv = priv; + + /* Default timeouts and durations */ + chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A); + chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B); + chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C); + chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D); + chip->vendor.duration[TPM_SHORT] = + msecs_to_jiffies(TPM2_DURATION_SHORT); + chip->vendor.duration[TPM_MEDIUM] = + msecs_to_jiffies(TPM2_DURATION_MEDIUM); + chip->vendor.duration[TPM_LONG] = + msecs_to_jiffies(TPM2_DURATION_LONG); + + chip->acpi_dev_handle = device->handle; + + rc = tpm2_do_selftest(chip); + if (rc) + return rc; + + return tpm_chip_register(chip); +} + +static int crb_acpi_remove(struct acpi_device *device) +{ + struct device *dev = &device->dev; + struct tpm_chip *chip = dev_get_drvdata(dev); + + tpm_chip_unregister(chip); + return 0; +} + +static struct acpi_device_id crb_device_ids[] = { + {"MSFT0101", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, crb_device_ids); + +static struct acpi_driver crb_acpi_driver = { + .name = "tpm_crb", + .ids = crb_device_ids, + .ops = { + .add = crb_acpi_add, + .remove = crb_acpi_remove, + }, + .drv = { + .pm = &crb_pm, + }, +}; + +module_acpi_driver(crb_acpi_driver); +MODULE_AUTHOR("Jarkko Sakkinen "); +MODULE_DESCRIPTION("TPM2 Driver"); +MODULE_VERSION("0.1"); +MODULE_LICENSE("GPL"); From aec04cbdf7231c1b0da76172de82dfa2388a80d7 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 12 Dec 2014 11:46:40 -0800 Subject: [PATCH 34/64] tpm: TPM 2.0 FIFO Interface Detect TPM 2.0 by sending idempotent TPM 2.x command. Ordinals for TPM 2.0 are higher than TPM 1.x commands so this should be fail-safe. Using STS3 is unreliable because some chips just report 0xff and not what the spec says. Before TPM family is detected, timeouts are set to the maximum values for both TPM 1.x and TPM 2.x. In addition to this, suspend/resume functionality is implemented for TPM 2.x. Signed-off-by: Jarkko Sakkinen Signed-off-by: Will Arthur Reviewed-by: Jasob Gunthorpe Reviewed-by: Stefan Berger Reviewed-by: Peter Huewe Tested-by: Peter Huewe Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_tis.c | 112 +++++++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 23 deletions(-) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 239cf0bbc1a1..20a61bc98db8 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2005, 2006 IBM Corporation + * Copyright (C) 2014 Intel Corporation * * Authors: * Leendert van Doorn @@ -64,12 +65,22 @@ enum tis_defaults { TIS_LONG_TIMEOUT = 2000, /* 2 sec */ }; + +/* Some timeout values are needed before it is known whether the chip is + * TPM 1.0 or TPM 2.0. + */ +#define TIS_TIMEOUT_A_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_A) +#define TIS_TIMEOUT_B_MAX max(TIS_LONG_TIMEOUT, TPM2_TIMEOUT_B) +#define TIS_TIMEOUT_C_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_C) +#define TIS_TIMEOUT_D_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_D) + #define TPM_ACCESS(l) (0x0000 | ((l) << 12)) #define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12)) #define TPM_INT_VECTOR(l) (0x000C | ((l) << 12)) #define TPM_INT_STATUS(l) (0x0010 | ((l) << 12)) #define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12)) #define TPM_STS(l) (0x0018 | ((l) << 12)) +#define TPM_STS3(l) (0x001b | ((l) << 12)) #define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12)) #define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) @@ -363,6 +374,7 @@ static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len) { int rc; u32 ordinal; + unsigned long dur; rc = tpm_tis_send_data(chip, buf, len); if (rc < 0) @@ -374,9 +386,14 @@ static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len) if (chip->vendor.irq) { ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); + + if (chip->flags & TPM_CHIP_FLAG_TPM2) + dur = tpm2_calc_ordinal_duration(chip, ordinal); + else + dur = tpm_calc_ordinal_duration(chip, ordinal); + if (wait_for_tpm_stat - (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, - tpm_calc_ordinal_duration(chip, ordinal), + (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur, &chip->vendor.read_queue, false) < 0) { rc = -ETIME; goto out_err; @@ -598,17 +615,19 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, return PTR_ERR(chip); chip->vendor.priv = priv; +#ifdef CONFIG_ACPI chip->acpi_dev_handle = acpi_dev_handle; +#endif chip->vendor.iobase = devm_ioremap(dev, start, len); if (!chip->vendor.iobase) return -EIO; - /* Default timeouts */ - chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); - chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); - chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + /* Maximum timeouts */ + chip->vendor.timeout_a = TIS_TIMEOUT_A_MAX; + chip->vendor.timeout_b = TIS_TIMEOUT_B_MAX; + chip->vendor.timeout_c = TIS_TIMEOUT_C_MAX; + chip->vendor.timeout_d = TIS_TIMEOUT_D_MAX; if (wait_startup(chip, 0) != 0) { rc = -ENODEV; @@ -620,11 +639,18 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, goto out_err; } + /* Every TPM 2.x command has a higher ordinal than TPM 1.x commands. + * Therefore, we can use an idempotent TPM 2.x command to probe TPM 2.x. + */ + rc = tpm2_gen_interrupt(chip, true); + if (rc == 0 || rc == TPM2_RC_INITIALIZE) + chip->flags |= TPM_CHIP_FLAG_TPM2; + vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); chip->vendor.manufacturer_id = vendor; - dev_info(dev, - "1.2 TPM (device-id 0x%X, rev-id %d)\n", + dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n", + (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2", vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); if (!itpm) { @@ -720,7 +746,10 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, chip->vendor.probed_irq = 0; /* Generate Interrupts */ - tpm_gen_interrupt(chip); + if (chip->flags & TPM_CHIP_FLAG_TPM2) + tpm2_gen_interrupt(chip, false); + else + tpm_gen_interrupt(chip); chip->vendor.irq = chip->vendor.probed_irq; @@ -765,16 +794,44 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, } } - if (tpm_get_timeouts(chip)) { - dev_err(dev, "Could not get TPM timeouts and durations\n"); - rc = -ENODEV; - goto out_err; - } + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A); + chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B); + chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C); + chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D); + chip->vendor.duration[TPM_SHORT] = + msecs_to_jiffies(TPM2_DURATION_SHORT); + chip->vendor.duration[TPM_MEDIUM] = + msecs_to_jiffies(TPM2_DURATION_MEDIUM); + chip->vendor.duration[TPM_LONG] = + msecs_to_jiffies(TPM2_DURATION_LONG); - if (tpm_do_selftest(chip)) { - dev_err(dev, "TPM self test failed\n"); - rc = -ENODEV; - goto out_err; + rc = tpm2_do_selftest(chip); + if (rc == TPM2_RC_INITIALIZE) { + dev_warn(dev, "Firmware has not started TPM\n"); + rc = tpm2_startup(chip, TPM2_SU_CLEAR); + if (!rc) + rc = tpm2_do_selftest(chip); + } + + if (rc) { + dev_err(dev, "TPM self test failed\n"); + if (rc > 0) + rc = -ENODEV; + goto out_err; + } + } else { + if (tpm_get_timeouts(chip)) { + dev_err(dev, "Could not get TPM timeouts and durations\n"); + rc = -ENODEV; + goto out_err; + } + + if (tpm_do_selftest(chip)) { + dev_err(dev, "TPM self test failed\n"); + rc = -ENODEV; + goto out_err; + } } return tpm_chip_register(chip); @@ -808,14 +865,23 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) static int tpm_tis_resume(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); - int ret; + int ret = 0; if (chip->vendor.irq) tpm_tis_reenable_interrupts(chip); - ret = tpm_pm_resume(dev); - if (!ret) - tpm_do_selftest(chip); + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + /* NOP if firmware properly does this. */ + tpm2_startup(chip, TPM2_SU_STATE); + + ret = tpm2_shutdown(chip, TPM2_SU_STATE); + if (!ret) + ret = tpm2_do_selftest(chip); + } else { + ret = tpm_pm_resume(dev); + if (!ret) + tpm_do_selftest(chip); + } return ret; } From c4eadfafb91d5501095c55ffadaa1168743f39d3 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 13 Jan 2015 23:13:14 +0100 Subject: [PATCH 35/64] tpm/tpm_i2c_stm_st33: Add status check when reading data on the FIFO Add a return value check when reading data from the FIFO register. Cc: Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Reviewed-by: Peter Huewe Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 48c4808d5a7a..4f70296f3a7f 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -441,7 +441,7 @@ again: */ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) { - int size = 0, burstcnt, len; + int size = 0, burstcnt, len, ret; struct tpm_stm_dev *tpm_dev; tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); @@ -455,7 +455,10 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) if (burstcnt < 0) return burstcnt; len = min_t(int, burstcnt, count - size); - I2C_READ_DATA(tpm_dev, TPM_DATA_FIFO, buf + size, len); + ret = I2C_READ_DATA(tpm_dev, TPM_DATA_FIFO, buf + size, len); + if (ret < 0) + return ret; + size += len; } return size; From ac77d33e91efcccb7b5b555a41481a6d775b6f69 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 13 Jan 2015 23:13:09 +0100 Subject: [PATCH 36/64] tpm/tpm_i2c_stm_st33: Remove sparse spaces Remove some useless spaces (new line or space) Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Reviewed-by: Peter Huewe Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 4f70296f3a7f..f05b0a43d87b 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -238,7 +238,6 @@ static int check_locality(struct tpm_chip *chip) return chip->vendor.locality; return -EACCES; - } /* check_locality() */ /* @@ -352,7 +351,7 @@ static u8 interrupt_to_status(u8 irq_mask) { u8 status = 0; - if ((irq_mask & TPM_INTF_STS_VALID_INT) == TPM_INTF_STS_VALID_INT) + if ((irq_mask & TPM_INTF_STS_VALID_INT) == TPM_INTF_STS_VALID_INT) status |= TPM_STS_VALID; if ((irq_mask & TPM_INTF_DATA_AVAIL_INT) == TPM_INTF_DATA_AVAIL_INT) status |= TPM_STS_DATA_AVAIL; @@ -573,7 +572,7 @@ out_err: * @param: buf, the buffer to store datas. * @param: count, the number of bytes to send. * @return: In case of success the number of bytes received. - * In other case, a < 0 value describing the issue. + * In other case, a < 0 value describing the issue. */ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf, size_t count) @@ -636,7 +635,6 @@ static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip) struct device_node *pp; struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip); struct i2c_client *client = tpm_dev->client; - int gpio; int ret; @@ -849,7 +847,7 @@ static int tpm_stm_i2c_pm_suspend(struct device *dev) ret = tpm_pm_suspend(dev); return ret; -} /* tpm_stm_i2c_suspend() */ +} /* tpm_stm_i2c_suspend() */ /* * tpm_stm_i2c_pm_resume resume the TPM device From fc9ad777c3ebbeaf423f75e0d8b04db42b3c9ebf Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 13 Jan 2015 23:13:10 +0100 Subject: [PATCH 37/64] tpm/tpm_i2c_stm_st33: Sanity cleanup Cleanup header description and correct some indent. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Reviewed-by: Peter Huewe Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index f05b0a43d87b..d6e87d73f949 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -814,8 +814,7 @@ _tpm_clean_answer: /* * tpm_stm_i2c_remove remove the TPM device - * @param: client, the i2c_client drescription (TPM I2C description). - * clear_bit(0, &chip->is_open); + * @param: client, the i2c_client description (TPM I2C description). * @return: 0 in case of success. */ static int tpm_stm_i2c_remove(struct i2c_client *client) @@ -890,7 +889,8 @@ MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match); #endif static SIMPLE_DEV_PM_OPS(tpm_stm_i2c_ops, tpm_stm_i2c_pm_suspend, - tpm_stm_i2c_pm_resume); + tpm_stm_i2c_pm_resume); + static struct i2c_driver tpm_stm_i2c_driver = { .driver = { .owner = THIS_MODULE, From 7b1ee96f074cc931a2c226b33607fe7a74d5cba3 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 13 Jan 2015 23:13:11 +0100 Subject: [PATCH 38/64] tpm/tpm_i2c_stm_st33: Replace remaining r by ret Some places are still using r instead of ret. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Reviewed-by: Peter Huewe Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index d6e87d73f949..86a24ced66c0 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -374,7 +374,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, wait_queue_head_t *queue, bool check_cancel) { unsigned long stop; - int r; + int ret; bool canceled = false; bool condition; u32 cur_intrs; @@ -400,7 +400,7 @@ again: if ((long) timeout <= 0) return -1; - r = wait_event_interruptible_timeout(*queue, + ret = wait_event_interruptible_timeout(*queue, cur_intrs != tpm_dev->intrs, timeout); interrupt |= clear_interruption(tpm_dev); @@ -408,12 +408,12 @@ again: condition = wait_for_tpm_stat_cond(chip, mask, check_cancel, &canceled); - if (r >= 0 && condition) { + if (ret >= 0 && condition) { if (canceled) return -ECANCELED; return 0; } - if (r == -ERESTARTSYS && freezing(current)) { + if (ret == -ERESTARTSYS && freezing(current)) { clear_thread_flag(TIF_SIGPENDING); goto again; } From 3eda7d0ea3a0365aa72a2007f9450f314d92f065 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 13 Jan 2015 23:13:13 +0100 Subject: [PATCH 39/64] tpm/tpm_i2c_stm_st33: Change tpm_i2c_stm_st33.h to tpm_stm_st33.h include/linux/platform_data/tpm_i2c_stm_st33.h can be used by other st33 tpm device driver not using i2c protocol. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Reviewed-by: Peter Huewe Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_i2c_stm_st33.c | 2 +- .../{tpm_i2c_stm_st33.h => tpm_stm_st33.h} | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) rename include/linux/platform_data/{tpm_i2c_stm_st33.h => tpm_stm_st33.h} (85%) diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index 86a24ced66c0..dbab8d0d875e 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -50,7 +50,7 @@ #include #include -#include +#include #include "tpm.h" #define TPM_ACCESS 0x0 diff --git a/include/linux/platform_data/tpm_i2c_stm_st33.h b/include/linux/platform_data/tpm_stm_st33.h similarity index 85% rename from include/linux/platform_data/tpm_i2c_stm_st33.h rename to include/linux/platform_data/tpm_stm_st33.h index 85775cf5f9a5..ff75310c0f47 100644 --- a/include/linux/platform_data/tpm_i2c_stm_st33.h +++ b/include/linux/platform_data/tpm_stm_st33.h @@ -22,18 +22,18 @@ * * @Author: Christophe RICARD tpmsupport@st.com * - * @File: stm_st33_tpm_i2c.h + * @File: stm_st33_tpm.h * * @Date: 09/15/2010 */ -#ifndef __STM_ST33_TPM_I2C_MAIN_H__ -#define __STM_ST33_TPM_I2C_MAIN_H__ +#ifndef __STM_ST33_TPM_H__ +#define __STM_ST33_TPM_H__ - -#define TPM_ST33_I2C "st33zp24_i2c" +#define TPM_ST33_I2C "st33zp24-i2c" +#define TPM_ST33_SPI "st33zp24-spi" struct st33zp24_platform_data { int io_lpcpd; }; -#endif /* __STM_ST33_TPM_I2C_MAIN_H__ */ +#endif /* __STM_ST33_TPM_H__ */ From 961be6650bd4de3ac0dbbb997fa35aabc553d52b Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Tue, 13 Jan 2015 23:13:15 +0100 Subject: [PATCH 40/64] tpm/tpm_i2c_stm_st33/dts/st33zp24-i2c: Rename st33zp24 dts documentation st33zp24 exists in i2c and spi version. Both have different possible configuration. st33zp24.txt is renamed st33zp24-i2c.txt. Reviewed-by: Jason Gunthorpe Signed-off-by: Christophe Ricard Reviewed-by: Peter Huewe Signed-off-by: Peter Huewe --- .../bindings/security/tpm/{st33zp24.txt => st33zp24-i2c.txt} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Documentation/devicetree/bindings/security/tpm/{st33zp24.txt => st33zp24-i2c.txt} (97%) diff --git a/Documentation/devicetree/bindings/security/tpm/st33zp24.txt b/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt similarity index 97% rename from Documentation/devicetree/bindings/security/tpm/st33zp24.txt rename to Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt index 0a7361dae65f..3ad115efed1e 100644 --- a/Documentation/devicetree/bindings/security/tpm/st33zp24.txt +++ b/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt @@ -25,7 +25,7 @@ Example (for ARM-based BeagleBoard xM with ST33ZP24 on I2C2): compatible = "st,st33zp24-i2c"; - reg = <0x013>; + reg = <0x13>; clock-frequency = <400000>; interrupt-parent = <&gpio5>; From f78c81b429ccb0a0574a1f169d208ce159007cb1 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Sat, 17 Jan 2015 15:17:51 +0100 Subject: [PATCH 41/64] MAINTAINERS: Add Patchwork and Git URL for TPMDD Maybe it helps people finding the right tree and also simplifies tracking of their patches Signed-off-by: Peter Huewe --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index e18aef54b4b2..ddf762511cb3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9723,6 +9723,8 @@ M: Peter Huewe M: Marcel Selhorst W: http://tpmdd.sourceforge.net L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers) +Q: git git://github.com/PeterHuewe/linux-tpmdd.git +T: https://github.com/PeterHuewe/linux-tpmdd S: Maintained F: drivers/char/tpm/ From 3b09825dd8758a59c1a70e18df5bc8d04f8e5ced Mon Sep 17 00:00:00 2001 From: Bruno E O Meneguele Date: Sat, 17 Jan 2015 17:03:30 +0100 Subject: [PATCH 42/64] char/tpm: fixed white spaces coding style issues Fixed some coding style issues reported by checkpatch. Signed-off-by: Bruno E O Meneguele [phuewe: ported to latest code] Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm.h | 6 +++--- drivers/char/tpm/tpm_i2c_stm_st33.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index cc421cfde389..7b0727c5e803 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -10,13 +10,13 @@ * Maintained by: * * Device driver for TCG/TCPA TPM (trusted platform module). - * Specifications at www.trustedcomputinggroup.org + * Specifications at www.trustedcomputinggroup.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2 of the * License. - * + * */ #include #include @@ -141,7 +141,7 @@ struct tpm_vendor_specific { u16 manufacturer_id; }; -#define TPM_VPRIV(c) (c)->vendor.priv +#define TPM_VPRIV(c) ((c)->vendor.priv) #define TPM_VID_INTEL 0x8086 #define TPM_VID_WINBOND 0x1050 diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c index dbab8d0d875e..612845b36c29 100644 --- a/drivers/char/tpm/tpm_i2c_stm_st33.c +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c @@ -777,7 +777,7 @@ tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) IRQF_TRIGGER_HIGH, "TPM SERIRQ management", chip); if (ret < 0) { - dev_err(chip->pdev , "TPM SERIRQ signals %d not available\n", + dev_err(chip->pdev, "TPM SERIRQ signals %d not available\n", client->irq); goto _tpm_clean_answer; } From 1a28979b322bb28d8f95f76f080c53dbb9a8222d Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 26 Nov 2014 15:31:06 +0100 Subject: [PATCH 43/64] smack: miscellaneous small fixes in function comments Signed-off-by: Lukasz Pawelczyk --- security/smack/smack_lsm.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index f1b17a476e12..dcfaddd955d1 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -202,6 +202,7 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file, /** * smk_fetch - Fetch the smack label from a file. + * @name: type of the label (attribute) * @ip: a pointer to the inode * @dp: a pointer to the dentry * @@ -254,7 +255,9 @@ struct inode_smack *new_inode_smack(struct smack_known *skp) /** * new_task_smack - allocate a task security blob - * @smack: a pointer to the Smack label to use in the blob + * @task: a pointer to the Smack label for the running task + * @forked: a pointer to the Smack label for the forked task + * @gfp: type of the memory for the allocation * * Returns the new blob or NULL if there's no memory available */ @@ -277,8 +280,9 @@ static struct task_smack *new_task_smack(struct smack_known *task, /** * smk_copy_rules - copy a rule set - * @nhead - new rules header pointer - * @ohead - old rules header pointer + * @nhead: new rules header pointer + * @ohead: old rules header pointer + * @gfp: type of the memory for the allocation * * Returns 0 on success, -ENOMEM on error */ @@ -3834,11 +3838,11 @@ static void smack_key_free(struct key *key) key->security = NULL; } -/* +/** * smack_key_permission - Smack access on a key * @key_ref: gets to the object * @cred: the credentials to use - * @perm: unused + * @perm: requested key permissions * * Return 0 if the task has read and write to the object, * an error code otherwise From 68390ccf8b0a3470032f053d50379cfd49fbe952 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 26 Nov 2014 15:31:07 +0100 Subject: [PATCH 44/64] smack: fix logic in smack_inode_init_security function In principle if this function was called with "value" == NULL and "len" not NULL it could return different results for the "len" compared to a case where "name" was not NULL. This is a hypothetical case that does not exist in the kernel, but it's a logic bug nonetheless. Signed-off-by: Lukasz Pawelczyk --- security/smack/smack_lsm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index dcfaddd955d1..048d92e81a34 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -800,7 +800,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, if (name) *name = XATTR_SMACK_SUFFIX; - if (value) { + if (value && len) { rcu_read_lock(); may = smk_access_entry(skp->smk_known, dsp->smk_known, &skp->smk_rules); @@ -821,10 +821,9 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, *value = kstrdup(isp->smk_known, GFP_NOFS); if (*value == NULL) return -ENOMEM; - } - if (len) *len = strlen(isp->smk_known); + } return 0; } From 1d8c2326a4a2a4d942f9165b5702fe6f869ccf48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stelmach?= Date: Tue, 16 Dec 2014 16:53:08 +0100 Subject: [PATCH 45/64] smack: introduce a special case for tmpfs in smack_d_instantiate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Files created with __shmem_file_stup() appear to have somewhat fake dentries which make them look like root directories and not get the label the current process or ("*") star meant for tmpfs files. Signed-off-by: Łukasz Stelmach --- security/smack/smack_lsm.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 048d92e81a34..2160e88a2e4e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3036,7 +3036,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) * of the superblock. */ if (opt_dentry->d_parent == opt_dentry) { - if (sbp->s_magic == CGROUP_SUPER_MAGIC) { + switch (sbp->s_magic) { + case CGROUP_SUPER_MAGIC: /* * The cgroup filesystem is never mounted, * so there's no opportunity to set the mount @@ -3044,8 +3045,19 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) */ sbsp->smk_root = &smack_known_star; sbsp->smk_default = &smack_known_star; + isp->smk_inode = sbsp->smk_root; + break; + case TMPFS_MAGIC: + /* + * What about shmem/tmpfs anonymous files with dentry + * obtained from d_alloc_pseudo()? + */ + isp->smk_inode = smk_of_current(); + break; + default: + isp->smk_inode = sbsp->smk_root; + break; } - isp->smk_inode = sbsp->smk_root; isp->smk_flags |= SMK_INODE_INSTANT; goto unlockandout; } From 96be7b5424948ae39d29d5149eaec0bd6edd7404 Mon Sep 17 00:00:00 2001 From: Zbigniew Jasinski Date: Mon, 29 Dec 2014 15:34:58 +0100 Subject: [PATCH 46/64] smack: Fix a bidirectional UDS connect check typo The 54e70ec5eb090193b03e69d551fa6771a5a217c4 commit introduced a bidirectional check that should have checked for mutual WRITE access between two labels. Due to a typo subject's OUT label is checked with object's OUT. Should be OUT to IN. Signed-off-by: Zbigniew Jasinski --- security/smack/smack_lsm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 2160e88a2e4e..654345de62e7 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3312,7 +3312,7 @@ static int smack_unix_stream_connect(struct sock *sock, if (!smack_privileged(CAP_MAC_OVERRIDE)) { skp = ssp->smk_out; - okp = osp->smk_out; + okp = osp->smk_in; #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); smk_ad_setfield_u_net_sk(&ad, other); @@ -3320,6 +3320,8 @@ static int smack_unix_stream_connect(struct sock *sock, rc = smk_access(skp, okp, MAY_WRITE, &ad); rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc); if (rc == 0) { + okp = osp->smk_out; + skp = ssp->smk_in; rc = smk_access(okp, skp, MAY_WRITE, NULL); rc = smk_bu_note("UDS connect", okp, skp, MAY_WRITE, rc); From 914309995ed5c6c737df4135ac5ba2b67cff194d Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Mon, 19 Jan 2015 10:43:40 +0200 Subject: [PATCH 47/64] char/tpm/tpm_crb: fix build error SIMPLE_DEV_PM_OPS() was inside #ifdef CONFIG_PM_SLEEP. Fixes: 30fc8d1 ("tpm: TPM 2.0 CRB Interface") Signed-off-by: Jarkko Sakkinen Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm_crb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index c248a356d5c9..3dd23cfae4fe 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -107,9 +107,9 @@ static int crb_resume(struct device *dev) return rc; } +#endif static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, crb_resume); -#endif static u8 crb_status(struct tpm_chip *chip) { From 743410a03bbf110da8942a715cf1358344ecc281 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 20 Jan 2015 12:03:35 +0200 Subject: [PATCH 48/64] tpm: fix format string error in tpm-chip.c dev_set_name() takes three arguments where the second argument is a format string. This patch fixes the call accordingly in tpm-chip.c Reported-by: kbuild test robot Fixes: 313d21eeab92 ("tpm: device class for tpm") Signed-off-by: Jarkko Sakkinen Signed-off-by: Peter Huewe --- drivers/char/tpm/tpm-chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 6459af7c1646..1d278ccd751f 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -125,7 +125,7 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev, else chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num); - dev_set_name(&chip->dev, chip->devname); + dev_set_name(&chip->dev, "%s", chip->devname); device_initialize(&chip->dev); From 5e7270a6dd14fa6e3bb10128f200305b4a75f350 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Fri, 12 Dec 2014 17:19:19 -0800 Subject: [PATCH 49/64] Smack: Rework file hooks This is one of those cases where you look at code you did years ago and wonder what you might have been thinking. There are a number of LSM hooks that work off of file pointers, and most of them really want the security data from the inode. Some, however, really want the security context that the process had when the file was opened. The difference went undetected in Smack until it started getting used in a real system with real testing. At that point it was clear that something was amiss. This patch corrects the misuse of the f_security value in several of the hooks. The behavior will not usually be any different, as the process had to be able to open the file in the first place, and the old check almost always succeeded, as will the new, but for different reasons. Thanks to the Samsung Tizen development team that identified this. Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 40 ++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 654345de62e7..1fa72317bbec 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -160,7 +160,7 @@ static int smk_bu_file(struct file *file, int mode, int rc) { struct task_smack *tsp = current_security(); struct smack_known *sskp = tsp->smk_task; - struct inode *inode = file->f_inode; + struct inode *inode = file_inode(file); char acc[SMK_NUM_ACCESS_TYPE + 1]; if (rc <= 0) @@ -168,7 +168,7 @@ static int smk_bu_file(struct file *file, int mode, int rc) smk_bu_mode(mode, acc); pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %pD) %s\n", - sskp->smk_known, (char *)file->f_security, acc, + sskp->smk_known, smk_of_inode(inode)->smk_known, acc, inode->i_sb->s_id, inode->i_ino, file, current->comm); return 0; @@ -1347,6 +1347,9 @@ static int smack_file_permission(struct file *file, int mask) * The security blob for a file is a pointer to the master * label list, so no allocation is done. * + * f_security is the owner security information. It + * isn't used on file access checks, it's for send_sigio. + * * Returns 0 */ static int smack_file_alloc_security(struct file *file) @@ -1384,17 +1387,18 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd, { int rc = 0; struct smk_audit_info ad; + struct inode *inode = file_inode(file); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); if (_IOC_DIR(cmd) & _IOC_WRITE) { - rc = smk_curacc(file->f_security, MAY_WRITE, &ad); + rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad); rc = smk_bu_file(file, MAY_WRITE, rc); } if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) { - rc = smk_curacc(file->f_security, MAY_READ, &ad); + rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad); rc = smk_bu_file(file, MAY_READ, rc); } @@ -1412,10 +1416,11 @@ static int smack_file_lock(struct file *file, unsigned int cmd) { struct smk_audit_info ad; int rc; + struct inode *inode = file_inode(file); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_curacc(file->f_security, MAY_LOCK, &ad); + rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad); rc = smk_bu_file(file, MAY_LOCK, rc); return rc; } @@ -1437,7 +1442,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, { struct smk_audit_info ad; int rc = 0; - + struct inode *inode = file_inode(file); switch (cmd) { case F_GETLK: @@ -1446,14 +1451,14 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd, case F_SETLKW: smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_curacc(file->f_security, MAY_LOCK, &ad); + rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad); rc = smk_bu_file(file, MAY_LOCK, rc); break; case F_SETOWN: case F_SETSIG: smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_curacc(file->f_security, MAY_WRITE, &ad); + rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad); rc = smk_bu_file(file, MAY_WRITE, rc); break; default: @@ -1571,14 +1576,10 @@ static int smack_mmap_file(struct file *file, * smack_file_set_fowner - set the file security blob value * @file: object in question * - * Returns 0 - * Further research may be required on this one. */ static void smack_file_set_fowner(struct file *file) { - struct smack_known *skp = smk_of_current(); - - file->f_security = skp; + file->f_security = smk_of_current(); } /** @@ -1630,6 +1631,7 @@ static int smack_file_receive(struct file *file) int rc; int may = 0; struct smk_audit_info ad; + struct inode *inode = file_inode(file); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); @@ -1641,7 +1643,7 @@ static int smack_file_receive(struct file *file) if (file->f_mode & FMODE_WRITE) may |= MAY_WRITE; - rc = smk_curacc(file->f_security, may, &ad); + rc = smk_curacc(smk_of_inode(inode), may, &ad); rc = smk_bu_file(file, may, rc); return rc; } @@ -1661,21 +1663,17 @@ static int smack_file_receive(struct file *file) static int smack_file_open(struct file *file, const struct cred *cred) { struct task_smack *tsp = cred->security; - struct inode_smack *isp = file_inode(file)->i_security; + struct inode *inode = file_inode(file); struct smk_audit_info ad; int rc; - if (smack_privileged(CAP_MAC_OVERRIDE)) { - file->f_security = isp->smk_inode; + if (smack_privileged(CAP_MAC_OVERRIDE)) return 0; - } smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); smk_ad_setfield_u_fs_path(&ad, file->f_path); - rc = smk_access(tsp->smk_task, isp->smk_inode, MAY_READ, &ad); + rc = smk_access(tsp->smk_task, smk_of_inode(inode), MAY_READ, &ad); rc = smk_bu_credfile(cred, file, MAY_READ, rc); - if (rc == 0) - file->f_security = isp->smk_inode; return rc; } From 69f287ae6fc8357e0bc561353a2d585b89ee8cdc Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Fri, 12 Dec 2014 17:08:40 -0800 Subject: [PATCH 50/64] Smack: secmark support for netfilter Smack uses CIPSO to label internet packets and thus provide for access control on delivery of packets. The netfilter facility was not used to allow for Smack to work properly without netfilter configuration. Smack does not need netfilter, however there are cases where it would be handy. As a side effect, the labeling of local IPv4 packets can be optimized and the handling of local IPv6 packets is just all out better. The best part is that the netfilter tools use "contexts" that are just strings, and they work just as well for Smack as they do for SELinux. All of the conditional compilation for IPv6 was implemented by Rafal Krypa Signed-off-by: Casey Schaufler --- security/smack/Kconfig | 12 ++++ security/smack/Makefile | 1 + security/smack/smack.h | 1 + security/smack/smack_lsm.c | 94 ++++++++++++++++++++++++++++--- security/smack/smack_netfilter.c | 96 ++++++++++++++++++++++++++++++++ 5 files changed, 196 insertions(+), 8 deletions(-) create mode 100644 security/smack/smack_netfilter.c diff --git a/security/smack/Kconfig b/security/smack/Kconfig index b065f9789418..271adae81796 100644 --- a/security/smack/Kconfig +++ b/security/smack/Kconfig @@ -28,3 +28,15 @@ config SECURITY_SMACK_BRINGUP access rule set once the behavior is well understood. This is a superior mechanism to the oft abused "permissive" mode of other systems. + If you are unsure how to answer this question, answer N. + +config SECURITY_SMACK_NETFILTER + bool "Packet marking using secmarks for netfilter" + depends on SECURITY_SMACK + depends on NETWORK_SECMARK + depends on NETFILTER + default n + help + This enables security marking of network packets using + Smack labels. + If you are unsure how to answer this question, answer N. diff --git a/security/smack/Makefile b/security/smack/Makefile index 67a63aaec827..616cf93b368e 100644 --- a/security/smack/Makefile +++ b/security/smack/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_SECURITY_SMACK) := smack.o smack-y := smack_lsm.o smack_access.o smackfs.o +smack-$(CONFIG_NETFILTER) += smack_netfilter.o diff --git a/security/smack/smack.h b/security/smack/smack.h index b828a379377c..7629eaeb1fb2 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -248,6 +248,7 @@ struct smack_known *smk_find_entry(const char *); /* * Shared data. */ +extern int smack_enabled; extern int smack_cipso_direct; extern int smack_cipso_mapped; extern struct smack_known *smack_net_ambient; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 1fa72317bbec..81b30e32c526 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -52,8 +52,11 @@ #define SMK_RECEIVING 1 #define SMK_SENDING 2 +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) LIST_HEAD(smk_ipv6_port_list); +#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ static struct kmem_cache *smack_inode_cache; +int smack_enabled; #ifdef CONFIG_SECURITY_SMACK_BRINGUP static void smk_bu_mode(int mode, char *s) @@ -2213,6 +2216,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) return smack_netlabel(sk, sk_lbl); } +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) /** * smk_ipv6_port_label - Smack port access table management * @sock: socket @@ -2362,6 +2366,7 @@ auditout: rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc); return rc; } +#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ /** * smack_inode_setsecurity - set smack xattrs @@ -2422,8 +2427,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, } else return -EOPNOTSUPP; +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) if (sock->sk->sk_family == PF_INET6) smk_ipv6_port_label(sock, NULL); +#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ return 0; } @@ -2451,6 +2458,7 @@ static int smack_socket_post_create(struct socket *sock, int family, return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); } +#ifndef CONFIG_SECURITY_SMACK_NETFILTER /** * smack_socket_bind - record port binding information. * @sock: the socket @@ -2464,11 +2472,14 @@ static int smack_socket_post_create(struct socket *sock, int family, static int smack_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) { +#if IS_ENABLED(CONFIG_IPV6) if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) smk_ipv6_port_label(sock, address); +#endif return 0; } +#endif /* !CONFIG_SECURITY_SMACK_NETFILTER */ /** * smack_socket_connect - connect access check @@ -2497,8 +2508,10 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, case PF_INET6: if (addrlen < sizeof(struct sockaddr_in6)) return -EINVAL; +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap, SMK_CONNECTING); +#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ break; } return rc; @@ -3381,7 +3394,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) { struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name; +#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ int rc = 0; /* @@ -3395,7 +3410,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, rc = smack_netlabel_send(sock->sk, sip); break; case AF_INET6: +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); +#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ break; } return rc; @@ -3486,6 +3503,7 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, return smack_net_ambient; } +#if IS_ENABLED(CONFIG_IPV6) static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip) { u8 nexthdr; @@ -3532,6 +3550,7 @@ static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip) } return proto; } +#endif /* CONFIG_IPV6 */ /** * smack_socket_sock_rcv_skb - Smack packet delivery access check @@ -3544,15 +3563,30 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) { struct netlbl_lsm_secattr secattr; struct socket_smack *ssp = sk->sk_security; - struct smack_known *skp; - struct sockaddr_in6 sadd; + struct smack_known *skp = NULL; int rc = 0; struct smk_audit_info ad; #ifdef CONFIG_AUDIT struct lsm_network_audit net; #endif +#if IS_ENABLED(CONFIG_IPV6) + struct sockaddr_in6 sadd; + int proto; +#endif /* CONFIG_IPV6 */ + switch (sk->sk_family) { case PF_INET: +#ifdef CONFIG_SECURITY_SMACK_NETFILTER + /* + * If there is a secmark use it rather than the CIPSO label. + * If there is no secmark fall back to CIPSO. + * The secmark is assumed to reflect policy better. + */ + if (skb && skb->secmark != 0) { + skp = smack_from_secid(skb->secmark); + goto access_check; + } +#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ /* * Translate what netlabel gave us. */ @@ -3566,6 +3600,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) netlbl_secattr_destroy(&secattr); +#ifdef CONFIG_SECURITY_SMACK_NETFILTER +access_check: +#endif #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); ad.a.u.net->family = sk->sk_family; @@ -3584,14 +3621,32 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) if (rc != 0) netlbl_skbuff_err(skb, rc, 0); break; +#if IS_ENABLED(CONFIG_IPV6) case PF_INET6: - rc = smk_skb_to_addr_ipv6(skb, &sadd); - if (rc == IPPROTO_UDP || rc == IPPROTO_TCP) - rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING); + proto = smk_skb_to_addr_ipv6(skb, &sadd); + if (proto != IPPROTO_UDP && proto != IPPROTO_TCP) + break; +#ifdef CONFIG_SECURITY_SMACK_NETFILTER + if (skb && skb->secmark != 0) + skp = smack_from_secid(skb->secmark); else - rc = 0; + skp = smack_net_ambient; +#ifdef CONFIG_AUDIT + smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); + ad.a.u.net->family = sk->sk_family; + ad.a.u.net->netif = skb->skb_iif; + ipv6_skb_to_auditdata(skb, &ad.a, NULL); +#endif /* CONFIG_AUDIT */ + rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); + rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in, + MAY_WRITE, rc); +#else /* CONFIG_SECURITY_SMACK_NETFILTER */ + rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING); +#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ break; +#endif /* CONFIG_IPV6 */ } + return rc; } @@ -3653,16 +3708,25 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, if (skb != NULL) { if (skb->protocol == htons(ETH_P_IP)) family = PF_INET; +#if IS_ENABLED(CONFIG_IPV6) else if (skb->protocol == htons(ETH_P_IPV6)) family = PF_INET6; +#endif /* CONFIG_IPV6 */ } if (family == PF_UNSPEC && sock != NULL) family = sock->sk->sk_family; - if (family == PF_UNIX) { + switch (family) { + case PF_UNIX: ssp = sock->sk->sk_security; s = ssp->smk_out->smk_secid; - } else if (family == PF_INET || family == PF_INET6) { + break; + case PF_INET: +#ifdef CONFIG_SECURITY_SMACK_NETFILTER + s = skb->secmark; + if (s != 0) + break; +#endif /* * Translate what netlabel gave us. */ @@ -3675,6 +3739,14 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, s = skp->smk_secid; } netlbl_secattr_destroy(&secattr); + break; +#if IS_ENABLED(CONFIG_IPV6) + case PF_INET6: +#ifdef CONFIG_SECURITY_SMACK_NETFILTER + s = skb->secmark; +#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ + break; +#endif /* CONFIG_IPV6 */ } *secid = s; if (s == 0) @@ -3730,6 +3802,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, struct lsm_network_audit net; #endif +#if IS_ENABLED(CONFIG_IPV6) if (family == PF_INET6) { /* * Handle mapped IPv4 packets arriving @@ -3741,6 +3814,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, else return 0; } +#endif /* CONFIG_IPV6 */ netlbl_secattr_init(&secattr); rc = netlbl_skbuff_getattr(skb, family, &secattr); @@ -4199,7 +4273,9 @@ struct security_operations smack_ops = { .unix_may_send = smack_unix_may_send, .socket_post_create = smack_socket_post_create, +#ifndef CONFIG_SECURITY_SMACK_NETFILTER .socket_bind = smack_socket_bind, +#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ .socket_connect = smack_socket_connect, .socket_sendmsg = smack_socket_sendmsg, .socket_sock_rcv_skb = smack_socket_sock_rcv_skb, @@ -4280,6 +4356,8 @@ static __init int smack_init(void) if (!security_module_enable(&smack_ops)) return 0; + smack_enabled = 1; + smack_inode_cache = KMEM_CACHE(inode_smack, 0); if (!smack_inode_cache) return -ENOMEM; diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c new file mode 100644 index 000000000000..c952632afb0d --- /dev/null +++ b/security/smack/smack_netfilter.c @@ -0,0 +1,96 @@ +/* + * Simplified MAC Kernel (smack) security module + * + * This file contains the Smack netfilter implementation + * + * Author: + * Casey Schaufler + * + * Copyright (C) 2014 Casey Schaufler + * Copyright (C) 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#include "smack.h" + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +static unsigned int smack_ipv6_output(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct socket_smack *ssp; + struct smack_known *skp; + + if (skb && skb->sk && skb->sk->sk_security) { + ssp = skb->sk->sk_security; + skp = ssp->smk_out; + skb->secmark = skp->smk_secid; + } + + return NF_ACCEPT; +} +#endif /* IPV6 */ + +static unsigned int smack_ipv4_output(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct socket_smack *ssp; + struct smack_known *skp; + + if (skb && skb->sk && skb->sk->sk_security) { + ssp = skb->sk->sk_security; + skp = ssp->smk_out; + skb->secmark = skp->smk_secid; + } + + return NF_ACCEPT; +} + +static struct nf_hook_ops smack_nf_ops[] = { + { + .hook = smack_ipv4_output, + .owner = THIS_MODULE, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_OUT, + .priority = NF_IP_PRI_SELINUX_FIRST, + }, +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + { + .hook = smack_ipv6_output, + .owner = THIS_MODULE, + .pf = NFPROTO_IPV6, + .hooknum = NF_INET_LOCAL_OUT, + .priority = NF_IP6_PRI_SELINUX_FIRST, + }, +#endif /* IPV6 */ +}; + +static int __init smack_nf_ip_init(void) +{ + int err; + + if (smack_enabled == 0) + return 0; + + printk(KERN_DEBUG "Smack: Registering netfilter hooks\n"); + + err = nf_register_hooks(smack_nf_ops, ARRAY_SIZE(smack_nf_ops)); + if (err) + pr_info("Smack: nf_register_hooks: error %d\n", err); + + return 0; +} + +__initcall(smack_nf_ip_init); From 138a868f009bfca8633032cdb91e2b02e292658b Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Thu, 8 Jan 2015 18:52:45 +0100 Subject: [PATCH 51/64] smack: Add missing logging in bidirectional UDS connect check During UDS connection check, both sides are checked for write access to the other side. But only the first check is performed with audit support. The second one didn't produce any audit logs. This simple patch fixes that. Signed-off-by: Rafal Krypa --- security/smack/smack_lsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 81b30e32c526..f60ded3a8da1 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3333,7 +3333,7 @@ static int smack_unix_stream_connect(struct sock *sock, if (rc == 0) { okp = osp->smk_out; skp = ssp->smk_in; - rc = smk_access(okp, skp, MAY_WRITE, NULL); + rc = smk_access(okp, skp, MAY_WRITE, &ad); rc = smk_bu_note("UDS connect", okp, skp, MAY_WRITE, rc); } From 6d1cff2a885850b78b40c34777b46cf5da5d1050 Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Tue, 13 Jan 2015 18:52:40 +0300 Subject: [PATCH 52/64] smack: fix possible use after frees in task_security() callers We hit use after free on dereferncing pointer to task_smack struct in smk_of_task() called from smack_task_to_inode(). task_security() macro uses task_cred_xxx() to get pointer to the task_smack. task_cred_xxx() could be used only for non-pointer members of task's credentials. It cannot be used for pointer members since what they point to may disapper after dropping RCU read lock. Mainly task_security() used this way: smk_of_task(task_security(p)) Intead of this introduce function smk_of_task_struct() which takes task_struct as argument and returns pointer to smk_known struct and do this under RCU read lock. Bogus task_security() macro is not used anymore, so remove it. KASan's report for this: AddressSanitizer: use after free in smack_task_to_inode+0x50/0x70 at addr c4635600 ============================================================================= BUG kmalloc-64 (Tainted: PO): kasan error ----------------------------------------------------------------------------- Disabling lock debugging due to kernel taint INFO: Allocated in new_task_smack+0x44/0xd8 age=39 cpu=0 pid=1866 kmem_cache_alloc_trace+0x88/0x1bc new_task_smack+0x44/0xd8 smack_cred_prepare+0x48/0x21c security_prepare_creds+0x44/0x4c prepare_creds+0xdc/0x110 smack_setprocattr+0x104/0x150 security_setprocattr+0x4c/0x54 proc_pid_attr_write+0x12c/0x194 vfs_write+0x1b0/0x370 SyS_write+0x5c/0x94 ret_fast_syscall+0x0/0x48 INFO: Freed in smack_cred_free+0xc4/0xd0 age=27 cpu=0 pid=1564 kfree+0x270/0x290 smack_cred_free+0xc4/0xd0 security_cred_free+0x34/0x3c put_cred_rcu+0x58/0xcc rcu_process_callbacks+0x738/0x998 __do_softirq+0x264/0x4cc do_softirq+0x94/0xf4 irq_exit+0xbc/0x120 handle_IRQ+0x104/0x134 gic_handle_irq+0x70/0xac __irq_svc+0x44/0x78 _raw_spin_unlock+0x18/0x48 sync_inodes_sb+0x17c/0x1d8 sync_filesystem+0xac/0xfc vdfs_file_fsync+0x90/0xc0 vfs_fsync_range+0x74/0x7c INFO: Slab 0xd3b23f50 objects=32 used=31 fp=0xc4635600 flags=0x4080 INFO: Object 0xc4635600 @offset=5632 fp=0x (null) Bytes b4 c46355f0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ Object c4635600: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Object c4635610: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Object c4635620: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Object c4635630: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk. Redzone c4635640: bb bb bb bb .... Padding c46356e8: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ Padding c46356f8: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ CPU: 5 PID: 834 Comm: launchpad_prelo Tainted: PBO 3.10.30 #1 Backtrace: [] (dump_backtrace+0x0/0x158) from [] (show_stack+0x20/0x24) r7:c4634010 r6:d3b23f50 r5:c4635600 r4:d1002140 [] (show_stack+0x0/0x24) from [] (dump_stack+0x20/0x28) [] (dump_stack+0x0/0x28) from [] (print_trailer+0x124/0x144) [] (print_trailer+0x0/0x144) from [] (object_err+0x3c/0x44) r7:c4635600 r6:d1002140 r5:d3b23f50 r4:c4635600 [] (object_err+0x0/0x44) from [] (kasan_report_error+0x2b8/0x538) r6:d1002140 r5:d3b23f50 r4:c6429cf8 r3:c09e1aa7 [] (kasan_report_error+0x0/0x538) from [] (__asan_load4+0xd4/0xf8) [] (__asan_load4+0x0/0xf8) from [] (smack_task_to_inode+0x50/0x70) r5:c4635600 r4:ca9da000 [] (smack_task_to_inode+0x0/0x70) from [] (security_task_to_inode+0x3c/0x44) r5:cca25e80 r4:c0ba9780 [] (security_task_to_inode+0x0/0x44) from [] (pid_revalidate+0x124/0x178) r6:00000000 r5:cca25e80 r4:cbabe3c0 r3:00008124 [] (pid_revalidate+0x0/0x178) from [] (lookup_fast+0x35c/0x43y4) r9:c6429efc r8:00000101 r7:c079d940 r6:c6429e90 r5:c6429ed8 r4:c83c4148 [] (lookup_fast+0x0/0x434) from [] (do_last.isra.24+0x1c0/0x1108) [] (do_last.isra.24+0x0/0x1108) from [] (path_openat.isra.25+0xf4/0x648) [] (path_openat.isra.25+0x0/0x648) from [] (do_filp_open+0x3c/0x88) [] (do_filp_open+0x0/0x88) from [] (do_sys_open+0xf0/0x198) r7:00000001 r6:c0ea2180 r5:0000000b r4:00000000 [] (do_sys_open+0x0/0x198) from [] (SyS_open+0x30/0x34) [] (SyS_open+0x0/0x34) from [] (ret_fast_syscall+0x0/0x48) Read of size 4 by thread T834: Memory state around the buggy address: c4635380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc c4635400: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc c4635480: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc c4635500: 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc fc c4635580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc >c4635600: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ^ c4635680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb c4635700: 00 00 00 00 04 fc fc fc fc fc fc fc fc fc fc fc c4635780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc c4635800: 00 00 00 00 00 00 04 fc fc fc fc fc fc fc fc fc c4635880: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ================================================================== Signed-off-by: Andrey Ryabinin Cc: --- security/smack/smack.h | 10 ++++++++++ security/smack/smack_lsm.c | 24 +++++++++++++----------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/security/smack/smack.h b/security/smack/smack.h index 7629eaeb1fb2..67ccb7b2b89b 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -299,6 +299,16 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp) return tsp->smk_task; } +static inline struct smack_known *smk_of_task_struct(const struct task_struct *t) +{ + struct smack_known *skp; + + rcu_read_lock(); + skp = smk_of_task(__task_cred(t)->security); + rcu_read_unlock(); + return skp; +} + /* * Present a pointer to the forked smack label entry in an task blob. */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index f60ded3a8da1..a0ccce4e46f8 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -43,8 +43,6 @@ #include #include "smack.h" -#define task_security(task) (task_cred_xxx((task), security)) - #define TRANS_TRUE "TRUE" #define TRANS_TRUE_SIZE 4 @@ -123,7 +121,7 @@ static int smk_bu_current(char *note, struct smack_known *oskp, static int smk_bu_task(struct task_struct *otp, int mode, int rc) { struct task_smack *tsp = current_security(); - struct task_smack *otsp = task_security(otp); + struct smack_known *smk_task = smk_of_task_struct(otp); char acc[SMK_NUM_ACCESS_TYPE + 1]; if (rc <= 0) @@ -131,7 +129,7 @@ static int smk_bu_task(struct task_struct *otp, int mode, int rc) smk_bu_mode(mode, acc); pr_info("Smack Bringup: (%s %s %s) %s to %s\n", - tsp->smk_task->smk_known, otsp->smk_task->smk_known, acc, + tsp->smk_task->smk_known, smk_task->smk_known, acc, current->comm, otp->comm); return 0; } @@ -352,7 +350,8 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, saip = &ad; } - tsp = task_security(tracer); + rcu_read_lock(); + tsp = __task_cred(tracer)->security; tracer_known = smk_of_task(tsp); if ((mode & PTRACE_MODE_ATTACH) && @@ -372,11 +371,14 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, tracee_known->smk_known, 0, rc, saip); + rcu_read_unlock(); return rc; } /* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */ rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip); + + rcu_read_unlock(); return rc; } @@ -403,7 +405,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) if (rc != 0) return rc; - skp = smk_of_task(task_security(ctp)); + skp = smk_of_task_struct(ctp); rc = smk_ptrace_rule_check(current, skp, mode, __func__); return rc; @@ -1830,7 +1832,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access, const char *caller) { struct smk_audit_info ad; - struct smack_known *skp = smk_of_task(task_security(p)); + struct smack_known *skp = smk_of_task_struct(p); int rc; smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK); @@ -1883,7 +1885,7 @@ static int smack_task_getsid(struct task_struct *p) */ static void smack_task_getsecid(struct task_struct *p, u32 *secid) { - struct smack_known *skp = smk_of_task(task_security(p)); + struct smack_known *skp = smk_of_task_struct(p); *secid = skp->smk_secid; } @@ -1990,7 +1992,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info, { struct smk_audit_info ad; struct smack_known *skp; - struct smack_known *tkp = smk_of_task(task_security(p)); + struct smack_known *tkp = smk_of_task_struct(p); int rc; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); @@ -2044,7 +2046,7 @@ static int smack_task_wait(struct task_struct *p) static void smack_task_to_inode(struct task_struct *p, struct inode *inode) { struct inode_smack *isp = inode->i_security; - struct smack_known *skp = smk_of_task(task_security(p)); + struct smack_known *skp = smk_of_task_struct(p); isp->smk_inode = skp; } @@ -3226,7 +3228,7 @@ unlockandout: */ static int smack_getprocattr(struct task_struct *p, char *name, char **value) { - struct smack_known *skp = smk_of_task(task_security(p)); + struct smack_known *skp = smk_of_task_struct(p); char *cp; int slen; From 961be7ef6963806cb978ccd6acf6bf84b0c63346 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Thu, 22 Jan 2015 00:42:50 +0100 Subject: [PATCH 53/64] tpm/tpm_tis: Add missing ifdef CONFIG_ACPI for pnp_acpi_device This fixes a build failure if CONFIG_PNP is set but CONFIG_ACPI is not: drivers/char/tpm/tpm_tis.c: In function ?tpm_tis_pnp_init?: drivers/char/tpm/tpm_tis.c:912:45: error: invalid type argument of ?->? (have ?int?) acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle; If CONFIG_PNPACPI is not set pnp_acpi_device is defined as 0 and thus accesing the handle is not possible. Fixes: 0dc553652102 ("tpm: fix raciness of PPI interface lookup") Reported-by: Jim Davis Signed-off-by: Peter Huewe Signed-off-by: James Morris --- drivers/char/tpm/tpm_tis.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 20a61bc98db8..6725bef7cb96 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -908,8 +908,10 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev, if (is_itpm(pnp_dev)) itpm = true; +#ifdef CONFIG_ACPI if (pnp_acpi_device(pnp_dev)) acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle; +#endif return tpm_tis_init(&pnp_dev->dev, acpi_dev_handle, start, len, irq); } From bfd33c4b4b1ac718d481efee10f3a16d88757577 Mon Sep 17 00:00:00 2001 From: Dmitry Kasatkin Date: Thu, 15 Jan 2015 14:18:18 +0200 Subject: [PATCH 54/64] MAINTAINERS: email update Changed to my private email address as I left Samsung. Signed-off-by: Dmitry Kasatkin --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index ddf762511cb3..e9098d034b9d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4888,7 +4888,7 @@ F: drivers/ipack/ INTEGRITY MEASUREMENT ARCHITECTURE (IMA) M: Mimi Zohar -M: Dmitry Kasatkin +M: Dmitry Kasatkin L: linux-ima-devel@lists.sourceforge.net L: linux-ima-user@lists.sourceforge.net L: linux-security-module@vger.kernel.org From dabd39cc2fb1b0e97313ebbe7309ea8e05b7cfb5 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 22 Jan 2015 22:34:32 +0000 Subject: [PATCH 55/64] KEYS: Make /proc/keys unconditional if CONFIG_KEYS=y Now that /proc/keys is used by libkeyutils to look up a key by type and description, we should make it unconditional and remove CONFIG_DEBUG_PROC_KEYS. Reported-by: Jiri Kosina Signed-off-by: David Howells Tested-by: Jiri Kosina --- Documentation/security/keys.txt | 2 -- security/keys/Kconfig | 18 ------------------ security/keys/proc.c | 8 -------- 3 files changed, 28 deletions(-) diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt index 821c936e1a63..c9e7f4f223a5 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt @@ -323,8 +323,6 @@ about the status of the key service: U Under construction by callback to userspace N Negative key - This file must be enabled at kernel configuration time as it allows anyone - to list the keys database. (*) /proc/key-users diff --git a/security/keys/Kconfig b/security/keys/Kconfig index a4f3f8c48d6e..72483b8f1be5 100644 --- a/security/keys/Kconfig +++ b/security/keys/Kconfig @@ -80,21 +80,3 @@ config ENCRYPTED_KEYS Userspace only ever sees/stores encrypted blobs. If you are unsure as to whether this is required, answer N. - -config KEYS_DEBUG_PROC_KEYS - bool "Enable the /proc/keys file by which keys may be viewed" - depends on KEYS - help - This option turns on support for the /proc/keys file - through which - can be listed all the keys on the system that are viewable by the - reading process. - - The only keys included in the list are those that grant View - permission to the reading process whether or not it possesses them. - Note that LSM security checks are still performed, and may further - filter out keys that the current process is not authorised to view. - - Only key attributes are listed here; key payloads are not included in - the resulting table. - - If you are unsure as to whether this is required, answer N. diff --git a/security/keys/proc.c b/security/keys/proc.c index 972eeb336b81..f0611a6368cd 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c @@ -18,7 +18,6 @@ #include #include "internal.h" -#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS static int proc_keys_open(struct inode *inode, struct file *file); static void *proc_keys_start(struct seq_file *p, loff_t *_pos); static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos); @@ -38,7 +37,6 @@ static const struct file_operations proc_keys_fops = { .llseek = seq_lseek, .release = seq_release, }; -#endif static int proc_key_users_open(struct inode *inode, struct file *file); static void *proc_key_users_start(struct seq_file *p, loff_t *_pos); @@ -67,11 +65,9 @@ static int __init key_proc_init(void) { struct proc_dir_entry *p; -#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS p = proc_create("keys", 0, NULL, &proc_keys_fops); if (!p) panic("Cannot create /proc/keys\n"); -#endif p = proc_create("key-users", 0, NULL, &proc_key_users_fops); if (!p) @@ -86,8 +82,6 @@ __initcall(key_proc_init); * Implement "/proc/keys" to provide a list of the keys on the system that * grant View permission to the caller. */ -#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS - static struct rb_node *key_serial_next(struct seq_file *p, struct rb_node *n) { struct user_namespace *user_ns = seq_user_ns(p); @@ -275,8 +269,6 @@ static int proc_keys_show(struct seq_file *m, void *v) return 0; } -#endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ - static struct rb_node *__key_user_next(struct user_namespace *user_ns, struct rb_node *n) { while (n) { From 89f703f0932341b316b2312581dacddba14b3876 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Jan 2015 22:24:00 +0100 Subject: [PATCH 56/64] X.509: shut up about included cert for silent build Every kernel build that includes X.509 support prints out a message like - Including cert signing_key.x509 This may be useful for some cases, but when doing automated build tests, it just means noise. To hide the message, this uses '$(kecho)' for printing the message, which means we still see it when building with V=1, but not at the normal level or when building with 'make -s'. Signed-off-by: Arnd Bergmann Signed-off-by: David Howells --- kernel/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/Makefile b/kernel/Makefile index a59481a3fa6c..23e17a7e7a63 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -142,7 +142,7 @@ endif kernel/system_certificates.o: $(obj)/x509_certificate_list quiet_cmd_x509certs = CERTS $@ - cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ $(foreach X509,$(X509_CERTIFICATES),; echo " - Including cert $(X509)") + cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ $(foreach X509,$(X509_CERTIFICATES),; $(kecho) " - Including cert $(X509)") targets += $(obj)/x509_certificate_list $(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list From e994393acd65e729a574aaca466eab22b5b39cc6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Jan 2015 22:24:31 +0100 Subject: [PATCH 57/64] X.509: silence asn1 compiler debug output The asn1_compiler process is particularly chatty and produces about the only stdout output for an allmodconfig kernel. In order to follow the general concept of 'no news is good news' for building kernels, this hides all the existing output unless the KBUILD_VERBOSE environment variable is set. Signed-off-by: Arnd Bergmann Signed-off-by: David Howells --- scripts/asn1_compiler.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c index 91c4117637ae..7750e9c31483 100644 --- a/scripts/asn1_compiler.c +++ b/scripts/asn1_compiler.c @@ -311,6 +311,9 @@ struct token { static struct token *token_list; static unsigned nr_tokens; +static _Bool verbose; + +#define debug(fmt, ...) do { if (verbose) printf(fmt, ## __VA_ARGS__); } while (0) static int directive_compare(const void *_key, const void *_pdir) { @@ -322,21 +325,21 @@ static int directive_compare(const void *_key, const void *_pdir) dlen = strlen(dir); clen = (dlen < token->size) ? dlen : token->size; - //printf("cmp(%*.*s,%s) = ", + //debug("cmp(%*.*s,%s) = ", // (int)token->size, (int)token->size, token->value, // dir); val = memcmp(token->value, dir, clen); if (val != 0) { - //printf("%d [cmp]\n", val); + //debug("%d [cmp]\n", val); return val; } if (dlen == token->size) { - //printf("0\n"); + //debug("0\n"); return 0; } - //printf("%d\n", (int)dlen - (int)token->size); + //debug("%d\n", (int)dlen - (int)token->size); return dlen - token->size; /* shorter -> negative */ } @@ -515,13 +518,13 @@ static void tokenise(char *buffer, char *end) } nr_tokens = tix; - printf("Extracted %u tokens\n", nr_tokens); + debug("Extracted %u tokens\n", nr_tokens); #if 0 { int n; for (n = 0; n < nr_tokens; n++) - printf("Token %3u: '%*.*s'\n", + debug("Token %3u: '%*.*s'\n", n, (int)token_list[n].size, (int)token_list[n].size, token_list[n].value); @@ -542,6 +545,7 @@ int main(int argc, char **argv) ssize_t readlen; FILE *out, *hdr; char *buffer, *p; + char *kbuild_verbose; int fd; if (argc != 4) { @@ -550,6 +554,10 @@ int main(int argc, char **argv) exit(2); } + kbuild_verbose = getenv("KBUILD_VERBOSE"); + if (kbuild_verbose) + verbose = atoi(kbuild_verbose); + filename = argv[1]; outputname = argv[2]; headername = argv[3]; @@ -748,11 +756,11 @@ static void build_type_list(void) qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); - printf("Extracted %u types\n", nr_types); + debug("Extracted %u types\n", nr_types); #if 0 for (n = 0; n < nr_types; n++) { struct type *type = type_index[n]; - printf("- %*.*s\n", + debug("- %*.*s\n", (int)type->name->size, (int)type->name->size, type->name->value); @@ -793,7 +801,7 @@ static void parse(void) } while (type++, !(type->flags & TYPE_STOP_MARKER)); - printf("Extracted %u actions\n", nr_actions); + debug("Extracted %u actions\n", nr_actions); } static struct element *element_list; @@ -1284,7 +1292,7 @@ static void render(FILE *out, FILE *hdr) } /* We do two passes - the first one calculates all the offsets */ - printf("Pass 1\n"); + debug("Pass 1\n"); nr_entries = 0; root = &type_list[0]; render_element(NULL, root->element, NULL); @@ -1295,7 +1303,7 @@ static void render(FILE *out, FILE *hdr) e->flags &= ~ELEMENT_RENDERED; /* And then we actually render */ - printf("Pass 2\n"); + debug("Pass 2\n"); fprintf(out, "\n"); fprintf(out, "static const unsigned char %s_machine[] = {\n", grammar_name); From 82b0b2c2b1e64ad6c5309a9eeba806af9812666b Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Fri, 23 Jan 2015 09:31:01 -0800 Subject: [PATCH 58/64] Smack: Repair netfilter dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On 1/23/2015 8:20 AM, Jim Davis wrote: > Building with the attached random configuration file, > > security/smack/smack_netfilter.c: In function ‘smack_ipv4_output’: > security/smack/smack_netfilter.c:55:6: error: ‘struct sk_buff’ has no > member named ‘secmark’ > skb->secmark = skp->smk_secid; > ^ > make[2]: *** [security/smack/smack_netfilter.o] Error 1 The existing Makefile used the wrong configuration option to determine if smack_netfilter should be built. This sets it right. Signed-off-by: Casey Schaufler --- security/smack/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/smack/Makefile b/security/smack/Makefile index 616cf93b368e..ee2ebd504541 100644 --- a/security/smack/Makefile +++ b/security/smack/Makefile @@ -5,4 +5,4 @@ obj-$(CONFIG_SECURITY_SMACK) := smack.o smack-y := smack_lsm.o smack_access.o smackfs.o -smack-$(CONFIG_NETFILTER) += smack_netfilter.o +smack-$(CONFIG_SECURITY_SMACK_NETFILTER) += smack_netfilter.o From 11cd64a234d5a1a7111627ef947beb0e5fad9e71 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 30 Jan 2015 11:04:12 +0000 Subject: [PATCH 59/64] ima: /proc/keys is now mandatory /proc/keys is now mandatory and its config option no longer exists, so it doesn't need selecting. Reported-by: Paul Bolle Signed-off-by: David Howells Signed-off-by: Mimi Zohar Signed-off-by: James Morris --- security/integrity/ima/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 57515bc915c0..df303346029b 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -126,7 +126,6 @@ config IMA_TRUSTED_KEYRING bool "Require all keys on the .ima keyring be signed" depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING depends on INTEGRITY_ASYMMETRIC_KEYS - select KEYS_DEBUG_PROC_KEYS default y help This option requires that all keys added to the .ima From e230f12c98232de0c40a81f28a34d2cff8450e7f Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Wed, 4 Feb 2015 11:34:30 -0500 Subject: [PATCH 60/64] selinux: Remove unused function avc_sidcmp() Remove the function avc_sidcmp() that is not used anywhere. This was partially found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist [PM: rewrite the patch subject line] Signed-off-by: Paul Moore --- security/selinux/avc.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/security/selinux/avc.c b/security/selinux/avc.c index a18f1fa6440b..afcc0aed9393 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -517,11 +517,6 @@ out: return rc; } -static inline int avc_sidcmp(u32 x, u32 y) -{ - return (x == y || x == SECSID_WILD || y == SECSID_WILD); -} - /** * avc_update_node Update an AVC entry * @event : Updating event From 2088d60e3b2f53d0c9590a0202eeff85b288b1eb Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 4 Feb 2015 11:34:30 -0500 Subject: [PATCH 61/64] selinux: quiet the filesystem labeling behavior message While the filesystem labeling method is only printed at the KERN_DEBUG level, this still appears in dmesg and on modern Linux distributions that create a lot of tmpfs mounts for session handling, the dmesg can easily be filled with a lot of "SELinux: initialized (dev X ..." messages. This patch removes this notification for the normal case but leaves the error message intact (displayed when mounting a filesystem with an unknown labeling behavior). Reported-by: Dave Jones Signed-off-by: Paul Moore --- security/selinux/hooks.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6da7532893a1..c253caa90bb4 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -456,10 +456,6 @@ static int sb_finish_set_opts(struct super_block *sb) if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", sb->s_id, sb->s_type->name); - else - printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n", - sb->s_id, sb->s_type->name, - labeling_behaviors[sbsec->behavior-1]); sbsec->flags |= SE_SBINITIALIZED; if (selinux_is_sblabel_mnt(sb)) From d5f3a5f6e7e7822df5680d4fe39bf0b6979a1535 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 4 Feb 2015 11:34:30 -0500 Subject: [PATCH 62/64] selinux: add security in-core xattr support for pstore and debugfs - add "pstore" and "debugfs" to list of in-core exceptions - change fstype checks to boolean equation - change from strncmp to strcmp for checking Signed-off-by: Mark Salyzyn Acked-by: Stephen Smalley [PM: tweaked the subject line prefix to "selinux"] Signed-off-by: Paul Moore --- security/selinux/hooks.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c253caa90bb4..87a915656eab 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -401,23 +401,14 @@ static int selinux_is_sblabel_mnt(struct super_block *sb) { struct superblock_security_struct *sbsec = sb->s_security; - if (sbsec->behavior == SECURITY_FS_USE_XATTR || - sbsec->behavior == SECURITY_FS_USE_TRANS || - sbsec->behavior == SECURITY_FS_USE_TASK) - return 1; - - /* Special handling for sysfs. Is genfs but also has setxattr handler*/ - if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0) - return 1; - - /* - * Special handling for rootfs. Is genfs but supports - * setting SELinux context on in-core inodes. - */ - if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0) - return 1; - - return 0; + return sbsec->behavior == SECURITY_FS_USE_XATTR || + sbsec->behavior == SECURITY_FS_USE_TRANS || + sbsec->behavior == SECURITY_FS_USE_TASK || + /* Special handling. Genfs but also in-core setxattr handler */ + !strcmp(sb->s_type->name, "sysfs") || + !strcmp(sb->s_type->name, "pstore") || + !strcmp(sb->s_type->name, "debugfs") || + !strcmp(sb->s_type->name, "rootfs"); } static int sb_finish_set_opts(struct super_block *sb) From 6eb4e2b41b264f57ee02d16ee61683952945484d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 4 Feb 2015 11:34:30 -0500 Subject: [PATCH 63/64] SELinux: fix error code in policydb_init() If hashtab_create() returns a NULL pointer then we should return -ENOMEM but instead the current code returns success. Signed-off-by: Dan Carpenter Acked-by: Serge Hallyn Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/ss/policydb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index bc2a586f095c..74aa224267c1 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -289,12 +289,16 @@ static int policydb_init(struct policydb *p) goto out; p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10)); - if (!p->filename_trans) + if (!p->filename_trans) { + rc = -ENOMEM; goto out; + } p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); - if (!p->range_tr) + if (!p->range_tr) { + rc = -ENOMEM; goto out; + } ebitmap_init(&p->filename_trans_ttypes); ebitmap_init(&p->policycaps); From 04f81f0154e4bf002be6f4d85668ce1257efa4d9 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 11 Feb 2015 14:46:37 -0500 Subject: [PATCH 64/64] cipso: don't use IPCB() to locate the CIPSO IP option Using the IPCB() macro to get the IPv4 options is convenient, but unfortunately NetLabel often needs to examine the CIPSO option outside of the scope of the IP layer in the stack. While historically IPCB() worked above the IP layer, due to the inclusion of the inet_skb_param struct at the head of the {tcp,udp}_skb_cb structs, recent commit 971f10ec ("tcp: better TCP_SKB_CB layout to reduce cache line misses") reordered the tcp_skb_cb struct and invalidated this IPCB() trick. This patch fixes the problem by creating a new function, cipso_v4_optptr(), which locates the CIPSO option inside the IP header without calling IPCB(). Unfortunately, this isn't as fast as a simple lookup so some additional tweaks were made to limit the use of this new function. Cc: # 3.18 Reported-by: Casey Schaufler Signed-off-by: Paul Moore Tested-by: Casey Schaufler --- include/net/cipso_ipv4.h | 25 +++++++++++------- net/ipv4/cipso_ipv4.c | 51 +++++++++++++++++++++--------------- net/netlabel/netlabel_kapi.c | 15 +++++++---- 3 files changed, 56 insertions(+), 35 deletions(-) diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h index a6fd939f202d..3ebb168b9afc 100644 --- a/include/net/cipso_ipv4.h +++ b/include/net/cipso_ipv4.h @@ -120,13 +120,6 @@ extern int cipso_v4_rbm_optfmt; extern int cipso_v4_rbm_strictvalid; #endif -/* - * Helper Functions - */ - -#define CIPSO_V4_OPTEXIST(x) (IPCB(x)->opt.cipso != 0) -#define CIPSO_V4_OPTPTR(x) (skb_network_header(x) + IPCB(x)->opt.cipso) - /* * DOI List Functions */ @@ -190,7 +183,7 @@ static inline int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, #ifdef CONFIG_NETLABEL void cipso_v4_cache_invalidate(void); -int cipso_v4_cache_add(const struct sk_buff *skb, +int cipso_v4_cache_add(const unsigned char *cipso_ptr, const struct netlbl_lsm_secattr *secattr); #else static inline void cipso_v4_cache_invalidate(void) @@ -198,7 +191,7 @@ static inline void cipso_v4_cache_invalidate(void) return; } -static inline int cipso_v4_cache_add(const struct sk_buff *skb, +static inline int cipso_v4_cache_add(const unsigned char *cipso_ptr, const struct netlbl_lsm_secattr *secattr) { return 0; @@ -211,6 +204,8 @@ static inline int cipso_v4_cache_add(const struct sk_buff *skb, #ifdef CONFIG_NETLABEL void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway); +int cipso_v4_getattr(const unsigned char *cipso, + struct netlbl_lsm_secattr *secattr); int cipso_v4_sock_setattr(struct sock *sk, const struct cipso_v4_doi *doi_def, const struct netlbl_lsm_secattr *secattr); @@ -226,6 +221,7 @@ int cipso_v4_skbuff_setattr(struct sk_buff *skb, int cipso_v4_skbuff_delattr(struct sk_buff *skb); int cipso_v4_skbuff_getattr(const struct sk_buff *skb, struct netlbl_lsm_secattr *secattr); +unsigned char *cipso_v4_optptr(const struct sk_buff *skb); int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option); #else static inline void cipso_v4_error(struct sk_buff *skb, @@ -235,6 +231,12 @@ static inline void cipso_v4_error(struct sk_buff *skb, return; } +static inline int cipso_v4_getattr(const unsigned char *cipso, + struct netlbl_lsm_secattr *secattr) +{ + return -ENOSYS; +} + static inline int cipso_v4_sock_setattr(struct sock *sk, const struct cipso_v4_doi *doi_def, const struct netlbl_lsm_secattr *secattr) @@ -282,6 +284,11 @@ static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb, return -ENOSYS; } +static inline unsigned char *cipso_v4_optptr(const struct sk_buff *skb) +{ + return NULL; +} + static inline int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option) { diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 5160c710f2eb..e361ea6f3fc8 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -378,20 +378,18 @@ static int cipso_v4_cache_check(const unsigned char *key, * negative values on failure. * */ -int cipso_v4_cache_add(const struct sk_buff *skb, +int cipso_v4_cache_add(const unsigned char *cipso_ptr, const struct netlbl_lsm_secattr *secattr) { int ret_val = -EPERM; u32 bkt; struct cipso_v4_map_cache_entry *entry = NULL; struct cipso_v4_map_cache_entry *old_entry = NULL; - unsigned char *cipso_ptr; u32 cipso_ptr_len; if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0) return 0; - cipso_ptr = CIPSO_V4_OPTPTR(skb); cipso_ptr_len = cipso_ptr[1]; entry = kzalloc(sizeof(*entry), GFP_ATOMIC); @@ -1578,6 +1576,33 @@ static int cipso_v4_parsetag_loc(const struct cipso_v4_doi *doi_def, return 0; } +/** + * cipso_v4_optptr - Find the CIPSO option in the packet + * @skb: the packet + * + * Description: + * Parse the packet's IP header looking for a CIPSO option. Returns a pointer + * to the start of the CIPSO option on success, NULL if one if not found. + * + */ +unsigned char *cipso_v4_optptr(const struct sk_buff *skb) +{ + const struct iphdr *iph = ip_hdr(skb); + unsigned char *optptr = (unsigned char *)&(ip_hdr(skb)[1]); + int optlen; + int taglen; + + for (optlen = iph->ihl*4 - sizeof(struct iphdr); optlen > 0; ) { + if (optptr[0] == IPOPT_CIPSO) + return optptr; + taglen = optptr[1]; + optlen -= taglen; + optptr += taglen; + } + + return NULL; +} + /** * cipso_v4_validate - Validate a CIPSO option * @option: the start of the option, on error it is set to point to the error @@ -2119,8 +2144,8 @@ void cipso_v4_req_delattr(struct request_sock *req) * on success and negative values on failure. * */ -static int cipso_v4_getattr(const unsigned char *cipso, - struct netlbl_lsm_secattr *secattr) +int cipso_v4_getattr(const unsigned char *cipso, + struct netlbl_lsm_secattr *secattr) { int ret_val = -ENOMSG; u32 doi; @@ -2305,22 +2330,6 @@ int cipso_v4_skbuff_delattr(struct sk_buff *skb) return 0; } -/** - * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option - * @skb: the packet - * @secattr: the security attributes - * - * Description: - * Parse the given packet's CIPSO option and return the security attributes. - * Returns zero on success and negative values on failure. - * - */ -int cipso_v4_skbuff_getattr(const struct sk_buff *skb, - struct netlbl_lsm_secattr *secattr) -{ - return cipso_v4_getattr(CIPSO_V4_OPTPTR(skb), secattr); -} - /* * Setup Functions */ diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c index a845cd4cf21e..28cddc85b700 100644 --- a/net/netlabel/netlabel_kapi.c +++ b/net/netlabel/netlabel_kapi.c @@ -1065,10 +1065,12 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb, u16 family, struct netlbl_lsm_secattr *secattr) { + unsigned char *ptr; + switch (family) { case AF_INET: - if (CIPSO_V4_OPTEXIST(skb) && - cipso_v4_skbuff_getattr(skb, secattr) == 0) + ptr = cipso_v4_optptr(skb); + if (ptr && cipso_v4_getattr(ptr, secattr) == 0) return 0; break; #if IS_ENABLED(CONFIG_IPV6) @@ -1094,7 +1096,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb, */ void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway) { - if (CIPSO_V4_OPTEXIST(skb)) + if (cipso_v4_optptr(skb)) cipso_v4_error(skb, error, gateway); } @@ -1126,11 +1128,14 @@ void netlbl_cache_invalidate(void) int netlbl_cache_add(const struct sk_buff *skb, const struct netlbl_lsm_secattr *secattr) { + unsigned char *ptr; + if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0) return -ENOMSG; - if (CIPSO_V4_OPTEXIST(skb)) - return cipso_v4_cache_add(skb, secattr); + ptr = cipso_v4_optptr(skb); + if (ptr) + return cipso_v4_cache_add(ptr, secattr); return -ENOMSG; }