Browse Source

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull security layer updates from James Morris:
 "Highlights:

   - Smack adds secmark support for Netfilter
   - /proc/keys is now mandatory if CONFIG_KEYS=y
   - TPM gets its own device class
   - Added TPM 2.0 support
   - Smack file hook rework (all Smack users should review this!)"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (64 commits)
  cipso: don't use IPCB() to locate the CIPSO IP option
  SELinux: fix error code in policydb_init()
  selinux: add security in-core xattr support for pstore and debugfs
  selinux: quiet the filesystem labeling behavior message
  selinux: Remove unused function avc_sidcmp()
  ima: /proc/keys is now mandatory
  Smack: Repair netfilter dependency
  X.509: silence asn1 compiler debug output
  X.509: shut up about included cert for silent build
  KEYS: Make /proc/keys unconditional if CONFIG_KEYS=y
  MAINTAINERS: email update
  tpm/tpm_tis: Add missing ifdef CONFIG_ACPI for pnp_acpi_device
  smack: fix possible use after frees in task_security() callers
  smack: Add missing logging in bidirectional UDS connect check
  Smack: secmark support for netfilter
  Smack: Rework file hooks
  tpm: fix format string error in tpm-chip.c
  char/tpm/tpm_crb: fix build error
  smack: Fix a bidirectional UDS connect check typo
  smack: introduce a special case for tmpfs in smack_d_instantiate()
  ...
Linus Torvalds 10 years ago
parent
commit
8cc748aa76
45 changed files with 2658 additions and 1082 deletions
  1. 11 11
      Documentation/ABI/stable/sysfs-class-tpm
  2. 36 0
      Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt
  3. 0 2
      Documentation/security/keys.txt
  4. 10 2
      MAINTAINERS
  5. 12 3
      drivers/char/tpm/Kconfig
  6. 3 2
      drivers/char/tpm/Makefile
  7. 256 0
      drivers/char/tpm/tpm-chip.c
  8. 6 36
      drivers/char/tpm/tpm-dev.c
  9. 86 177
      drivers/char/tpm/tpm-interface.c
  10. 5 24
      drivers/char/tpm/tpm-sysfs.c
  11. 105 19
      drivers/char/tpm/tpm.h
  12. 617 0
      drivers/char/tpm/tpm2-cmd.c
  13. 15 10
      drivers/char/tpm/tpm_atmel.c
  14. 354 0
      drivers/char/tpm/tpm_crb.c
  15. 19 33
      drivers/char/tpm/tpm_i2c_atmel.c
  16. 10 33
      drivers/char/tpm/tpm_i2c_infineon.c
  17. 27 42
      drivers/char/tpm/tpm_i2c_nuvoton.c
  18. 366 300
      drivers/char/tpm/tpm_i2c_stm_st33.c
  19. 16 11
      drivers/char/tpm/tpm_ibmvtpm.c
  20. 1 1
      drivers/char/tpm/tpm_ibmvtpm.h
  21. 28 23
      drivers/char/tpm/tpm_infineon.c
  22. 19 15
      drivers/char/tpm/tpm_nsc.c
  23. 1 1
      drivers/char/tpm/tpm_of.c
  24. 87 54
      drivers/char/tpm/tpm_ppi.c
  25. 190 86
      drivers/char/tpm/tpm_tis.c
  26. 8 6
      drivers/char/tpm/xen-tpmfront.c
  27. 8 30
      include/linux/platform_data/tpm_stm_st33.h
  28. 16 9
      include/net/cipso_ipv4.h
  29. 1 1
      kernel/Makefile
  30. 4 6
      lib/mpi/mpi-cmp.c
  31. 1 1
      lib/mpi/mpi-internal.h
  32. 30 21
      net/ipv4/cipso_ipv4.c
  33. 10 5
      net/netlabel/netlabel_kapi.c
  34. 19 11
      scripts/asn1_compiler.c
  35. 0 1
      security/integrity/ima/Kconfig
  36. 0 18
      security/keys/Kconfig
  37. 0 8
      security/keys/proc.c
  38. 0 5
      security/selinux/avc.c
  39. 8 21
      security/selinux/hooks.c
  40. 6 2
      security/selinux/ss/policydb.c
  41. 12 0
      security/smack/Kconfig
  42. 1 0
      security/smack/Makefile
  43. 11 0
      security/smack/smack.h
  44. 147 52
      security/smack/smack_lsm.c
  45. 96 0
      security/smack/smack_netfilter.c

+ 11 - 11
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
 Date:		April 2005
 KernelVersion:	2.6.12
 KernelVersion:	2.6.12
 Contact:	tpmdd-devel@lists.sf.net
 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
 		the properties of that TPM chip
 
 
 
 
-What:		/sys/class/misc/tpmX/device/active
+What:		/sys/class/tpm/tpmX/device/active
 Date:		April 2006
 Date:		April 2006
 KernelVersion:	2.6.17
 KernelVersion:	2.6.17
 Contact:	tpmdd-devel@lists.sf.net
 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
 		section 17 for more information on which commands are
 		available.
 		available.
 
 
-What:		/sys/class/misc/tpmX/device/cancel
+What:		/sys/class/tpm/tpmX/device/cancel
 Date:		June 2005
 Date:		June 2005
 KernelVersion:	2.6.13
 KernelVersion:	2.6.13
 Contact:	tpmdd-devel@lists.sf.net
 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
 		pending TPM command. Writing any value to cancel will call the
 		TPM vendor specific cancel operation.
 		TPM vendor specific cancel operation.
 
 
-What:		/sys/class/misc/tpmX/device/caps
+What:		/sys/class/tpm/tpmX/device/caps
 Date:		April 2005
 Date:		April 2005
 KernelVersion:	2.6.12
 KernelVersion:	2.6.12
 Contact:	tpmdd-devel@lists.sf.net
 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
 		the chip supports. Firmware version is that of the chip and
 		is manufacturer specific.
 		is manufacturer specific.
 
 
-What:		/sys/class/misc/tpmX/device/durations
+What:		/sys/class/tpm/tpmX/device/durations
 Date:		March 2011
 Date:		March 2011
 KernelVersion:	3.1
 KernelVersion:	3.1
 Contact:	tpmdd-devel@lists.sf.net
 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]"
 		scaled to be displayed in usecs. In this case "[adjusted]"
 		will be displayed in place of "[original]".
 		will be displayed in place of "[original]".
 
 
-What:		/sys/class/misc/tpmX/device/enabled
+What:		/sys/class/tpm/tpmX/device/enabled
 Date:		April 2006
 Date:		April 2006
 KernelVersion:	2.6.17
 KernelVersion:	2.6.17
 Contact:	tpmdd-devel@lists.sf.net
 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
 		may be visible but produce a '0' after some operation that
 		disables the TPM.
 		disables the TPM.
 
 
-What:		/sys/class/misc/tpmX/device/owned
+What:		/sys/class/tpm/tpmX/device/owned
 Date:		April 2006
 Date:		April 2006
 KernelVersion:	2.6.17
 KernelVersion:	2.6.17
 Contact:	tpmdd-devel@lists.sf.net
 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'
 		ordinal has been executed successfully in the chip. A '0'
 		indicates that ownership hasn't been taken.
 		indicates that ownership hasn't been taken.
 
 
-What:		/sys/class/misc/tpmX/device/pcrs
+What:		/sys/class/tpm/tpmX/device/pcrs
 Date:		April 2005
 Date:		April 2005
 KernelVersion:	2.6.12
 KernelVersion:	2.6.12
 Contact:	tpmdd-devel@lists.sf.net
 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
 		1.2 chips, PCRs represent SHA-1 hashes, which are 20 bytes
 		long. Use the "caps" property to determine TPM version.
 		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
 Date:		April 2005
 KernelVersion:	2.6.12
 KernelVersion:	2.6.12
 Contact:	tpmdd-devel@lists.sf.net
 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 Length: 256 (bytes)
 		Modulus:	The 256 byte Endorsement Key modulus
 		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
 Date:		April 2006
 KernelVersion:	2.6.17
 KernelVersion:	2.6.17
 Contact:	tpmdd-devel@lists.sf.net
 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
 		cycle. Whether a warm boot (reboot) will clear a TPM chip
 		from a temp_deactivated state is platform specific.
 		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
 Date:		March 2011
 KernelVersion:	3.1
 KernelVersion:	3.1
 Contact:	tpmdd-devel@lists.sf.net
 Contact:	tpmdd-devel@lists.sf.net

+ 36 - 0
Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.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 = <0x13>;
+                clock-frequency = <400000>;
+
+                interrupt-parent = <&gpio5>;
+                interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
+
+                lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
+        };
+};

+ 0 - 2
Documentation/security/keys.txt

@@ -323,8 +323,6 @@ about the status of the key service:
 	U	Under construction by callback to userspace
 	U	Under construction by callback to userspace
 	N	Negative key
 	N	Negative key
 
 
-     This file must be enabled at kernel configuration time as it allows anyone
-     to list the keys database.
 
 
  (*) /proc/key-users
  (*) /proc/key-users
 
 

+ 10 - 2
MAINTAINERS

@@ -4917,7 +4917,7 @@ F:	drivers/ipack/
 
 
 INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
 INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
 M:	Mimi Zohar <zohar@linux.vnet.ibm.com>
 M:	Mimi Zohar <zohar@linux.vnet.ibm.com>
-M:	Dmitry Kasatkin <d.kasatkin@samsung.com>
+M:	Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
 L:	linux-ima-devel@lists.sourceforge.net
 L:	linux-ima-devel@lists.sourceforge.net
 L:	linux-ima-user@lists.sourceforge.net
 L:	linux-ima-user@lists.sourceforge.net
 L:	linux-security-module@vger.kernel.org
 L:	linux-security-module@vger.kernel.org
@@ -9817,13 +9817,21 @@ F:	drivers/media/pci/tw68/
 
 
 TPM DEVICE DRIVER
 TPM DEVICE DRIVER
 M:	Peter Huewe <peterhuewe@gmx.de>
 M:	Peter Huewe <peterhuewe@gmx.de>
-M:	Ashley Lai <ashley@ashleylai.com>
 M:	Marcel Selhorst <tpmdd@selhorst.net>
 M:	Marcel Selhorst <tpmdd@selhorst.net>
 W:	http://tpmdd.sourceforge.net
 W:	http://tpmdd.sourceforge.net
 L:	tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
 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
 S:	Maintained
 F:	drivers/char/tpm/
 F:	drivers/char/tpm/
 
 
+TPM IBM_VTPM DEVICE DRIVER
+M:	Ashley Lai <ashleydlai@gmail.com>
+W:	http://tpmdd.sourceforge.net
+L:	tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
+S:	Maintained
+F:	drivers/char/tpm/tpm_ibmvtpm*
+
 TRACING
 TRACING
 M:	Steven Rostedt <rostedt@goodmis.org>
 M:	Steven Rostedt <rostedt@goodmis.org>
 M:	Ingo Molnar <mingo@redhat.com>
 M:	Ingo Molnar <mingo@redhat.com>

+ 12 - 3
drivers/char/tpm/Kconfig

@@ -100,15 +100,15 @@ config TCG_IBMVTPM
 	  will be accessible from within Linux.  To compile this driver
 	  will be accessible from within Linux.  To compile this driver
 	  as a module, choose M here; the module will be called tpm_ibmvtpm.
 	  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 I2C
 	depends on GPIOLIB
 	depends on GPIOLIB
 	---help---
 	---help---
 	  If you have a TPM security chip from STMicroelectronics working with
 	  If you have a TPM security chip from STMicroelectronics working with
 	  an I2C bus say Yes and it will be accessible from within Linux.
 	  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
 	  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
 config TCG_XEN
 	tristate "XEN TPM Interface"
 	tristate "XEN TPM Interface"
@@ -122,4 +122,13 @@ config TCG_XEN
 	  To compile this driver as a module, choose M here; the module
 	  To compile this driver as a module, choose M here; the module
 	  will be called xen-tpmfront.
 	  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
 endif # TCG_TPM

+ 3 - 2
drivers/char/tpm/Makefile

@@ -2,7 +2,7 @@
 # Makefile for the kernel tpm device drivers.
 # Makefile for the kernel tpm device drivers.
 #
 #
 obj-$(CONFIG_TCG_TPM) += tpm.o
 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 tpm2-cmd.o
 tpm-$(CONFIG_ACPI) += tpm_ppi.o
 tpm-$(CONFIG_ACPI) += tpm_ppi.o
 
 
 ifdef CONFIG_ACPI
 ifdef CONFIG_ACPI
@@ -20,5 +20,6 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
 obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
 obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
 obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
 obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
 obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.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
 obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
+obj-$(CONFIG_TCG_CRB) += tpm_crb.o

+ 256 - 0
drivers/char/tpm/tpm-chip.c

@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Authors:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Dave Safford <safford@watson.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * 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 <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/freezer.h>
+#include <linux/major.h>
+#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);
+
+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
+ */
+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->pdev->driver->owner)) {
+			chip = pos;
+			break;
+		}
+	}
+	rcu_read_unlock();
+	return chip;
+}
+
+/**
+ * tpm_dev_release() - free chip memory and the device number
+ * @dev: the character device for the TPM chip
+ *
+ * This is used as the release function for the character device.
+ */
+static void tpm_dev_release(struct device *dev)
+{
+	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+
+	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->pdev = dev;
+
+	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, "%s", 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 character device for the TPM chip
+ * @chip: TPM chip to use.
+ *
+ * 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.
+ *
+ * NOTE: This function should be only called after the chip initialization
+ * is complete.
+ *
+ * Called from tpm_<specific>.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;
+
+	/* 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;
+
+		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->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);
+}
+EXPORT_SYMBOL_GPL(tpm_chip_unregister);

+ 6 - 36
drivers/char/tpm/tpm-dev.c

@@ -17,7 +17,6 @@
  * License.
  * License.
  *
  *
  */
  */
-#include <linux/miscdevice.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/uaccess.h>
 #include "tpm.h"
 #include "tpm.h"
@@ -54,16 +53,15 @@ static void timeout_work(struct work_struct *work)
 
 
 static int tpm_open(struct inode *inode, struct file *file)
 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;
 	struct file_priv *priv;
 
 
 	/* It's assured that the chip will be opened just once,
 	/* It's assured that the chip will be opened just once,
 	 * by the check of is_open variable, which is protected
 	 * by the check of is_open variable, which is protected
 	 * by driver_lock. */
 	 * by driver_lock. */
 	if (test_and_set_bit(0, &chip->is_open)) {
 	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;
 		return -EBUSY;
 	}
 	}
 
 
@@ -81,7 +79,7 @@ static int tpm_open(struct inode *inode, struct file *file)
 	INIT_WORK(&priv->work, timeout_work);
 	INIT_WORK(&priv->work, timeout_work);
 
 
 	file->private_data = priv;
 	file->private_data = priv;
-	get_device(chip->dev);
+	get_device(chip->pdev);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -168,12 +166,12 @@ static int tpm_release(struct inode *inode, struct file *file)
 	file->private_data = NULL;
 	file->private_data = NULL;
 	atomic_set(&priv->data_pending, 0);
 	atomic_set(&priv->data_pending, 0);
 	clear_bit(0, &priv->chip->is_open);
 	clear_bit(0, &priv->chip->is_open);
-	put_device(priv->chip->dev);
+	put_device(priv->chip->pdev);
 	kfree(priv);
 	kfree(priv);
 	return 0;
 	return 0;
 }
 }
 
 
-static const struct file_operations tpm_fops = {
+const struct file_operations tpm_fops = {
 	.owner = THIS_MODULE,
 	.owner = THIS_MODULE,
 	.llseek = no_llseek,
 	.llseek = no_llseek,
 	.open = tpm_open,
 	.open = tpm_open,
@@ -182,32 +180,4 @@ static const struct file_operations tpm_fops = {
 	.release = tpm_release,
 	.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->dev;
-
-	rc = misc_register(&chip->vendor.miscdev);
-	if (rc) {
-		chip->vendor.miscdev.name = NULL;
-		dev_err(chip->dev,
-			"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);
-}

+ 86 - 177
drivers/char/tpm/tpm-interface.c

@@ -1,5 +1,6 @@
 /*
 /*
  * Copyright (C) 2004 IBM Corporation
  * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2014 Intel Corporation
  *
  *
  * Authors:
  * Authors:
  * Leendert van Doorn <leendert@watson.ibm.com>
  * Leendert van Doorn <leendert@watson.ibm.com>
@@ -47,10 +48,6 @@ module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
 MODULE_PARM_DESC(suspend_pcr,
 MODULE_PARM_DESC(suspend_pcr,
 		 "PCR to use for dummy writes to faciltate flush on suspend.");
 		 "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
  * Array with one entry per ordinal defining the maximum amount
  * of time the chip could take to return the result.  The ordinal
  * of time the chip could take to return the result.  The ordinal
@@ -346,7 +343,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 	if (count == 0)
 	if (count == 0)
 		return -ENODATA;
 		return -ENODATA;
 	if (count > bufsiz) {
 	if (count > bufsiz) {
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"invalid count value %x %zx\n", count, bufsiz);
 			"invalid count value %x %zx\n", count, bufsiz);
 		return -E2BIG;
 		return -E2BIG;
 	}
 	}
@@ -355,7 +352,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 
 
 	rc = chip->ops->send(chip, (u8 *) buf, count);
 	rc = chip->ops->send(chip, (u8 *) buf, count);
 	if (rc < 0) {
 	if (rc < 0) {
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"tpm_transmit: tpm_send: error %zd\n", rc);
 			"tpm_transmit: tpm_send: error %zd\n", rc);
 		goto out;
 		goto out;
 	}
 	}
@@ -363,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 	if (chip->vendor.irq)
 	if (chip->vendor.irq)
 		goto out_recv;
 		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 {
 	do {
 		u8 status = chip->ops->status(chip);
 		u8 status = chip->ops->status(chip);
 		if ((status & chip->ops->req_complete_mask) ==
 		if ((status & chip->ops->req_complete_mask) ==
@@ -371,7 +371,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 			goto out_recv;
 			goto out_recv;
 
 
 		if (chip->ops->req_canceled(chip, status)) {
 		if (chip->ops->req_canceled(chip, status)) {
-			dev_err(chip->dev, "Operation Canceled\n");
+			dev_err(chip->pdev, "Operation Canceled\n");
 			rc = -ECANCELED;
 			rc = -ECANCELED;
 			goto out;
 			goto out;
 		}
 		}
@@ -381,14 +381,14 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 	} while (time_before(jiffies, stop));
 	} while (time_before(jiffies, stop));
 
 
 	chip->ops->cancel(chip);
 	chip->ops->cancel(chip);
-	dev_err(chip->dev, "Operation Timed out\n");
+	dev_err(chip->pdev, "Operation Timed out\n");
 	rc = -ETIME;
 	rc = -ETIME;
 	goto out;
 	goto out;
 
 
 out_recv:
 out_recv:
 	rc = chip->ops->recv(chip, (u8 *) buf, bufsiz);
 	rc = chip->ops->recv(chip, (u8 *) buf, bufsiz);
 	if (rc < 0)
 	if (rc < 0)
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"tpm_transmit: tpm_recv: error %zd\n", rc);
 			"tpm_transmit: tpm_recv: error %zd\n", rc);
 out:
 out:
 	mutex_unlock(&chip->tpm_mutex);
 	mutex_unlock(&chip->tpm_mutex);
@@ -398,9 +398,10 @@ out:
 #define TPM_DIGEST_SIZE 20
 #define TPM_DIGEST_SIZE 20
 #define TPM_RET_CODE_IDX 6
 #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;
 	int err;
 
 
 	len = tpm_transmit(chip, (u8 *) cmd, len);
 	len = tpm_transmit(chip, (u8 *) cmd, len);
@@ -409,9 +410,12 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
 	else if (len < TPM_HEADER_SIZE)
 	else if (len < TPM_HEADER_SIZE)
 		return -EFAULT;
 		return -EFAULT;
 
 
-	err = be32_to_cpu(cmd->header.out.return_code);
+	header = cmd;
+
+	err = be32_to_cpu(header->return_code);
 	if (err != 0 && desc)
 	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;
 	return err;
 }
 }
@@ -448,7 +452,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_size = cpu_to_be32(4);
 		tpm_cmd.params.getcap_in.subcap = subcap_id;
 		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)
 	if (!rc)
 		*cap = tpm_cmd.params.getcap_out.cap;
 		*cap = tpm_cmd.params.getcap_out.cap;
 	return rc;
 	return rc;
@@ -464,8 +468,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_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
 	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);
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
 
 
@@ -483,9 +487,10 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
 {
 {
 	struct tpm_cmd_t start_cmd;
 	struct tpm_cmd_t start_cmd;
 	start_cmd.header.in = tpm_startup_header;
 	start_cmd.header.in = tpm_startup_header;
+
 	start_cmd.params.startup_in.startup_type = startup_type;
 	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)
 int tpm_get_timeouts(struct tpm_chip *chip)
@@ -500,12 +505,12 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 	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_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
 	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) {
 	if (rc == TPM_ERR_INVALID_POSTINIT) {
 		/* The TPM is not started, we are the first to talk to it.
 		/* The TPM is not started, we are the first to talk to it.
 		   Execute a startup command. */
 		   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))
 		if (tpm_startup(chip, TPM_ST_CLEAR))
 			return rc;
 			return rc;
 
 
@@ -513,11 +518,11 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 		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_size = cpu_to_be32(4);
 		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
 		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);
 				  NULL);
 	}
 	}
 	if (rc) {
 	if (rc) {
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"A TPM error (%zd) occurred attempting to determine the timeouts\n",
 			"A TPM error (%zd) occurred attempting to determine the timeouts\n",
 			rc);
 			rc);
 		goto duration;
 		goto duration;
@@ -556,7 +561,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 
 
 	/* Report adjusted timeouts */
 	/* Report adjusted timeouts */
 	if (chip->vendor.timeout_adjusted) {
 	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",
 			 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[0], new_timeout[0],
 			 old_timeout[1], new_timeout[1],
 			 old_timeout[1], new_timeout[1],
@@ -575,8 +580,8 @@ duration:
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
 	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)
 	if (rc)
 		return rc;
 		return rc;
 
 
@@ -603,7 +608,7 @@ duration:
 		chip->vendor.duration[TPM_MEDIUM] *= 1000;
 		chip->vendor.duration[TPM_MEDIUM] *= 1000;
 		chip->vendor.duration[TPM_LONG] *= 1000;
 		chip->vendor.duration[TPM_LONG] *= 1000;
 		chip->vendor.duration_adjusted = true;
 		chip->vendor.duration_adjusted = true;
-		dev_info(chip->dev, "Adjusting TPM timeout parameters.");
+		dev_info(chip->pdev, "Adjusting TPM timeout parameters.");
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -631,32 +636,11 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
 	struct tpm_cmd_t cmd;
 	struct tpm_cmd_t cmd;
 
 
 	cmd.header.in = continue_selftest_header;
 	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;
 	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 TPM_ORDINAL_PCRREAD cpu_to_be32(21)
 #define READ_PCR_RESULT_SIZE 30
 #define READ_PCR_RESULT_SIZE 30
 static struct tpm_input_header pcrread_header = {
 static struct tpm_input_header pcrread_header = {
@@ -672,8 +656,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
 
 
 	cmd.header.in = pcrread_header;
 	cmd.header.in = pcrread_header;
 	cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
 	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)
 	if (rc == 0)
 		memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
 		memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
@@ -700,7 +684,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
 	chip = tpm_chip_find_get(chip_num);
 	chip = tpm_chip_find_get(chip_num);
 	if (chip == NULL)
 	if (chip == NULL)
 		return -ENODEV;
 		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);
 	tpm_chip_put(chip);
 	return rc;
 	return rc;
 }
 }
@@ -734,11 +721,17 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
 	if (chip == NULL)
 	if (chip == NULL)
 		return -ENODEV;
 		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.header.in = pcrextend_header;
 	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
 	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
 	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
 	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);
 	tpm_chip_put(chip);
 	return rc;
 	return rc;
@@ -781,7 +774,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
 		 * around 300ms while the self test is ongoing, keep trying
 		 * around 300ms while the self test is ongoing, keep trying
 		 * until the self test duration expires. */
 		 * until the self test duration expires. */
 		if (rc == -ETIME) {
 		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);
 			msleep(delay_msec);
 			continue;
 			continue;
 		}
 		}
@@ -791,7 +784,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
 
 
 		rc = be32_to_cpu(cmd.header.out.return_code);
 		rc = be32_to_cpu(cmd.header.out.return_code);
 		if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
 		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/deactivated (0x%X)\n", rc);
 			/* TPM is disabled and/or deactivated; driver can
 			/* TPM is disabled and/or deactivated; driver can
 			 * proceed and TPM does handle commands for
 			 * proceed and TPM does handle commands for
@@ -817,7 +810,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
 	if (chip == NULL)
 	if (chip == NULL)
 		return -ENODEV;
 		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);
 	tpm_chip_put(chip);
 	return rc;
 	return rc;
@@ -884,30 +877,6 @@ again:
 }
 }
 EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
 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 TPM_ORD_SAVESTATE cpu_to_be32(152)
 #define SAVESTATE_RESULT_SIZE 10
 #define SAVESTATE_RESULT_SIZE 10
 
 
@@ -932,20 +901,23 @@ int tpm_pm_suspend(struct device *dev)
 	if (chip == NULL)
 	if (chip == NULL)
 		return -ENODEV;
 		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 */
 	/* for buggy tpm, flush pcrs with extend to selected dummy */
 	if (tpm_suspend_pcr) {
 	if (tpm_suspend_pcr) {
 		cmd.header.in = pcrextend_header;
 		cmd.header.in = pcrextend_header;
 		cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
 		cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
 		memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
 		memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
 		       TPM_DIGEST_SIZE);
 		       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 */
 	/* now do the actual savestate */
 	for (try = 0; try < TPM_RETRY; try++) {
 	for (try = 0; try < TPM_RETRY; try++) {
 		cmd.header.in = savestate_header;
 		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
 		 * If the TPM indicates that it is too busy to respond to
@@ -963,10 +935,10 @@ int tpm_pm_suspend(struct device *dev)
 	}
 	}
 
 
 	if (rc)
 	if (rc)
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"Error (%d) sending savestate before suspend\n", rc);
 			"Error (%d) sending savestate before suspend\n", rc);
 	else if (try > 0)
 	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);
 			 try * TPM_TIMEOUT_RETRY);
 
 
 	return rc;
 	return rc;
@@ -1018,11 +990,17 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 	if (chip == NULL)
 	if (chip == NULL)
 		return -ENODEV;
 		return -ENODEV;
 
 
+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+		err = tpm2_get_random(chip, out, max);
+		tpm_chip_put(chip);
+		return err;
+	}
+
 	do {
 	do {
 		tpm_cmd.header.in = tpm_getrandom_header;
 		tpm_cmd.header.in = tpm_getrandom_header;
 		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
 		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,
 				   TPM_GETRANDOM_RESULT_SIZE + num_bytes,
 				   "attempting get random");
 				   "attempting get random");
 		if (err)
 		if (err)
@@ -1041,103 +1019,34 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 }
 }
 EXPORT_SYMBOL_GPL(tpm_get_random);
 EXPORT_SYMBOL_GPL(tpm_get_random);
 
 
-/* In case vendor provided release function, call it too.*/
-
-void tpm_dev_vendor_release(struct tpm_chip *chip)
+static int __init tpm_init(void)
 {
 {
-	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);
+	int rc;
 
 
-	if (!chip)
-		return;
+	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);
+	}
 
 
-	tpm_dev_vendor_release(chip);
+	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;
+	}
 
 
-	chip->release(dev);
-	kfree(chip);
+	return 0;
 }
 }
 
 
-/*
- * Called from tpm_<specific>.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)
+static void __exit tpm_exit(void)
 {
 {
-	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_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;
+	class_destroy(tpm_class);
+	unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES);
 }
 }
-EXPORT_SYMBOL_GPL(tpm_register_hardware);
+
+subsys_initcall(tpm_init);
+module_exit(tpm_exit);
 
 
 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
 MODULE_DESCRIPTION("TPM Driver");
 MODULE_DESCRIPTION("TPM Driver");

+ 5 - 24
drivers/char/tpm/tpm-sysfs.c

@@ -20,25 +20,6 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include "tpm.h"
 #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 READ_PUBEK_RESULT_SIZE 314
 #define TPM_ORD_READPUBEK cpu_to_be32(124)
 #define TPM_ORD_READPUBEK cpu_to_be32(124)
 static struct tpm_input_header tpm_readpubek_header = {
 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);
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 
 
 	tpm_cmd.header.in = tpm_readpubek_header;
 	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)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -303,16 +284,16 @@ static const struct attribute_group tpm_dev_group = {
 int tpm_sysfs_add_device(struct tpm_chip *chip)
 int tpm_sysfs_add_device(struct tpm_chip *chip)
 {
 {
 	int err;
 	int err;
-	err = sysfs_create_group(&chip->dev->kobj,
+	err = sysfs_create_group(&chip->pdev->kobj,
 				 &tpm_dev_group);
 				 &tpm_dev_group);
 
 
 	if (err)
 	if (err)
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"failed to create sysfs attributes, %d\n", err);
 			"failed to create sysfs attributes, %d\n", err);
 	return err;
 	return err;
 }
 }
 
 
 void tpm_sysfs_del_device(struct tpm_chip *chip)
 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);
 }
 }

+ 105 - 19
drivers/char/tpm/tpm.h

@@ -10,23 +10,24 @@
  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  *
  *
  * Device driver for TCG/TCPA TPM (trusted platform module).
  * 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
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation, version 2 of the
  * published by the Free Software Foundation, version 2 of the
  * License.
  * License.
- * 
+ *
  */
  */
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
 #include <linux/fs.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
-#include <linux/miscdevice.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/tpm.h>
 #include <linux/tpm.h>
+#include <linux/acpi.h>
+#include <linux/cdev.h>
 
 
 enum tpm_const {
 enum tpm_const {
 	TPM_MINOR = 224,	/* officially assigned */
 	TPM_MINOR = 224,	/* officially assigned */
@@ -61,6 +62,59 @@ enum tpm_duration {
 #define TPM_ERR_INVALID_POSTINIT 38
 #define TPM_ERR_INVALID_POSTINIT 38
 
 
 #define TPM_HEADER_SIZE		10
 #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_chip;
 
 
 struct tpm_vendor_specific {
 struct tpm_vendor_specific {
@@ -73,7 +127,6 @@ struct tpm_vendor_specific {
 	int region_size;
 	int region_size;
 	int have_region;
 	int have_region;
 
 
-	struct miscdevice miscdev;
 	struct list_head list;
 	struct list_head list;
 	int locality;
 	int locality;
 	unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
 	unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
@@ -88,15 +141,27 @@ struct tpm_vendor_specific {
 	u16 manufacturer_id;
 	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_INTEL    0x8086
 #define TPM_VID_WINBOND  0x1050
 #define TPM_VID_WINBOND  0x1050
 #define TPM_VID_STM      0x104A
 #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),
+	TPM_CHIP_FLAG_TPM2		= BIT(2),
+};
+
 struct tpm_chip {
 struct tpm_chip {
-	struct device *dev;	/* Device stuff */
+	struct device *pdev;	/* Device stuff */
+	struct device dev;
+	struct cdev cdev;
+
 	const struct tpm_class_ops *ops;
 	const struct tpm_class_ops *ops;
+	unsigned int flags;
 
 
 	int dev_num;		/* /dev/tpm# */
 	int dev_num;		/* /dev/tpm# */
 	char devname[7];
 	char devname[7];
@@ -109,15 +174,19 @@ struct tpm_chip {
 
 
 	struct dentry **bios_dir;
 	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;
 	struct list_head list;
-	void (*release) (struct device *);
 };
 };
 
 
 #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
 #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
 
 
 static inline void tpm_chip_put(struct tpm_chip *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)
 static inline int tpm_read_index(int base, int index)
@@ -313,40 +382,57 @@ struct tpm_cmd_t {
 	tpm_cmd_params	params;
 	tpm_cmd_params	params;
 } __packed;
 } __packed;
 
 
-ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
+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,
 ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 		     size_t bufsiz);
 		     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 int tpm_get_timeouts(struct tpm_chip *);
 extern void tpm_gen_interrupt(struct tpm_chip *);
 extern void tpm_gen_interrupt(struct tpm_chip *);
 extern int tpm_do_selftest(struct tpm_chip *);
 extern int tpm_do_selftest(struct tpm_chip *);
 extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
 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_suspend(struct device *);
 extern int tpm_pm_resume(struct device *);
 extern int tpm_pm_resume(struct device *);
 extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
 extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
 			     wait_queue_head_t *, bool);
 			     wait_queue_head_t *, bool);
 
 
-int tpm_dev_add_device(struct tpm_chip *chip);
-void tpm_dev_del_device(struct tpm_chip *chip);
+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_sysfs_add_device(struct tpm_chip *chip);
 int tpm_sysfs_add_device(struct tpm_chip *chip);
 void tpm_sysfs_del_device(struct tpm_chip *chip);
 void tpm_sysfs_del_device(struct tpm_chip *chip);
 
 
 int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
 int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
 
 
 #ifdef CONFIG_ACPI
 #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
 #else
-static inline int tpm_add_ppi(struct kobject *parent)
+static inline int tpm_add_ppi(struct tpm_chip *chip)
 {
 {
 	return 0;
 	return 0;
 }
 }
 
 
-static inline void tpm_remove_ppi(struct kobject *parent)
+static inline void tpm_remove_ppi(struct tpm_chip *chip)
 {
 {
 }
 }
 #endif
 #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);

+ 617 - 0
drivers/char/tpm/tpm2-cmd.c

@@ -0,0 +1,617 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Authors:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * 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);

+ 15 - 10
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++) {
 	for (i = 0; i < 6; i++) {
 		status = ioread8(chip->vendor.iobase + 1);
 		status = ioread8(chip->vendor.iobase + 1);
 		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
 		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;
 			return -EIO;
 		}
 		}
 		*buf++ = ioread8(chip->vendor.iobase);
 		*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);
 	size = be32_to_cpu(*native_size);
 
 
 	if (count < size) {
 	if (count < size) {
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"Recv size(%d) less than available space\n", size);
 			"Recv size(%d) less than available space\n", size);
 		for (; i < size; i++) {	/* clear the waiting data anyway */
 		for (; i < size; i++) {	/* clear the waiting data anyway */
 			status = ioread8(chip->vendor.iobase + 1);
 			status = ioread8(chip->vendor.iobase + 1);
 			if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
 			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;
 				return -EIO;
 			}
 			}
 		}
 		}
@@ -76,7 +76,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	for (; i < size; i++) {
 	for (; i < size; i++) {
 		status = ioread8(chip->vendor.iobase + 1);
 		status = ioread8(chip->vendor.iobase + 1);
 		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
 		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;
 			return -EIO;
 		}
 		}
 		*buf++ = ioread8(chip->vendor.iobase);
 		*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);
 	status = ioread8(chip->vendor.iobase + 1);
 
 
 	if (status & ATML_STATUS_DATA_AVAIL) {
 	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;
 		return -EIO;
 	}
 	}
 
 
@@ -97,9 +97,9 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
 {
 {
 	int i;
 	int i;
 
 
-	dev_dbg(chip->dev, "tpm_atml_send:\n");
+	dev_dbg(chip->pdev, "tpm_atml_send:\n");
 	for (i = 0; i < count; i++) {
 	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);
  		iowrite8(buf[i], chip->vendor.iobase);
 	}
 	}
 
 
@@ -138,11 +138,11 @@ static void atml_plat_remove(void)
 	struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
 	struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
 
 
 	if (chip) {
 	if (chip) {
+		tpm_chip_unregister(chip);
 		if (chip->vendor.have_region)
 		if (chip->vendor.have_region)
 			atmel_release_region(chip->vendor.base,
 			atmel_release_region(chip->vendor.base,
 					     chip->vendor.region_size);
 					     chip->vendor.region_size);
 		atmel_put_base_addr(chip->vendor.iobase);
 		atmel_put_base_addr(chip->vendor.iobase);
-		tpm_remove_hardware(chip->dev);
 		platform_device_unregister(pdev);
 		platform_device_unregister(pdev);
 	}
 	}
 }
 }
@@ -183,8 +183,9 @@ static int __init init_atmel(void)
 		goto err_rel_reg;
 		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;
 		goto err_unreg_dev;
 	}
 	}
 
 
@@ -193,6 +194,10 @@ static int __init init_atmel(void)
 	chip->vendor.have_region = have_region;
 	chip->vendor.have_region = have_region;
 	chip->vendor.region_size = region_size;
 	chip->vendor.region_size = region_size;
 
 
+	rc = tpm_chip_register(chip);
+	if (rc)
+		goto err_unreg_dev;
+
 	return 0;
 	return 0;
 
 
 err_unreg_dev:
 err_unreg_dev:

+ 354 - 0
drivers/char/tpm/tpm_crb.c

@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Authors:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * 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 <linux/acpi.h>
+#include <linux/highmem.h>
+#include <linux/rculist.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#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;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, crb_resume);
+
+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 <jarkko.sakkinen@linux.intel.com>");
+MODULE_DESCRIPTION("TPM2 Driver");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");

+ 19 - 33
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)
 static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
 {
 {
 	struct priv_data *priv = chip->vendor.priv;
 	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;
 	s32 status;
 
 
 	priv->len = 0;
 	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);
 	status = i2c_master_send(client, buf, len);
 
 
-	dev_dbg(chip->dev,
+	dev_dbg(chip->pdev,
 		"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
 		"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
 		(int)min_t(size_t, 64, len), buf, len, status);
 		(int)min_t(size_t, 64, len), buf, len, status);
 	return 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)
 static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 {
 {
 	struct priv_data *priv = chip->vendor.priv;
 	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 *hdr =
 		(struct tpm_output_header *)priv->buffer;
 		(struct tpm_output_header *)priv->buffer;
 	u32 expected_len;
 	u32 expected_len;
@@ -88,7 +88,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	if (priv->len >= expected_len) {
 	if (priv->len >= expected_len) {
-		dev_dbg(chip->dev,
+		dev_dbg(chip->pdev,
 			"%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
 			"%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
 			(int)min_t(size_t, 64, expected_len), buf, count,
 			(int)min_t(size_t, 64, expected_len), buf, count,
 			expected_len);
 			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);
 	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__,
 		"%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
 		(int)min_t(size_t, 64, expected_len), buf, count,
 		(int)min_t(size_t, 64, expected_len), buf, count,
 		expected_len);
 		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)
 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)
 static u8 i2c_atmel_read_status(struct tpm_chip *chip)
 {
 {
 	struct priv_data *priv = chip->vendor.priv;
 	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;
 	int rc;
 
 
 	/* The TPM fails the I2C read until it is ready, so we do the entire
 	/* 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
 	/* Once the TPM has completed the command the command remains readable
 	 * until another command is issued. */
 	 * until another command is issued. */
 	rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer));
 	rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer));
-	dev_dbg(chip->dev,
+	dev_dbg(chip->pdev,
 		"%s: sts=%d", __func__, rc);
 		"%s: sts=%d", __func__, rc);
 	if (rc <= 0)
 	if (rc <= 0)
 		return 0;
 		return 0;
@@ -153,21 +153,20 @@ static const struct tpm_class_ops i2c_atmel = {
 static int i2c_atmel_probe(struct i2c_client *client,
 static int i2c_atmel_probe(struct i2c_client *client,
 			   const struct i2c_device_id *id)
 			   const struct i2c_device_id *id)
 {
 {
-	int rc;
 	struct tpm_chip *chip;
 	struct tpm_chip *chip;
 	struct device *dev = &client->dev;
 	struct device *dev = &client->dev;
 
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 		return -ENODEV;
 		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),
 	chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
 					 GFP_KERNEL);
 					 GFP_KERNEL);
+	if (!chip->vendor.priv)
+		return -ENOMEM;
 
 
 	/* Default timeouts */
 	/* Default timeouts */
 	chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT);
 	chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT);
@@ -179,33 +178,20 @@ static int i2c_atmel_probe(struct i2c_client *client,
 	/* There is no known way to probe for this device, and all version
 	/* 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
 	 * information seems to be read via TPM commands. Thus we rely on the
 	 * TPM startup process in the common code to detect the device. */
 	 * TPM startup process in the common code to detect the device. */
-	if (tpm_get_timeouts(chip)) {
-		rc = -ENODEV;
-		goto out_err;
-	}
-
-	if (tpm_do_selftest(chip)) {
-		rc = -ENODEV;
-		goto out_err;
-	}
+	if (tpm_get_timeouts(chip))
+		return -ENODEV;
 
 
-	return 0;
+	if (tpm_do_selftest(chip))
+		return -ENODEV;
 
 
-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)
 static int i2c_atmel_remove(struct i2c_client *client)
 {
 {
 	struct device *dev = &(client->dev);
 	struct device *dev = &(client->dev);
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-
-	if (chip)
-		tpm_dev_vendor_release(chip);
-	tpm_remove_hardware(dev);
-	kfree(chip);
+	tpm_chip_unregister(chip);
 	return 0;
 	return 0;
 }
 }
 
 

+ 10 - 33
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 */
 	/* read first 10 bytes, including tag, paramsize, and result */
 	size = recv_data(chip, buf, TPM_HEADER_SIZE);
 	size = recv_data(chip, buf, TPM_HEADER_SIZE);
 	if (size < 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;
 		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],
 	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
 			  expected - TPM_HEADER_SIZE);
 			  expected - TPM_HEADER_SIZE);
 	if (size < expected) {
 	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;
 		size = -ETIME;
 		goto out;
 		goto out;
 	}
 	}
 
 
 	wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
 	wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
 	if (status & TPM_STS_DATA_AVAIL) {	/* retry? */
 	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;
 		size = -EIO;
 		goto out;
 		goto out;
 	}
 	}
@@ -581,12 +581,9 @@ static int tpm_tis_i2c_init(struct device *dev)
 	int rc = 0;
 	int rc = 0;
 	struct tpm_chip *chip;
 	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 */
 	/* Disable interrupts */
 	chip->vendor.irq = 0;
 	chip->vendor.irq = 0;
@@ -600,7 +597,7 @@ static int tpm_tis_i2c_init(struct device *dev)
 	if (request_locality(chip, 0) != 0) {
 	if (request_locality(chip, 0) != 0) {
 		dev_err(dev, "could not request locality\n");
 		dev_err(dev, "could not request locality\n");
 		rc = -ENODEV;
 		rc = -ENODEV;
-		goto out_vendor;
+		goto out_err;
 	}
 	}
 
 
 	/* read four bytes from DID_VID register */
 	/* 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_get_timeouts(chip);
 	tpm_do_selftest(chip);
 	tpm_do_selftest(chip);
 
 
-	return 0;
-
+	return tpm_chip_register(chip);
 out_release:
 out_release:
 	release_locality(chip, chip->vendor.locality, 1);
 	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;
 	tpm_dev.client = NULL;
 out_err:
 out_err:
 	return rc;
 	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)
 static int tpm_tis_i2c_remove(struct i2c_client *client)
 {
 {
 	struct tpm_chip *chip = tpm_dev.chip;
 	struct tpm_chip *chip = tpm_dev.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_chip_unregister(chip);
+	release_locality(chip, chip->vendor.locality, 1);
 	tpm_dev.client = NULL;
 	tpm_dev.client = NULL;
 
 
 	return 0;
 	return 0;

+ 27 - 42
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 */
 /* read TPM_STS register */
 static u8 i2c_nuvoton_read_status(struct tpm_chip *chip)
 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;
 	s32 status;
 	u8 data;
 	u8 data;
 
 
 	status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data);
 	status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data);
 	if (status <= 0) {
 	if (status <= 0) {
-		dev_err(chip->dev, "%s() error return %d\n", __func__,
+		dev_err(chip->pdev, "%s() error return %d\n", __func__,
 			status);
 			status);
 		data = TPM_STS_ERR_VAL;
 		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 */
 /* write commandReady to TPM_STS register */
 static void i2c_nuvoton_ready(struct tpm_chip *chip)
 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;
 	s32 status;
 
 
 	/* this causes the current command to be aborted */
 	/* this causes the current command to be aborted */
 	status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY);
 	status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY);
 	if (status < 0)
 	if (status < 0)
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"%s() fail to write TPM_STS.commandReady\n", __func__);
 			"%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;
 				return 0;
 		} while (time_before(jiffies, stop));
 		} 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);
 		value);
 	return -ETIMEDOUT;
 	return -ETIMEDOUT;
 }
 }
@@ -240,7 +240,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
 					       &chip->vendor.read_queue) == 0) {
 					       &chip->vendor.read_queue) == 0) {
 		burst_count = i2c_nuvoton_get_burstcount(client, chip);
 		burst_count = i2c_nuvoton_get_burstcount(client, chip);
 		if (burst_count < 0) {
 		if (burst_count < 0) {
-			dev_err(chip->dev,
+			dev_err(chip->pdev,
 				"%s() fail to read burstCount=%d\n", __func__,
 				"%s() fail to read burstCount=%d\n", __func__,
 				burst_count);
 				burst_count);
 			return -EIO;
 			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,
 		rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_R,
 					  bytes2read, &buf[size]);
 					  bytes2read, &buf[size]);
 		if (rc < 0) {
 		if (rc < 0) {
-			dev_err(chip->dev,
+			dev_err(chip->pdev,
 				"%s() fail on i2c_nuvoton_read_buf()=%d\n",
 				"%s() fail on i2c_nuvoton_read_buf()=%d\n",
 				__func__, rc);
 				__func__, rc);
 			return -EIO;
 			return -EIO;
 		}
 		}
-		dev_dbg(chip->dev, "%s(%d):", __func__, bytes2read);
+		dev_dbg(chip->pdev, "%s(%d):", __func__, bytes2read);
 		size += bytes2read;
 		size += bytes2read;
 	}
 	}
 
 
@@ -264,7 +264,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
 /* Read TPM command results */
 /* Read TPM command results */
 static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 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);
 	struct i2c_client *client = to_i2c_client(dev);
 	s32 rc;
 	s32 rc;
 	int expected, status, burst_count, retries, size = 0;
 	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;
 		break;
 	}
 	}
 	i2c_nuvoton_ready(chip);
 	i2c_nuvoton_ready(chip);
-	dev_dbg(chip->dev, "%s() -> %d\n", __func__, size);
+	dev_dbg(chip->pdev, "%s() -> %d\n", __func__, size);
 	return 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)
 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);
 	struct i2c_client *client = to_i2c_client(dev);
 	u32 ordinal;
 	u32 ordinal;
 	size_t count = 0;
 	size_t count = 0;
@@ -530,14 +530,15 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
 	dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid,
 	dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid,
 		 (u8) (vid >> 16), (u8) (vid >> 24));
 		 (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),
 	chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
 					 GFP_KERNEL);
 					 GFP_KERNEL);
+	if (!chip->vendor.priv)
+		return -ENOMEM;
+
 	init_waitqueue_head(&chip->vendor.read_queue);
 	init_waitqueue_head(&chip->vendor.read_queue);
 	init_waitqueue_head(&chip->vendor.int_queue);
 	init_waitqueue_head(&chip->vendor.int_queue);
 
 
@@ -559,7 +560,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
 		rc = devm_request_irq(dev, chip->vendor.irq,
 		rc = devm_request_irq(dev, chip->vendor.irq,
 				      i2c_nuvoton_int_handler,
 				      i2c_nuvoton_int_handler,
 				      IRQF_TRIGGER_LOW,
 				      IRQF_TRIGGER_LOW,
-				      chip->vendor.miscdev.name,
+				      chip->devname,
 				      chip);
 				      chip);
 		if (rc) {
 		if (rc) {
 			dev_err(dev, "%s() Unable to request irq: %d for use\n",
 			dev_err(dev, "%s() Unable to request irq: %d for use\n",
@@ -584,7 +585,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
 							   TPM_DATA_FIFO_W,
 							   TPM_DATA_FIFO_W,
 							   1, (u8 *) (&rc));
 							   1, (u8 *) (&rc));
 				if (rc < 0)
 				if (rc < 0)
-					goto out_err;
+					return rc;
 				/* TPM_STS <- 0x40 (commandReady) */
 				/* TPM_STS <- 0x40 (commandReady) */
 				i2c_nuvoton_ready(chip);
 				i2c_nuvoton_ready(chip);
 			} else {
 			} else {
@@ -594,45 +595,29 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
 				 * only TPM_STS_VALID should be set
 				 * only TPM_STS_VALID should be set
 				 */
 				 */
 				if (i2c_nuvoton_read_status(chip) !=
 				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_do_selftest(chip)) {
-		rc = -ENODEV;
-		goto out_err;
-	}
+	if (tpm_get_timeouts(chip))
+		return -ENODEV;
 
 
-	return 0;
+	if (tpm_do_selftest(chip))
+		return -ENODEV;
 
 
-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)
 static int i2c_nuvoton_remove(struct i2c_client *client)
 {
 {
 	struct device *dev = &(client->dev);
 	struct device *dev = &(client->dev);
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-
-	if (chip)
-		tpm_dev_vendor_release(chip);
-	tpm_remove_hardware(dev);
-	kfree(chip);
+	tpm_chip_unregister(chip);
 	return 0;
 	return 0;
 }
 }
 
 
-
 static const struct i2c_device_id i2c_nuvoton_id[] = {
 static const struct i2c_device_id i2c_nuvoton_id[] = {
 	{I2C_DRIVER_NAME, 0},
 	{I2C_DRIVER_NAME, 0},
 	{}
 	{}

+ 366 - 300
drivers/char/tpm/tpm_i2c_stm_st33.c

@@ -1,6 +1,6 @@
 /*
 /*
  * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
  * 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
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -12,11 +12,10 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  * 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 <http://www.gnu.org/licenses/>.
  *
  *
- * STMicroelectronics version 1.2.0, Copyright (C) 2010
+ * STMicroelectronics version 1.2.1, Copyright (C) 2014
  * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
  * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
  * This is free software, and you are welcome to redistribute it
  * This is free software, and you are welcome to redistribute it
  * under certain conditions.
  * under certain conditions.
@@ -27,7 +26,7 @@
  *
  *
  * @Synopsis:
  * @Synopsis:
  *	09/15/2010:	First shot driver tpm_tis driver for
  *	09/15/2010:	First shot driver tpm_tis driver for
-			 lpc is used as model.
+ *			 lpc is used as model.
  */
  */
 
 
 #include <linux/pci.h>
 #include <linux/pci.h>
@@ -39,18 +38,38 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
+#include <linux/freezer.h>
 #include <linux/string.h>
 #include <linux/string.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
-#include <linux/spinlock.h>
 #include <linux/sysfs.h>
 #include <linux/sysfs.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/uaccess.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
 
 
+#include <linux/platform_data/tpm_stm_st33.h>
 #include "tpm.h"
 #include "tpm.h"
-#include "tpm_i2c_stm_st33.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
+
 
 
 enum stm33zp24_access {
 enum stm33zp24_access {
 	TPM_ACCESS_VALID = 0x80,
 	TPM_ACCESS_VALID = 0x80,
@@ -82,6 +101,14 @@ enum tis_defaults {
 	TIS_LONG_TIMEOUT = 2000,
 	TIS_LONG_TIMEOUT = 2000,
 };
 };
 
 
+struct tpm_stm_dev {
+	struct i2c_client *client;
+	struct tpm_chip *chip;
+	u8 buf[TPM_BUFSIZE + 1];
+	u32 intrs;
+	int io_lpcpd;
+};
+
 /*
 /*
  * write8_reg
  * write8_reg
  * Send byte to the TIS register according to the ST33ZP24 I2C protocol.
  * Send byte to the TIS register according to the ST33ZP24 I2C protocol.
@@ -90,17 +117,12 @@ enum tis_defaults {
  * @param: tpm_size, The length of the data
  * @param: tpm_size, The length of the data
  * @return: Returns negative errno, or else the number of bytes written.
  * @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)
 		      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() */
 } /* write8_reg() */
 
 
 /*
 /*
@@ -111,101 +133,58 @@ static int write8_reg(struct i2c_client *client, u8 tpm_register,
  * @param: tpm_size, tpm TPM response size to read.
  * @param: tpm_size, tpm TPM response size to read.
  * @return: number of byte read successfully: should be one if success.
  * @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 *tpm_data, int tpm_size)
 {
 {
 	u8 status = 0;
 	u8 status = 0;
 	u8 data;
 	u8 data;
 
 
 	data = TPM_DUMMY_BYTE;
 	data = TPM_DUMMY_BYTE;
-	status = write8_reg(client, tpm_register, &data, 1);
+	status = write8_reg(tpm_dev, tpm_register, &data, 1);
 	if (status == 2)
 	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;
 	return status;
 } /* read8_reg() */
 } /* read8_reg() */
 
 
 /*
 /*
  * I2C_WRITE_DATA
  * I2C_WRITE_DATA
  * Send byte to the TIS register according to the ST33ZP24 I2C protocol.
  * 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_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_data, the tpm_data to write inside the tpm_register
  * @param: tpm_size, The length of the data
  * @param: tpm_size, The length of the data
  * @return: number of byte written successfully: should be one if success.
  * @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))
 	TPM_WRITE_DIRECTION, tpm_data, tpm_size))
 
 
 /*
 /*
  * I2C_READ_DATA
  * I2C_READ_DATA
  * Recv byte from the TIS register according to the ST33ZP24 I2C protocol.
  * 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_register, the tpm tis register where the data should be read
  * @param: tpm_data, the TPM response
  * @param: tpm_data, the TPM response
  * @param: tpm_size, tpm TPM response size to read.
  * @param: tpm_size, tpm TPM response size to read.
  * @return: number of byte read successfully: should be one if success.
  * @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_interruption
  * clear the TPM interrupt register.
  * clear the TPM interrupt register.
  * @param: tpm, the chip description
  * @param: tpm, the chip description
+ * @return: the TPM_INT_STATUS value
  */
  */
-static void clear_interruption(struct i2c_client *client)
+static u8 clear_interruption(struct tpm_stm_dev *tpm_dev)
 {
 {
 	u8 interrupt;
 	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);
-} /* 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 st33zp24_platform_data *pin_infos;
-
-	client = (struct i2c_client *)TPM_VPRIV(chip);
-	pin_infos = client->dev.platform_data;
-
-	status = wait_for_completion_interruptible_timeout(
-					&pin_infos->irq_detection,
-						timeout);
-	if (status > 0)
-		enable_irq(gpio_to_irq(pin_infos->io_serirq));
-	gpio_direction_input(pin_infos->io_serirq);
-
-	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 i2c_client *client;
-
-	client = (struct i2c_client *)TPM_VPRIV(chip);
 
 
-	status = _wait_for_interrupt_serirq_timeout(chip, timeout);
-	if (!status) {
-		status = -EBUSY;
-	} else {
-		clear_interruption(client);
-		if (condition)
-			status = 1;
-	}
-	return status;
-}
+	I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1);
+	I2C_WRITE_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1);
+	return interrupt;
+} /* clear_interruption() */
 
 
 /*
 /*
  * tpm_stm_i2c_cancel, cancel is not implemented.
  * tpm_stm_i2c_cancel, cancel is not implemented.
@@ -213,16 +192,14 @@ static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition,
  */
  */
 static void tpm_stm_i2c_cancel(struct tpm_chip *chip)
 static void tpm_stm_i2c_cancel(struct tpm_chip *chip)
 {
 {
-	struct i2c_client *client;
+	struct tpm_stm_dev *tpm_dev;
 	u8 data;
 	u8 data;
 
 
-	client = (struct i2c_client *)TPM_VPRIV(chip);
+	tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
 
 
 	data = TPM_STS_COMMAND_READY;
 	data = TPM_STS_COMMAND_READY;
-	I2C_WRITE_DATA(client, TPM_STS, &data, 1);
-	if (chip->vendor.irq)
-		wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a);
-}	/* tpm_stm_i2c_cancel() */
+	I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1);
+} /* tpm_stm_i2c_cancel() */
 
 
 /*
 /*
  * tpm_stm_spi_status return the TPM_STS register
  * tpm_stm_spi_status return the TPM_STS register
@@ -231,13 +208,14 @@ static void tpm_stm_i2c_cancel(struct tpm_chip *chip)
  */
  */
 static u8 tpm_stm_i2c_status(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;
 	u8 data;
-	client = (struct i2c_client *)TPM_VPRIV(chip);
 
 
-	I2C_READ_DATA(client, TPM_STS, &data, 1);
+	tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
+
+	I2C_READ_DATA(tpm_dev, TPM_STS, &data, 1);
 	return data;
 	return data;
-}				/* tpm_stm_i2c_status() */
+} /* tpm_stm_i2c_status() */
 
 
 
 
 /*
 /*
@@ -247,20 +225,19 @@ static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
  */
  */
 static int check_locality(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 data;
 	u8 status;
 	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 &
 	if (status && (data &
 		(TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
 		(TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
 		(TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID))
 		(TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID))
 		return chip->vendor.locality;
 		return chip->vendor.locality;
 
 
 	return -EACCES;
 	return -EACCES;
-
 } /* check_locality() */
 } /* check_locality() */
 
 
 /*
 /*
@@ -271,37 +248,31 @@ static int check_locality(struct tpm_chip *chip)
 static int request_locality(struct tpm_chip *chip)
 static int request_locality(struct tpm_chip *chip)
 {
 {
 	unsigned long stop;
 	unsigned long stop;
-	long rc;
-	struct i2c_client *client;
+	long ret;
+	struct tpm_stm_dev *tpm_dev;
 	u8 data;
 	u8 data;
 
 
-	client = (struct i2c_client *)TPM_VPRIV(chip);
-
 	if (check_locality(chip) == chip->vendor.locality)
 	if (check_locality(chip) == chip->vendor.locality)
 		return chip->vendor.locality;
 		return chip->vendor.locality;
 
 
+	tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
+
 	data = TPM_ACCESS_REQUEST_USE;
 	data = TPM_ACCESS_REQUEST_USE;
-	rc = I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
-	if (rc < 0)
+	ret = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1);
+	if (ret < 0)
 		goto end;
 		goto end;
 
 
-	if (chip->vendor.irq) {
-		rc = wait_for_serirq_timeout(chip, (check_locality
-						       (chip) >= 0),
-						      chip->vendor.timeout_a);
-		if (rc > 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;
 			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));
-	}
-	rc = -EACCES;
+		msleep(TPM_TIMEOUT);
+	} while (time_before(jiffies, stop));
+	ret = -EACCES;
 end:
 end:
-	return rc;
+	return ret;
 } /* request_locality() */
 } /* request_locality() */
 
 
 /*
 /*
@@ -310,13 +281,13 @@ end:
  */
  */
 static void release_locality(struct tpm_chip *chip)
 static void release_locality(struct tpm_chip *chip)
 {
 {
-	struct i2c_client *client;
+	struct tpm_stm_dev *tpm_dev;
 	u8 data;
 	u8 data;
 
 
-	client = (struct i2c_client *)TPM_VPRIV(chip);
+	tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
 	data = TPM_ACCESS_ACTIVE_LOCALITY;
 	data = TPM_ACCESS_ACTIVE_LOCALITY;
 
 
-	I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
+	I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1);
 }
 }
 
 
 /*
 /*
@@ -329,19 +300,20 @@ static int get_burstcount(struct tpm_chip *chip)
 	unsigned long stop;
 	unsigned long stop;
 	int burstcnt, status;
 	int burstcnt, status;
 	u8 tpm_reg, temp;
 	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;
 	stop = jiffies + chip->vendor.timeout_d;
 	do {
 	do {
 		tpm_reg = TPM_STS + 1;
 		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)
 		if (status < 0)
 			goto end;
 			goto end;
 
 
 		tpm_reg = tpm_reg + 1;
 		tpm_reg = tpm_reg + 1;
 		burstcnt = temp;
 		burstcnt = temp;
-		status = I2C_READ_DATA(client, tpm_reg, &temp, 1);
+		status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1);
 		if (status < 0)
 		if (status < 0)
 			goto end;
 			goto end;
 
 
@@ -355,36 +327,107 @@ end:
 	return -EBUSY;
 	return -EBUSY;
 } /* get_burstcount() */
 } /* 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
  * wait_for_stat wait for a TPM_STS value
  * @param: chip, the tpm chip description
  * @param: chip, the tpm chip description
  * @param: mask, the value mask to wait
  * @param: mask, the value mask to wait
  * @param: timeout, the timeout
  * @param: timeout, the timeout
  * @param: queue, the wait queue.
  * @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.
  * @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,
 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;
 	unsigned long stop;
-	long rc;
-	u8 status;
+	int ret;
+	bool canceled = false;
+	bool condition;
+	u32 cur_intrs;
+	u8 interrupt, status;
+	struct tpm_stm_dev *tpm_dev;
 
 
-	 if (chip->vendor.irq) {
-		rc = wait_for_serirq_timeout(chip, ((tpm_stm_i2c_status
-							(chip) & mask) ==
-						       mask), timeout);
-		if (rc > 0)
+	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) {
+		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;
+
+		ret = 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 (ret >= 0 && condition) {
+			if (canceled)
+				return -ECANCELED;
 			return 0;
 			return 0;
+		}
+		if (ret == -ERESTARTSYS && freezing(current)) {
+			clear_thread_flag(TIF_SIGPENDING);
+			goto again;
+		}
+		disable_irq_nosync(chip->vendor.irq);
+
 	} else {
 	} else {
-		stop = jiffies + timeout;
 		do {
 		do {
 			msleep(TPM_TIMEOUT);
 			msleep(TPM_TIMEOUT);
-			status = tpm_stm_i2c_status(chip);
+			status = chip->ops->status(chip);
 			if ((status & mask) == mask)
 			if ((status & mask) == mask)
 				return 0;
 				return 0;
 		} while (time_before(jiffies, stop));
 		} while (time_before(jiffies, stop));
 	}
 	}
+
 	return -ETIME;
 	return -ETIME;
 } /* wait_for_stat() */
 } /* wait_for_stat() */
 
 
@@ -397,22 +440,24 @@ 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)
 static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
 {
 {
-	int size = 0, burstcnt, len;
-	struct i2c_client *client;
+	int size = 0, burstcnt, len, ret;
+	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 &&
 	while (size < count &&
 	       wait_for_stat(chip,
 	       wait_for_stat(chip,
 			     TPM_STS_DATA_AVAIL | TPM_STS_VALID,
 			     TPM_STS_DATA_AVAIL | TPM_STS_VALID,
 			     chip->vendor.timeout_c,
 			     chip->vendor.timeout_c,
-			     &chip->vendor.read_queue)
-	       == 0) {
+			     &chip->vendor.read_queue, true) == 0) {
 		burstcnt = get_burstcount(chip);
 		burstcnt = get_burstcount(chip);
 		if (burstcnt < 0)
 		if (burstcnt < 0)
 			return burstcnt;
 			return burstcnt;
 		len = min_t(int, burstcnt, count - size);
 		len = min_t(int, burstcnt, count - size);
-		I2C_READ_DATA(client, 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;
 		size += len;
 	}
 	}
 	return size;
 	return size;
@@ -427,15 +472,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)
 static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)
 {
 {
 	struct tpm_chip *chip = 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);
+	tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
 
 
-	client = (struct i2c_client *)TPM_VPRIV(chip);
-	pin_infos = client->dev.platform_data;
+	tpm_dev->intrs++;
+	wake_up_interruptible(&chip->vendor.read_queue);
+	disable_irq_nosync(chip->vendor.irq);
 
 
-	complete(&pin_infos->irq_detection);
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 } /* tpm_ioserirq_handler() */
 } /* tpm_ioserirq_handler() */
 
 
@@ -457,13 +501,15 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
 	int ret;
 	int ret;
 	u8 data;
 	u8 data;
 	struct i2c_client *client;
 	struct i2c_client *client;
+	struct tpm_stm_dev *tpm_dev;
 
 
-	if (chip == NULL)
+	if (!chip)
 		return -EBUSY;
 		return -EBUSY;
 	if (len < TPM_HEADER_SIZE)
 	if (len < TPM_HEADER_SIZE)
 		return -EBUSY;
 		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;
 	client->flags = 0;
 
 
@@ -476,7 +522,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
 		tpm_stm_i2c_cancel(chip);
 		tpm_stm_i2c_cancel(chip);
 		if (wait_for_stat
 		if (wait_for_stat
 		    (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
 		    (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
-		     &chip->vendor.int_queue) < 0) {
+		     &chip->vendor.read_queue, false) < 0) {
 			ret = -ETIME;
 			ret = -ETIME;
 			goto out_err;
 			goto out_err;
 		}
 		}
@@ -487,7 +533,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
 		if (burstcnt < 0)
 		if (burstcnt < 0)
 			return burstcnt;
 			return burstcnt;
 		size = min_t(int, len - i - 1, burstcnt);
 		size = min_t(int, len - i - 1, burstcnt);
-		ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size);
+		ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + i, size);
 		if (ret < 0)
 		if (ret < 0)
 			goto out_err;
 			goto out_err;
 
 
@@ -500,7 +546,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
 		goto out_err;
 		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)
 	if (ret < 0)
 		goto out_err;
 		goto out_err;
 
 
@@ -511,7 +557,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
 	}
 	}
 
 
 	data = TPM_STS_GO;
 	data = TPM_STS_GO;
-	I2C_WRITE_DATA(client, TPM_STS, &data, 1);
+	I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1);
 
 
 	return len;
 	return len;
 out_err:
 out_err:
@@ -526,7 +572,7 @@ out_err:
  * @param: buf,	the buffer to store datas.
  * @param: buf,	the buffer to store datas.
  * @param: count, the number of bytes to send.
  * @param: count, the number of bytes to send.
  * @return: In case of success the number of bytes received.
  * @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,
 static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
 			    size_t count)
 			    size_t count)
@@ -534,7 +580,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
 	int size = 0;
 	int size = 0;
 	int expected;
 	int expected;
 
 
-	if (chip == NULL)
+	if (!chip)
 		return -EBUSY;
 		return -EBUSY;
 
 
 	if (count < TPM_HEADER_SIZE) {
 	if (count < TPM_HEADER_SIZE) {
@@ -544,7 +590,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
 
 
 	size = recv_data(chip, buf, TPM_HEADER_SIZE);
 	size = recv_data(chip, buf, TPM_HEADER_SIZE);
 	if (size < 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;
 		goto out;
 	}
 	}
 
 
@@ -555,9 +601,9 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
 	}
 	}
 
 
 	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
 	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
-					expected - TPM_HEADER_SIZE);
+			expected - TPM_HEADER_SIZE);
 	if (size < expected) {
 	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;
 		size = -ETIME;
 		goto out;
 		goto out;
 	}
 	}
@@ -568,7 +614,7 @@ out:
 	return size;
 	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);
 	return (status == TPM_STS_COMMAND_READY);
 }
 }
@@ -580,75 +626,134 @@ static const struct tpm_class_ops st_i2c_tpm = {
 	.status = tpm_stm_i2c_status,
 	.status = tpm_stm_i2c_status,
 	.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
 	.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
 	.req_complete_val = 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;
-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;
+	int gpio;
+	int ret;
+
+	pp = client->dev.of_node;
+	if (!pp) {
+		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->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
+		 * 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->pdev, "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 power_mgt = 1;
-module_param(power_mgt, int, 0444);
-MODULE_PARM_DESC(power_mgt, "Power Management");
+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) {
+		dev_err(chip->pdev, "No platform data\n");
+		return -ENODEV;
+	}
+
+	/* 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->pdev, "%s : reset gpio_request failed\n",
+				__FILE__);
+			return ret;
+		}
+	}
+
+	return 0;
+}
 
 
 /*
 /*
- * 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: client, the i2c_client drescription (TPM I2C description).
  * @param: id, the i2c_device_id struct.
  * @param: id, the i2c_device_id struct.
  * @return: 0 in case of success.
  * @return: 0 in case of success.
  *	 -1 in other case.
  *	 -1 in other case.
  */
  */
 static int
 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 err;
-	u8 intmask;
+	int ret;
+	u8 intmask = 0;
 	struct tpm_chip *chip;
 	struct tpm_chip *chip;
 	struct st33zp24_platform_data *platform_data;
 	struct st33zp24_platform_data *platform_data;
+	struct tpm_stm_dev *tpm_dev;
 
 
-	if (client == NULL) {
+	if (!client) {
 		pr_info("%s: i2c client is NULL. Device not accessible.\n",
 		pr_info("%s: i2c client is NULL. Device not accessible.\n",
 			__func__);
 			__func__);
-		err = -ENODEV;
-		goto end;
+		return -ENODEV;
 	}
 	}
 
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		dev_info(&client->dev, "client not i2c capable\n");
 		dev_info(&client->dev, "client not i2c capable\n");
-		err = -ENODEV;
-		goto end;
+		return -ENODEV;
 	}
 	}
 
 
-	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)
+		return -ENOMEM;
 
 
-	platform_data = client->dev.platform_data;
+	chip = tpmm_chip_alloc(&client->dev, &st_i2c_tpm);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 
-	if (!platform_data) {
-		dev_info(&client->dev, "chip not available\n");
-		err = -ENODEV;
-		goto _tpm_clean_answer;
-	}
+	TPM_VPRIV(chip) = tpm_dev;
+	tpm_dev->client = client;
 
 
-	platform_data->tpm_i2c_buffer[0] =
-	    kmalloc(TPM_BUFSIZE * sizeof(u8), 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);
-	if (platform_data->tpm_i2c_buffer[1] == NULL) {
-		err = -ENOMEM;
-		goto _tpm_clean_response1;
+	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;
 	}
 	}
 
 
-	TPM_VPRIV(chip) = client;
-
 	chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
 	chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
 	chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
 	chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
 	chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
 	chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
@@ -656,59 +761,44 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
 
 	chip->vendor.locality = LOCALITY0;
 	chip->vendor.locality = LOCALITY0;
 
 
-	if (power_mgt) {
-		err = gpio_request(platform_data->io_lpcpd, "TPM IO_LPCPD");
-		if (err)
-			goto _gpio_init1;
-		gpio_set_value(platform_data->io_lpcpd, 1);
-	}
+	if (client->irq) {
+		/* INTERRUPT Setup */
+		init_waitqueue_head(&chip->vendor.read_queue);
+		tpm_dev->intrs = 0;
 
 
-	if (interrupts) {
-		init_completion(&platform_data->irq_detection);
 		if (request_locality(chip) != LOCALITY0) {
 		if (request_locality(chip) != LOCALITY0) {
-			err = -ENODEV;
-			goto _tpm_clean_response2;
+			ret = -ENODEV;
+			goto _tpm_clean_answer;
 		}
 		}
-		err = gpio_request(platform_data->io_serirq, "TPM IO_SERIRQ");
-		if (err)
-			goto _gpio_init2;
 
 
-		clear_interruption(client);
-		err = request_irq(gpio_to_irq(platform_data->io_serirq),
-				&tpm_ioserirq_handler,
+		clear_interruption(tpm_dev);
+		ret = devm_request_irq(&client->dev, client->irq,
+				tpm_ioserirq_handler,
 				IRQF_TRIGGER_HIGH,
 				IRQF_TRIGGER_HIGH,
 				"TPM SERIRQ management", chip);
 				"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));
-			goto _irq_set;
+		if (ret < 0) {
+			dev_err(chip->pdev, "TPM SERIRQ signals %d not available\n",
+				client->irq);
+			goto _tpm_clean_answer;
 		}
 		}
 
 
-		err = I2C_READ_DATA(client, TPM_INT_ENABLE, &intmask, 1);
-		if (err < 0)
-			goto _irq_set;
-
 		intmask |= TPM_INTF_CMD_READY_INT
 		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_STS_VALID_INT
 			|  TPM_INTF_DATA_AVAIL_INT;
 			|  TPM_INTF_DATA_AVAIL_INT;
 
 
-		err = I2C_WRITE_DATA(client, TPM_INT_ENABLE, &intmask, 1);
-		if (err < 0)
-			goto _irq_set;
+		ret = I2C_WRITE_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1);
+		if (ret < 0)
+			goto _tpm_clean_answer;
 
 
 		intmask = TPM_GLOBAL_INT_ENABLE;
 		intmask = TPM_GLOBAL_INT_ENABLE;
-		err = I2C_WRITE_DATA(client, (TPM_INT_ENABLE + 3), &intmask, 1);
-		if (err < 0)
-			goto _irq_set;
+		ret = I2C_WRITE_DATA(tpm_dev, (TPM_INT_ENABLE + 3),
+				     &intmask, 1);
+		if (ret < 0)
+			goto _tpm_clean_answer;
 
 
-		err = I2C_READ_DATA(client, TPM_INT_STATUS, &intmask, 1);
-		if (err < 0)
-			goto _irq_set;
+		chip->vendor.irq = client->irq;
 
 
-		chip->vendor.irq = interrupts;
+		disable_irq_nosync(chip->vendor.irq);
 
 
 		tpm_gen_interrupt(chip);
 		tpm_gen_interrupt(chip);
 	}
 	}
@@ -716,130 +806,106 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	tpm_get_timeouts(chip);
 	tpm_get_timeouts(chip);
 	tpm_do_selftest(chip);
 	tpm_do_selftest(chip);
 
 
-	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);
-_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;
+	return tpm_chip_register(chip);
 _tpm_clean_answer:
 _tpm_clean_answer:
-	tpm_remove_hardware(chip->dev);
-end:
-	pr_info("TPM I2C initialisation fail\n");
-	return err;
+	dev_info(chip->pdev, "TPM I2C initialisation fail\n");
+	return ret;
 }
 }
 
 
 /*
 /*
- * tpm_st33_i2c_remove remove the TPM device
- * @param: client, the i2c_client drescription (TPM I2C description).
-		clear_bit(0, &chip->is_open);
+ * tpm_stm_i2c_remove remove the TPM device
+ * @param: client, the i2c_client description (TPM I2C description).
  * @return: 0 in case of success.
  * @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);
-	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);
-
-		tpm_remove_hardware(chip->dev);
+	struct tpm_chip *chip =
+		(struct tpm_chip *) i2c_get_clientdata(client);
 
 
-		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;
-		}
-	}
+	if (chip)
+		tpm_chip_unregister(chip);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 #ifdef CONFIG_PM_SLEEP
 #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: client, the i2c_client drescription (TPM I2C description).
  * @param: mesg, the power management message.
  * @param: mesg, the power management message.
  * @return: 0 in case of success.
  * @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;
 	struct st33zp24_platform_data *pin_infos = dev->platform_data;
 	int ret = 0;
 	int ret = 0;
 
 
-	if (power_mgt) {
+	if (gpio_is_valid(pin_infos->io_lpcpd))
 		gpio_set_value(pin_infos->io_lpcpd, 0);
 		gpio_set_value(pin_infos->io_lpcpd, 0);
-	} else {
+	else
 		ret = tpm_pm_suspend(dev);
 		ret = tpm_pm_suspend(dev);
-	}
+
 	return ret;
 	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).
  * @param: client, the i2c_client drescription (TPM I2C description).
  * @return: 0 in case of success.
  * @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 tpm_chip *chip = dev_get_drvdata(dev);
 	struct st33zp24_platform_data *pin_infos = dev->platform_data;
 	struct st33zp24_platform_data *pin_infos = dev->platform_data;
 
 
 	int ret = 0;
 	int ret = 0;
 
 
-	if (power_mgt) {
+	if (gpio_is_valid(pin_infos->io_lpcpd)) {
 		gpio_set_value(pin_infos->io_lpcpd, 1);
 		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 {
 	} else {
 		ret = tpm_pm_resume(dev);
 		ret = tpm_pm_resume(dev);
 		if (!ret)
 		if (!ret)
 			tpm_do_selftest(chip);
 			tpm_do_selftest(chip);
 	}
 	}
 	return ret;
 	return ret;
-}				/* tpm_st33_i2c_pm_resume() */
+} /* tpm_stm_i2c_pm_resume() */
 #endif
 #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},
 	{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);
+
+#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
+
+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 = {
 	.driver = {
-		   .owner = THIS_MODULE,
-		   .name = TPM_ST33_I2C,
-		   .pm = &tpm_st33_i2c_ops,
-		   },
-	.probe = tpm_st33_i2c_probe,
-	.remove = tpm_st33_i2c_remove,
-	.id_table = tpm_st33_i2c_id
+		.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,
+	.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_AUTHOR("Christophe Ricard (tpmsupport@st.com)");
 MODULE_DESCRIPTION("STM TPM I2C ST33 Driver");
 MODULE_DESCRIPTION("STM TPM I2C ST33 Driver");
-MODULE_VERSION("1.2.0");
+MODULE_VERSION("1.2.1");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 16 - 11
drivers/char/tpm/tpm_ibmvtpm.c

@@ -1,7 +1,7 @@
 /*
 /*
  * Copyright (C) 2012 IBM Corporation
  * Copyright (C) 2012 IBM Corporation
  *
  *
- * Author: Ashley Lai <adlai@us.ibm.com>
+ * Author: Ashley Lai <ashleydlai@gmail.com>
  *
  *
  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  *
  *
@@ -270,8 +270,11 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
 static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
 static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
 {
 {
 	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
 	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
+	struct tpm_chip *chip = dev_get_drvdata(ibmvtpm->dev);
 	int rc = 0;
 	int rc = 0;
 
 
+	tpm_chip_unregister(chip);
+
 	free_irq(vdev->irq, ibmvtpm);
 	free_irq(vdev->irq, ibmvtpm);
 
 
 	do {
 	do {
@@ -290,8 +293,6 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
 		kfree(ibmvtpm->rtce_buf);
 		kfree(ibmvtpm->rtce_buf);
 	}
 	}
 
 
-	tpm_remove_hardware(ibmvtpm->dev);
-
 	kfree(ibmvtpm);
 	kfree(ibmvtpm);
 
 
 	return 0;
 	return 0;
@@ -307,6 +308,14 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
 static unsigned long tpm_ibmvtpm_get_desired_dma(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);
 	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;
 	return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size;
 }
 }
 
 
@@ -555,11 +564,9 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
 	struct tpm_chip *chip;
 	struct tpm_chip *chip;
 	int rc = -ENOMEM, rc1;
 	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);
 	ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
 	if (!ibmvtpm) {
 	if (!ibmvtpm) {
@@ -629,7 +636,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
 	if (rc)
 	if (rc)
 		goto init_irq_cleanup;
 		goto init_irq_cleanup;
 
 
-	return rc;
+	return tpm_chip_register(chip);
 init_irq_cleanup:
 init_irq_cleanup:
 	do {
 	do {
 		rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
 		rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
@@ -644,8 +651,6 @@ cleanup:
 		kfree(ibmvtpm);
 		kfree(ibmvtpm);
 	}
 	}
 
 
-	tpm_remove_hardware(dev);
-
 	return rc;
 	return rc;
 }
 }
 
 

+ 1 - 1
drivers/char/tpm/tpm_ibmvtpm.h

@@ -1,7 +1,7 @@
 /*
 /*
  * Copyright (C) 2012 IBM Corporation
  * Copyright (C) 2012 IBM Corporation
  *
  *
- * Author: Ashley Lai <adlai@us.ibm.com>
+ * Author: Ashley Lai <ashleydlai@gmail.com>
  *
  *
  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  *
  *

+ 28 - 23
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 (i == TPM_MAX_TRIES) {	/* timeout occurs */
 		if (wait_for_bit == STAT_XFE)
 		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)
 		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 -EIO;
 	}
 	}
 	return 0;
 	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)
 static void tpm_wtx(struct tpm_chip *chip)
 {
 {
 	number_of_wtx++;
 	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);
 		 number_of_wtx, TPM_MAX_WTX_PACKAGES);
 	wait_and_send(chip, TPM_VL_VER);
 	wait_and_send(chip, TPM_VL_VER);
 	wait_and_send(chip, TPM_CTRL_WTX);
 	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)
 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_VL_VER);
 	wait_and_send(chip, TPM_CTRL_WTX_ABORT);
 	wait_and_send(chip, TPM_CTRL_WTX_ABORT);
 	wait_and_send(chip, 0x00);
 	wait_and_send(chip, 0x00);
@@ -257,7 +257,7 @@ recv_begin:
 	}
 	}
 
 
 	if (buf[0] != TPM_VL_VER) {
 	if (buf[0] != TPM_VL_VER) {
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"Wrong transport protocol implementation!\n");
 			"Wrong transport protocol implementation!\n");
 		return -EIO;
 		return -EIO;
 	}
 	}
@@ -272,7 +272,7 @@ recv_begin:
 		}
 		}
 
 
 		if ((size == 0x6D00) && (buf[1] == 0x80)) {
 		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;
 			return -EIO;
 		}
 		}
 
 
@@ -284,7 +284,7 @@ recv_begin:
 	}
 	}
 
 
 	if (buf[1] == TPM_CTRL_WTX) {
 	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) {
 		if (number_of_wtx < TPM_MAX_WTX_PACKAGES) {
 			tpm_wtx(chip);
 			tpm_wtx(chip);
 			goto recv_begin;
 			goto recv_begin;
@@ -295,14 +295,14 @@ recv_begin:
 	}
 	}
 
 
 	if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) {
 	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;
 		return size;
 	}
 	}
 
 
 	if (buf[1] == TPM_CTRL_ERROR) {
 	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)
 		if (buf[4] == TPM_INF_NAK)
-			dev_err(chip->dev,
+			dev_err(chip->pdev,
 				"-> Negative acknowledgement"
 				"-> Negative acknowledgement"
 				" - retransmit command!\n");
 				" - retransmit command!\n");
 		return -EIO;
 		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);
 	ret = empty_fifo(chip, 1);
 	if (ret) {
 	if (ret) {
-		dev_err(chip->dev, "Timeout while clearing FIFO\n");
+		dev_err(chip->pdev, "Timeout while clearing FIFO\n");
 		return -EIO;
 		return -EIO;
 	}
 	}
 
 
@@ -546,7 +546,14 @@ static int tpm_inf_pnp_probe(struct pnp_dev *dev,
 			 vendorid[0], vendorid[1],
 			 vendorid[0], vendorid[1],
 			 productid[0], productid[1], chipname);
 			 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;
 			goto err_release_region;
 
 
 		return 0;
 		return 0;
@@ -572,17 +579,15 @@ static void tpm_inf_pnp_remove(struct pnp_dev *dev)
 {
 {
 	struct tpm_chip *chip = pnp_get_drvdata(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);
 	}
 	}
 }
 }
 
 

+ 19 - 15
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));
 	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;
 	return -EBUSY;
 }
 }
 
 
@@ -129,12 +129,12 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
 		return -EIO;
 		return -EIO;
 
 
 	if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
 	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;
 		return -EIO;
 	}
 	}
 	if ((data =
 	if ((data =
 	     inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
 	     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);
 			data);
 		return -EIO;
 		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++) {
 	for (p = buffer; p < &buffer[count]; p++) {
 		if (wait_for_stat
 		if (wait_for_stat
 		    (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
 		    (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
-			dev_err(chip->dev,
+			dev_err(chip->pdev,
 				"OBF timeout (while reading data)\n");
 				"OBF timeout (while reading data)\n");
 			return -EIO;
 			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 &&
 	if ((data & NSC_STATUS_F0) == 0 &&
 	(wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 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;
 		return -EIO;
 	}
 	}
 	if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) {
 	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);
 			"expected end of command(0x%x)\n", data);
 		return -EIO;
 		return -EIO;
 	}
 	}
@@ -189,19 +189,19 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
 		return -EIO;
 		return -EIO;
 
 
 	if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
 	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;
 		return -EIO;
 	}
 	}
 
 
 	outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND);
 	outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND);
 	if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
 	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;
 		return -EIO;
 	}
 	}
 
 
 	for (i = 0; i < count; i++) {
 	for (i = 0; i < count; i++) {
 		if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
 		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");
 				"IBF timeout (while writing data)\n");
 			return -EIO;
 			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) {
 	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;
 		return -EIO;
 	}
 	}
 	outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND);
 	outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND);
@@ -247,10 +247,9 @@ static struct platform_device *pdev = NULL;
 static void tpm_nsc_remove(struct device *dev)
 static void tpm_nsc_remove(struct device *dev)
 {
 {
 	struct tpm_chip *chip = dev_get_drvdata(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);
 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;
 		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;
 		rc = -ENODEV;
 		goto err_rel_reg;
 		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 TPM detected\n");
 	dev_dbg(&pdev->dev,
 	dev_dbg(&pdev->dev,
 		"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
 		"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",

+ 1 - 1
drivers/char/tpm/tpm_of.c

@@ -1,7 +1,7 @@
 /*
 /*
  * Copyright 2012 IBM Corporation
  * Copyright 2012 IBM Corporation
  *
  *
- * Author: Ashley Lai <adlai@us.ibm.com>
+ * Author: Ashley Lai <ashleydlai@gmail.com>
  *
  *
  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  *
  *

+ 87 - 54
drivers/char/tpm/tpm_ppi.c

@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2012-2014 Intel Corporation
+ *
+ * Authors:
+ * Xiaoyan Zhang <xiaoyan.zhang@intel.com>
+ * Jiang Liu <jiang.liu@linux.intel.com>
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * 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 <linux/acpi.h>
 #include <linux/acpi.h>
 #include "tpm.h"
 #include "tpm.h"
 
 
@@ -12,7 +31,6 @@
 #define PPI_TPM_REQ_MAX		22
 #define PPI_TPM_REQ_MAX		22
 #define PPI_VS_REQ_START	128
 #define PPI_VS_REQ_START	128
 #define PPI_VS_REQ_END		255
 #define PPI_VS_REQ_END		255
-#define PPI_VERSION_LEN		3
 
 
 static const u8 tpm_ppi_uuid[] = {
 static const u8 tpm_ppi_uuid[] = {
 	0xA6, 0xFA, 0xDD, 0x3D,
 	0xA6, 0xFA, 0xDD, 0x3D,
@@ -22,45 +40,22 @@ static const u8 tpm_ppi_uuid[] = {
 	0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
 	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 *
 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,
 static ssize_t tpm_show_ppi_version(struct device *dev,
 				    struct device_attribute *attr, char *buf)
 				    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,
 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;
 	ssize_t size = -EINVAL;
 	union acpi_object *obj;
 	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)
 	if (!obj)
 		return -ENXIO;
 		return -ENXIO;
 
 
@@ -103,14 +100,15 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
 	int func = TPM_PPI_FN_SUBREQ;
 	int func = TPM_PPI_FN_SUBREQ;
 	union acpi_object *obj, tmp;
 	union acpi_object *obj, tmp;
 	union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &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
 	 * the function to submit TPM operation request to pre-os environment
 	 * is updated with function index from SUBREQ to SUBREQ2 since PPI
 	 * is updated with function index from SUBREQ to SUBREQ2 since PPI
 	 * version 1.1
 	 * 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;
 		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
 	 * 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.
 	 * 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)
 		if (sscanf(buf, "%d", &req) != 1)
 			return -EINVAL;
 			return -EINVAL;
 		argv4.type = ACPI_TYPE_BUFFER;
 		argv4.type = ACPI_TYPE_BUFFER;
@@ -131,7 +129,8 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
 			return -EINVAL;
 			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) {
 	if (!obj) {
 		return -ENXIO;
 		return -ENXIO;
 	} else {
 	} else {
@@ -157,6 +156,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
 		.buffer.length = 0,
 		.buffer.length = 0,
 		.buffer.pointer = NULL
 		.buffer.pointer = NULL
 	};
 	};
+	struct tpm_chip *chip = dev_get_drvdata(dev);
 
 
 	static char *info[] = {
 	static char *info[] = {
 		"None",
 		"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
 	 * (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
 	 * 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 = &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) {
 	if (!obj) {
 		return -ENXIO;
 		return -ENXIO;
 	} else {
 	} else {
@@ -196,8 +197,10 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
 	acpi_status status = -EINVAL;
 	acpi_status status = -EINVAL;
 	union acpi_object *obj, *ret_obj;
 	union acpi_object *obj, *ret_obj;
 	u64 req, res;
 	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)
 	if (!obj)
 		return -ENXIO;
 		return -ENXIO;
 
 
@@ -248,7 +251,8 @@ cleanup:
 	return status;
 	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;
 	int i;
 	u32 ret;
 	u32 ret;
@@ -264,14 +268,15 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
 		"User not required",
 		"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))
 			    1 << TPM_PPI_FN_GETOPR))
 		return -EPERM;
 		return -EPERM;
 
 
 	tmp.integer.type = ACPI_TYPE_INTEGER;
 	tmp.integer.type = ACPI_TYPE_INTEGER;
 	for (i = start; i <= end; i++) {
 	for (i = start; i <= end; i++) {
 		tmp.integer.value = 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) {
 		if (!obj) {
 			return -ENOMEM;
 			return -ENOMEM;
 		} else {
 		} else {
@@ -291,14 +296,20 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
 					   struct device_attribute *attr,
 					   struct device_attribute *attr,
 					   char *buf)
 					   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,
 static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
 					  struct device_attribute *attr,
 					  struct device_attribute *attr,
 					  char *buf)
 					  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);
 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
 	.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->pdev->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->pdev->kobj, &ppi_attr_grp);
 }
 }

+ 190 - 86
drivers/char/tpm/tpm_tis.c

@@ -1,5 +1,6 @@
 /*
 /*
  * Copyright (C) 2005, 2006 IBM Corporation
  * Copyright (C) 2005, 2006 IBM Corporation
+ * Copyright (C) 2014 Intel Corporation
  *
  *
  * Authors:
  * Authors:
  * Leendert van Doorn <leendert@watson.ibm.com>
  * Leendert van Doorn <leendert@watson.ibm.com>
@@ -64,19 +65,30 @@ enum tis_defaults {
 	TIS_LONG_TIMEOUT = 2000,	/* 2 sec */
 	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_ACCESS(l)			(0x0000 | ((l) << 12))
 #define	TPM_INT_ENABLE(l)		(0x0008 | ((l) << 12))
 #define	TPM_INT_ENABLE(l)		(0x0008 | ((l) << 12))
 #define	TPM_INT_VECTOR(l)		(0x000C | ((l) << 12))
 #define	TPM_INT_VECTOR(l)		(0x000C | ((l) << 12))
 #define	TPM_INT_STATUS(l)		(0x0010 | ((l) << 12))
 #define	TPM_INT_STATUS(l)		(0x0010 | ((l) << 12))
 #define	TPM_INTF_CAPS(l)		(0x0014 | ((l) << 12))
 #define	TPM_INTF_CAPS(l)		(0x0014 | ((l) << 12))
 #define	TPM_STS(l)			(0x0018 | ((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_DATA_FIFO(l)		(0x0024 | ((l) << 12))
 
 
 #define	TPM_DID_VID(l)			(0x0F00 | ((l) << 12))
 #define	TPM_DID_VID(l)			(0x0F00 | ((l) << 12))
 #define	TPM_RID(l)			(0x0F04 | ((l) << 12))
 #define	TPM_RID(l)			(0x0F04 | ((l) << 12))
 
 
-static LIST_HEAD(tis_chips);
-static DEFINE_MUTEX(tis_lock);
+struct priv_data {
+	bool irq_tested;
+};
 
 
 #if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
 #if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
 static int is_itpm(struct pnp_dev *dev)
 static int is_itpm(struct pnp_dev *dev)
@@ -241,7 +253,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	/* read first 10 bytes, including tag, paramsize, and result */
 	/* read first 10 bytes, including tag, paramsize, and result */
 	if ((size =
 	if ((size =
 	     recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_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;
 		goto out;
 	}
 	}
 
 
@@ -254,7 +266,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	if ((size +=
 	if ((size +=
 	     recv_data(chip, &buf[TPM_HEADER_SIZE],
 	     recv_data(chip, &buf[TPM_HEADER_SIZE],
 		       expected - TPM_HEADER_SIZE)) < expected) {
 		       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;
 		size = -ETIME;
 		goto out;
 		goto out;
 	}
 	}
@@ -263,7 +275,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 			  &chip->vendor.int_queue, false);
 			  &chip->vendor.int_queue, false);
 	status = tpm_tis_status(chip);
 	status = tpm_tis_status(chip);
 	if (status & TPM_STS_DATA_AVAIL) {	/* retry? */
 	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;
 		size = -EIO;
 		goto out;
 		goto out;
 	}
 	}
@@ -338,15 +350,31 @@ out_err:
 	return rc;
 	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)
  * 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
  * tpm.c can skip polling for the data to be available as the interrupt is
  * waited for here
  * 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;
 	int rc;
 	u32 ordinal;
 	u32 ordinal;
+	unsigned long dur;
 
 
 	rc = tpm_tis_send_data(chip, buf, len);
 	rc = tpm_tis_send_data(chip, buf, len);
 	if (rc < 0)
 	if (rc < 0)
@@ -358,9 +386,14 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
 
 
 	if (chip->vendor.irq) {
 	if (chip->vendor.irq) {
 		ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
 		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
 		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) {
 		     &chip->vendor.read_queue, false) < 0) {
 			rc = -ETIME;
 			rc = -ETIME;
 			goto out_err;
 			goto out_err;
@@ -373,6 +406,30 @@ out_err:
 	return rc;
 	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->pdev,
+			FW_BUG "TPM interrupt not working, polling instead\n");
+	}
+	priv->irq_tested = true;
+	return rc;
+}
+
 struct tis_vendor_timeout_override {
 struct tis_vendor_timeout_override {
 	u32 did_vid;
 	u32 did_vid;
 	unsigned long timeout_us[4];
 	unsigned long timeout_us[4];
@@ -436,7 +493,7 @@ static int probe_itpm(struct tpm_chip *chip)
 
 
 	rc = tpm_tis_send_data(chip, cmd_getticks, len);
 	rc = tpm_tis_send_data(chip, cmd_getticks, len);
 	if (rc == 0) {
 	if (rc == 0) {
-		dev_info(chip->dev, "Detected an iTPM.\n");
+		dev_info(chip->pdev, "Detected an iTPM.\n");
 		rc = 1;
 		rc = 1;
 	} else
 	} else
 		rc = -EFAULT;
 		rc = -EFAULT;
@@ -505,6 +562,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
 	if (interrupt == 0)
 	if (interrupt == 0)
 		return IRQ_NONE;
 		return IRQ_NONE;
 
 
+	((struct priv_data *)chip->vendor.priv)->irq_tested = true;
 	if (interrupt & TPM_INTF_DATA_AVAIL_INT)
 	if (interrupt & TPM_INTF_DATA_AVAIL_INT)
 		wake_up_interruptible(&chip->vendor.read_queue);
 		wake_up_interruptible(&chip->vendor.read_queue);
 	if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT)
 	if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT)
@@ -528,27 +586,48 @@ static bool interrupts = true;
 module_param(interrupts, bool, 0444);
 module_param(interrupts, bool, 0444);
 MODULE_PARM_DESC(interrupts, "Enable interrupts");
 MODULE_PARM_DESC(interrupts, "Enable interrupts");
 
 
-static int tpm_tis_init(struct device *dev, resource_size_t start,
-			resource_size_t len, unsigned int irq)
+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, acpi_handle acpi_dev_handle,
+			resource_size_t start, resource_size_t len,
+			unsigned int irq)
 {
 {
 	u32 vendor, intfcaps, intmask;
 	u32 vendor, intfcaps, intmask;
 	int rc, i, irq_s, irq_e, probe;
 	int rc, i, irq_s, irq_e, probe;
 	struct tpm_chip *chip;
 	struct tpm_chip *chip;
+	struct priv_data *priv;
 
 
-	if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
-		return -ENODEV;
+	priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
 
 
-	chip->vendor.iobase = ioremap(start, len);
-	if (!chip->vendor.iobase) {
-		rc = -EIO;
-		goto out_err;
-	}
+	chip = tpmm_chip_alloc(dev, &tpm_tis);
+	if (IS_ERR(chip))
+		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) {
 	if (wait_startup(chip, 0) != 0) {
 		rc = -ENODEV;
 		rc = -ENODEV;
@@ -560,11 +639,18 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 		goto out_err;
 		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));
 	vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
 	chip->vendor.manufacturer_id = vendor;
 	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)));
 		 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
 
 
 	if (!itpm) {
 	if (!itpm) {
@@ -605,19 +691,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 	if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
 	if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
 		dev_dbg(dev, "\tData Avail Int Support\n");
 		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 */
 	/* INTERRUPT Setup */
 	init_waitqueue_head(&chip->vendor.read_queue);
 	init_waitqueue_head(&chip->vendor.read_queue);
 	init_waitqueue_head(&chip->vendor.int_queue);
 	init_waitqueue_head(&chip->vendor.int_queue);
@@ -649,10 +722,10 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 		for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
 		for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
 			iowrite8(i, chip->vendor.iobase +
 			iowrite8(i, chip->vendor.iobase +
 				 TPM_INT_VECTOR(chip->vendor.locality));
 				 TPM_INT_VECTOR(chip->vendor.locality));
-			if (request_irq
-			    (i, tis_int_probe, IRQF_SHARED,
-			     chip->vendor.miscdev.name, chip) != 0) {
-				dev_info(chip->dev,
+			if (devm_request_irq
+			    (dev, i, tis_int_probe, IRQF_SHARED,
+			     chip->devname, chip) != 0) {
+				dev_info(chip->pdev,
 					 "Unable to request irq: %d for probe\n",
 					 "Unable to request irq: %d for probe\n",
 					 i);
 					 i);
 				continue;
 				continue;
@@ -673,7 +746,10 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 			chip->vendor.probed_irq = 0;
 			chip->vendor.probed_irq = 0;
 
 
 			/* Generate Interrupts */
 			/* 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;
 			chip->vendor.irq = chip->vendor.probed_irq;
 
 
@@ -690,17 +766,16 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 			iowrite32(intmask,
 			iowrite32(intmask,
 				  chip->vendor.iobase +
 				  chip->vendor.iobase +
 				  TPM_INT_ENABLE(chip->vendor.locality));
 				  TPM_INT_ENABLE(chip->vendor.locality));
-			free_irq(i, chip);
 		}
 		}
 	}
 	}
 	if (chip->vendor.irq) {
 	if (chip->vendor.irq) {
 		iowrite8(chip->vendor.irq,
 		iowrite8(chip->vendor.irq,
 			 chip->vendor.iobase +
 			 chip->vendor.iobase +
 			 TPM_INT_VECTOR(chip->vendor.locality));
 			 TPM_INT_VECTOR(chip->vendor.locality));
-		if (request_irq
-		    (chip->vendor.irq, tis_int_handler, IRQF_SHARED,
-		     chip->vendor.miscdev.name, chip) != 0) {
-			dev_info(chip->dev,
+		if (devm_request_irq
+		    (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
+		     chip->devname, chip) != 0) {
+			dev_info(chip->pdev,
 				 "Unable to request irq: %d for use\n",
 				 "Unable to request irq: %d for use\n",
 				 chip->vendor.irq);
 				 chip->vendor.irq);
 			chip->vendor.irq = 0;
 			chip->vendor.irq = 0;
@@ -719,17 +794,49 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 		}
 		}
 	}
 	}
 
 
-	INIT_LIST_HEAD(&chip->vendor.list);
-	mutex_lock(&tis_lock);
-	list_add(&chip->vendor.list, &tis_chips);
-	mutex_unlock(&tis_lock);
+	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);
+
+		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;
+		}
 
 
-	return 0;
+		if (tpm_do_selftest(chip)) {
+			dev_err(dev, "TPM self test failed\n");
+			rc = -ENODEV;
+			goto out_err;
+		}
+	}
+
+	return tpm_chip_register(chip);
 out_err:
 out_err:
-	if (chip->vendor.iobase)
-		iounmap(chip->vendor.iobase);
-	tpm_remove_hardware(chip->dev);
+	tpm_tis_remove(chip);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -758,14 +865,23 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
 static int tpm_tis_resume(struct device *dev)
 static int tpm_tis_resume(struct device *dev)
 {
 {
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-	int ret;
+	int ret = 0;
 
 
 	if (chip->vendor.irq)
 	if (chip->vendor.irq)
 		tpm_tis_reenable_interrupts(chip);
 		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;
 	return ret;
 }
 }
@@ -779,6 +895,7 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
 {
 {
 	resource_size_t start, len;
 	resource_size_t start, len;
 	unsigned int irq = 0;
 	unsigned int irq = 0;
+	acpi_handle acpi_dev_handle = NULL;
 
 
 	start = pnp_mem_start(pnp_dev, 0);
 	start = pnp_mem_start(pnp_dev, 0);
 	len = pnp_mem_len(pnp_dev, 0);
 	len = pnp_mem_len(pnp_dev, 0);
@@ -791,7 +908,12 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
 	if (is_itpm(pnp_dev))
 	if (is_itpm(pnp_dev))
 		itpm = true;
 		itpm = true;
 
 
-	return tpm_tis_init(&pnp_dev->dev, start, len, irq);
+#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);
 }
 }
 
 
 static struct pnp_device_id tpm_pnp_tbl[] = {
 static struct pnp_device_id tpm_pnp_tbl[] = {
@@ -811,13 +933,10 @@ MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
 static void tpm_tis_pnp_remove(struct pnp_dev *dev)
 static void tpm_tis_pnp_remove(struct pnp_dev *dev)
 {
 {
 	struct tpm_chip *chip = pnp_get_drvdata(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 = {
 static struct pnp_driver tis_pnp_driver = {
 	.name = "tpm_tis",
 	.name = "tpm_tis",
 	.id_table = tpm_pnp_tbl,
 	.id_table = tpm_pnp_tbl,
@@ -836,7 +955,7 @@ MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
 
 
 static struct platform_driver tis_drv = {
 static struct platform_driver tis_drv = {
 	.driver = {
 	.driver = {
-		.name = "tpm_tis",
+		.name		= "tpm_tis",
 		.pm		= &tpm_tis_pm,
 		.pm		= &tpm_tis_pm,
 	},
 	},
 };
 };
@@ -862,7 +981,7 @@ static int __init init_tis(void)
 		rc = PTR_ERR(pdev);
 		rc = PTR_ERR(pdev);
 		goto err_dev;
 		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)
 	if (rc)
 		goto err_init;
 		goto err_init;
 	return 0;
 	return 0;
@@ -875,31 +994,16 @@ err_dev:
 
 
 static void __exit cleanup_tis(void)
 static void __exit cleanup_tis(void)
 {
 {
-	struct tpm_vendor_specific *i, *j;
 	struct tpm_chip *chip;
 	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
 #ifdef CONFIG_PNP
 	if (!force) {
 	if (!force) {
 		pnp_unregister_driver(&tis_pnp_driver);
 		pnp_unregister_driver(&tis_pnp_driver);
 		return;
 		return;
 	}
 	}
 #endif
 #endif
+	chip = dev_get_drvdata(&pdev->dev);
+	tpm_chip_unregister(chip);
+	tpm_tis_remove(chip);
 	platform_device_unregister(pdev);
 	platform_device_unregister(pdev);
 	platform_driver_unregister(&tis_drv);
 	platform_driver_unregister(&tis_drv);
 }
 }

+ 8 - 6
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;
 	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);
 	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)
 		const struct xenbus_device_id *id)
 {
 {
 	struct tpm_private *priv;
 	struct tpm_private *priv;
+	struct tpm_chip *chip;
 	int rv;
 	int rv;
 
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -302,21 +303,22 @@ static int tpmfront_probe(struct xenbus_device *dev,
 
 
 	rv = setup_ring(dev, priv);
 	rv = setup_ring(dev, priv);
 	if (rv) {
 	if (rv) {
-		tpm_remove_hardware(&dev->dev);
+		chip = dev_get_drvdata(&dev->dev);
+		tpm_chip_unregister(chip);
 		ring_free(priv);
 		ring_free(priv);
 		return rv;
 		return rv;
 	}
 	}
 
 
 	tpm_get_timeouts(priv->chip);
 	tpm_get_timeouts(priv->chip);
 
 
-	return rv;
+	return tpm_chip_register(priv->chip);
 }
 }
 
 
 static int tpmfront_remove(struct xenbus_device *dev)
 static int tpmfront_remove(struct xenbus_device *dev)
 {
 {
 	struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
 	struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
 	struct tpm_private *priv = TPM_VPRIV(chip);
 	struct tpm_private *priv = TPM_VPRIV(chip);
-	tpm_remove_hardware(&dev->dev);
+	tpm_chip_unregister(chip);
 	ring_free(priv);
 	ring_free(priv);
 	TPM_VPRIV(chip) = NULL;
 	TPM_VPRIV(chip) = NULL;
 	return 0;
 	return 0;

+ 8 - 30
drivers/char/tpm/tpm_i2c_stm_st33.h → include/linux/platform_data/tpm_stm_st33.h

@@ -12,9 +12,8 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  * 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 <http://www.gnu.org/licenses/>.
  *
  *
  * STMicroelectronics version 1.2.0, Copyright (C) 2010
  * STMicroelectronics version 1.2.0, Copyright (C) 2010
  * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
  * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
@@ -23,39 +22,18 @@
  *
  *
  * @Author: Christophe RICARD tpmsupport@st.com
  * @Author: Christophe RICARD tpmsupport@st.com
  *
  *
- * @File: stm_st33_tpm_i2c.h
+ * @File: stm_st33_tpm.h
  *
  *
  * @Date: 09/15/2010
  * @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_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"
+#define TPM_ST33_I2C			"st33zp24-i2c"
+#define TPM_ST33_SPI			"st33zp24-spi"
 
 
 struct st33zp24_platform_data {
 struct st33zp24_platform_data {
-	int io_serirq;
 	int io_lpcpd;
 	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__ */
+#endif /* __STM_ST33_TPM_H__ */

+ 16 - 9
include/net/cipso_ipv4.h

@@ -120,13 +120,6 @@ extern int cipso_v4_rbm_optfmt;
 extern int cipso_v4_rbm_strictvalid;
 extern int cipso_v4_rbm_strictvalid;
 #endif
 #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
  * DOI List Functions
  */
  */
@@ -190,7 +183,7 @@ static inline int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
 
 
 #ifdef CONFIG_NETLABEL
 #ifdef CONFIG_NETLABEL
 void cipso_v4_cache_invalidate(void);
 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);
 		       const struct netlbl_lsm_secattr *secattr);
 #else
 #else
 static inline void cipso_v4_cache_invalidate(void)
 static inline void cipso_v4_cache_invalidate(void)
@@ -198,7 +191,7 @@ static inline void cipso_v4_cache_invalidate(void)
 	return;
 	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)
 				     const struct netlbl_lsm_secattr *secattr)
 {
 {
 	return 0;
 	return 0;
@@ -211,6 +204,8 @@ static inline int cipso_v4_cache_add(const struct sk_buff *skb,
 
 
 #ifdef CONFIG_NETLABEL
 #ifdef CONFIG_NETLABEL
 void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
 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,
 int cipso_v4_sock_setattr(struct sock *sk,
 			  const struct cipso_v4_doi *doi_def,
 			  const struct cipso_v4_doi *doi_def,
 			  const struct netlbl_lsm_secattr *secattr);
 			  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_delattr(struct sk_buff *skb);
 int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
 int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
 			    struct netlbl_lsm_secattr *secattr);
 			    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);
 int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option);
 #else
 #else
 static inline void cipso_v4_error(struct sk_buff *skb,
 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;
 	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,
 static inline int cipso_v4_sock_setattr(struct sock *sk,
 				      const struct cipso_v4_doi *doi_def,
 				      const struct cipso_v4_doi *doi_def,
 				      const struct netlbl_lsm_secattr *secattr)
 				      const struct netlbl_lsm_secattr *secattr)
@@ -282,6 +284,11 @@ static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
 	return -ENOSYS;
 	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,
 static inline int cipso_v4_validate(const struct sk_buff *skb,
 				    unsigned char **option)
 				    unsigned char **option)
 {
 {

+ 1 - 1
kernel/Makefile

@@ -143,7 +143,7 @@ endif
 kernel/system_certificates.o: $(obj)/x509_certificate_list
 kernel/system_certificates.o: $(obj)/x509_certificate_list
 
 
 quiet_cmd_x509certs  = CERTS   $@
 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
 targets += $(obj)/x509_certificate_list
 $(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list
 $(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list

+ 4 - 6
lib/mpi/mpi-cmp.c

@@ -57,14 +57,12 @@ int mpi_cmp(MPI u, MPI v)
 	if (usize != vsize && !u->sign && !v->sign)
 	if (usize != vsize && !u->sign && !v->sign)
 		return usize - vsize;
 		return usize - vsize;
 	if (usize != vsize && u->sign && v->sign)
 	if (usize != vsize && u->sign && v->sign)
-		return vsize + usize;
+		return vsize - usize;
 	if (!usize)
 	if (!usize)
 		return 0;
 		return 0;
 	cmp = mpihelp_cmp(u->d, v->d, usize);
 	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);
 EXPORT_SYMBOL_GPL(mpi_cmp);

+ 1 - 1
lib/mpi/mpi-internal.h

@@ -84,7 +84,7 @@ static inline int RESIZE_IF_NEEDED(MPI a, unsigned b)
 	do {					\
 	do {					\
 		mpi_size_t _i;			\
 		mpi_size_t _i;			\
 		for (_i = 0; _i < (n); _i++)	\
 		for (_i = 0; _i < (n); _i++)	\
-			(d)[_i] = (d)[_i];	\
+			(d)[_i] = (s)[_i];	\
 	} while (0)
 	} while (0)
 
 
 #define MPN_COPY_DECR(d, s, n) \
 #define MPN_COPY_DECR(d, s, n) \

+ 30 - 21
net/ipv4/cipso_ipv4.c

@@ -378,20 +378,18 @@ static int cipso_v4_cache_check(const unsigned char *key,
  * negative values on failure.
  * 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)
 		       const struct netlbl_lsm_secattr *secattr)
 {
 {
 	int ret_val = -EPERM;
 	int ret_val = -EPERM;
 	u32 bkt;
 	u32 bkt;
 	struct cipso_v4_map_cache_entry *entry = NULL;
 	struct cipso_v4_map_cache_entry *entry = NULL;
 	struct cipso_v4_map_cache_entry *old_entry = NULL;
 	struct cipso_v4_map_cache_entry *old_entry = NULL;
-	unsigned char *cipso_ptr;
 	u32 cipso_ptr_len;
 	u32 cipso_ptr_len;
 
 
 	if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
 	if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
 		return 0;
 		return 0;
 
 
-	cipso_ptr = CIPSO_V4_OPTPTR(skb);
 	cipso_ptr_len = cipso_ptr[1];
 	cipso_ptr_len = cipso_ptr[1];
 
 
 	entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 	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;
 	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
  * cipso_v4_validate - Validate a CIPSO option
  * @option: the start of the option, on error it is set to point to the error
  * @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.
  * 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;
 	int ret_val = -ENOMSG;
 	u32 doi;
 	u32 doi;
@@ -2305,22 +2330,6 @@ int cipso_v4_skbuff_delattr(struct sk_buff *skb)
 	return 0;
 	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
  * Setup Functions
  */
  */

+ 10 - 5
net/netlabel/netlabel_kapi.c

@@ -1065,10 +1065,12 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
 			  u16 family,
 			  u16 family,
 			  struct netlbl_lsm_secattr *secattr)
 			  struct netlbl_lsm_secattr *secattr)
 {
 {
+	unsigned char *ptr;
+
 	switch (family) {
 	switch (family) {
 	case AF_INET:
 	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;
 			return 0;
 		break;
 		break;
 #if IS_ENABLED(CONFIG_IPV6)
 #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)
 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);
 		cipso_v4_error(skb, error, gateway);
 }
 }
 
 
@@ -1126,11 +1128,14 @@ void netlbl_cache_invalidate(void)
 int netlbl_cache_add(const struct sk_buff *skb,
 int netlbl_cache_add(const struct sk_buff *skb,
 		     const struct netlbl_lsm_secattr *secattr)
 		     const struct netlbl_lsm_secattr *secattr)
 {
 {
+	unsigned char *ptr;
+
 	if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
 	if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
 		return -ENOMSG;
 		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;
 	return -ENOMSG;
 }
 }

+ 19 - 11
scripts/asn1_compiler.c

@@ -311,6 +311,9 @@ struct token {
 
 
 static struct token *token_list;
 static struct token *token_list;
 static unsigned nr_tokens;
 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)
 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);
 	dlen = strlen(dir);
 	clen = (dlen < token->size) ? dlen : token->size;
 	clen = (dlen < token->size) ? dlen : token->size;
 
 
-	//printf("cmp(%*.*s,%s) = ",
+	//debug("cmp(%*.*s,%s) = ",
 	//       (int)token->size, (int)token->size, token->value,
 	//       (int)token->size, (int)token->size, token->value,
 	//       dir);
 	//       dir);
 
 
 	val = memcmp(token->value, dir, clen);
 	val = memcmp(token->value, dir, clen);
 	if (val != 0) {
 	if (val != 0) {
-		//printf("%d [cmp]\n", val);
+		//debug("%d [cmp]\n", val);
 		return val;
 		return val;
 	}
 	}
 
 
 	if (dlen == token->size) {
 	if (dlen == token->size) {
-		//printf("0\n");
+		//debug("0\n");
 		return 0;
 		return 0;
 	}
 	}
-	//printf("%d\n", (int)dlen - (int)token->size);
+	//debug("%d\n", (int)dlen - (int)token->size);
 	return dlen - token->size; /* shorter -> negative */
 	return dlen - token->size; /* shorter -> negative */
 }
 }
 
 
@@ -515,13 +518,13 @@ static void tokenise(char *buffer, char *end)
 	}
 	}
 
 
 	nr_tokens = tix;
 	nr_tokens = tix;
-	printf("Extracted %u tokens\n", nr_tokens);
+	debug("Extracted %u tokens\n", nr_tokens);
 
 
 #if 0
 #if 0
 	{
 	{
 		int n;
 		int n;
 		for (n = 0; n < nr_tokens; n++)
 		for (n = 0; n < nr_tokens; n++)
-			printf("Token %3u: '%*.*s'\n",
+			debug("Token %3u: '%*.*s'\n",
 			       n,
 			       n,
 			       (int)token_list[n].size, (int)token_list[n].size,
 			       (int)token_list[n].size, (int)token_list[n].size,
 			       token_list[n].value);
 			       token_list[n].value);
@@ -542,6 +545,7 @@ int main(int argc, char **argv)
 	ssize_t readlen;
 	ssize_t readlen;
 	FILE *out, *hdr;
 	FILE *out, *hdr;
 	char *buffer, *p;
 	char *buffer, *p;
+	char *kbuild_verbose;
 	int fd;
 	int fd;
 
 
 	if (argc != 4) {
 	if (argc != 4) {
@@ -550,6 +554,10 @@ int main(int argc, char **argv)
 		exit(2);
 		exit(2);
 	}
 	}
 
 
+	kbuild_verbose = getenv("KBUILD_VERBOSE");
+	if (kbuild_verbose)
+		verbose = atoi(kbuild_verbose);
+
 	filename = argv[1];
 	filename = argv[1];
 	outputname = argv[2];
 	outputname = argv[2];
 	headername = argv[3];
 	headername = argv[3];
@@ -748,11 +756,11 @@ static void build_type_list(void)
 
 
 	qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
 	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
 #if 0
 	for (n = 0; n < nr_types; n++) {
 	for (n = 0; n < nr_types; n++) {
 		struct type *type = type_index[n];
 		struct type *type = type_index[n];
-		printf("- %*.*s\n",
+		debug("- %*.*s\n",
 		       (int)type->name->size,
 		       (int)type->name->size,
 		       (int)type->name->size,
 		       (int)type->name->size,
 		       type->name->value);
 		       type->name->value);
@@ -793,7 +801,7 @@ static void parse(void)
 
 
 	} while (type++, !(type->flags & TYPE_STOP_MARKER));
 	} 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;
 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 */
 	/* We do two passes - the first one calculates all the offsets */
-	printf("Pass 1\n");
+	debug("Pass 1\n");
 	nr_entries = 0;
 	nr_entries = 0;
 	root = &type_list[0];
 	root = &type_list[0];
 	render_element(NULL, root->element, NULL);
 	render_element(NULL, root->element, NULL);
@@ -1295,7 +1303,7 @@ static void render(FILE *out, FILE *hdr)
 		e->flags &= ~ELEMENT_RENDERED;
 		e->flags &= ~ELEMENT_RENDERED;
 
 
 	/* And then we actually render */
 	/* And then we actually render */
-	printf("Pass 2\n");
+	debug("Pass 2\n");
 	fprintf(out, "\n");
 	fprintf(out, "\n");
 	fprintf(out, "static const unsigned char %s_machine[] = {\n",
 	fprintf(out, "static const unsigned char %s_machine[] = {\n",
 		grammar_name);
 		grammar_name);

+ 0 - 1
security/integrity/ima/Kconfig

@@ -126,7 +126,6 @@ config IMA_TRUSTED_KEYRING
 	bool "Require all keys on the .ima keyring be signed"
 	bool "Require all keys on the .ima keyring be signed"
 	depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
 	depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
 	depends on INTEGRITY_ASYMMETRIC_KEYS
 	depends on INTEGRITY_ASYMMETRIC_KEYS
-	select KEYS_DEBUG_PROC_KEYS
 	default y
 	default y
 	help
 	help
 	   This option requires that all keys added to the .ima
 	   This option requires that all keys added to the .ima

+ 0 - 18
security/keys/Kconfig

@@ -80,21 +80,3 @@ config ENCRYPTED_KEYS
 	  Userspace only ever sees/stores encrypted blobs.
 	  Userspace only ever sees/stores encrypted blobs.
 
 
 	  If you are unsure as to whether this is required, answer N.
 	  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.

+ 0 - 8
security/keys/proc.c

@@ -18,7 +18,6 @@
 #include <asm/errno.h>
 #include <asm/errno.h>
 #include "internal.h"
 #include "internal.h"
 
 
-#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
 static int proc_keys_open(struct inode *inode, struct file *file);
 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_start(struct seq_file *p, loff_t *_pos);
 static void *proc_keys_next(struct seq_file *p, void *v, 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,
 	.llseek		= seq_lseek,
 	.release	= seq_release,
 	.release	= seq_release,
 };
 };
-#endif
 
 
 static int proc_key_users_open(struct inode *inode, struct file *file);
 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);
 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;
 	struct proc_dir_entry *p;
 
 
-#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
 	p = proc_create("keys", 0, NULL, &proc_keys_fops);
 	p = proc_create("keys", 0, NULL, &proc_keys_fops);
 	if (!p)
 	if (!p)
 		panic("Cannot create /proc/keys\n");
 		panic("Cannot create /proc/keys\n");
-#endif
 
 
 	p = proc_create("key-users", 0, NULL, &proc_key_users_fops);
 	p = proc_create("key-users", 0, NULL, &proc_key_users_fops);
 	if (!p)
 	if (!p)
@@ -86,8 +82,6 @@ __initcall(key_proc_init);
  * Implement "/proc/keys" to provide a list of the keys on the system that
  * Implement "/proc/keys" to provide a list of the keys on the system that
  * grant View permission to the caller.
  * 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)
 static struct rb_node *key_serial_next(struct seq_file *p, struct rb_node *n)
 {
 {
 	struct user_namespace *user_ns = seq_user_ns(p);
 	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;
 	return 0;
 }
 }
 
 
-#endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */
-
 static struct rb_node *__key_user_next(struct user_namespace *user_ns, struct rb_node *n)
 static struct rb_node *__key_user_next(struct user_namespace *user_ns, struct rb_node *n)
 {
 {
 	while (n) {
 	while (n) {

+ 0 - 5
security/selinux/avc.c

@@ -517,11 +517,6 @@ out:
 	return rc;
 	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
  * avc_update_node Update an AVC entry
  * @event : Updating event
  * @event : Updating event

+ 8 - 21
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;
 	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)
 static int sb_finish_set_opts(struct super_block *sb)
@@ -456,10 +447,6 @@ static int sb_finish_set_opts(struct super_block *sb)
 	if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
 	if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
 		printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
 		printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
 		       sb->s_id, sb->s_type->name);
 		       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;
 	sbsec->flags |= SE_SBINITIALIZED;
 	if (selinux_is_sblabel_mnt(sb))
 	if (selinux_is_sblabel_mnt(sb))

+ 6 - 2
security/selinux/ss/policydb.c

@@ -289,12 +289,16 @@ static int policydb_init(struct policydb *p)
 		goto out;
 		goto out;
 
 
 	p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
 	p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
-	if (!p->filename_trans)
+	if (!p->filename_trans) {
+		rc = -ENOMEM;
 		goto out;
 		goto out;
+	}
 
 
 	p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
 	p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
-	if (!p->range_tr)
+	if (!p->range_tr) {
+		rc = -ENOMEM;
 		goto out;
 		goto out;
+	}
 
 
 	ebitmap_init(&p->filename_trans_ttypes);
 	ebitmap_init(&p->filename_trans_ttypes);
 	ebitmap_init(&p->policycaps);
 	ebitmap_init(&p->policycaps);

+ 12 - 0
security/smack/Kconfig

@@ -28,3 +28,15 @@ config SECURITY_SMACK_BRINGUP
 	  access rule set once the behavior is well understood.
 	  access rule set once the behavior is well understood.
 	  This is a superior mechanism to the oft abused
 	  This is a superior mechanism to the oft abused
 	  "permissive" mode of other systems.
 	  "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.

+ 1 - 0
security/smack/Makefile

@@ -5,3 +5,4 @@
 obj-$(CONFIG_SECURITY_SMACK) := smack.o
 obj-$(CONFIG_SECURITY_SMACK) := smack.o
 
 
 smack-y := smack_lsm.o smack_access.o smackfs.o
 smack-y := smack_lsm.o smack_access.o smackfs.o
+smack-$(CONFIG_SECURITY_SMACK_NETFILTER) += smack_netfilter.o

+ 11 - 0
security/smack/smack.h

@@ -248,6 +248,7 @@ struct smack_known *smk_find_entry(const char *);
 /*
 /*
  * Shared data.
  * Shared data.
  */
  */
+extern int smack_enabled;
 extern int smack_cipso_direct;
 extern int smack_cipso_direct;
 extern int smack_cipso_mapped;
 extern int smack_cipso_mapped;
 extern struct smack_known *smack_net_ambient;
 extern struct smack_known *smack_net_ambient;
@@ -298,6 +299,16 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
 	return tsp->smk_task;
 	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.
  * Present a pointer to the forked smack label entry in an task blob.
  */
  */

+ 147 - 52
security/smack/smack_lsm.c

@@ -43,8 +43,6 @@
 #include <linux/binfmts.h>
 #include <linux/binfmts.h>
 #include "smack.h"
 #include "smack.h"
 
 
-#define task_security(task)	(task_cred_xxx((task), security))
-
 #define TRANS_TRUE	"TRUE"
 #define TRANS_TRUE	"TRUE"
 #define TRANS_TRUE_SIZE	4
 #define TRANS_TRUE_SIZE	4
 
 
@@ -52,8 +50,11 @@
 #define SMK_RECEIVING	1
 #define SMK_RECEIVING	1
 #define SMK_SENDING	2
 #define SMK_SENDING	2
 
 
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
 LIST_HEAD(smk_ipv6_port_list);
 LIST_HEAD(smk_ipv6_port_list);
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
 static struct kmem_cache *smack_inode_cache;
 static struct kmem_cache *smack_inode_cache;
+int smack_enabled;
 
 
 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
 static void smk_bu_mode(int mode, char *s)
 static void smk_bu_mode(int mode, char *s)
@@ -120,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)
 static int smk_bu_task(struct task_struct *otp, int mode, int rc)
 {
 {
 	struct task_smack *tsp = current_security();
 	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];
 	char acc[SMK_NUM_ACCESS_TYPE + 1];
 
 
 	if (rc <= 0)
 	if (rc <= 0)
@@ -128,7 +129,7 @@ static int smk_bu_task(struct task_struct *otp, int mode, int rc)
 
 
 	smk_bu_mode(mode, acc);
 	smk_bu_mode(mode, acc);
 	pr_info("Smack Bringup: (%s %s %s) %s to %s\n",
 	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);
 		current->comm, otp->comm);
 	return 0;
 	return 0;
 }
 }
@@ -160,7 +161,7 @@ static int smk_bu_file(struct file *file, int mode, int rc)
 {
 {
 	struct task_smack *tsp = current_security();
 	struct task_smack *tsp = current_security();
 	struct smack_known *sskp = tsp->smk_task;
 	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];
 	char acc[SMK_NUM_ACCESS_TYPE + 1];
 
 
 	if (rc <= 0)
 	if (rc <= 0)
@@ -168,7 +169,7 @@ static int smk_bu_file(struct file *file, int mode, int rc)
 
 
 	smk_bu_mode(mode, acc);
 	smk_bu_mode(mode, acc);
 	pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %pD) %s\n",
 	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,
 		inode->i_sb->s_id, inode->i_ino, file,
 		current->comm);
 		current->comm);
 	return 0;
 	return 0;
@@ -202,6 +203,7 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file,
 
 
 /**
 /**
  * smk_fetch - Fetch the smack label from a file.
  * smk_fetch - Fetch the smack label from a file.
+ * @name: type of the label (attribute)
  * @ip: a pointer to the inode
  * @ip: a pointer to the inode
  * @dp: a pointer to the dentry
  * @dp: a pointer to the dentry
  *
  *
@@ -254,7 +256,9 @@ struct inode_smack *new_inode_smack(struct smack_known *skp)
 
 
 /**
 /**
  * new_task_smack - allocate a task security blob
  * 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
  * Returns the new blob or NULL if there's no memory available
  */
  */
@@ -277,8 +281,9 @@ static struct task_smack *new_task_smack(struct smack_known *task,
 
 
 /**
 /**
  * smk_copy_rules - copy a rule set
  * 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
  * Returns 0 on success, -ENOMEM on error
  */
  */
@@ -345,7 +350,8 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
 		saip = &ad;
 		saip = &ad;
 	}
 	}
 
 
-	tsp = task_security(tracer);
+	rcu_read_lock();
+	tsp = __task_cred(tracer)->security;
 	tracer_known = smk_of_task(tsp);
 	tracer_known = smk_of_task(tsp);
 
 
 	if ((mode & PTRACE_MODE_ATTACH) &&
 	if ((mode & PTRACE_MODE_ATTACH) &&
@@ -365,11 +371,14 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
 				  tracee_known->smk_known,
 				  tracee_known->smk_known,
 				  0, rc, saip);
 				  0, rc, saip);
 
 
+		rcu_read_unlock();
 		return rc;
 		return rc;
 	}
 	}
 
 
 	/* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
 	/* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */
 	rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip);
 	rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip);
+
+	rcu_read_unlock();
 	return rc;
 	return rc;
 }
 }
 
 
@@ -396,7 +405,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
 	if (rc != 0)
 	if (rc != 0)
 		return rc;
 		return rc;
 
 
-	skp = smk_of_task(task_security(ctp));
+	skp = smk_of_task_struct(ctp);
 
 
 	rc = smk_ptrace_rule_check(current, skp, mode, __func__);
 	rc = smk_ptrace_rule_check(current, skp, mode, __func__);
 	return rc;
 	return rc;
@@ -796,7 +805,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
 	if (name)
 	if (name)
 		*name = XATTR_SMACK_SUFFIX;
 		*name = XATTR_SMACK_SUFFIX;
 
 
-	if (value) {
+	if (value && len) {
 		rcu_read_lock();
 		rcu_read_lock();
 		may = smk_access_entry(skp->smk_known, dsp->smk_known,
 		may = smk_access_entry(skp->smk_known, dsp->smk_known,
 				       &skp->smk_rules);
 				       &skp->smk_rules);
@@ -817,10 +826,9 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
 		*value = kstrdup(isp->smk_known, GFP_NOFS);
 		*value = kstrdup(isp->smk_known, GFP_NOFS);
 		if (*value == NULL)
 		if (*value == NULL)
 			return -ENOMEM;
 			return -ENOMEM;
-	}
 
 
-	if (len)
 		*len = strlen(isp->smk_known);
 		*len = strlen(isp->smk_known);
+	}
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1344,6 +1352,9 @@ static int smack_file_permission(struct file *file, int mask)
  * The security blob for a file is a pointer to the master
  * The security blob for a file is a pointer to the master
  * label list, so no allocation is done.
  * 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
  * Returns 0
  */
  */
 static int smack_file_alloc_security(struct file *file)
 static int smack_file_alloc_security(struct file *file)
@@ -1381,17 +1392,18 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
 {
 {
 	int rc = 0;
 	int rc = 0;
 	struct smk_audit_info ad;
 	struct smk_audit_info ad;
+	struct inode *inode = file_inode(file);
 
 
 	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 	smk_ad_setfield_u_fs_path(&ad, file->f_path);
 	smk_ad_setfield_u_fs_path(&ad, file->f_path);
 
 
 	if (_IOC_DIR(cmd) & _IOC_WRITE) {
 	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);
 		rc = smk_bu_file(file, MAY_WRITE, rc);
 	}
 	}
 
 
 	if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) {
 	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);
 		rc = smk_bu_file(file, MAY_READ, rc);
 	}
 	}
 
 
@@ -1409,10 +1421,11 @@ static int smack_file_lock(struct file *file, unsigned int cmd)
 {
 {
 	struct smk_audit_info ad;
 	struct smk_audit_info ad;
 	int rc;
 	int rc;
+	struct inode *inode = file_inode(file);
 
 
 	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 	smk_ad_setfield_u_fs_path(&ad, file->f_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);
 	rc = smk_bu_file(file, MAY_LOCK, rc);
 	return rc;
 	return rc;
 }
 }
@@ -1434,7 +1447,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
 {
 {
 	struct smk_audit_info ad;
 	struct smk_audit_info ad;
 	int rc = 0;
 	int rc = 0;
-
+	struct inode *inode = file_inode(file);
 
 
 	switch (cmd) {
 	switch (cmd) {
 	case F_GETLK:
 	case F_GETLK:
@@ -1443,14 +1456,14 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
 	case F_SETLKW:
 	case F_SETLKW:
 		smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 		smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 		smk_ad_setfield_u_fs_path(&ad, file->f_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);
 		rc = smk_bu_file(file, MAY_LOCK, rc);
 		break;
 		break;
 	case F_SETOWN:
 	case F_SETOWN:
 	case F_SETSIG:
 	case F_SETSIG:
 		smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 		smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 		smk_ad_setfield_u_fs_path(&ad, file->f_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);
 		rc = smk_bu_file(file, MAY_WRITE, rc);
 		break;
 		break;
 	default:
 	default:
@@ -1568,14 +1581,10 @@ static int smack_mmap_file(struct file *file,
  * smack_file_set_fowner - set the file security blob value
  * smack_file_set_fowner - set the file security blob value
  * @file: object in question
  * @file: object in question
  *
  *
- * Returns 0
- * Further research may be required on this one.
  */
  */
 static void smack_file_set_fowner(struct file *file)
 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();
 }
 }
 
 
 /**
 /**
@@ -1627,6 +1636,7 @@ static int smack_file_receive(struct file *file)
 	int rc;
 	int rc;
 	int may = 0;
 	int may = 0;
 	struct smk_audit_info ad;
 	struct smk_audit_info ad;
+	struct inode *inode = file_inode(file);
 
 
 	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 	smk_ad_setfield_u_fs_path(&ad, file->f_path);
 	smk_ad_setfield_u_fs_path(&ad, file->f_path);
@@ -1638,7 +1648,7 @@ static int smack_file_receive(struct file *file)
 	if (file->f_mode & FMODE_WRITE)
 	if (file->f_mode & FMODE_WRITE)
 		may |= MAY_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);
 	rc = smk_bu_file(file, may, rc);
 	return rc;
 	return rc;
 }
 }
@@ -1658,21 +1668,17 @@ static int smack_file_receive(struct file *file)
 static int smack_file_open(struct file *file, const struct cred *cred)
 static int smack_file_open(struct file *file, const struct cred *cred)
 {
 {
 	struct task_smack *tsp = cred->security;
 	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;
 	struct smk_audit_info ad;
 	int rc;
 	int rc;
 
 
-	if (smack_privileged(CAP_MAC_OVERRIDE)) {
-		file->f_security = isp->smk_inode;
+	if (smack_privileged(CAP_MAC_OVERRIDE))
 		return 0;
 		return 0;
-	}
 
 
 	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 	smk_ad_setfield_u_fs_path(&ad, file->f_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);
 	rc = smk_bu_credfile(cred, file, MAY_READ, rc);
-	if (rc == 0)
-		file->f_security = isp->smk_inode;
 
 
 	return rc;
 	return rc;
 }
 }
@@ -1826,7 +1832,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
 				const char *caller)
 				const char *caller)
 {
 {
 	struct smk_audit_info ad;
 	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;
 	int rc;
 
 
 	smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
 	smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
@@ -1879,7 +1885,7 @@ static int smack_task_getsid(struct task_struct *p)
  */
  */
 static void smack_task_getsecid(struct task_struct *p, u32 *secid)
 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;
 	*secid = skp->smk_secid;
 }
 }
@@ -1986,7 +1992,7 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,
 {
 {
 	struct smk_audit_info ad;
 	struct smk_audit_info ad;
 	struct smack_known *skp;
 	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;
 	int rc;
 
 
 	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
 	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
@@ -2040,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)
 static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
 {
 {
 	struct inode_smack *isp = inode->i_security;
 	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;
 	isp->smk_inode = skp;
 }
 }
@@ -2212,6 +2218,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
 	return smack_netlabel(sk, sk_lbl);
 	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
  * smk_ipv6_port_label - Smack port access table management
  * @sock: socket
  * @sock: socket
@@ -2361,6 +2368,7 @@ auditout:
 	rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc);
 	rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc);
 	return rc;
 	return rc;
 }
 }
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
 
 
 /**
 /**
  * smack_inode_setsecurity - set smack xattrs
  * smack_inode_setsecurity - set smack xattrs
@@ -2421,8 +2429,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
 	} else
 	} else
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 
 
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
 	if (sock->sk->sk_family == PF_INET6)
 	if (sock->sk->sk_family == PF_INET6)
 		smk_ipv6_port_label(sock, NULL);
 		smk_ipv6_port_label(sock, NULL);
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
 
 
 	return 0;
 	return 0;
 }
 }
@@ -2450,6 +2460,7 @@ static int smack_socket_post_create(struct socket *sock, int family,
 	return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
 	return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
 }
 }
 
 
+#ifndef CONFIG_SECURITY_SMACK_NETFILTER
 /**
 /**
  * smack_socket_bind - record port binding information.
  * smack_socket_bind - record port binding information.
  * @sock: the socket
  * @sock: the socket
@@ -2463,11 +2474,14 @@ static int smack_socket_post_create(struct socket *sock, int family,
 static int smack_socket_bind(struct socket *sock, struct sockaddr *address,
 static int smack_socket_bind(struct socket *sock, struct sockaddr *address,
 				int addrlen)
 				int addrlen)
 {
 {
+#if IS_ENABLED(CONFIG_IPV6)
 	if (sock->sk != NULL && sock->sk->sk_family == PF_INET6)
 	if (sock->sk != NULL && sock->sk->sk_family == PF_INET6)
 		smk_ipv6_port_label(sock, address);
 		smk_ipv6_port_label(sock, address);
+#endif
 
 
 	return 0;
 	return 0;
 }
 }
+#endif /* !CONFIG_SECURITY_SMACK_NETFILTER */
 
 
 /**
 /**
  * smack_socket_connect - connect access check
  * smack_socket_connect - connect access check
@@ -2496,8 +2510,10 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
 	case PF_INET6:
 	case PF_INET6:
 		if (addrlen < sizeof(struct sockaddr_in6))
 		if (addrlen < sizeof(struct sockaddr_in6))
 			return -EINVAL;
 			return -EINVAL;
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
 		rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap,
 		rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap,
 						SMK_CONNECTING);
 						SMK_CONNECTING);
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
 		break;
 		break;
 	}
 	}
 	return rc;
 	return rc;
@@ -3033,7 +3049,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
 	 * of the superblock.
 	 * of the superblock.
 	 */
 	 */
 	if (opt_dentry->d_parent == opt_dentry) {
 	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,
 			 * The cgroup filesystem is never mounted,
 			 * so there's no opportunity to set the mount
 			 * so there's no opportunity to set the mount
@@ -3041,8 +3058,19 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
 			 */
 			 */
 			sbsp->smk_root = &smack_known_star;
 			sbsp->smk_root = &smack_known_star;
 			sbsp->smk_default = &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;
 		isp->smk_flags |= SMK_INODE_INSTANT;
 		goto unlockandout;
 		goto unlockandout;
 	}
 	}
@@ -3200,7 +3228,7 @@ unlockandout:
  */
  */
 static int smack_getprocattr(struct task_struct *p, char *name, char **value)
 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;
 	char *cp;
 	int slen;
 	int slen;
 
 
@@ -3297,7 +3325,7 @@ static int smack_unix_stream_connect(struct sock *sock,
 
 
 	if (!smack_privileged(CAP_MAC_OVERRIDE)) {
 	if (!smack_privileged(CAP_MAC_OVERRIDE)) {
 		skp = ssp->smk_out;
 		skp = ssp->smk_out;
-		okp = osp->smk_out;
+		okp = osp->smk_in;
 #ifdef CONFIG_AUDIT
 #ifdef CONFIG_AUDIT
 		smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
 		smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
 		smk_ad_setfield_u_net_sk(&ad, other);
 		smk_ad_setfield_u_net_sk(&ad, other);
@@ -3305,7 +3333,9 @@ static int smack_unix_stream_connect(struct sock *sock,
 		rc = smk_access(skp, okp, MAY_WRITE, &ad);
 		rc = smk_access(skp, okp, MAY_WRITE, &ad);
 		rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc);
 		rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc);
 		if (rc == 0) {
 		if (rc == 0) {
-			rc = smk_access(okp, skp, MAY_WRITE, NULL);
+			okp = osp->smk_out;
+			skp = ssp->smk_in;
+			rc = smk_access(okp, skp, MAY_WRITE, &ad);
 			rc = smk_bu_note("UDS connect", okp, skp,
 			rc = smk_bu_note("UDS connect", okp, skp,
 						MAY_WRITE, rc);
 						MAY_WRITE, rc);
 		}
 		}
@@ -3366,7 +3396,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
 				int size)
 				int size)
 {
 {
 	struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
 	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;
 	struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name;
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
 	int rc = 0;
 	int rc = 0;
 
 
 	/*
 	/*
@@ -3380,7 +3412,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
 		rc = smack_netlabel_send(sock->sk, sip);
 		rc = smack_netlabel_send(sock->sk, sip);
 		break;
 		break;
 	case AF_INET6:
 	case AF_INET6:
+#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
 		rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING);
 		rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING);
+#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */
 		break;
 		break;
 	}
 	}
 	return rc;
 	return rc;
@@ -3471,6 +3505,7 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
 	return smack_net_ambient;
 	return smack_net_ambient;
 }
 }
 
 
+#if IS_ENABLED(CONFIG_IPV6)
 static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
 static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
 {
 {
 	u8 nexthdr;
 	u8 nexthdr;
@@ -3517,6 +3552,7 @@ static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
 	}
 	}
 	return proto;
 	return proto;
 }
 }
+#endif /* CONFIG_IPV6 */
 
 
 /**
 /**
  * smack_socket_sock_rcv_skb - Smack packet delivery access check
  * smack_socket_sock_rcv_skb - Smack packet delivery access check
@@ -3529,15 +3565,30 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
 {
 	struct netlbl_lsm_secattr secattr;
 	struct netlbl_lsm_secattr secattr;
 	struct socket_smack *ssp = sk->sk_security;
 	struct socket_smack *ssp = sk->sk_security;
-	struct smack_known *skp;
-	struct sockaddr_in6 sadd;
+	struct smack_known *skp = NULL;
 	int rc = 0;
 	int rc = 0;
 	struct smk_audit_info ad;
 	struct smk_audit_info ad;
 #ifdef CONFIG_AUDIT
 #ifdef CONFIG_AUDIT
 	struct lsm_network_audit net;
 	struct lsm_network_audit net;
 #endif
 #endif
+#if IS_ENABLED(CONFIG_IPV6)
+	struct sockaddr_in6 sadd;
+	int proto;
+#endif /* CONFIG_IPV6 */
+
 	switch (sk->sk_family) {
 	switch (sk->sk_family) {
 	case PF_INET:
 	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.
 		 * Translate what netlabel gave us.
 		 */
 		 */
@@ -3551,6 +3602,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
 
 		netlbl_secattr_destroy(&secattr);
 		netlbl_secattr_destroy(&secattr);
 
 
+#ifdef CONFIG_SECURITY_SMACK_NETFILTER
+access_check:
+#endif
 #ifdef CONFIG_AUDIT
 #ifdef CONFIG_AUDIT
 		smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
 		smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
 		ad.a.u.net->family = sk->sk_family;
 		ad.a.u.net->family = sk->sk_family;
@@ -3569,14 +3623,32 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 		if (rc != 0)
 		if (rc != 0)
 			netlbl_skbuff_err(skb, rc, 0);
 			netlbl_skbuff_err(skb, rc, 0);
 		break;
 		break;
+#if IS_ENABLED(CONFIG_IPV6)
 	case PF_INET6:
 	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
 		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;
 		break;
+#endif /* CONFIG_IPV6 */
 	}
 	}
+
 	return rc;
 	return rc;
 }
 }
 
 
@@ -3638,16 +3710,25 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
 	if (skb != NULL) {
 	if (skb != NULL) {
 		if (skb->protocol == htons(ETH_P_IP))
 		if (skb->protocol == htons(ETH_P_IP))
 			family = PF_INET;
 			family = PF_INET;
+#if IS_ENABLED(CONFIG_IPV6)
 		else if (skb->protocol == htons(ETH_P_IPV6))
 		else if (skb->protocol == htons(ETH_P_IPV6))
 			family = PF_INET6;
 			family = PF_INET6;
+#endif /* CONFIG_IPV6 */
 	}
 	}
 	if (family == PF_UNSPEC && sock != NULL)
 	if (family == PF_UNSPEC && sock != NULL)
 		family = sock->sk->sk_family;
 		family = sock->sk->sk_family;
 
 
-	if (family == PF_UNIX) {
+	switch (family) {
+	case PF_UNIX:
 		ssp = sock->sk->sk_security;
 		ssp = sock->sk->sk_security;
 		s = ssp->smk_out->smk_secid;
 		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.
 		 * Translate what netlabel gave us.
 		 */
 		 */
@@ -3660,6 +3741,14 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
 			s = skp->smk_secid;
 			s = skp->smk_secid;
 		}
 		}
 		netlbl_secattr_destroy(&secattr);
 		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;
 	*secid = s;
 	if (s == 0)
 	if (s == 0)
@@ -3715,6 +3804,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
 	struct lsm_network_audit net;
 	struct lsm_network_audit net;
 #endif
 #endif
 
 
+#if IS_ENABLED(CONFIG_IPV6)
 	if (family == PF_INET6) {
 	if (family == PF_INET6) {
 		/*
 		/*
 		 * Handle mapped IPv4 packets arriving
 		 * Handle mapped IPv4 packets arriving
@@ -3726,6 +3816,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
 		else
 		else
 			return 0;
 			return 0;
 	}
 	}
+#endif /* CONFIG_IPV6 */
 
 
 	netlbl_secattr_init(&secattr);
 	netlbl_secattr_init(&secattr);
 	rc = netlbl_skbuff_getattr(skb, family, &secattr);
 	rc = netlbl_skbuff_getattr(skb, family, &secattr);
@@ -3834,11 +3925,11 @@ static void smack_key_free(struct key *key)
 	key->security = NULL;
 	key->security = NULL;
 }
 }
 
 
-/*
+/**
  * smack_key_permission - Smack access on a key
  * smack_key_permission - Smack access on a key
  * @key_ref: gets to the object
  * @key_ref: gets to the object
  * @cred: the credentials to use
  * @cred: the credentials to use
- * @perm: unused
+ * @perm: requested key permissions
  *
  *
  * Return 0 if the task has read and write to the object,
  * Return 0 if the task has read and write to the object,
  * an error code otherwise
  * an error code otherwise
@@ -4184,7 +4275,9 @@ struct security_operations smack_ops = {
 	.unix_may_send = 		smack_unix_may_send,
 	.unix_may_send = 		smack_unix_may_send,
 
 
 	.socket_post_create = 		smack_socket_post_create,
 	.socket_post_create = 		smack_socket_post_create,
+#ifndef CONFIG_SECURITY_SMACK_NETFILTER
 	.socket_bind =			smack_socket_bind,
 	.socket_bind =			smack_socket_bind,
+#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
 	.socket_connect =		smack_socket_connect,
 	.socket_connect =		smack_socket_connect,
 	.socket_sendmsg =		smack_socket_sendmsg,
 	.socket_sendmsg =		smack_socket_sendmsg,
 	.socket_sock_rcv_skb = 		smack_socket_sock_rcv_skb,
 	.socket_sock_rcv_skb = 		smack_socket_sock_rcv_skb,
@@ -4265,6 +4358,8 @@ static __init int smack_init(void)
 	if (!security_module_enable(&smack_ops))
 	if (!security_module_enable(&smack_ops))
 		return 0;
 		return 0;
 
 
+	smack_enabled = 1;
+
 	smack_inode_cache = KMEM_CACHE(inode_smack, 0);
 	smack_inode_cache = KMEM_CACHE(inode_smack, 0);
 	if (!smack_inode_cache)
 	if (!smack_inode_cache)
 		return -ENOMEM;
 		return -ENOMEM;

+ 96 - 0
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 <casey@schaufler-ca.com>
+ *
+ *  Copyright (C) 2014 Casey Schaufler <casey@schaufler-ca.com>
+ *  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 <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netdevice.h>
+#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);