All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 00/10] TPM 2.0 support
@ 2014-11-11 13:45 ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech, Jarkko Sakkinen

This patch set enables TPM2 protocol and provides drivers for FIFO and
CRB interfaces.

v2:
- Improved struct tpm_chip life-cycle by taking advantage of devres
  API.
- Refined sysfs attributes as simple key-values thereby not repeating
  mistakes in TPM1 sysfs attributes.
- Documented functions in tpm-chip.c and tpm2-cmd.c.
- Documented sysfs attributes.

v3:
- Lots of fixes in calling order in device drivers (thanks to Jason
  Gunthorpe for pointing these out!).
- Attach sysfs attributes to the misc device because it represents
  TPM device to the user space.

v4:
- Disable sysfs attibutes for TPM 2.0 for until we can sort out the 
  best approach for them.
- Fixed all the style issues found with checkpatch.pl.

v5:
- missing EXPORT_SYMBOL_GPL()
- own class for TPM devices used for TPM 2.0 devices and onwards.

v6:
- Non-racy initialization for sysfs attributes using struct device's
  groups field.
- The class 'tpm' is used now for all TPM devices. For the first device
  node major MISC_MAJOR and minor TPM_MINOR is used in order to retain
  backwards compatability.

v7:
- Release device number and free struct tpm_chip memory inside
  tpm_dev_release callback.
- Moved code from tpm-interface.c and tpm_dev.c to tpm-chip.c.

Opens:
- What we should do with PPI and BIOS log sysfs attributes?
  Can we associate them with the character device without
  breaking anything? Can we postpone this issue after
  this patch set has been pulled?

Jarkko Sakkinen (9):
  tpm: merge duplicate transmit_cmd() functions
  tpm: two-phase chip management functions
  tpm: fix multiple race conditions in tpm_ppi.c
  tpm: rename chip->dev to chip->pdev
  tpm: device class for tpm
  tpm: fix: move sysfs attributes to the correct place.
  tpm: TPM 2.0 baseline support
  tpm: TPM 2.0 CRB Interface
  tpm: TPM 2.0 sysfs attributes

Will Arthur (1):
  tpm: TPM 2.0 FIFO Interface

 Documentation/ABI/stable/sysfs-class-tpm2 |  57 +++
 drivers/char/tpm/Kconfig                  |   9 +
 drivers/char/tpm/Makefile                 |   3 +-
 drivers/char/tpm/tpm-chip.c               | 266 ++++++++++++++
 drivers/char/tpm/tpm-dev.c                |  44 +--
 drivers/char/tpm/tpm-interface.c          | 261 +++++---------
 drivers/char/tpm/tpm-sysfs.c              |  46 +--
 drivers/char/tpm/tpm.h                    | 134 ++++++-
 drivers/char/tpm/tpm2-cmd.c               | 566 ++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm2-sysfs.c             | 152 ++++++++
 drivers/char/tpm/tpm_atmel.c              |  25 +-
 drivers/char/tpm/tpm_crb.c                | 323 +++++++++++++++++
 drivers/char/tpm/tpm_i2c_atmel.c          |  49 +--
 drivers/char/tpm/tpm_i2c_infineon.c       |  43 +--
 drivers/char/tpm/tpm_i2c_nuvoton.c        |  68 ++--
 drivers/char/tpm/tpm_i2c_stm_st33.c       |  44 +--
 drivers/char/tpm/tpm_ibmvtpm.c            |  17 +-
 drivers/char/tpm/tpm_infineon.c           |  51 +--
 drivers/char/tpm/tpm_nsc.c                |  34 +-
 drivers/char/tpm/tpm_ppi.c                | 136 ++++---
 drivers/char/tpm/tpm_tis.c                | 180 ++++++----
 drivers/char/tpm/xen-tpmfront.c           |  14 +-
 22 files changed, 1920 insertions(+), 602 deletions(-)
 create mode 100644 Documentation/ABI/stable/sysfs-class-tpm2
 create mode 100644 drivers/char/tpm/tpm-chip.c
 create mode 100644 drivers/char/tpm/tpm2-cmd.c
 create mode 100644 drivers/char/tpm/tpm2-sysfs.c
 create mode 100644 drivers/char/tpm/tpm_crb.c

-- 
2.1.0


^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v7 00/10] TPM 2.0 support
@ 2014-11-11 13:45 ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Jarkko Sakkinen

This patch set enables TPM2 protocol and provides drivers for FIFO and
CRB interfaces.

v2:
- Improved struct tpm_chip life-cycle by taking advantage of devres
  API.
- Refined sysfs attributes as simple key-values thereby not repeating
  mistakes in TPM1 sysfs attributes.
- Documented functions in tpm-chip.c and tpm2-cmd.c.
- Documented sysfs attributes.

v3:
- Lots of fixes in calling order in device drivers (thanks to Jason
  Gunthorpe for pointing these out!).
- Attach sysfs attributes to the misc device because it represents
  TPM device to the user space.

v4:
- Disable sysfs attibutes for TPM 2.0 for until we can sort out the 
  best approach for them.
- Fixed all the style issues found with checkpatch.pl.

v5:
- missing EXPORT_SYMBOL_GPL()
- own class for TPM devices used for TPM 2.0 devices and onwards.

v6:
- Non-racy initialization for sysfs attributes using struct device's
  groups field.
- The class 'tpm' is used now for all TPM devices. For the first device
  node major MISC_MAJOR and minor TPM_MINOR is used in order to retain
  backwards compatability.

v7:
- Release device number and free struct tpm_chip memory inside
  tpm_dev_release callback.
- Moved code from tpm-interface.c and tpm_dev.c to tpm-chip.c.

Opens:
- What we should do with PPI and BIOS log sysfs attributes?
  Can we associate them with the character device without
  breaking anything? Can we postpone this issue after
  this patch set has been pulled?

Jarkko Sakkinen (9):
  tpm: merge duplicate transmit_cmd() functions
  tpm: two-phase chip management functions
  tpm: fix multiple race conditions in tpm_ppi.c
  tpm: rename chip->dev to chip->pdev
  tpm: device class for tpm
  tpm: fix: move sysfs attributes to the correct place.
  tpm: TPM 2.0 baseline support
  tpm: TPM 2.0 CRB Interface
  tpm: TPM 2.0 sysfs attributes

Will Arthur (1):
  tpm: TPM 2.0 FIFO Interface

 Documentation/ABI/stable/sysfs-class-tpm2 |  57 +++
 drivers/char/tpm/Kconfig                  |   9 +
 drivers/char/tpm/Makefile                 |   3 +-
 drivers/char/tpm/tpm-chip.c               | 266 ++++++++++++++
 drivers/char/tpm/tpm-dev.c                |  44 +--
 drivers/char/tpm/tpm-interface.c          | 261 +++++---------
 drivers/char/tpm/tpm-sysfs.c              |  46 +--
 drivers/char/tpm/tpm.h                    | 134 ++++++-
 drivers/char/tpm/tpm2-cmd.c               | 566 ++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm2-sysfs.c             | 152 ++++++++
 drivers/char/tpm/tpm_atmel.c              |  25 +-
 drivers/char/tpm/tpm_crb.c                | 323 +++++++++++++++++
 drivers/char/tpm/tpm_i2c_atmel.c          |  49 +--
 drivers/char/tpm/tpm_i2c_infineon.c       |  43 +--
 drivers/char/tpm/tpm_i2c_nuvoton.c        |  68 ++--
 drivers/char/tpm/tpm_i2c_stm_st33.c       |  44 +--
 drivers/char/tpm/tpm_ibmvtpm.c            |  17 +-
 drivers/char/tpm/tpm_infineon.c           |  51 +--
 drivers/char/tpm/tpm_nsc.c                |  34 +-
 drivers/char/tpm/tpm_ppi.c                | 136 ++++---
 drivers/char/tpm/tpm_tis.c                | 180 ++++++----
 drivers/char/tpm/xen-tpmfront.c           |  14 +-
 22 files changed, 1920 insertions(+), 602 deletions(-)
 create mode 100644 Documentation/ABI/stable/sysfs-class-tpm2
 create mode 100644 drivers/char/tpm/tpm-chip.c
 create mode 100644 drivers/char/tpm/tpm2-cmd.c
 create mode 100644 drivers/char/tpm/tpm2-sysfs.c
 create mode 100644 drivers/char/tpm/tpm_crb.c

-- 
2.1.0

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v7 01/10] tpm: merge duplicate transmit_cmd() functions
@ 2014-11-11 13:45   ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech, Jarkko Sakkinen

Merged transmit_cmd() functions in tpm-interface.c and tpm-sysfs.c.
Added "tpm_" prefix for consistency sake. Changed cmd parameter as
opaque. This enables to use separate command structures for TPM1
and TPM2 commands in future. Loose coupling works fine here.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/char/tpm/tpm-interface.c | 49 +++++++++++++++++++++-------------------
 drivers/char/tpm/tpm-sysfs.c     | 23 ++-----------------
 drivers/char/tpm/tpm.h           |  3 ++-
 3 files changed, 30 insertions(+), 45 deletions(-)

diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 6af1700..0150b7c 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -398,9 +398,10 @@ out:
 #define TPM_DIGEST_SIZE 20
 #define TPM_RET_CODE_IDX 6
 
-static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
-			    int len, const char *desc)
+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd,
+			 int len, const char *desc)
 {
+	struct tpm_output_header *header;
 	int err;
 
 	len = tpm_transmit(chip, (u8 *) cmd, len);
@@ -409,7 +410,9 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
 	else if (len < TPM_HEADER_SIZE)
 		return -EFAULT;
 
-	err = be32_to_cpu(cmd->header.out.return_code);
+	header = (struct tpm_output_header *) cmd;
+
+	err = be32_to_cpu(header->return_code);
 	if (err != 0 && desc)
 		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
 
@@ -448,7 +451,7 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
 		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 		tpm_cmd.params.getcap_in.subcap = subcap_id;
 	}
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
 	if (!rc)
 		*cap = tpm_cmd.params.getcap_out.cap;
 	return rc;
@@ -464,8 +467,8 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
 
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
-			"attempting to determine the timeouts");
+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+			      "attempting to determine the timeouts");
 }
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
 
@@ -484,8 +487,8 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
 	struct tpm_cmd_t start_cmd;
 	start_cmd.header.in = tpm_startup_header;
 	start_cmd.params.startup_in.startup_type = startup_type;
-	return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
-			    "attempting to start the TPM");
+	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
+				"attempting to start the TPM");
 }
 
 int tpm_get_timeouts(struct tpm_chip *chip)
@@ -500,7 +503,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
 
 	if (rc == TPM_ERR_INVALID_POSTINIT) {
 		/* The TPM is not started, we are the first to talk to it.
@@ -513,7 +516,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
-		rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+		rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
 				  NULL);
 	}
 	if (rc) {
@@ -575,8 +578,8 @@ duration:
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
 
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
-			"attempting to determine the durations");
+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+			      "attempting to determine the durations");
 	if (rc)
 		return rc;
 
@@ -631,8 +634,8 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
 	struct tpm_cmd_t cmd;
 
 	cmd.header.in = continue_selftest_header;
-	rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
-			  "continue selftest");
+	rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
+			      "continue selftest");
 	return rc;
 }
 
@@ -672,8 +675,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
 
 	cmd.header.in = pcrread_header;
 	cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
-	rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
-			  "attempting to read a pcr value");
+	rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
+			      "attempting to read a pcr value");
 
 	if (rc == 0)
 		memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
@@ -737,8 +740,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
 	cmd.header.in = pcrextend_header;
 	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
 	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
-	rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
-			  "attempting extend a PCR value");
+	rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+			      "attempting extend a PCR value");
 
 	tpm_chip_put(chip);
 	return rc;
@@ -817,7 +820,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
 	if (chip == NULL)
 		return -ENODEV;
 
-	rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
+	rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
 
 	tpm_chip_put(chip);
 	return rc;
@@ -938,14 +941,14 @@ int tpm_pm_suspend(struct device *dev)
 		cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
 		memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
 		       TPM_DIGEST_SIZE);
-		rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
-				  "extending dummy pcr before suspend");
+		rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+				      "extending dummy pcr before suspend");
 	}
 
 	/* now do the actual savestate */
 	for (try = 0; try < TPM_RETRY; try++) {
 		cmd.header.in = savestate_header;
-		rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
+		rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
 
 		/*
 		 * If the TPM indicates that it is too busy to respond to
@@ -1022,7 +1025,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 		tpm_cmd.header.in = tpm_getrandom_header;
 		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
 
-		err = transmit_cmd(chip, &tpm_cmd,
+		err = tpm_transmit_cmd(chip, &tpm_cmd,
 				   TPM_GETRANDOM_RESULT_SIZE + num_bytes,
 				   "attempting get random");
 		if (err)
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index 01730a2..8ecb052 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -20,25 +20,6 @@
 #include <linux/device.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 TPM_ORD_READPUBEK cpu_to_be32(124)
 static struct tpm_input_header tpm_readpubek_header = {
@@ -58,8 +39,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 
 	tpm_cmd.header.in = tpm_readpubek_header;
-	err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
-			   "attempting to read the PUBEK");
+	err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
+			       "attempting to read the PUBEK");
 	if (err)
 		goto out;
 
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index e4d0888..e638eb0 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -314,9 +314,10 @@ struct tpm_cmd_t {
 } __packed;
 
 ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
-
 ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 		     size_t bufsiz);
+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len,
+			 const char *desc);
 extern int tpm_get_timeouts(struct tpm_chip *);
 extern void tpm_gen_interrupt(struct tpm_chip *);
 extern int tpm_do_selftest(struct tpm_chip *);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 01/10] tpm: merge duplicate transmit_cmd() functions
@ 2014-11-11 13:45   ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Jarkko Sakkinen

Merged transmit_cmd() functions in tpm-interface.c and tpm-sysfs.c.
Added "tpm_" prefix for consistency sake. Changed cmd parameter as
opaque. This enables to use separate command structures for TPM1
and TPM2 commands in future. Loose coupling works fine here.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
 drivers/char/tpm/tpm-interface.c | 49 +++++++++++++++++++++-------------------
 drivers/char/tpm/tpm-sysfs.c     | 23 ++-----------------
 drivers/char/tpm/tpm.h           |  3 ++-
 3 files changed, 30 insertions(+), 45 deletions(-)

diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 6af1700..0150b7c 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -398,9 +398,10 @@ out:
 #define TPM_DIGEST_SIZE 20
 #define TPM_RET_CODE_IDX 6
 
-static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
-			    int len, const char *desc)
+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd,
+			 int len, const char *desc)
 {
+	struct tpm_output_header *header;
 	int err;
 
 	len = tpm_transmit(chip, (u8 *) cmd, len);
@@ -409,7 +410,9 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
 	else if (len < TPM_HEADER_SIZE)
 		return -EFAULT;
 
-	err = be32_to_cpu(cmd->header.out.return_code);
+	header = (struct tpm_output_header *) cmd;
+
+	err = be32_to_cpu(header->return_code);
 	if (err != 0 && desc)
 		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
 
@@ -448,7 +451,7 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
 		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 		tpm_cmd.params.getcap_in.subcap = subcap_id;
 	}
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
 	if (!rc)
 		*cap = tpm_cmd.params.getcap_out.cap;
 	return rc;
@@ -464,8 +467,8 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
 
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
-			"attempting to determine the timeouts");
+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+			      "attempting to determine the timeouts");
 }
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
 
@@ -484,8 +487,8 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
 	struct tpm_cmd_t start_cmd;
 	start_cmd.header.in = tpm_startup_header;
 	start_cmd.params.startup_in.startup_type = startup_type;
-	return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
-			    "attempting to start the TPM");
+	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
+				"attempting to start the TPM");
 }
 
 int tpm_get_timeouts(struct tpm_chip *chip)
@@ -500,7 +503,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
 
 	if (rc == TPM_ERR_INVALID_POSTINIT) {
 		/* The TPM is not started, we are the first to talk to it.
@@ -513,7 +516,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
-		rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+		rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
 				  NULL);
 	}
 	if (rc) {
@@ -575,8 +578,8 @@ duration:
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
 
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
-			"attempting to determine the durations");
+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+			      "attempting to determine the durations");
 	if (rc)
 		return rc;
 
@@ -631,8 +634,8 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
 	struct tpm_cmd_t cmd;
 
 	cmd.header.in = continue_selftest_header;
-	rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
-			  "continue selftest");
+	rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
+			      "continue selftest");
 	return rc;
 }
 
@@ -672,8 +675,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
 
 	cmd.header.in = pcrread_header;
 	cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
-	rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
-			  "attempting to read a pcr value");
+	rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
+			      "attempting to read a pcr value");
 
 	if (rc == 0)
 		memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
@@ -737,8 +740,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
 	cmd.header.in = pcrextend_header;
 	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
 	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
-	rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
-			  "attempting extend a PCR value");
+	rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+			      "attempting extend a PCR value");
 
 	tpm_chip_put(chip);
 	return rc;
@@ -817,7 +820,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
 	if (chip == NULL)
 		return -ENODEV;
 
-	rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
+	rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
 
 	tpm_chip_put(chip);
 	return rc;
@@ -938,14 +941,14 @@ int tpm_pm_suspend(struct device *dev)
 		cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
 		memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
 		       TPM_DIGEST_SIZE);
-		rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
-				  "extending dummy pcr before suspend");
+		rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+				      "extending dummy pcr before suspend");
 	}
 
 	/* now do the actual savestate */
 	for (try = 0; try < TPM_RETRY; try++) {
 		cmd.header.in = savestate_header;
-		rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
+		rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
 
 		/*
 		 * If the TPM indicates that it is too busy to respond to
@@ -1022,7 +1025,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 		tpm_cmd.header.in = tpm_getrandom_header;
 		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
 
-		err = transmit_cmd(chip, &tpm_cmd,
+		err = tpm_transmit_cmd(chip, &tpm_cmd,
 				   TPM_GETRANDOM_RESULT_SIZE + num_bytes,
 				   "attempting get random");
 		if (err)
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index 01730a2..8ecb052 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -20,25 +20,6 @@
 #include <linux/device.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 TPM_ORD_READPUBEK cpu_to_be32(124)
 static struct tpm_input_header tpm_readpubek_header = {
@@ -58,8 +39,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
 	struct tpm_chip *chip = dev_get_drvdata(dev);
 
 	tpm_cmd.header.in = tpm_readpubek_header;
-	err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
-			   "attempting to read the PUBEK");
+	err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
+			       "attempting to read the PUBEK");
 	if (err)
 		goto out;
 
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index e4d0888..e638eb0 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -314,9 +314,10 @@ struct tpm_cmd_t {
 } __packed;
 
 ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
-
 ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 		     size_t bufsiz);
+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len,
+			 const char *desc);
 extern int tpm_get_timeouts(struct tpm_chip *);
 extern void tpm_gen_interrupt(struct tpm_chip *);
 extern int tpm_do_selftest(struct tpm_chip *);
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 02/10] tpm: two-phase chip management functions
@ 2014-11-11 13:45   ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech, Jarkko Sakkinen

tpm_register_hardware() and tpm_remove_hardware() are called often
before initializing the device. This is wrong order since it could
be that main TPM driver needs a fully initialized chip to be able to
do its job. For example, now it is impossible to move common startup
functions such as tpm_do_selftest() to tpm_register_hardware().

Added tpmm_chip_alloc() and tpm_chip_register() where tpm_chip_alloc()
reserves memory resources and tpm_chip_register() initializes the
device driver. This way it is possible to alter struct tpm_chip
attributes and initialize the device driver before passing it to
tpm_chip_register().

The framework takes care of freeing struct tpm_chip by using devres
API. The broken release callback has been wiped. For example, ACPI
drivers do not ever get this callback.

This is a interm step to get proper life-cycle for TPM device drivers.
The next steps are adding proper ref counting and locking to tpm_chip
that is used in every place in the TPM driver.

Big thank you to Jason Gunthorpe for carefully reviewing this part
of the code. Without his contribution reaching the best quality would
not have been possible.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/char/tpm/Makefile           |   2 +-
 drivers/char/tpm/tpm-chip.c         | 196 ++++++++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm-interface.c    | 148 +--------------------------
 drivers/char/tpm/tpm.h              |  11 +-
 drivers/char/tpm/tpm_atmel.c        |  11 +-
 drivers/char/tpm/tpm_i2c_atmel.c    |  33 ++----
 drivers/char/tpm/tpm_i2c_infineon.c |  37 ++-----
 drivers/char/tpm/tpm_i2c_nuvoton.c  |  44 +++-----
 drivers/char/tpm/tpm_i2c_stm_st33.c |  38 +++----
 drivers/char/tpm/tpm_ibmvtpm.c      |  17 ++--
 drivers/char/tpm/tpm_infineon.c     |  29 +++---
 drivers/char/tpm/tpm_nsc.c          |  14 ++-
 drivers/char/tpm/tpm_tis.c          |  78 ++++++--------
 drivers/char/tpm/xen-tpmfront.c     |  14 +--
 14 files changed, 329 insertions(+), 343 deletions(-)
 create mode 100644 drivers/char/tpm/tpm-chip.c

diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 4d85dd6..837da04 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the kernel tpm device drivers.
 #
 obj-$(CONFIG_TCG_TPM) += tpm.o
-tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o
+tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o
 tpm-$(CONFIG_ACPI) += tpm_ppi.o
 
 ifdef CONFIG_ACPI
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
new file mode 100644
index 0000000..cf3ad24
--- /dev/null
+++ b/drivers/char/tpm/tpm-chip.c
@@ -0,0 +1,196 @@
+/*
+ * 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 "tpm.h"
+#include "tpm_eventlog.h"
+
+static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
+static LIST_HEAD(tpm_chip_list);
+static DEFINE_SPINLOCK(driver_lock);
+
+/*
+ * tpm_chip_find_get - return tpm_chip for a given chip number
+ * @chip_num the device number for the chip
+ */
+struct tpm_chip *tpm_chip_find_get(int chip_num)
+{
+	struct tpm_chip *pos, *chip = NULL;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
+		if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
+			continue;
+
+		if (try_module_get(pos->dev->driver->owner)) {
+			chip = pos;
+			break;
+		}
+	}
+	rcu_read_unlock();
+	return chip;
+}
+
+/**
+ * tpmm_chip_remove() - free chip memory and device number
+ * @data: points to struct tpm_chip instance
+ *
+ * This is used internally by tpmm_chip_alloc() and called by devres
+ * when the device is released. This function does the opposite of
+ * tpmm_chip_alloc() freeing memory and the device number.
+ */
+static void tpmm_chip_remove(void *data)
+{
+	struct tpm_chip *chip = (struct tpm_chip *) data;
+
+	spin_lock(&driver_lock);
+	clear_bit(chip->dev_num, dev_mask);
+	spin_unlock(&driver_lock);
+	kfree(chip);
+}
+
+/**
+ * tpmm_chip_alloc() - allocate a new struct tpm_chip instance
+ * @dev: device to which the chip is associated
+ * @ops: struct tpm_class_ops instance
+ *
+ * Allocates a new struct tpm_chip instance and assigns a free
+ * device number for it. Caller does not have to worry about
+ * freeing the allocated resources. When the devices is removed
+ * devres calls tpmm_chip_remove() to do the job.
+ */
+struct tpm_chip *tpmm_chip_alloc(struct device *dev,
+				 const struct tpm_class_ops *ops)
+{
+	struct tpm_chip *chip;
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_init(&chip->tpm_mutex);
+	INIT_LIST_HEAD(&chip->list);
+
+	chip->ops = ops;
+
+	spin_lock(&driver_lock);
+	chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
+	spin_unlock(&driver_lock);
+
+	if (chip->dev_num >= TPM_NUM_DEVICES) {
+		dev_err(dev, "No available tpm device numbers\n");
+		kfree(chip);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	set_bit(chip->dev_num, dev_mask);
+
+	scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm",
+		  chip->dev_num);
+
+	chip->dev = dev;
+	devm_add_action(dev, tpmm_chip_remove, chip);
+	dev_set_drvdata(dev, chip);
+
+	return chip;
+}
+EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
+
+/*
+ * tpm_chip_register() - create a misc driver for the TPM chip
+ * @chip: TPM chip to use.
+ *
+ * Creates a misc driver for the TPM chip and adds sysfs interfaces for
+ * the device, PPI and TCPA. As the last step this function adds the
+ * chip to the list of TPM chips available for use.
+ *
+ * NOTE: This function should be only called after the chip initialization
+ * is complete.
+ *
+ * Called from tpm_<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;
+
+	rc = tpm_sysfs_add_device(chip);
+	if (rc)
+		goto del_misc;
+
+	rc = tpm_add_ppi(&chip->dev->kobj);
+	if (rc)
+		goto del_sysfs;
+
+	chip->bios_dir = tpm_bios_log_setup(chip->devname);
+
+	/* Make the chip available. */
+	spin_lock(&driver_lock);
+	list_add_rcu(&chip->list, &tpm_chip_list);
+	spin_unlock(&driver_lock);
+
+	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)
+{
+	spin_lock(&driver_lock);
+	list_del_rcu(&chip->list);
+	spin_unlock(&driver_lock);
+	synchronize_rcu();
+
+	tpm_sysfs_del_device(chip);
+	tpm_remove_ppi(&chip->dev->kobj);
+
+	if (chip->bios_dir)
+		tpm_bios_log_teardown(chip->bios_dir);
+
+	tpm_dev_del_device(chip);
+}
+EXPORT_SYMBOL_GPL(tpm_chip_unregister);
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 0150b7c..915c610 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2014 Intel Corporation
  *
  * Authors:
  * Leendert van Doorn <leendert@watson.ibm.com>
@@ -47,10 +48,6 @@ module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
 MODULE_PARM_DESC(suspend_pcr,
 		 "PCR to use for dummy writes to faciltate flush on suspend.");
 
-static LIST_HEAD(tpm_chip_list);
-static DEFINE_SPINLOCK(driver_lock);
-static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
-
 /*
  * Array with one entry per ordinal defining the maximum amount
  * of time the chip could take to return the result.  The ordinal
@@ -639,27 +636,6 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
 	return rc;
 }
 
-/*
- * tpm_chip_find_get - return tpm_chip for given chip number
- */
-static struct tpm_chip *tpm_chip_find_get(int chip_num)
-{
-	struct tpm_chip *pos, *chip = NULL;
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
-		if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
-			continue;
-
-		if (try_module_get(pos->dev->driver->owner)) {
-			chip = pos;
-			break;
-		}
-	}
-	rcu_read_unlock();
-	return chip;
-}
-
 #define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
 #define READ_PCR_RESULT_SIZE 30
 static struct tpm_input_header pcrread_header = {
@@ -887,30 +863,6 @@ again:
 }
 EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
 
-void tpm_remove_hardware(struct device *dev)
-{
-	struct tpm_chip *chip = dev_get_drvdata(dev);
-
-	if (chip == NULL) {
-		dev_err(dev, "No device data found\n");
-		return;
-	}
-
-	spin_lock(&driver_lock);
-	list_del_rcu(&chip->list);
-	spin_unlock(&driver_lock);
-	synchronize_rcu();
-
-	tpm_dev_del_device(chip);
-	tpm_sysfs_del_device(chip);
-	tpm_remove_ppi(&dev->kobj);
-	tpm_bios_log_teardown(chip->bios_dir);
-
-	/* write it this way to be explicit (chip->dev == dev) */
-	put_device(chip->dev);
-}
-EXPORT_SYMBOL_GPL(tpm_remove_hardware);
-
 #define TPM_ORD_SAVESTATE cpu_to_be32(152)
 #define SAVESTATE_RESULT_SIZE 10
 
@@ -1044,104 +996,6 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 }
 EXPORT_SYMBOL_GPL(tpm_get_random);
 
-/* In case vendor provided release function, call it too.*/
-
-void tpm_dev_vendor_release(struct tpm_chip *chip)
-{
-	if (!chip)
-		return;
-
-	clear_bit(chip->dev_num, dev_mask);
-}
-EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
-
-
-/*
- * Once all references to platform device are down to 0,
- * release all allocated structures.
- */
-static void tpm_dev_release(struct device *dev)
-{
-	struct tpm_chip *chip = dev_get_drvdata(dev);
-
-	if (!chip)
-		return;
-
-	tpm_dev_vendor_release(chip);
-
-	chip->release(dev);
-	kfree(chip);
-}
-
-/*
- * Called from tpm_<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)
-{
-	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;
-}
-EXPORT_SYMBOL_GPL(tpm_register_hardware);
-
 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
 MODULE_DESCRIPTION("TPM Driver");
 MODULE_VERSION("2.0");
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index e638eb0..9880681 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -110,7 +110,6 @@ struct tpm_chip {
 	struct dentry **bios_dir;
 
 	struct list_head list;
-	void (*release) (struct device *);
 };
 
 #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
@@ -322,15 +321,17 @@ extern int tpm_get_timeouts(struct tpm_chip *);
 extern void tpm_gen_interrupt(struct tpm_chip *);
 extern int tpm_do_selftest(struct tpm_chip *);
 extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
-extern struct tpm_chip* tpm_register_hardware(struct device *,
-					      const struct tpm_class_ops *ops);
-extern void tpm_dev_vendor_release(struct tpm_chip *);
-extern void tpm_remove_hardware(struct device *);
 extern int tpm_pm_suspend(struct device *);
 extern int tpm_pm_resume(struct device *);
 extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
 			     wait_queue_head_t *, bool);
 
+struct tpm_chip *tpm_chip_find_get(int chip_num);
+extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
+				       const struct tpm_class_ops *ops);
+extern int tpm_chip_register(struct tpm_chip *chip);
+extern void tpm_chip_unregister(struct tpm_chip *chip);
+
 int tpm_dev_add_device(struct tpm_chip *chip);
 void tpm_dev_del_device(struct tpm_chip *chip);
 int tpm_sysfs_add_device(struct tpm_chip *chip);
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index 6069d13..8e2576a 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -138,11 +138,11 @@ static void atml_plat_remove(void)
 	struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
 
 	if (chip) {
+		tpm_chip_unregister(chip);
 		if (chip->vendor.have_region)
 			atmel_release_region(chip->vendor.base,
 					     chip->vendor.region_size);
 		atmel_put_base_addr(chip->vendor.iobase);
-		tpm_remove_hardware(chip->dev);
 		platform_device_unregister(pdev);
 	}
 }
@@ -184,8 +184,9 @@ static int __init init_atmel(void)
 		goto err_rel_reg;
 	}
 
-	if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) {
-		rc = -ENODEV;
+	chip = tpmm_chip_alloc(&pdev->dev, &tpm_atmel);
+	if (IS_ERR(chip)) {
+		rc = PTR_ERR(chip);
 		goto err_unreg_dev;
 	}
 
@@ -194,6 +195,10 @@ static int __init init_atmel(void)
 	chip->vendor.have_region = have_region;
 	chip->vendor.region_size = region_size;
 
+	rc = tpm_chip_register(chip);
+	if (rc)
+		goto err_unreg_dev;
+
 	return 0;
 
 err_unreg_dev:
diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c
index 7727292..8af3b4a 100644
--- a/drivers/char/tpm/tpm_i2c_atmel.c
+++ b/drivers/char/tpm/tpm_i2c_atmel.c
@@ -160,11 +160,9 @@ static int i2c_atmel_probe(struct i2c_client *client,
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 		return -ENODEV;
 
-	chip = tpm_register_hardware(dev, &i2c_atmel);
-	if (!chip) {
-		dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
-		return -ENODEV;
-	}
+	chip = tpmm_chip_alloc(dev, &i2c_atmel);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 	chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
 					 GFP_KERNEL);
@@ -179,21 +177,16 @@ static int i2c_atmel_probe(struct i2c_client *client,
 	/* There is no known way to probe for this device, and all version
 	 * information seems to be read via TPM commands. Thus we rely on the
 	 * TPM startup process in the common code to detect the device. */
-	if (tpm_get_timeouts(chip)) {
-		rc = -ENODEV;
-		goto out_err;
-	}
+	if (tpm_get_timeouts(chip))
+		return -ENODEV;
 
-	if (tpm_do_selftest(chip)) {
-		rc = -ENODEV;
-		goto out_err;
-	}
+	if (tpm_do_selftest(chip))
+		return -ENODEV;
 
-	return 0;
+	rc = tpm_chip_register(chip);
+	if (rc)
+		return rc;
 
-out_err:
-	tpm_dev_vendor_release(chip);
-	tpm_remove_hardware(chip->dev);
 	return rc;
 }
 
@@ -201,11 +194,7 @@ static int i2c_atmel_remove(struct i2c_client *client)
 {
 	struct device *dev = &(client->dev);
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-
-	if (chip)
-		tpm_dev_vendor_release(chip);
-	tpm_remove_hardware(dev);
-	kfree(chip);
+	tpm_chip_unregister(chip);
 	return 0;
 }
 
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
index 472af4b..03708e6 100644
--- a/drivers/char/tpm/tpm_i2c_infineon.c
+++ b/drivers/char/tpm/tpm_i2c_infineon.c
@@ -581,12 +581,9 @@ static int tpm_tis_i2c_init(struct device *dev)
 	int rc = 0;
 	struct tpm_chip *chip;
 
-	chip = tpm_register_hardware(dev, &tpm_tis_i2c);
-	if (!chip) {
-		dev_err(dev, "could not register hardware\n");
-		rc = -ENODEV;
-		goto out_err;
-	}
+	chip = tpmm_chip_alloc(dev, &tpm_tis_i2c);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 	/* Disable interrupts */
 	chip->vendor.irq = 0;
@@ -600,7 +597,7 @@ static int tpm_tis_i2c_init(struct device *dev)
 	if (request_locality(chip, 0) != 0) {
 		dev_err(dev, "could not request locality\n");
 		rc = -ENODEV;
-		goto out_vendor;
+		goto out_err;
 	}
 
 	/* read four bytes from DID_VID register */
@@ -628,21 +625,9 @@ static int tpm_tis_i2c_init(struct device *dev)
 	tpm_get_timeouts(chip);
 	tpm_do_selftest(chip);
 
-	return 0;
-
+	return tpm_chip_register(chip);
 out_release:
 	release_locality(chip, chip->vendor.locality, 1);
-
-out_vendor:
-	/* close file handles */
-	tpm_dev_vendor_release(chip);
-
-	/* remove hardware */
-	tpm_remove_hardware(chip->dev);
-
-	/* reset these pointers, otherwise we oops */
-	chip->dev->release = NULL;
-	chip->release = NULL;
 	tpm_dev.client = NULL;
 out_err:
 	return rc;
@@ -712,17 +697,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client,
 static int tpm_tis_i2c_remove(struct i2c_client *client)
 {
 	struct tpm_chip *chip = tpm_dev.chip;
-	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;
 
 	return 0;
diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c
index 7b158ef..09f0c46 100644
--- a/drivers/char/tpm/tpm_i2c_nuvoton.c
+++ b/drivers/char/tpm/tpm_i2c_nuvoton.c
@@ -530,11 +530,9 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
 	dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid,
 		 (u8) (vid >> 16), (u8) (vid >> 24));
 
-	chip = tpm_register_hardware(dev, &tpm_i2c);
-	if (!chip) {
-		dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
-		return -ENODEV;
-	}
+	chip = tpmm_chip_alloc(dev, &tpm_i2c);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 	chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
 					 GFP_KERNEL);
@@ -584,7 +582,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
 							   TPM_DATA_FIFO_W,
 							   1, (u8 *) (&rc));
 				if (rc < 0)
-					goto out_err;
+					return rc;
 				/* TPM_STS <- 0x40 (commandReady) */
 				i2c_nuvoton_ready(chip);
 			} else {
@@ -594,45 +592,33 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
 				 * only TPM_STS_VALID should be set
 				 */
 				if (i2c_nuvoton_read_status(chip) !=
-				    TPM_STS_VALID) {
-					rc = -EIO;
-					goto out_err;
-				}
+				    TPM_STS_VALID)
+					return -EIO;
 			}
 		}
 	}
 
-	if (tpm_get_timeouts(chip)) {
-		rc = -ENODEV;
-		goto out_err;
-	}
+	if (tpm_get_timeouts(chip))
+		return -ENODEV;
 
-	if (tpm_do_selftest(chip)) {
-		rc = -ENODEV;
-		goto out_err;
-	}
+	if (tpm_do_selftest(chip))
+		return -ENODEV;
 
-	return 0;
+	rc = tpm_chip_register(chip);
+	if (rc)
+		return rc;
 
-out_err:
-	tpm_dev_vendor_release(chip);
-	tpm_remove_hardware(chip->dev);
-	return rc;
+	return 0;
 }
 
 static int i2c_nuvoton_remove(struct i2c_client *client)
 {
 	struct device *dev = &(client->dev);
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-
-	if (chip)
-		tpm_dev_vendor_release(chip);
-	tpm_remove_hardware(dev);
-	kfree(chip);
+	tpm_chip_unregister(chip);
 	return 0;
 }
 
-
 static const struct i2c_device_id i2c_nuvoton_id[] = {
 	{I2C_DRIVER_NAME, 0},
 	{}
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index 4669e37..b9d1a38 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -609,37 +609,29 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	if (client == NULL) {
 		pr_info("%s: i2c client is NULL. Device not accessible.\n",
 			__func__);
-		err = -ENODEV;
-		goto end;
+		return -ENODEV;
 	}
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		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;
-	}
+	chip = tpmm_chip_alloc(&client->dev, &st_i2c_tpm);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 	platform_data = client->dev.platform_data;
 
 	if (!platform_data) {
 		dev_info(&client->dev, "chip not available\n");
-		err = -ENODEV;
-		goto _tpm_clean_answer;
+		return -ENODEV;
 	}
 
 	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;
-	}
+	if (platform_data->tpm_i2c_buffer[0] == NULL)
+		return -ENOMEM;
 	platform_data->tpm_i2c_buffer[1] =
 	    kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
 	if (platform_data->tpm_i2c_buffer[1] == NULL) {
@@ -716,8 +708,10 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	tpm_get_timeouts(chip);
 	tpm_do_selftest(chip);
 
-	dev_info(chip->dev, "TPM I2C Initialized\n");
-	return 0;
+	err = tpm_chip_register(chip);
+	if (!err)
+		return 0;
+
 _irq_set:
 	free_irq(gpio_to_irq(platform_data->io_serirq), (void *)chip);
 _gpio_init2:
@@ -732,10 +726,6 @@ _tpm_clean_response2:
 _tpm_clean_response1:
 	kzfree(platform_data->tpm_i2c_buffer[0]);
 	platform_data->tpm_i2c_buffer[0] = NULL;
-_tpm_clean_answer:
-	tpm_remove_hardware(chip->dev);
-end:
-	pr_info("TPM I2C initialisation fail\n");
 	return err;
 }
 
@@ -752,13 +742,13 @@ static int tpm_st33_i2c_remove(struct i2c_client *client)
 		((struct i2c_client *)TPM_VPRIV(chip))->dev.platform_data;
 
 	if (pin_infos != NULL) {
+		tpm_chip_unregister(chip);
+
 		free_irq(pin_infos->io_serirq, chip);
 
 		gpio_free(pin_infos->io_serirq);
 		gpio_free(pin_infos->io_lpcpd);
 
-		tpm_remove_hardware(chip->dev);
-
 		if (pin_infos->tpm_i2c_buffer[1] != NULL) {
 			kzfree(pin_infos->tpm_i2c_buffer[1]);
 			pin_infos->tpm_i2c_buffer[1] = NULL;
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
index af74c57..eb95796 100644
--- a/drivers/char/tpm/tpm_ibmvtpm.c
+++ b/drivers/char/tpm/tpm_ibmvtpm.c
@@ -270,8 +270,11 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
 static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
 {
 	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
+	struct tpm_chip *chip = dev_get_drvdata(ibmvtpm->dev);
 	int rc = 0;
 
+	tpm_chip_unregister(chip);
+
 	free_irq(vdev->irq, ibmvtpm);
 
 	do {
@@ -290,8 +293,6 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
 		kfree(ibmvtpm->rtce_buf);
 	}
 
-	tpm_remove_hardware(ibmvtpm->dev);
-
 	kfree(ibmvtpm);
 
 	return 0;
@@ -555,11 +556,9 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
 	struct tpm_chip *chip;
 	int rc = -ENOMEM, rc1;
 
-	chip = tpm_register_hardware(dev, &tpm_ibmvtpm);
-	if (!chip) {
-		dev_err(dev, "tpm_register_hardware failed\n");
-		return -ENODEV;
-	}
+	chip = tpmm_chip_alloc(dev, &tpm_ibmvtpm);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 	ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
 	if (!ibmvtpm) {
@@ -629,7 +628,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
 	if (rc)
 		goto init_irq_cleanup;
 
-	return rc;
+	return tpm_chip_register(chip);
 init_irq_cleanup:
 	do {
 		rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
@@ -644,8 +643,6 @@ cleanup:
 		kfree(ibmvtpm);
 	}
 
-	tpm_remove_hardware(dev);
-
 	return rc;
 }
 
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index dc0a255..dcdb671 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -546,7 +546,14 @@ static int tpm_inf_pnp_probe(struct pnp_dev *dev,
 			 vendorid[0], vendorid[1],
 			 productid[0], productid[1], chipname);
 
-		if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf)))
+		chip = tpmm_chip_alloc(&dev->dev, &tpm_inf);
+		if (IS_ERR(chip)) {
+			rc = PTR_ERR(chip);
+			goto err_release_region;
+		}
+
+		rc = tpm_chip_register(chip);
+		if (rc)
 			goto err_release_region;
 
 		return 0;
@@ -572,17 +579,15 @@ static void tpm_inf_pnp_remove(struct pnp_dev *dev)
 {
 	struct tpm_chip *chip = pnp_get_drvdata(dev);
 
-	if (chip) {
-		if (tpm_dev.iotype == TPM_INF_IO_PORT) {
-			release_region(tpm_dev.data_regs, tpm_dev.data_size);
-			release_region(tpm_dev.config_port,
-				       tpm_dev.config_size);
-		} else {
-			iounmap(tpm_dev.mem_base);
-			release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
-		}
-		tpm_dev_vendor_release(chip);
-		tpm_remove_hardware(chip->dev);
+	tpm_chip_unregister(chip);
+
+	if (tpm_dev.iotype == TPM_INF_IO_PORT) {
+		release_region(tpm_dev.data_regs, tpm_dev.data_size);
+		release_region(tpm_dev.config_port,
+			       tpm_dev.config_size);
+	} else {
+		iounmap(tpm_dev.mem_base);
+		release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
 	}
 }
 
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 3179ec9..00c5470 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -247,10 +247,9 @@ static struct platform_device *pdev = NULL;
 static void tpm_nsc_remove(struct device *dev)
 {
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-	if ( chip ) {
-		release_region(chip->vendor.base, 2);
-		tpm_remove_hardware(chip->dev);
-	}
+
+	tpm_chip_unregister(chip);
+	release_region(chip->vendor.base, 2);
 }
 
 static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume);
@@ -308,11 +307,16 @@ static int __init init_nsc(void)
 		goto err_del_dev;
 	}
 
-	if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) {
+	chip = tpmm_chip_alloc(&pdev->dev, &tpm_nsc);
+	if (IS_ERR(chip)) {
 		rc = -ENODEV;
 		goto err_rel_reg;
 	}
 
+	rc = tpm_chip_register(chip);
+	if (rc)
+		goto err_rel_reg;
+
 	dev_dbg(&pdev->dev, "NSC TPM detected\n");
 	dev_dbg(&pdev->dev,
 		"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 2c46734..0066b68 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -75,9 +75,6 @@ enum tis_defaults {
 #define	TPM_DID_VID(l)			(0x0F00 | ((l) << 12))
 #define	TPM_RID(l)			(0x0F04 | ((l) << 12))
 
-static LIST_HEAD(tis_chips);
-static DEFINE_MUTEX(tis_lock);
-
 #if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
 static int is_itpm(struct pnp_dev *dev)
 {
@@ -528,6 +525,17 @@ static bool interrupts = true;
 module_param(interrupts, bool, 0444);
 MODULE_PARM_DESC(interrupts, "Enable interrupts");
 
+static void tpm_tis_remove(struct tpm_chip *chip)
+{
+	iowrite32(~TPM_GLOBAL_INT_ENABLE &
+		  ioread32(chip->vendor.iobase +
+			   TPM_INT_ENABLE(chip->vendor.
+					  locality)),
+		  chip->vendor.iobase +
+		  TPM_INT_ENABLE(chip->vendor.locality));
+	release_locality(chip, chip->vendor.locality, 1);
+}
+
 static int tpm_tis_init(struct device *dev, resource_size_t start,
 			resource_size_t len, unsigned int irq)
 {
@@ -535,14 +543,13 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 	int rc, i, irq_s, irq_e, probe;
 	struct tpm_chip *chip;
 
-	if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
-		return -ENODEV;
+	chip = tpmm_chip_alloc(dev, &tpm_tis);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
-	chip->vendor.iobase = ioremap(start, len);
-	if (!chip->vendor.iobase) {
-		rc = -EIO;
-		goto out_err;
-	}
+	chip->vendor.iobase = devm_ioremap(dev, start, len);
+	if (!chip->vendor.iobase)
+		return -EIO;
 
 	/* Default timeouts */
 	chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
@@ -649,8 +656,8 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 		for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
 			iowrite8(i, chip->vendor.iobase +
 				 TPM_INT_VECTOR(chip->vendor.locality));
-			if (request_irq
-			    (i, tis_int_probe, IRQF_SHARED,
+			if (devm_request_irq
+			    (dev, i, tis_int_probe, IRQF_SHARED,
 			     chip->vendor.miscdev.name, chip) != 0) {
 				dev_info(chip->dev,
 					 "Unable to request irq: %d for probe\n",
@@ -690,15 +697,14 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 			iowrite32(intmask,
 				  chip->vendor.iobase +
 				  TPM_INT_ENABLE(chip->vendor.locality));
-			free_irq(i, chip);
 		}
 	}
 	if (chip->vendor.irq) {
 		iowrite8(chip->vendor.irq,
 			 chip->vendor.iobase +
 			 TPM_INT_VECTOR(chip->vendor.locality));
-		if (request_irq
-		    (chip->vendor.irq, tis_int_handler, IRQF_SHARED,
+		if (devm_request_irq
+		    (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
 		     chip->vendor.miscdev.name, chip) != 0) {
 			dev_info(chip->dev,
 				 "Unable to request irq: %d for use\n",
@@ -719,17 +725,9 @@ 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);
-
-
-	return 0;
+	return tpm_chip_register(chip);
 out_err:
-	if (chip->vendor.iobase)
-		iounmap(chip->vendor.iobase);
-	tpm_remove_hardware(chip->dev);
+	tpm_tis_remove(chip);
 	return rc;
 }
 
@@ -811,13 +809,10 @@ MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
 static void tpm_tis_pnp_remove(struct pnp_dev *dev)
 {
 	struct tpm_chip *chip = pnp_get_drvdata(dev);
-
-	tpm_dev_vendor_release(chip);
-
-	kfree(chip);
+	tpm_chip_unregister(chip);
+	tpm_tis_remove(chip);
 }
 
-
 static struct pnp_driver tis_pnp_driver = {
 	.name = "tpm_tis",
 	.id_table = tpm_pnp_tbl,
@@ -836,7 +831,7 @@ MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
 
 static struct platform_driver tis_drv = {
 	.driver = {
-		.name = "tpm_tis",
+		.name		= "tpm_tis",
 		.owner		= THIS_MODULE,
 		.pm		= &tpm_tis_pm,
 	},
@@ -876,31 +871,16 @@ err_dev:
 
 static void __exit cleanup_tis(void)
 {
-	struct tpm_vendor_specific *i, *j;
 	struct tpm_chip *chip;
-	mutex_lock(&tis_lock);
-	list_for_each_entry_safe(i, j, &tis_chips, list) {
-		chip = to_tpm_chip(i);
-		tpm_remove_hardware(chip->dev);
-		iowrite32(~TPM_GLOBAL_INT_ENABLE &
-			  ioread32(chip->vendor.iobase +
-				   TPM_INT_ENABLE(chip->vendor.
-						  locality)),
-			  chip->vendor.iobase +
-			  TPM_INT_ENABLE(chip->vendor.locality));
-		release_locality(chip, chip->vendor.locality, 1);
-		if (chip->vendor.irq)
-			free_irq(chip->vendor.irq, chip);
-		iounmap(i->iobase);
-		list_del(&i->list);
-	}
-	mutex_unlock(&tis_lock);
 #ifdef CONFIG_PNP
 	if (!force) {
 		pnp_unregister_driver(&tis_pnp_driver);
 		return;
 	}
 #endif
+	chip = dev_get_drvdata(&pdev->dev);
+	tpm_chip_unregister(chip);
+	tpm_tis_remove(chip);
 	platform_device_unregister(pdev);
 	platform_driver_unregister(&tis_drv);
 }
diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c
index 441b44e..c3b4f5a 100644
--- a/drivers/char/tpm/xen-tpmfront.c
+++ b/drivers/char/tpm/xen-tpmfront.c
@@ -175,9 +175,9 @@ static int setup_chip(struct device *dev, struct tpm_private *priv)
 {
 	struct tpm_chip *chip;
 
-	chip = tpm_register_hardware(dev, &tpm_vtpm);
-	if (!chip)
-		return -ENODEV;
+	chip = tpmm_chip_alloc(dev, &tpm_vtpm);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 	init_waitqueue_head(&chip->vendor.read_queue);
 
@@ -286,6 +286,7 @@ static int tpmfront_probe(struct xenbus_device *dev,
 		const struct xenbus_device_id *id)
 {
 	struct tpm_private *priv;
+	struct tpm_chip *chip;
 	int rv;
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -302,21 +303,22 @@ static int tpmfront_probe(struct xenbus_device *dev,
 
 	rv = setup_ring(dev, priv);
 	if (rv) {
-		tpm_remove_hardware(&dev->dev);
+		chip = dev_get_drvdata(&dev->dev);
+		tpm_chip_unregister(chip);
 		ring_free(priv);
 		return rv;
 	}
 
 	tpm_get_timeouts(priv->chip);
 
-	return rv;
+	return tpm_chip_register(priv->chip);
 }
 
 static int tpmfront_remove(struct xenbus_device *dev)
 {
 	struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
 	struct tpm_private *priv = TPM_VPRIV(chip);
-	tpm_remove_hardware(&dev->dev);
+	tpm_chip_unregister(chip);
 	ring_free(priv);
 	TPM_VPRIV(chip) = NULL;
 	return 0;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 02/10] tpm: two-phase chip management functions
@ 2014-11-11 13:45   ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Jarkko Sakkinen

tpm_register_hardware() and tpm_remove_hardware() are called often
before initializing the device. This is wrong order since it could
be that main TPM driver needs a fully initialized chip to be able to
do its job. For example, now it is impossible to move common startup
functions such as tpm_do_selftest() to tpm_register_hardware().

Added tpmm_chip_alloc() and tpm_chip_register() where tpm_chip_alloc()
reserves memory resources and tpm_chip_register() initializes the
device driver. This way it is possible to alter struct tpm_chip
attributes and initialize the device driver before passing it to
tpm_chip_register().

The framework takes care of freeing struct tpm_chip by using devres
API. The broken release callback has been wiped. For example, ACPI
drivers do not ever get this callback.

This is a interm step to get proper life-cycle for TPM device drivers.
The next steps are adding proper ref counting and locking to tpm_chip
that is used in every place in the TPM driver.

Big thank you to Jason Gunthorpe for carefully reviewing this part
of the code. Without his contribution reaching the best quality would
not have been possible.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
 drivers/char/tpm/Makefile           |   2 +-
 drivers/char/tpm/tpm-chip.c         | 196 ++++++++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm-interface.c    | 148 +--------------------------
 drivers/char/tpm/tpm.h              |  11 +-
 drivers/char/tpm/tpm_atmel.c        |  11 +-
 drivers/char/tpm/tpm_i2c_atmel.c    |  33 ++----
 drivers/char/tpm/tpm_i2c_infineon.c |  37 ++-----
 drivers/char/tpm/tpm_i2c_nuvoton.c  |  44 +++-----
 drivers/char/tpm/tpm_i2c_stm_st33.c |  38 +++----
 drivers/char/tpm/tpm_ibmvtpm.c      |  17 ++--
 drivers/char/tpm/tpm_infineon.c     |  29 +++---
 drivers/char/tpm/tpm_nsc.c          |  14 ++-
 drivers/char/tpm/tpm_tis.c          |  78 ++++++--------
 drivers/char/tpm/xen-tpmfront.c     |  14 +--
 14 files changed, 329 insertions(+), 343 deletions(-)
 create mode 100644 drivers/char/tpm/tpm-chip.c

diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 4d85dd6..837da04 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the kernel tpm device drivers.
 #
 obj-$(CONFIG_TCG_TPM) += tpm.o
-tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o
+tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o
 tpm-$(CONFIG_ACPI) += tpm_ppi.o
 
 ifdef CONFIG_ACPI
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
new file mode 100644
index 0000000..cf3ad24
--- /dev/null
+++ b/drivers/char/tpm/tpm-chip.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Authors:
+ * Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
+ * Leendert van Doorn <leendert-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org>
+ * Dave Safford <safford-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org>
+ * Reiner Sailer <sailer-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org>
+ * Kylene Hall <kjhall-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
+ *
+ * Maintained by: <tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
+ *
+ * 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 "tpm.h"
+#include "tpm_eventlog.h"
+
+static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
+static LIST_HEAD(tpm_chip_list);
+static DEFINE_SPINLOCK(driver_lock);
+
+/*
+ * tpm_chip_find_get - return tpm_chip for a given chip number
+ * @chip_num the device number for the chip
+ */
+struct tpm_chip *tpm_chip_find_get(int chip_num)
+{
+	struct tpm_chip *pos, *chip = NULL;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
+		if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
+			continue;
+
+		if (try_module_get(pos->dev->driver->owner)) {
+			chip = pos;
+			break;
+		}
+	}
+	rcu_read_unlock();
+	return chip;
+}
+
+/**
+ * tpmm_chip_remove() - free chip memory and device number
+ * @data: points to struct tpm_chip instance
+ *
+ * This is used internally by tpmm_chip_alloc() and called by devres
+ * when the device is released. This function does the opposite of
+ * tpmm_chip_alloc() freeing memory and the device number.
+ */
+static void tpmm_chip_remove(void *data)
+{
+	struct tpm_chip *chip = (struct tpm_chip *) data;
+
+	spin_lock(&driver_lock);
+	clear_bit(chip->dev_num, dev_mask);
+	spin_unlock(&driver_lock);
+	kfree(chip);
+}
+
+/**
+ * tpmm_chip_alloc() - allocate a new struct tpm_chip instance
+ * @dev: device to which the chip is associated
+ * @ops: struct tpm_class_ops instance
+ *
+ * Allocates a new struct tpm_chip instance and assigns a free
+ * device number for it. Caller does not have to worry about
+ * freeing the allocated resources. When the devices is removed
+ * devres calls tpmm_chip_remove() to do the job.
+ */
+struct tpm_chip *tpmm_chip_alloc(struct device *dev,
+				 const struct tpm_class_ops *ops)
+{
+	struct tpm_chip *chip;
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_init(&chip->tpm_mutex);
+	INIT_LIST_HEAD(&chip->list);
+
+	chip->ops = ops;
+
+	spin_lock(&driver_lock);
+	chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
+	spin_unlock(&driver_lock);
+
+	if (chip->dev_num >= TPM_NUM_DEVICES) {
+		dev_err(dev, "No available tpm device numbers\n");
+		kfree(chip);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	set_bit(chip->dev_num, dev_mask);
+
+	scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm",
+		  chip->dev_num);
+
+	chip->dev = dev;
+	devm_add_action(dev, tpmm_chip_remove, chip);
+	dev_set_drvdata(dev, chip);
+
+	return chip;
+}
+EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
+
+/*
+ * tpm_chip_register() - create a misc driver for the TPM chip
+ * @chip: TPM chip to use.
+ *
+ * Creates a misc driver for the TPM chip and adds sysfs interfaces for
+ * the device, PPI and TCPA. As the last step this function adds the
+ * chip to the list of TPM chips available for use.
+ *
+ * NOTE: This function should be only called after the chip initialization
+ * is complete.
+ *
+ * Called from tpm_<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;
+
+	rc = tpm_sysfs_add_device(chip);
+	if (rc)
+		goto del_misc;
+
+	rc = tpm_add_ppi(&chip->dev->kobj);
+	if (rc)
+		goto del_sysfs;
+
+	chip->bios_dir = tpm_bios_log_setup(chip->devname);
+
+	/* Make the chip available. */
+	spin_lock(&driver_lock);
+	list_add_rcu(&chip->list, &tpm_chip_list);
+	spin_unlock(&driver_lock);
+
+	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)
+{
+	spin_lock(&driver_lock);
+	list_del_rcu(&chip->list);
+	spin_unlock(&driver_lock);
+	synchronize_rcu();
+
+	tpm_sysfs_del_device(chip);
+	tpm_remove_ppi(&chip->dev->kobj);
+
+	if (chip->bios_dir)
+		tpm_bios_log_teardown(chip->bios_dir);
+
+	tpm_dev_del_device(chip);
+}
+EXPORT_SYMBOL_GPL(tpm_chip_unregister);
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 0150b7c..915c610 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2014 Intel Corporation
  *
  * Authors:
  * Leendert van Doorn <leendert-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org>
@@ -47,10 +48,6 @@ module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
 MODULE_PARM_DESC(suspend_pcr,
 		 "PCR to use for dummy writes to faciltate flush on suspend.");
 
-static LIST_HEAD(tpm_chip_list);
-static DEFINE_SPINLOCK(driver_lock);
-static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
-
 /*
  * Array with one entry per ordinal defining the maximum amount
  * of time the chip could take to return the result.  The ordinal
@@ -639,27 +636,6 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
 	return rc;
 }
 
-/*
- * tpm_chip_find_get - return tpm_chip for given chip number
- */
-static struct tpm_chip *tpm_chip_find_get(int chip_num)
-{
-	struct tpm_chip *pos, *chip = NULL;
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
-		if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
-			continue;
-
-		if (try_module_get(pos->dev->driver->owner)) {
-			chip = pos;
-			break;
-		}
-	}
-	rcu_read_unlock();
-	return chip;
-}
-
 #define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
 #define READ_PCR_RESULT_SIZE 30
 static struct tpm_input_header pcrread_header = {
@@ -887,30 +863,6 @@ again:
 }
 EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
 
-void tpm_remove_hardware(struct device *dev)
-{
-	struct tpm_chip *chip = dev_get_drvdata(dev);
-
-	if (chip == NULL) {
-		dev_err(dev, "No device data found\n");
-		return;
-	}
-
-	spin_lock(&driver_lock);
-	list_del_rcu(&chip->list);
-	spin_unlock(&driver_lock);
-	synchronize_rcu();
-
-	tpm_dev_del_device(chip);
-	tpm_sysfs_del_device(chip);
-	tpm_remove_ppi(&dev->kobj);
-	tpm_bios_log_teardown(chip->bios_dir);
-
-	/* write it this way to be explicit (chip->dev == dev) */
-	put_device(chip->dev);
-}
-EXPORT_SYMBOL_GPL(tpm_remove_hardware);
-
 #define TPM_ORD_SAVESTATE cpu_to_be32(152)
 #define SAVESTATE_RESULT_SIZE 10
 
@@ -1044,104 +996,6 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 }
 EXPORT_SYMBOL_GPL(tpm_get_random);
 
-/* In case vendor provided release function, call it too.*/
-
-void tpm_dev_vendor_release(struct tpm_chip *chip)
-{
-	if (!chip)
-		return;
-
-	clear_bit(chip->dev_num, dev_mask);
-}
-EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
-
-
-/*
- * Once all references to platform device are down to 0,
- * release all allocated structures.
- */
-static void tpm_dev_release(struct device *dev)
-{
-	struct tpm_chip *chip = dev_get_drvdata(dev);
-
-	if (!chip)
-		return;
-
-	tpm_dev_vendor_release(chip);
-
-	chip->release(dev);
-	kfree(chip);
-}
-
-/*
- * Called from tpm_<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)
-{
-	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;
-}
-EXPORT_SYMBOL_GPL(tpm_register_hardware);
-
 MODULE_AUTHOR("Leendert van Doorn (leendert-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org)");
 MODULE_DESCRIPTION("TPM Driver");
 MODULE_VERSION("2.0");
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index e638eb0..9880681 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -110,7 +110,6 @@ struct tpm_chip {
 	struct dentry **bios_dir;
 
 	struct list_head list;
-	void (*release) (struct device *);
 };
 
 #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
@@ -322,15 +321,17 @@ extern int tpm_get_timeouts(struct tpm_chip *);
 extern void tpm_gen_interrupt(struct tpm_chip *);
 extern int tpm_do_selftest(struct tpm_chip *);
 extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
-extern struct tpm_chip* tpm_register_hardware(struct device *,
-					      const struct tpm_class_ops *ops);
-extern void tpm_dev_vendor_release(struct tpm_chip *);
-extern void tpm_remove_hardware(struct device *);
 extern int tpm_pm_suspend(struct device *);
 extern int tpm_pm_resume(struct device *);
 extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
 			     wait_queue_head_t *, bool);
 
+struct tpm_chip *tpm_chip_find_get(int chip_num);
+extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
+				       const struct tpm_class_ops *ops);
+extern int tpm_chip_register(struct tpm_chip *chip);
+extern void tpm_chip_unregister(struct tpm_chip *chip);
+
 int tpm_dev_add_device(struct tpm_chip *chip);
 void tpm_dev_del_device(struct tpm_chip *chip);
 int tpm_sysfs_add_device(struct tpm_chip *chip);
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index 6069d13..8e2576a 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -138,11 +138,11 @@ static void atml_plat_remove(void)
 	struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
 
 	if (chip) {
+		tpm_chip_unregister(chip);
 		if (chip->vendor.have_region)
 			atmel_release_region(chip->vendor.base,
 					     chip->vendor.region_size);
 		atmel_put_base_addr(chip->vendor.iobase);
-		tpm_remove_hardware(chip->dev);
 		platform_device_unregister(pdev);
 	}
 }
@@ -184,8 +184,9 @@ static int __init init_atmel(void)
 		goto err_rel_reg;
 	}
 
-	if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) {
-		rc = -ENODEV;
+	chip = tpmm_chip_alloc(&pdev->dev, &tpm_atmel);
+	if (IS_ERR(chip)) {
+		rc = PTR_ERR(chip);
 		goto err_unreg_dev;
 	}
 
@@ -194,6 +195,10 @@ static int __init init_atmel(void)
 	chip->vendor.have_region = have_region;
 	chip->vendor.region_size = region_size;
 
+	rc = tpm_chip_register(chip);
+	if (rc)
+		goto err_unreg_dev;
+
 	return 0;
 
 err_unreg_dev:
diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c
index 7727292..8af3b4a 100644
--- a/drivers/char/tpm/tpm_i2c_atmel.c
+++ b/drivers/char/tpm/tpm_i2c_atmel.c
@@ -160,11 +160,9 @@ static int i2c_atmel_probe(struct i2c_client *client,
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 		return -ENODEV;
 
-	chip = tpm_register_hardware(dev, &i2c_atmel);
-	if (!chip) {
-		dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
-		return -ENODEV;
-	}
+	chip = tpmm_chip_alloc(dev, &i2c_atmel);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 	chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
 					 GFP_KERNEL);
@@ -179,21 +177,16 @@ static int i2c_atmel_probe(struct i2c_client *client,
 	/* There is no known way to probe for this device, and all version
 	 * information seems to be read via TPM commands. Thus we rely on the
 	 * TPM startup process in the common code to detect the device. */
-	if (tpm_get_timeouts(chip)) {
-		rc = -ENODEV;
-		goto out_err;
-	}
+	if (tpm_get_timeouts(chip))
+		return -ENODEV;
 
-	if (tpm_do_selftest(chip)) {
-		rc = -ENODEV;
-		goto out_err;
-	}
+	if (tpm_do_selftest(chip))
+		return -ENODEV;
 
-	return 0;
+	rc = tpm_chip_register(chip);
+	if (rc)
+		return rc;
 
-out_err:
-	tpm_dev_vendor_release(chip);
-	tpm_remove_hardware(chip->dev);
 	return rc;
 }
 
@@ -201,11 +194,7 @@ static int i2c_atmel_remove(struct i2c_client *client)
 {
 	struct device *dev = &(client->dev);
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-
-	if (chip)
-		tpm_dev_vendor_release(chip);
-	tpm_remove_hardware(dev);
-	kfree(chip);
+	tpm_chip_unregister(chip);
 	return 0;
 }
 
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
index 472af4b..03708e6 100644
--- a/drivers/char/tpm/tpm_i2c_infineon.c
+++ b/drivers/char/tpm/tpm_i2c_infineon.c
@@ -581,12 +581,9 @@ static int tpm_tis_i2c_init(struct device *dev)
 	int rc = 0;
 	struct tpm_chip *chip;
 
-	chip = tpm_register_hardware(dev, &tpm_tis_i2c);
-	if (!chip) {
-		dev_err(dev, "could not register hardware\n");
-		rc = -ENODEV;
-		goto out_err;
-	}
+	chip = tpmm_chip_alloc(dev, &tpm_tis_i2c);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 	/* Disable interrupts */
 	chip->vendor.irq = 0;
@@ -600,7 +597,7 @@ static int tpm_tis_i2c_init(struct device *dev)
 	if (request_locality(chip, 0) != 0) {
 		dev_err(dev, "could not request locality\n");
 		rc = -ENODEV;
-		goto out_vendor;
+		goto out_err;
 	}
 
 	/* read four bytes from DID_VID register */
@@ -628,21 +625,9 @@ static int tpm_tis_i2c_init(struct device *dev)
 	tpm_get_timeouts(chip);
 	tpm_do_selftest(chip);
 
-	return 0;
-
+	return tpm_chip_register(chip);
 out_release:
 	release_locality(chip, chip->vendor.locality, 1);
-
-out_vendor:
-	/* close file handles */
-	tpm_dev_vendor_release(chip);
-
-	/* remove hardware */
-	tpm_remove_hardware(chip->dev);
-
-	/* reset these pointers, otherwise we oops */
-	chip->dev->release = NULL;
-	chip->release = NULL;
 	tpm_dev.client = NULL;
 out_err:
 	return rc;
@@ -712,17 +697,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client,
 static int tpm_tis_i2c_remove(struct i2c_client *client)
 {
 	struct tpm_chip *chip = tpm_dev.chip;
-	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;
 
 	return 0;
diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c
index 7b158ef..09f0c46 100644
--- a/drivers/char/tpm/tpm_i2c_nuvoton.c
+++ b/drivers/char/tpm/tpm_i2c_nuvoton.c
@@ -530,11 +530,9 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
 	dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid,
 		 (u8) (vid >> 16), (u8) (vid >> 24));
 
-	chip = tpm_register_hardware(dev, &tpm_i2c);
-	if (!chip) {
-		dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
-		return -ENODEV;
-	}
+	chip = tpmm_chip_alloc(dev, &tpm_i2c);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 	chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
 					 GFP_KERNEL);
@@ -584,7 +582,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
 							   TPM_DATA_FIFO_W,
 							   1, (u8 *) (&rc));
 				if (rc < 0)
-					goto out_err;
+					return rc;
 				/* TPM_STS <- 0x40 (commandReady) */
 				i2c_nuvoton_ready(chip);
 			} else {
@@ -594,45 +592,33 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
 				 * only TPM_STS_VALID should be set
 				 */
 				if (i2c_nuvoton_read_status(chip) !=
-				    TPM_STS_VALID) {
-					rc = -EIO;
-					goto out_err;
-				}
+				    TPM_STS_VALID)
+					return -EIO;
 			}
 		}
 	}
 
-	if (tpm_get_timeouts(chip)) {
-		rc = -ENODEV;
-		goto out_err;
-	}
+	if (tpm_get_timeouts(chip))
+		return -ENODEV;
 
-	if (tpm_do_selftest(chip)) {
-		rc = -ENODEV;
-		goto out_err;
-	}
+	if (tpm_do_selftest(chip))
+		return -ENODEV;
 
-	return 0;
+	rc = tpm_chip_register(chip);
+	if (rc)
+		return rc;
 
-out_err:
-	tpm_dev_vendor_release(chip);
-	tpm_remove_hardware(chip->dev);
-	return rc;
+	return 0;
 }
 
 static int i2c_nuvoton_remove(struct i2c_client *client)
 {
 	struct device *dev = &(client->dev);
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-
-	if (chip)
-		tpm_dev_vendor_release(chip);
-	tpm_remove_hardware(dev);
-	kfree(chip);
+	tpm_chip_unregister(chip);
 	return 0;
 }
 
-
 static const struct i2c_device_id i2c_nuvoton_id[] = {
 	{I2C_DRIVER_NAME, 0},
 	{}
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index 4669e37..b9d1a38 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -609,37 +609,29 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	if (client == NULL) {
 		pr_info("%s: i2c client is NULL. Device not accessible.\n",
 			__func__);
-		err = -ENODEV;
-		goto end;
+		return -ENODEV;
 	}
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		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;
-	}
+	chip = tpmm_chip_alloc(&client->dev, &st_i2c_tpm);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 	platform_data = client->dev.platform_data;
 
 	if (!platform_data) {
 		dev_info(&client->dev, "chip not available\n");
-		err = -ENODEV;
-		goto _tpm_clean_answer;
+		return -ENODEV;
 	}
 
 	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;
-	}
+	if (platform_data->tpm_i2c_buffer[0] == NULL)
+		return -ENOMEM;
 	platform_data->tpm_i2c_buffer[1] =
 	    kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
 	if (platform_data->tpm_i2c_buffer[1] == NULL) {
@@ -716,8 +708,10 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	tpm_get_timeouts(chip);
 	tpm_do_selftest(chip);
 
-	dev_info(chip->dev, "TPM I2C Initialized\n");
-	return 0;
+	err = tpm_chip_register(chip);
+	if (!err)
+		return 0;
+
 _irq_set:
 	free_irq(gpio_to_irq(platform_data->io_serirq), (void *)chip);
 _gpio_init2:
@@ -732,10 +726,6 @@ _tpm_clean_response2:
 _tpm_clean_response1:
 	kzfree(platform_data->tpm_i2c_buffer[0]);
 	platform_data->tpm_i2c_buffer[0] = NULL;
-_tpm_clean_answer:
-	tpm_remove_hardware(chip->dev);
-end:
-	pr_info("TPM I2C initialisation fail\n");
 	return err;
 }
 
@@ -752,13 +742,13 @@ static int tpm_st33_i2c_remove(struct i2c_client *client)
 		((struct i2c_client *)TPM_VPRIV(chip))->dev.platform_data;
 
 	if (pin_infos != NULL) {
+		tpm_chip_unregister(chip);
+
 		free_irq(pin_infos->io_serirq, chip);
 
 		gpio_free(pin_infos->io_serirq);
 		gpio_free(pin_infos->io_lpcpd);
 
-		tpm_remove_hardware(chip->dev);
-
 		if (pin_infos->tpm_i2c_buffer[1] != NULL) {
 			kzfree(pin_infos->tpm_i2c_buffer[1]);
 			pin_infos->tpm_i2c_buffer[1] = NULL;
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
index af74c57..eb95796 100644
--- a/drivers/char/tpm/tpm_ibmvtpm.c
+++ b/drivers/char/tpm/tpm_ibmvtpm.c
@@ -270,8 +270,11 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
 static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
 {
 	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
+	struct tpm_chip *chip = dev_get_drvdata(ibmvtpm->dev);
 	int rc = 0;
 
+	tpm_chip_unregister(chip);
+
 	free_irq(vdev->irq, ibmvtpm);
 
 	do {
@@ -290,8 +293,6 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
 		kfree(ibmvtpm->rtce_buf);
 	}
 
-	tpm_remove_hardware(ibmvtpm->dev);
-
 	kfree(ibmvtpm);
 
 	return 0;
@@ -555,11 +556,9 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
 	struct tpm_chip *chip;
 	int rc = -ENOMEM, rc1;
 
-	chip = tpm_register_hardware(dev, &tpm_ibmvtpm);
-	if (!chip) {
-		dev_err(dev, "tpm_register_hardware failed\n");
-		return -ENODEV;
-	}
+	chip = tpmm_chip_alloc(dev, &tpm_ibmvtpm);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 	ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
 	if (!ibmvtpm) {
@@ -629,7 +628,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
 	if (rc)
 		goto init_irq_cleanup;
 
-	return rc;
+	return tpm_chip_register(chip);
 init_irq_cleanup:
 	do {
 		rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
@@ -644,8 +643,6 @@ cleanup:
 		kfree(ibmvtpm);
 	}
 
-	tpm_remove_hardware(dev);
-
 	return rc;
 }
 
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index dc0a255..dcdb671 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -546,7 +546,14 @@ static int tpm_inf_pnp_probe(struct pnp_dev *dev,
 			 vendorid[0], vendorid[1],
 			 productid[0], productid[1], chipname);
 
-		if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf)))
+		chip = tpmm_chip_alloc(&dev->dev, &tpm_inf);
+		if (IS_ERR(chip)) {
+			rc = PTR_ERR(chip);
+			goto err_release_region;
+		}
+
+		rc = tpm_chip_register(chip);
+		if (rc)
 			goto err_release_region;
 
 		return 0;
@@ -572,17 +579,15 @@ static void tpm_inf_pnp_remove(struct pnp_dev *dev)
 {
 	struct tpm_chip *chip = pnp_get_drvdata(dev);
 
-	if (chip) {
-		if (tpm_dev.iotype == TPM_INF_IO_PORT) {
-			release_region(tpm_dev.data_regs, tpm_dev.data_size);
-			release_region(tpm_dev.config_port,
-				       tpm_dev.config_size);
-		} else {
-			iounmap(tpm_dev.mem_base);
-			release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
-		}
-		tpm_dev_vendor_release(chip);
-		tpm_remove_hardware(chip->dev);
+	tpm_chip_unregister(chip);
+
+	if (tpm_dev.iotype == TPM_INF_IO_PORT) {
+		release_region(tpm_dev.data_regs, tpm_dev.data_size);
+		release_region(tpm_dev.config_port,
+			       tpm_dev.config_size);
+	} else {
+		iounmap(tpm_dev.mem_base);
+		release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
 	}
 }
 
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 3179ec9..00c5470 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -247,10 +247,9 @@ static struct platform_device *pdev = NULL;
 static void tpm_nsc_remove(struct device *dev)
 {
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-	if ( chip ) {
-		release_region(chip->vendor.base, 2);
-		tpm_remove_hardware(chip->dev);
-	}
+
+	tpm_chip_unregister(chip);
+	release_region(chip->vendor.base, 2);
 }
 
 static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume);
@@ -308,11 +307,16 @@ static int __init init_nsc(void)
 		goto err_del_dev;
 	}
 
-	if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) {
+	chip = tpmm_chip_alloc(&pdev->dev, &tpm_nsc);
+	if (IS_ERR(chip)) {
 		rc = -ENODEV;
 		goto err_rel_reg;
 	}
 
+	rc = tpm_chip_register(chip);
+	if (rc)
+		goto err_rel_reg;
+
 	dev_dbg(&pdev->dev, "NSC TPM detected\n");
 	dev_dbg(&pdev->dev,
 		"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 2c46734..0066b68 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -75,9 +75,6 @@ enum tis_defaults {
 #define	TPM_DID_VID(l)			(0x0F00 | ((l) << 12))
 #define	TPM_RID(l)			(0x0F04 | ((l) << 12))
 
-static LIST_HEAD(tis_chips);
-static DEFINE_MUTEX(tis_lock);
-
 #if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
 static int is_itpm(struct pnp_dev *dev)
 {
@@ -528,6 +525,17 @@ static bool interrupts = true;
 module_param(interrupts, bool, 0444);
 MODULE_PARM_DESC(interrupts, "Enable interrupts");
 
+static void tpm_tis_remove(struct tpm_chip *chip)
+{
+	iowrite32(~TPM_GLOBAL_INT_ENABLE &
+		  ioread32(chip->vendor.iobase +
+			   TPM_INT_ENABLE(chip->vendor.
+					  locality)),
+		  chip->vendor.iobase +
+		  TPM_INT_ENABLE(chip->vendor.locality));
+	release_locality(chip, chip->vendor.locality, 1);
+}
+
 static int tpm_tis_init(struct device *dev, resource_size_t start,
 			resource_size_t len, unsigned int irq)
 {
@@ -535,14 +543,13 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 	int rc, i, irq_s, irq_e, probe;
 	struct tpm_chip *chip;
 
-	if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
-		return -ENODEV;
+	chip = tpmm_chip_alloc(dev, &tpm_tis);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
-	chip->vendor.iobase = ioremap(start, len);
-	if (!chip->vendor.iobase) {
-		rc = -EIO;
-		goto out_err;
-	}
+	chip->vendor.iobase = devm_ioremap(dev, start, len);
+	if (!chip->vendor.iobase)
+		return -EIO;
 
 	/* Default timeouts */
 	chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
@@ -649,8 +656,8 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 		for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
 			iowrite8(i, chip->vendor.iobase +
 				 TPM_INT_VECTOR(chip->vendor.locality));
-			if (request_irq
-			    (i, tis_int_probe, IRQF_SHARED,
+			if (devm_request_irq
+			    (dev, i, tis_int_probe, IRQF_SHARED,
 			     chip->vendor.miscdev.name, chip) != 0) {
 				dev_info(chip->dev,
 					 "Unable to request irq: %d for probe\n",
@@ -690,15 +697,14 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 			iowrite32(intmask,
 				  chip->vendor.iobase +
 				  TPM_INT_ENABLE(chip->vendor.locality));
-			free_irq(i, chip);
 		}
 	}
 	if (chip->vendor.irq) {
 		iowrite8(chip->vendor.irq,
 			 chip->vendor.iobase +
 			 TPM_INT_VECTOR(chip->vendor.locality));
-		if (request_irq
-		    (chip->vendor.irq, tis_int_handler, IRQF_SHARED,
+		if (devm_request_irq
+		    (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
 		     chip->vendor.miscdev.name, chip) != 0) {
 			dev_info(chip->dev,
 				 "Unable to request irq: %d for use\n",
@@ -719,17 +725,9 @@ 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);
-
-
-	return 0;
+	return tpm_chip_register(chip);
 out_err:
-	if (chip->vendor.iobase)
-		iounmap(chip->vendor.iobase);
-	tpm_remove_hardware(chip->dev);
+	tpm_tis_remove(chip);
 	return rc;
 }
 
@@ -811,13 +809,10 @@ MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
 static void tpm_tis_pnp_remove(struct pnp_dev *dev)
 {
 	struct tpm_chip *chip = pnp_get_drvdata(dev);
-
-	tpm_dev_vendor_release(chip);
-
-	kfree(chip);
+	tpm_chip_unregister(chip);
+	tpm_tis_remove(chip);
 }
 
-
 static struct pnp_driver tis_pnp_driver = {
 	.name = "tpm_tis",
 	.id_table = tpm_pnp_tbl,
@@ -836,7 +831,7 @@ MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
 
 static struct platform_driver tis_drv = {
 	.driver = {
-		.name = "tpm_tis",
+		.name		= "tpm_tis",
 		.owner		= THIS_MODULE,
 		.pm		= &tpm_tis_pm,
 	},
@@ -876,31 +871,16 @@ err_dev:
 
 static void __exit cleanup_tis(void)
 {
-	struct tpm_vendor_specific *i, *j;
 	struct tpm_chip *chip;
-	mutex_lock(&tis_lock);
-	list_for_each_entry_safe(i, j, &tis_chips, list) {
-		chip = to_tpm_chip(i);
-		tpm_remove_hardware(chip->dev);
-		iowrite32(~TPM_GLOBAL_INT_ENABLE &
-			  ioread32(chip->vendor.iobase +
-				   TPM_INT_ENABLE(chip->vendor.
-						  locality)),
-			  chip->vendor.iobase +
-			  TPM_INT_ENABLE(chip->vendor.locality));
-		release_locality(chip, chip->vendor.locality, 1);
-		if (chip->vendor.irq)
-			free_irq(chip->vendor.irq, chip);
-		iounmap(i->iobase);
-		list_del(&i->list);
-	}
-	mutex_unlock(&tis_lock);
 #ifdef CONFIG_PNP
 	if (!force) {
 		pnp_unregister_driver(&tis_pnp_driver);
 		return;
 	}
 #endif
+	chip = dev_get_drvdata(&pdev->dev);
+	tpm_chip_unregister(chip);
+	tpm_tis_remove(chip);
 	platform_device_unregister(pdev);
 	platform_driver_unregister(&tis_drv);
 }
diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c
index 441b44e..c3b4f5a 100644
--- a/drivers/char/tpm/xen-tpmfront.c
+++ b/drivers/char/tpm/xen-tpmfront.c
@@ -175,9 +175,9 @@ static int setup_chip(struct device *dev, struct tpm_private *priv)
 {
 	struct tpm_chip *chip;
 
-	chip = tpm_register_hardware(dev, &tpm_vtpm);
-	if (!chip)
-		return -ENODEV;
+	chip = tpmm_chip_alloc(dev, &tpm_vtpm);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
 	init_waitqueue_head(&chip->vendor.read_queue);
 
@@ -286,6 +286,7 @@ static int tpmfront_probe(struct xenbus_device *dev,
 		const struct xenbus_device_id *id)
 {
 	struct tpm_private *priv;
+	struct tpm_chip *chip;
 	int rv;
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -302,21 +303,22 @@ static int tpmfront_probe(struct xenbus_device *dev,
 
 	rv = setup_ring(dev, priv);
 	if (rv) {
-		tpm_remove_hardware(&dev->dev);
+		chip = dev_get_drvdata(&dev->dev);
+		tpm_chip_unregister(chip);
 		ring_free(priv);
 		return rv;
 	}
 
 	tpm_get_timeouts(priv->chip);
 
-	return rv;
+	return tpm_chip_register(priv->chip);
 }
 
 static int tpmfront_remove(struct xenbus_device *dev)
 {
 	struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
 	struct tpm_private *priv = TPM_VPRIV(chip);
-	tpm_remove_hardware(&dev->dev);
+	tpm_chip_unregister(chip);
 	ring_free(priv);
 	TPM_VPRIV(chip) = NULL;
 	return 0;
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 03/10] tpm: fix multiple race conditions in tpm_ppi.c
  2014-11-11 13:45 ` Jarkko Sakkinen
                   ` (2 preceding siblings ...)
  (?)
@ 2014-11-11 13:45 ` Jarkko Sakkinen
  2014-11-25 21:40   ` [tpmdd-devel] " Stefan Berger
  -1 siblings, 1 reply; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech, Jarkko Sakkinen

Traversal of the ACPI device tree was not done right. It should lookup
PPI only under the ACPI device that it is associated. Otherwise, it could
match to a wrong PPI interface if there are two TPM devices in the device
tree.

Removed global ACPI handle and version string from tpm_ppi.c as this
is racy. Instead they should be associated with the chip.

Additionally, added the missing copyright platter to tpm_ppi.c.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/char/tpm/tpm-chip.c |   4 +-
 drivers/char/tpm/tpm.h      |  16 ++++--
 drivers/char/tpm/tpm_ppi.c  | 136 +++++++++++++++++++++++++++-----------------
 drivers/char/tpm/tpm_tis.c  |  15 +++--
 4 files changed, 108 insertions(+), 63 deletions(-)

diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index cf3ad24..647867c 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -148,7 +148,7 @@ int tpm_chip_register(struct tpm_chip *chip)
 	if (rc)
 		goto del_misc;
 
-	rc = tpm_add_ppi(&chip->dev->kobj);
+	rc = tpm_add_ppi(chip);
 	if (rc)
 		goto del_sysfs;
 
@@ -186,7 +186,7 @@ void tpm_chip_unregister(struct tpm_chip *chip)
 	synchronize_rcu();
 
 	tpm_sysfs_del_device(chip);
-	tpm_remove_ppi(&chip->dev->kobj);
+	tpm_remove_ppi(chip);
 
 	if (chip->bios_dir)
 		tpm_bios_log_teardown(chip->bios_dir);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 9880681..69f4003 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -27,6 +27,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/tpm.h>
+#include <linux/acpi.h>
 
 enum tpm_const {
 	TPM_MINOR = 224,	/* officially assigned */
@@ -94,6 +95,8 @@ struct tpm_vendor_specific {
 #define TPM_VID_WINBOND  0x1050
 #define TPM_VID_STM      0x104A
 
+#define TPM_PPI_VERSION_LEN		3
+
 struct tpm_chip {
 	struct device *dev;	/* Device stuff */
 	const struct tpm_class_ops *ops;
@@ -109,6 +112,11 @@ struct tpm_chip {
 
 	struct dentry **bios_dir;
 
+#ifdef CONFIG_ACPI
+	acpi_handle acpi_dev_handle;
+	char ppi_version[TPM_PPI_VERSION_LEN + 1];
+#endif /* CONFIG_ACPI */
+
 	struct list_head list;
 };
 
@@ -340,15 +348,15 @@ void tpm_sysfs_del_device(struct tpm_chip *chip);
 int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
 
 #ifdef CONFIG_ACPI
-extern int tpm_add_ppi(struct kobject *);
-extern void tpm_remove_ppi(struct kobject *);
+extern int tpm_add_ppi(struct tpm_chip *chip);
+extern void tpm_remove_ppi(struct tpm_chip *chip);
 #else
-static inline int tpm_add_ppi(struct kobject *parent)
+static inline int tpm_add_ppi(struct tpm_chip *chip)
 {
 	return 0;
 }
 
-static inline void tpm_remove_ppi(struct kobject *parent)
+static inline void tpm_remove_ppi(struct tpm_chip *chip)
 {
 }
 #endif
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c
index 61dcc80..6acdb17 100644
--- a/drivers/char/tpm/tpm_ppi.c
+++ b/drivers/char/tpm/tpm_ppi.c
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2012-2014 Intel Corporation
+ *
+ * Authors:
+ * Xiaoyan Zhang <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 "tpm.h"
 
@@ -22,45 +41,22 @@ static const u8 tpm_ppi_uuid[] = {
 	0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
 };
 
-static char tpm_ppi_version[PPI_VERSION_LEN + 1];
-static acpi_handle tpm_ppi_handle;
-
-static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context,
-				void **return_value)
-{
-	union acpi_object *obj;
-
-	if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
-			    1 << TPM_PPI_FN_VERSION))
-		return AE_OK;
-
-	/* Cache version string */
-	obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid,
-				      TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
-				      NULL, ACPI_TYPE_STRING);
-	if (obj) {
-		strlcpy(tpm_ppi_version, obj->string.pointer,
-			PPI_VERSION_LEN + 1);
-		ACPI_FREE(obj);
-	}
-
-	*return_value = handle;
-
-	return AE_CTRL_TERMINATE;
-}
-
 static inline union acpi_object *
-tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4)
+tpm_eval_dsm(acpi_handle dev_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(!dev_handle);
+	return acpi_evaluate_dsm_typed(dev_handle, tpm_ppi_uuid,
+				       TPM_PPI_REVISION_ID,
+				       func, argv4, type);
 }
 
 static ssize_t tpm_show_ppi_version(struct device *dev,
 				    struct device_attribute *attr, char *buf)
 {
-	return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version);
+	struct tpm_chip *chip = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version);
 }
 
 static ssize_t tpm_show_ppi_request(struct device *dev,
@@ -68,8 +64,10 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
 {
 	ssize_t size = -EINVAL;
 	union acpi_object *obj;
+	struct tpm_chip *chip = dev_get_drvdata(dev);
 
-	obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL);
+	obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
+			   ACPI_TYPE_PACKAGE, NULL);
 	if (!obj)
 		return -ENXIO;
 
@@ -103,14 +101,15 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
 	int func = TPM_PPI_FN_SUBREQ;
 	union acpi_object *obj, tmp;
 	union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
+	struct tpm_chip *chip = dev_get_drvdata(dev);
 
 	/*
 	 * the function to submit TPM operation request to pre-os environment
 	 * is updated with function index from SUBREQ to SUBREQ2 since PPI
 	 * version 1.1
 	 */
-	if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
-			   1 << TPM_PPI_FN_SUBREQ2))
+	if (acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
+			   TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2))
 		func = TPM_PPI_FN_SUBREQ2;
 
 	/*
@@ -119,7 +118,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
 	 * string/package type. For PPI version 1.0 and 1.1, use buffer type
 	 * for compatibility, and use package type since 1.2 according to spec.
 	 */
-	if (strcmp(tpm_ppi_version, "1.2") < 0) {
+	if (strcmp(chip->ppi_version, "1.2") < 0) {
 		if (sscanf(buf, "%d", &req) != 1)
 			return -EINVAL;
 		argv4.type = ACPI_TYPE_BUFFER;
@@ -131,7 +130,8 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
 			return -EINVAL;
 	}
 
-	obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4);
+	obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER,
+			   &argv4);
 	if (!obj) {
 		return -ENXIO;
 	} else {
@@ -157,6 +157,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
 		.buffer.length = 0,
 		.buffer.pointer = NULL
 	};
+	struct tpm_chip *chip = dev_get_drvdata(dev);
 
 	static char *info[] = {
 		"None",
@@ -171,9 +172,10 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
 	 * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
 	 * compatibility, define params[3].type as buffer, if PPI version < 1.2
 	 */
-	if (strcmp(tpm_ppi_version, "1.2") < 0)
+	if (strcmp(chip->ppi_version, "1.2") < 0)
 		obj = &tmp;
-	obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj);
+	obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT,
+			   ACPI_TYPE_INTEGER, obj);
 	if (!obj) {
 		return -ENXIO;
 	} else {
@@ -196,8 +198,10 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
 	acpi_status status = -EINVAL;
 	union acpi_object *obj, *ret_obj;
 	u64 req, res;
+	struct tpm_chip *chip = dev_get_drvdata(dev);
 
-	obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL);
+	obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
+			   ACPI_TYPE_PACKAGE, NULL);
 	if (!obj)
 		return -ENXIO;
 
@@ -248,7 +252,8 @@ cleanup:
 	return status;
 }
 
-static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
+static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
+				   u32 end)
 {
 	int i;
 	u32 ret;
@@ -264,14 +269,15 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
 		"User not required",
 	};
 
-	if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
+	if (!acpi_check_dsm(dev_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
 			    1 << TPM_PPI_FN_GETOPR))
 		return -EPERM;
 
 	tmp.integer.type = ACPI_TYPE_INTEGER;
 	for (i = start; i <= end; i++) {
 		tmp.integer.value = i;
-		obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv);
+		obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
+				   ACPI_TYPE_INTEGER, &argv);
 		if (!obj) {
 			return -ENOMEM;
 		} else {
@@ -291,14 +297,20 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
 					   struct device_attribute *attr,
 					   char *buf)
 {
-	return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX);
+	struct tpm_chip *chip = dev_get_drvdata(dev);
+
+	return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
+				   PPI_TPM_REQ_MAX);
 }
 
 static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
 					  struct device_attribute *attr,
 					  char *buf)
 {
-	return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END);
+	struct tpm_chip *chip = dev_get_drvdata(dev);
+
+	return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
+				   PPI_VS_REQ_END);
 }
 
 static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL);
@@ -323,16 +335,34 @@ static struct attribute_group ppi_attr_grp = {
 	.attrs = ppi_attrs
 };
 
-int tpm_add_ppi(struct kobject *parent)
+int tpm_add_ppi(struct tpm_chip *chip)
 {
-	/* Cache TPM ACPI handle and version string */
-	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
-			    ppi_callback, NULL, NULL, &tpm_ppi_handle);
-	return tpm_ppi_handle ? sysfs_create_group(parent, &ppi_attr_grp) : 0;
+	union acpi_object *obj;
+
+	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)
+		return -ENOMEM;
+
+	strlcpy(chip->ppi_version, obj->string.pointer,
+		PPI_VERSION_LEN + 1);
+
+	ACPI_FREE(obj);
+
+	return sysfs_create_group(&chip->dev->kobj, &ppi_attr_grp);
 }
 
-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->ppi_version[0] != '\0')
+		sysfs_remove_group(&chip->dev->kobj, &ppi_attr_grp);
 }
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 0066b68..00ed222 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -536,8 +536,9 @@ static void tpm_tis_remove(struct tpm_chip *chip)
 	release_locality(chip, chip->vendor.locality, 1);
 }
 
-static int tpm_tis_init(struct device *dev, resource_size_t start,
-			resource_size_t len, unsigned int irq)
+static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
+			resource_size_t start, resource_size_t len,
+			unsigned int irq)
 {
 	u32 vendor, intfcaps, intmask;
 	int rc, i, irq_s, irq_e, probe;
@@ -547,6 +548,8 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 	if (IS_ERR(chip))
 		return PTR_ERR(chip);
 
+	chip->acpi_dev_handle = acpi_dev_handle;
+
 	chip->vendor.iobase = devm_ioremap(dev, start, len);
 	if (!chip->vendor.iobase)
 		return -EIO;
@@ -777,6 +780,7 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
 {
 	resource_size_t start, len;
 	unsigned int irq = 0;
+	acpi_handle acpi_dev_handle = NULL;
 
 	start = pnp_mem_start(pnp_dev, 0);
 	len = pnp_mem_len(pnp_dev, 0);
@@ -789,7 +793,10 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
 	if (is_itpm(pnp_dev))
 		itpm = true;
 
-	return tpm_tis_init(&pnp_dev->dev, start, len, irq);
+	if (pnp_acpi_device(pnp_dev))
+		acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle;
+
+	return tpm_tis_init(&pnp_dev->dev, acpi_dev_handle, start, len, irq);
 }
 
 static struct pnp_device_id tpm_pnp_tbl[] = {
@@ -858,7 +865,7 @@ static int __init init_tis(void)
 		rc = PTR_ERR(pdev);
 		goto err_dev;
 	}
-	rc = tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0);
+	rc = tpm_tis_init(&pdev->dev, NULL, TIS_MEM_BASE, TIS_MEM_LEN, 0);
 	if (rc)
 		goto err_init;
 	return 0;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 04/10] tpm: rename chip->dev to chip->pdev
  2014-11-11 13:45 ` Jarkko Sakkinen
                   ` (3 preceding siblings ...)
  (?)
@ 2014-11-11 13:45 ` Jarkko Sakkinen
  2014-11-25 21:44     ` Stefan Berger
  -1 siblings, 1 reply; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech, Jarkko Sakkinen

Rename chip->dev to chip->pdev to make it explicit that this not the
character device but actually represents the platform device.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/char/tpm/tpm-chip.c         |  4 ++--
 drivers/char/tpm/tpm-dev.c          | 10 +++++-----
 drivers/char/tpm/tpm-interface.c    | 29 +++++++++++++++--------------
 drivers/char/tpm/tpm-sysfs.c        |  6 +++---
 drivers/char/tpm/tpm.h              |  4 ++--
 drivers/char/tpm/tpm_atmel.c        | 14 +++++++-------
 drivers/char/tpm/tpm_i2c_atmel.c    | 16 ++++++++--------
 drivers/char/tpm/tpm_i2c_infineon.c |  6 +++---
 drivers/char/tpm/tpm_i2c_nuvoton.c  | 22 +++++++++++-----------
 drivers/char/tpm/tpm_i2c_stm_st33.c |  6 +++---
 drivers/char/tpm/tpm_infineon.c     | 22 +++++++++++-----------
 drivers/char/tpm/tpm_nsc.c          | 20 ++++++++++----------
 drivers/char/tpm/tpm_ppi.c          |  4 ++--
 drivers/char/tpm/tpm_tis.c          | 12 ++++++------
 14 files changed, 88 insertions(+), 87 deletions(-)

diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 647867c..96ea8eb 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -45,7 +45,7 @@ struct tpm_chip *tpm_chip_find_get(int chip_num)
 		if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
 			continue;
 
-		if (try_module_get(pos->dev->driver->owner)) {
+		if (try_module_get(pos->pdev->driver->owner)) {
 			chip = pos;
 			break;
 		}
@@ -111,7 +111,7 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
 	scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm",
 		  chip->dev_num);
 
-	chip->dev = dev;
+	chip->pdev = dev;
 	devm_add_action(dev, tpmm_chip_remove, chip);
 	dev_set_drvdata(dev, chip);
 
diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
index d9b774e..3568321 100644
--- a/drivers/char/tpm/tpm-dev.c
+++ b/drivers/char/tpm/tpm-dev.c
@@ -63,7 +63,7 @@ static int tpm_open(struct inode *inode, struct file *file)
 	 * by the check of is_open variable, which is protected
 	 * by driver_lock. */
 	if (test_and_set_bit(0, &chip->is_open)) {
-		dev_dbg(chip->dev, "Another process owns this TPM\n");
+		dev_dbg(chip->pdev, "Another process owns this TPM\n");
 		return -EBUSY;
 	}
 
@@ -81,7 +81,7 @@ static int tpm_open(struct inode *inode, struct file *file)
 	INIT_WORK(&priv->work, timeout_work);
 
 	file->private_data = priv;
-	get_device(chip->dev);
+	get_device(chip->pdev);
 	return 0;
 }
 
@@ -168,7 +168,7 @@ static int tpm_release(struct inode *inode, struct file *file)
 	file->private_data = NULL;
 	atomic_set(&priv->data_pending, 0);
 	clear_bit(0, &priv->chip->is_open);
-	put_device(priv->chip->dev);
+	put_device(priv->chip->pdev);
 	kfree(priv);
 	return 0;
 }
@@ -193,12 +193,12 @@ int tpm_dev_add_device(struct tpm_chip *chip)
 		chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR;
 
 	chip->vendor.miscdev.name = chip->devname;
-	chip->vendor.miscdev.parent = chip->dev;
+	chip->vendor.miscdev.parent = chip->pdev;
 
 	rc = misc_register(&chip->vendor.miscdev);
 	if (rc) {
 		chip->vendor.miscdev.name = NULL;
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"unable to misc_register %s, minor %d err=%d\n",
 			chip->vendor.miscdev.name,
 			chip->vendor.miscdev.minor, rc);
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 915c610..e6b08bd 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -343,7 +343,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 	if (count == 0)
 		return -ENODATA;
 	if (count > bufsiz) {
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"invalid count value %x %zx\n", count, bufsiz);
 		return -E2BIG;
 	}
@@ -352,7 +352,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 
 	rc = chip->ops->send(chip, (u8 *) buf, count);
 	if (rc < 0) {
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"tpm_transmit: tpm_send: error %zd\n", rc);
 		goto out;
 	}
@@ -368,7 +368,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 			goto out_recv;
 
 		if (chip->ops->req_canceled(chip, status)) {
-			dev_err(chip->dev, "Operation Canceled\n");
+			dev_err(chip->pdev, "Operation Canceled\n");
 			rc = -ECANCELED;
 			goto out;
 		}
@@ -378,14 +378,14 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 	} while (time_before(jiffies, stop));
 
 	chip->ops->cancel(chip);
-	dev_err(chip->dev, "Operation Timed out\n");
+	dev_err(chip->pdev, "Operation Timed out\n");
 	rc = -ETIME;
 	goto out;
 
 out_recv:
 	rc = chip->ops->recv(chip, (u8 *) buf, bufsiz);
 	if (rc < 0)
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"tpm_transmit: tpm_recv: error %zd\n", rc);
 out:
 	mutex_unlock(&chip->tpm_mutex);
@@ -411,7 +411,8 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd,
 
 	err = be32_to_cpu(header->return_code);
 	if (err != 0 && desc)
-		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
+		dev_err(chip->pdev, "A TPM error (%d) occurred %s\n", err,
+			desc);
 
 	return err;
 }
@@ -505,7 +506,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 	if (rc == TPM_ERR_INVALID_POSTINIT) {
 		/* The TPM is not started, we are the first to talk to it.
 		   Execute a startup command. */
-		dev_info(chip->dev, "Issuing TPM_STARTUP");
+		dev_info(chip->pdev, "Issuing TPM_STARTUP");
 		if (tpm_startup(chip, TPM_ST_CLEAR))
 			return rc;
 
@@ -517,7 +518,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 				  NULL);
 	}
 	if (rc) {
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"A TPM error (%zd) occurred attempting to determine the timeouts\n",
 			rc);
 		goto duration;
@@ -556,7 +557,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 
 	/* Report adjusted timeouts */
 	if (chip->vendor.timeout_adjusted) {
-		dev_info(chip->dev,
+		dev_info(chip->pdev,
 			 HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
 			 old_timeout[0], new_timeout[0],
 			 old_timeout[1], new_timeout[1],
@@ -603,7 +604,7 @@ duration:
 		chip->vendor.duration[TPM_MEDIUM] *= 1000;
 		chip->vendor.duration[TPM_LONG] *= 1000;
 		chip->vendor.duration_adjusted = true;
-		dev_info(chip->dev, "Adjusting TPM timeout parameters.");
+		dev_info(chip->pdev, "Adjusting TPM timeout parameters.");
 	}
 	return 0;
 }
@@ -760,7 +761,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
 		 * around 300ms while the self test is ongoing, keep trying
 		 * until the self test duration expires. */
 		if (rc == -ETIME) {
-			dev_info(chip->dev, HW_ERR "TPM command timed out during continue self test");
+			dev_info(chip->pdev, HW_ERR "TPM command timed out during continue self test");
 			msleep(delay_msec);
 			continue;
 		}
@@ -770,7 +771,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
 
 		rc = be32_to_cpu(cmd.header.out.return_code);
 		if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
-			dev_info(chip->dev,
+			dev_info(chip->pdev,
 				 "TPM is disabled/deactivated (0x%X)\n", rc);
 			/* TPM is disabled and/or deactivated; driver can
 			 * proceed and TPM does handle commands for
@@ -918,10 +919,10 @@ int tpm_pm_suspend(struct device *dev)
 	}
 
 	if (rc)
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"Error (%d) sending savestate before suspend\n", rc);
 	else if (try > 0)
-		dev_warn(chip->dev, "TPM savestate took %dms\n",
+		dev_warn(chip->pdev, "TPM savestate took %dms\n",
 			 try * TPM_TIMEOUT_RETRY);
 
 	return rc;
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index 8ecb052..ee66fd4 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -284,16 +284,16 @@ static const struct attribute_group tpm_dev_group = {
 int tpm_sysfs_add_device(struct tpm_chip *chip)
 {
 	int err;
-	err = sysfs_create_group(&chip->dev->kobj,
+	err = sysfs_create_group(&chip->pdev->kobj,
 				 &tpm_dev_group);
 
 	if (err)
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"failed to create sysfs attributes, %d\n", err);
 	return err;
 }
 
 void tpm_sysfs_del_device(struct tpm_chip *chip)
 {
-	sysfs_remove_group(&chip->dev->kobj, &tpm_dev_group);
+	sysfs_remove_group(&chip->pdev->kobj, &tpm_dev_group);
 }
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 69f4003..b3a7c76 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -98,7 +98,7 @@ struct tpm_vendor_specific {
 #define TPM_PPI_VERSION_LEN		3
 
 struct tpm_chip {
-	struct device *dev;	/* Device stuff */
+	struct device *pdev;	/* Device stuff */
 	const struct tpm_class_ops *ops;
 
 	int dev_num;		/* /dev/tpm# */
@@ -124,7 +124,7 @@ struct tpm_chip {
 
 static inline void tpm_chip_put(struct tpm_chip *chip)
 {
-	module_put(chip->dev->driver->owner);
+	module_put(chip->pdev->driver->owner);
 }
 
 static inline int tpm_read_index(int base, int index)
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index 8e2576a..8a52ebe 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -49,7 +49,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	for (i = 0; i < 6; i++) {
 		status = ioread8(chip->vendor.iobase + 1);
 		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
-			dev_err(chip->dev, "error reading header\n");
+			dev_err(chip->pdev, "error reading header\n");
 			return -EIO;
 		}
 		*buf++ = ioread8(chip->vendor.iobase);
@@ -60,12 +60,12 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	size = be32_to_cpu(*native_size);
 
 	if (count < size) {
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"Recv size(%d) less than available space\n", size);
 		for (; i < size; i++) {	/* clear the waiting data anyway */
 			status = ioread8(chip->vendor.iobase + 1);
 			if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
-				dev_err(chip->dev, "error reading data\n");
+				dev_err(chip->pdev, "error reading data\n");
 				return -EIO;
 			}
 		}
@@ -76,7 +76,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	for (; i < size; i++) {
 		status = ioread8(chip->vendor.iobase + 1);
 		if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
-			dev_err(chip->dev, "error reading data\n");
+			dev_err(chip->pdev, "error reading data\n");
 			return -EIO;
 		}
 		*buf++ = ioread8(chip->vendor.iobase);
@@ -86,7 +86,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	status = ioread8(chip->vendor.iobase + 1);
 
 	if (status & ATML_STATUS_DATA_AVAIL) {
-		dev_err(chip->dev, "data available is stuck\n");
+		dev_err(chip->pdev, "data available is stuck\n");
 		return -EIO;
 	}
 
@@ -97,9 +97,9 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
 {
 	int i;
 
-	dev_dbg(chip->dev, "tpm_atml_send:\n");
+	dev_dbg(chip->pdev, "tpm_atml_send:\n");
 	for (i = 0; i < count; i++) {
-		dev_dbg(chip->dev, "%d 0x%x(%d)\n",  i, buf[i], buf[i]);
+		dev_dbg(chip->pdev, "%d 0x%x(%d)\n",  i, buf[i], buf[i]);
  		iowrite8(buf[i], chip->vendor.iobase);
 	}
 
diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c
index 8af3b4a..dfef1ae 100644
--- a/drivers/char/tpm/tpm_i2c_atmel.c
+++ b/drivers/char/tpm/tpm_i2c_atmel.c
@@ -52,7 +52,7 @@ struct priv_data {
 static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
 {
 	struct priv_data *priv = chip->vendor.priv;
-	struct i2c_client *client = to_i2c_client(chip->dev);
+	struct i2c_client *client = to_i2c_client(chip->pdev);
 	s32 status;
 
 	priv->len = 0;
@@ -62,7 +62,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
 
 	status = i2c_master_send(client, buf, len);
 
-	dev_dbg(chip->dev,
+	dev_dbg(chip->pdev,
 		"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
 		(int)min_t(size_t, 64, len), buf, len, status);
 	return status;
@@ -71,7 +71,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
 static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 {
 	struct priv_data *priv = chip->vendor.priv;
-	struct i2c_client *client = to_i2c_client(chip->dev);
+	struct i2c_client *client = to_i2c_client(chip->pdev);
 	struct tpm_output_header *hdr =
 		(struct tpm_output_header *)priv->buffer;
 	u32 expected_len;
@@ -88,7 +88,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 		return -ENOMEM;
 
 	if (priv->len >= expected_len) {
-		dev_dbg(chip->dev,
+		dev_dbg(chip->pdev,
 			"%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
 			(int)min_t(size_t, 64, expected_len), buf, count,
 			expected_len);
@@ -97,7 +97,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	}
 
 	rc = i2c_master_recv(client, buf, expected_len);
-	dev_dbg(chip->dev,
+	dev_dbg(chip->pdev,
 		"%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
 		(int)min_t(size_t, 64, expected_len), buf, count,
 		expected_len);
@@ -106,13 +106,13 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 
 static void i2c_atmel_cancel(struct tpm_chip *chip)
 {
-	dev_err(chip->dev, "TPM operation cancellation was requested, but is not supported");
+	dev_err(chip->pdev, "TPM operation cancellation was requested, but is not supported");
 }
 
 static u8 i2c_atmel_read_status(struct tpm_chip *chip)
 {
 	struct priv_data *priv = chip->vendor.priv;
-	struct i2c_client *client = to_i2c_client(chip->dev);
+	struct i2c_client *client = to_i2c_client(chip->pdev);
 	int rc;
 
 	/* The TPM fails the I2C read until it is ready, so we do the entire
@@ -125,7 +125,7 @@ static u8 i2c_atmel_read_status(struct tpm_chip *chip)
 	/* Once the TPM has completed the command the command remains readable
 	 * until another command is issued. */
 	rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer));
-	dev_dbg(chip->dev,
+	dev_dbg(chip->pdev,
 		"%s: sts=%d", __func__, rc);
 	if (rc <= 0)
 		return 0;
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
index 03708e6..33c5f36 100644
--- a/drivers/char/tpm/tpm_i2c_infineon.c
+++ b/drivers/char/tpm/tpm_i2c_infineon.c
@@ -446,7 +446,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	/* read first 10 bytes, including tag, paramsize, and result */
 	size = recv_data(chip, buf, TPM_HEADER_SIZE);
 	if (size < TPM_HEADER_SIZE) {
-		dev_err(chip->dev, "Unable to read header\n");
+		dev_err(chip->pdev, "Unable to read header\n");
 		goto out;
 	}
 
@@ -459,14 +459,14 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
 			  expected - TPM_HEADER_SIZE);
 	if (size < expected) {
-		dev_err(chip->dev, "Unable to read remainder of result\n");
+		dev_err(chip->pdev, "Unable to read remainder of result\n");
 		size = -ETIME;
 		goto out;
 	}
 
 	wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
 	if (status & TPM_STS_DATA_AVAIL) {	/* retry? */
-		dev_err(chip->dev, "Error left over data\n");
+		dev_err(chip->pdev, "Error left over data\n");
 		size = -EIO;
 		goto out;
 	}
diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c
index 09f0c46..92ee9fa 100644
--- a/drivers/char/tpm/tpm_i2c_nuvoton.c
+++ b/drivers/char/tpm/tpm_i2c_nuvoton.c
@@ -96,13 +96,13 @@ static s32 i2c_nuvoton_write_buf(struct i2c_client *client, u8 offset, u8 size,
 /* read TPM_STS register */
 static u8 i2c_nuvoton_read_status(struct tpm_chip *chip)
 {
-	struct i2c_client *client = to_i2c_client(chip->dev);
+	struct i2c_client *client = to_i2c_client(chip->pdev);
 	s32 status;
 	u8 data;
 
 	status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data);
 	if (status <= 0) {
-		dev_err(chip->dev, "%s() error return %d\n", __func__,
+		dev_err(chip->pdev, "%s() error return %d\n", __func__,
 			status);
 		data = TPM_STS_ERR_VAL;
 	}
@@ -127,13 +127,13 @@ static s32 i2c_nuvoton_write_status(struct i2c_client *client, u8 data)
 /* write commandReady to TPM_STS register */
 static void i2c_nuvoton_ready(struct tpm_chip *chip)
 {
-	struct i2c_client *client = to_i2c_client(chip->dev);
+	struct i2c_client *client = to_i2c_client(chip->pdev);
 	s32 status;
 
 	/* this causes the current command to be aborted */
 	status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY);
 	if (status < 0)
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"%s() fail to write TPM_STS.commandReady\n", __func__);
 }
 
@@ -212,7 +212,7 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value,
 				return 0;
 		} while (time_before(jiffies, stop));
 	}
-	dev_err(chip->dev, "%s(%02x, %02x) -> timeout\n", __func__, mask,
+	dev_err(chip->pdev, "%s(%02x, %02x) -> timeout\n", __func__, mask,
 		value);
 	return -ETIMEDOUT;
 }
@@ -240,7 +240,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
 					       &chip->vendor.read_queue) == 0) {
 		burst_count = i2c_nuvoton_get_burstcount(client, chip);
 		if (burst_count < 0) {
-			dev_err(chip->dev,
+			dev_err(chip->pdev,
 				"%s() fail to read burstCount=%d\n", __func__,
 				burst_count);
 			return -EIO;
@@ -249,12 +249,12 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
 		rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_R,
 					  bytes2read, &buf[size]);
 		if (rc < 0) {
-			dev_err(chip->dev,
+			dev_err(chip->pdev,
 				"%s() fail on i2c_nuvoton_read_buf()=%d\n",
 				__func__, rc);
 			return -EIO;
 		}
-		dev_dbg(chip->dev, "%s(%d):", __func__, bytes2read);
+		dev_dbg(chip->pdev, "%s(%d):", __func__, bytes2read);
 		size += bytes2read;
 	}
 
@@ -264,7 +264,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
 /* Read TPM command results */
 static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 {
-	struct device *dev = chip->dev;
+	struct device *dev = chip->pdev;
 	struct i2c_client *client = to_i2c_client(dev);
 	s32 rc;
 	int expected, status, burst_count, retries, size = 0;
@@ -334,7 +334,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 		break;
 	}
 	i2c_nuvoton_ready(chip);
-	dev_dbg(chip->dev, "%s() -> %d\n", __func__, size);
+	dev_dbg(chip->pdev, "%s() -> %d\n", __func__, size);
 	return size;
 }
 
@@ -347,7 +347,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
  */
 static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len)
 {
-	struct device *dev = chip->dev;
+	struct device *dev = chip->pdev;
 	struct i2c_client *client = to_i2c_client(dev);
 	u32 ordinal;
 	size_t count = 0;
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index b9d1a38..64ef510 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -544,7 +544,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
 
 	size = recv_data(chip, buf, TPM_HEADER_SIZE);
 	if (size < TPM_HEADER_SIZE) {
-		dev_err(chip->dev, "Unable to read header\n");
+		dev_err(chip->pdev, "Unable to read header\n");
 		goto out;
 	}
 
@@ -557,7 +557,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
 	size += recv_data(chip, &buf[TPM_HEADER_SIZE],
 					expected - TPM_HEADER_SIZE);
 	if (size < expected) {
-		dev_err(chip->dev, "Unable to read remainder of result\n");
+		dev_err(chip->pdev, "Unable to read remainder of result\n");
 		size = -ETIME;
 		goto out;
 	}
@@ -671,7 +671,7 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
 				IRQF_TRIGGER_HIGH,
 				"TPM SERIRQ management", chip);
 		if (err < 0) {
-			dev_err(chip->dev , "TPM SERIRQ signals %d not available\n",
+			dev_err(chip->pdev , "TPM SERIRQ signals %d not available\n",
 				gpio_to_irq(platform_data->io_serirq));
 			goto _irq_set;
 		}
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index dcdb671..6d49213 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -195,9 +195,9 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
 	}
 	if (i == TPM_MAX_TRIES) {	/* timeout occurs */
 		if (wait_for_bit == STAT_XFE)
-			dev_err(chip->dev, "Timeout in wait(STAT_XFE)\n");
+			dev_err(chip->pdev, "Timeout in wait(STAT_XFE)\n");
 		if (wait_for_bit == STAT_RDA)
-			dev_err(chip->dev, "Timeout in wait(STAT_RDA)\n");
+			dev_err(chip->pdev, "Timeout in wait(STAT_RDA)\n");
 		return -EIO;
 	}
 	return 0;
@@ -220,7 +220,7 @@ static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
 static void tpm_wtx(struct tpm_chip *chip)
 {
 	number_of_wtx++;
-	dev_info(chip->dev, "Granting WTX (%02d / %02d)\n",
+	dev_info(chip->pdev, "Granting WTX (%02d / %02d)\n",
 		 number_of_wtx, TPM_MAX_WTX_PACKAGES);
 	wait_and_send(chip, TPM_VL_VER);
 	wait_and_send(chip, TPM_CTRL_WTX);
@@ -231,7 +231,7 @@ static void tpm_wtx(struct tpm_chip *chip)
 
 static void tpm_wtx_abort(struct tpm_chip *chip)
 {
-	dev_info(chip->dev, "Aborting WTX\n");
+	dev_info(chip->pdev, "Aborting WTX\n");
 	wait_and_send(chip, TPM_VL_VER);
 	wait_and_send(chip, TPM_CTRL_WTX_ABORT);
 	wait_and_send(chip, 0x00);
@@ -257,7 +257,7 @@ recv_begin:
 	}
 
 	if (buf[0] != TPM_VL_VER) {
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"Wrong transport protocol implementation!\n");
 		return -EIO;
 	}
@@ -272,7 +272,7 @@ recv_begin:
 		}
 
 		if ((size == 0x6D00) && (buf[1] == 0x80)) {
-			dev_err(chip->dev, "Error handling on vendor layer!\n");
+			dev_err(chip->pdev, "Error handling on vendor layer!\n");
 			return -EIO;
 		}
 
@@ -284,7 +284,7 @@ recv_begin:
 	}
 
 	if (buf[1] == TPM_CTRL_WTX) {
-		dev_info(chip->dev, "WTX-package received\n");
+		dev_info(chip->pdev, "WTX-package received\n");
 		if (number_of_wtx < TPM_MAX_WTX_PACKAGES) {
 			tpm_wtx(chip);
 			goto recv_begin;
@@ -295,14 +295,14 @@ recv_begin:
 	}
 
 	if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) {
-		dev_info(chip->dev, "WTX-abort acknowledged\n");
+		dev_info(chip->pdev, "WTX-abort acknowledged\n");
 		return size;
 	}
 
 	if (buf[1] == TPM_CTRL_ERROR) {
-		dev_err(chip->dev, "ERROR-package received:\n");
+		dev_err(chip->pdev, "ERROR-package received:\n");
 		if (buf[4] == TPM_INF_NAK)
-			dev_err(chip->dev,
+			dev_err(chip->pdev,
 				"-> Negative acknowledgement"
 				" - retransmit command!\n");
 		return -EIO;
@@ -321,7 +321,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
 
 	ret = empty_fifo(chip, 1);
 	if (ret) {
-		dev_err(chip->dev, "Timeout while clearing FIFO\n");
+		dev_err(chip->pdev, "Timeout while clearing FIFO\n");
 		return -EIO;
 	}
 
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 00c5470..072c298 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -113,7 +113,7 @@ static int nsc_wait_for_ready(struct tpm_chip *chip)
 	}
 	while (time_before(jiffies, stop));
 
-	dev_info(chip->dev, "wait for ready failed\n");
+	dev_info(chip->pdev, "wait for ready failed\n");
 	return -EBUSY;
 }
 
@@ -129,12 +129,12 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
 		return -EIO;
 
 	if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
-		dev_err(chip->dev, "F0 timeout\n");
+		dev_err(chip->pdev, "F0 timeout\n");
 		return -EIO;
 	}
 	if ((data =
 	     inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
-		dev_err(chip->dev, "not in normal mode (0x%x)\n",
+		dev_err(chip->pdev, "not in normal mode (0x%x)\n",
 			data);
 		return -EIO;
 	}
@@ -143,7 +143,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
 	for (p = buffer; p < &buffer[count]; p++) {
 		if (wait_for_stat
 		    (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
-			dev_err(chip->dev,
+			dev_err(chip->pdev,
 				"OBF timeout (while reading data)\n");
 			return -EIO;
 		}
@@ -154,11 +154,11 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
 
 	if ((data & NSC_STATUS_F0) == 0 &&
 	(wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
-		dev_err(chip->dev, "F0 not set\n");
+		dev_err(chip->pdev, "F0 not set\n");
 		return -EIO;
 	}
 	if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) {
-		dev_err(chip->dev,
+		dev_err(chip->pdev,
 			"expected end of command(0x%x)\n", data);
 		return -EIO;
 	}
@@ -189,19 +189,19 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
 		return -EIO;
 
 	if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
-		dev_err(chip->dev, "IBF timeout\n");
+		dev_err(chip->pdev, "IBF timeout\n");
 		return -EIO;
 	}
 
 	outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND);
 	if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
-		dev_err(chip->dev, "IBR timeout\n");
+		dev_err(chip->pdev, "IBR timeout\n");
 		return -EIO;
 	}
 
 	for (i = 0; i < count; i++) {
 		if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
-			dev_err(chip->dev,
+			dev_err(chip->pdev,
 				"IBF timeout (while writing data)\n");
 			return -EIO;
 		}
@@ -209,7 +209,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
 	}
 
 	if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
-		dev_err(chip->dev, "IBF timeout\n");
+		dev_err(chip->pdev, "IBF timeout\n");
 		return -EIO;
 	}
 	outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND);
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c
index 6acdb17..659de61 100644
--- a/drivers/char/tpm/tpm_ppi.c
+++ b/drivers/char/tpm/tpm_ppi.c
@@ -358,11 +358,11 @@ int tpm_add_ppi(struct tpm_chip *chip)
 
 	ACPI_FREE(obj);
 
-	return sysfs_create_group(&chip->dev->kobj, &ppi_attr_grp);
+	return sysfs_create_group(&chip->pdev->kobj, &ppi_attr_grp);
 }
 
 void tpm_remove_ppi(struct tpm_chip *chip)
 {
 	if (chip->ppi_version[0] != '\0')
-		sysfs_remove_group(&chip->dev->kobj, &ppi_attr_grp);
+		sysfs_remove_group(&chip->pdev->kobj, &ppi_attr_grp);
 }
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 00ed222..660d9af 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -238,7 +238,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	/* read first 10 bytes, including tag, paramsize, and result */
 	if ((size =
 	     recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
-		dev_err(chip->dev, "Unable to read header\n");
+		dev_err(chip->pdev, "Unable to read header\n");
 		goto out;
 	}
 
@@ -251,7 +251,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 	if ((size +=
 	     recv_data(chip, &buf[TPM_HEADER_SIZE],
 		       expected - TPM_HEADER_SIZE)) < expected) {
-		dev_err(chip->dev, "Unable to read remainder of result\n");
+		dev_err(chip->pdev, "Unable to read remainder of result\n");
 		size = -ETIME;
 		goto out;
 	}
@@ -260,7 +260,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 			  &chip->vendor.int_queue, false);
 	status = tpm_tis_status(chip);
 	if (status & TPM_STS_DATA_AVAIL) {	/* retry? */
-		dev_err(chip->dev, "Error left over data\n");
+		dev_err(chip->pdev, "Error left over data\n");
 		size = -EIO;
 		goto out;
 	}
@@ -433,7 +433,7 @@ static int probe_itpm(struct tpm_chip *chip)
 
 	rc = tpm_tis_send_data(chip, cmd_getticks, len);
 	if (rc == 0) {
-		dev_info(chip->dev, "Detected an iTPM.\n");
+		dev_info(chip->pdev, "Detected an iTPM.\n");
 		rc = 1;
 	} else
 		rc = -EFAULT;
@@ -662,7 +662,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 			if (devm_request_irq
 			    (dev, i, tis_int_probe, IRQF_SHARED,
 			     chip->vendor.miscdev.name, chip) != 0) {
-				dev_info(chip->dev,
+				dev_info(chip->pdev,
 					 "Unable to request irq: %d for probe\n",
 					 i);
 				continue;
@@ -709,7 +709,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 		if (devm_request_irq
 		    (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
 		     chip->vendor.miscdev.name, chip) != 0) {
-			dev_info(chip->dev,
+			dev_info(chip->pdev,
 				 "Unable to request irq: %d for use\n",
 				 chip->vendor.irq);
 			chip->vendor.irq = 0;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 05/10] tpm: device class for tpm
  2014-11-11 13:45 ` Jarkko Sakkinen
                   ` (4 preceding siblings ...)
  (?)
@ 2014-11-11 13:45 ` Jarkko Sakkinen
  2014-11-26 12:34     ` Stefan Berger
  -1 siblings, 1 reply; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech, Jarkko Sakkinen

Added own device class for TPM. Uses MISC_MAJOR:TPM_MINOR for the
first character device in order to retain backwards compatability.
Added tpm_dev_release() back attached to the character device.
devm now only calls put_device when the platform device is removed.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/char/tpm/tpm-chip.c        | 81 ++++++++++++++++++++++++++++++++++----
 drivers/char/tpm/tpm-dev.c         | 36 ++---------------
 drivers/char/tpm/tpm-interface.c   | 29 ++++++++++++++
 drivers/char/tpm/tpm.h             | 12 ++++--
 drivers/char/tpm/tpm_i2c_nuvoton.c |  2 +-
 drivers/char/tpm/tpm_tis.c         |  4 +-
 6 files changed, 116 insertions(+), 48 deletions(-)

diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 96ea8eb..df40eee 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -25,6 +25,7 @@
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <linux/freezer.h>
+#include <linux/major.h>
 #include "tpm.h"
 #include "tpm_eventlog.h"
 
@@ -32,6 +33,9 @@ static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
 static LIST_HEAD(tpm_chip_list);
 static DEFINE_SPINLOCK(driver_lock);
 
+struct class *tpm_class;
+dev_t tpm_devt;
+
 /*
  * tpm_chip_find_get - return tpm_chip for a given chip number
  * @chip_num the device number for the chip
@@ -55,16 +59,24 @@ struct tpm_chip *tpm_chip_find_get(int chip_num)
 }
 
 /**
- * tpmm_chip_remove() - free chip memory and device number
- * @data: points to struct tpm_chip instance
+ * tpmm_put_device() - wrap put_device() for devm
+ * @data: points to the device
+ */
+static void tpmm_put_device(void *data)
+{
+	struct device *dev = (struct device *) data;
+	put_device(dev);
+}
+
+/**
+ * tpm_dev_release() - free chip memory and the device number
+ * @dev: the character device for the TPM chip
  *
- * This is used internally by tpmm_chip_alloc() and called by devres
- * when the device is released. This function does the opposite of
- * tpmm_chip_alloc() freeing memory and the device number.
+ * This is used as the release function for the character device.
  */
-static void tpmm_chip_remove(void *data)
+static void tpm_dev_release(struct device *dev)
 {
-	struct tpm_chip *chip = (struct tpm_chip *) data;
+	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
 
 	spin_lock(&driver_lock);
 	clear_bit(chip->dev_num, dev_mask);
@@ -112,13 +124,66 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
 		  chip->dev_num);
 
 	chip->pdev = dev;
-	devm_add_action(dev, tpmm_chip_remove, chip);
+
 	dev_set_drvdata(dev, chip);
 
+	chip->dev.class = tpm_class;
+	chip->dev.release = tpm_dev_release;
+	chip->dev.parent = chip->pdev;
+
+	if (chip->dev_num == 0)
+		chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
+	else
+		chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
+
+	dev_set_name(&chip->dev, chip->devname);
+
+	device_initialize(&chip->dev);
+
+	chip->cdev.owner = chip->pdev->driver->owner;
+	cdev_init(&chip->cdev, &tpm_fops);
+
+	devm_add_action(dev, tpmm_put_device, chip);
 	return chip;
 }
 EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
 
+static int tpm_dev_add_device(struct tpm_chip *chip)
+{
+	int rc;
+
+	rc = device_add(&chip->dev);
+	if (rc) {
+		dev_err(&chip->dev,
+			"unable to device_register %s, major %d, minor %d " \
+			"err=%d\n",
+			chip->devname, MAJOR(chip->dev.devt),
+			MINOR(chip->dev.devt), rc);
+
+		return rc;
+	}
+
+	rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
+	if (rc) {
+		dev_err(&chip->dev,
+			"unable to cdev_add %s, major %d, minor %d " \
+			"err=%d\n",
+			chip->devname, MAJOR(chip->dev.devt),
+			MINOR(chip->dev.devt), rc);
+
+		device_unregister(&chip->dev);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void tpm_dev_del_device(struct tpm_chip *chip)
+{
+	cdev_del(&chip->cdev);
+	device_unregister(&chip->dev);
+}
+
 /*
  * tpm_chip_register() - create a misc driver for the TPM chip
  * @chip: TPM chip to use.
diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
index 3568321..de0337e 100644
--- a/drivers/char/tpm/tpm-dev.c
+++ b/drivers/char/tpm/tpm-dev.c
@@ -17,7 +17,6 @@
  * License.
  *
  */
-#include <linux/miscdevice.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include "tpm.h"
@@ -54,9 +53,8 @@ static void timeout_work(struct work_struct *work)
 
 static int tpm_open(struct inode *inode, struct file *file)
 {
-	struct miscdevice *misc = file->private_data;
-	struct tpm_chip *chip = container_of(misc, struct tpm_chip,
-					     vendor.miscdev);
+	struct tpm_chip *chip =
+		container_of(inode->i_cdev, struct tpm_chip, cdev);
 	struct file_priv *priv;
 
 	/* It's assured that the chip will be opened just once,
@@ -173,7 +171,7 @@ static int tpm_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
-static const struct file_operations tpm_fops = {
+const struct file_operations tpm_fops = {
 	.owner = THIS_MODULE,
 	.llseek = no_llseek,
 	.open = tpm_open,
@@ -182,32 +180,4 @@ static const struct file_operations tpm_fops = {
 	.release = tpm_release,
 };
 
-int tpm_dev_add_device(struct tpm_chip *chip)
-{
-	int rc;
 
-	chip->vendor.miscdev.fops = &tpm_fops;
-	if (chip->dev_num == 0)
-		chip->vendor.miscdev.minor = TPM_MINOR;
-	else
-		chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR;
-
-	chip->vendor.miscdev.name = chip->devname;
-	chip->vendor.miscdev.parent = chip->pdev;
-
-	rc = misc_register(&chip->vendor.miscdev);
-	if (rc) {
-		chip->vendor.miscdev.name = NULL;
-		dev_err(chip->pdev,
-			"unable to misc_register %s, minor %d err=%d\n",
-			chip->vendor.miscdev.name,
-			chip->vendor.miscdev.minor, rc);
-	}
-	return rc;
-}
-
-void tpm_dev_del_device(struct tpm_chip *chip)
-{
-	if (chip->vendor.miscdev.name)
-		misc_deregister(&chip->vendor.miscdev);
-}
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index e6b08bd..9e4ce4d 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -997,6 +997,35 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 }
 EXPORT_SYMBOL_GPL(tpm_get_random);
 
+static int __init tpm_init(void)
+{
+	int rc;
+
+	tpm_class = class_create(THIS_MODULE, "tpm");
+	if (IS_ERR(tpm_class)) {
+		pr_err("couldn't create tpm class\n");
+		return PTR_ERR(tpm_class);
+	}
+
+	rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm");
+	if (rc < 0) {
+		pr_err("tpm: failed to allocate char dev region\n");
+		class_destroy(tpm_class);
+		return rc;
+	}
+
+	return 0;
+}
+
+static void __exit tpm_exit(void)
+{
+	class_destroy(tpm_class);
+	unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES);
+}
+
+subsys_initcall(tpm_init);
+module_exit(tpm_exit);
+
 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
 MODULE_DESCRIPTION("TPM Driver");
 MODULE_VERSION("2.0");
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index b3a7c76..83103e0 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -23,11 +23,11 @@
 #include <linux/fs.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
-#include <linux/miscdevice.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/tpm.h>
 #include <linux/acpi.h>
+#include <linux/cdev.h>
 
 enum tpm_const {
 	TPM_MINOR = 224,	/* officially assigned */
@@ -74,7 +74,6 @@ struct tpm_vendor_specific {
 	int region_size;
 	int have_region;
 
-	struct miscdevice miscdev;
 	struct list_head list;
 	int locality;
 	unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
@@ -99,6 +98,9 @@ struct tpm_vendor_specific {
 
 struct tpm_chip {
 	struct device *pdev;	/* Device stuff */
+	struct device dev;
+	struct cdev cdev;
+
 	const struct tpm_class_ops *ops;
 
 	int dev_num;		/* /dev/tpm# */
@@ -320,6 +322,10 @@ struct tpm_cmd_t {
 	tpm_cmd_params	params;
 } __packed;
 
+extern struct class *tpm_class;
+extern dev_t tpm_devt;
+extern const struct file_operations tpm_fops;
+
 ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
 ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 		     size_t bufsiz);
@@ -340,8 +346,6 @@ extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
 extern int tpm_chip_register(struct tpm_chip *chip);
 extern void tpm_chip_unregister(struct tpm_chip *chip);
 
-int tpm_dev_add_device(struct tpm_chip *chip);
-void tpm_dev_del_device(struct tpm_chip *chip);
 int tpm_sysfs_add_device(struct tpm_chip *chip);
 void tpm_sysfs_del_device(struct tpm_chip *chip);
 
diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c
index 92ee9fa..14246e2 100644
--- a/drivers/char/tpm/tpm_i2c_nuvoton.c
+++ b/drivers/char/tpm/tpm_i2c_nuvoton.c
@@ -557,7 +557,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
 		rc = devm_request_irq(dev, chip->vendor.irq,
 				      i2c_nuvoton_int_handler,
 				      IRQF_TRIGGER_LOW,
-				      chip->vendor.miscdev.name,
+				      chip->devname,
 				      chip);
 		if (rc) {
 			dev_err(dev, "%s() Unable to request irq: %d for use\n",
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 660d9af..7a2c59b 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -661,7 +661,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 				 TPM_INT_VECTOR(chip->vendor.locality));
 			if (devm_request_irq
 			    (dev, i, tis_int_probe, IRQF_SHARED,
-			     chip->vendor.miscdev.name, chip) != 0) {
+			     chip->devname, chip) != 0) {
 				dev_info(chip->pdev,
 					 "Unable to request irq: %d for probe\n",
 					 i);
@@ -708,7 +708,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 			 TPM_INT_VECTOR(chip->vendor.locality));
 		if (devm_request_irq
 		    (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
-		     chip->vendor.miscdev.name, chip) != 0) {
+		     chip->devname, chip) != 0) {
 			dev_info(chip->pdev,
 				 "Unable to request irq: %d for use\n",
 				 chip->vendor.irq);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 06/10] tpm: fix: move sysfs attributes to the correct place.
  2014-11-11 13:45 ` Jarkko Sakkinen
                   ` (5 preceding siblings ...)
  (?)
@ 2014-11-11 13:45 ` Jarkko Sakkinen
  2014-11-18  9:29     ` Jarkko Sakkinen
  2014-11-26  0:48     ` Stefan Berger
  -1 siblings, 2 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech, Jarkko Sakkinen

The sysfs attributes of the TPM device were created to the platform
device directory that owns the character device instead of placing
them correctly to the directory of the character device,

They were also created in a racy way so that character device might
become visible before sysfs attributes become available.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/char/tpm/tpm-chip.c  | 15 ++++++---------
 drivers/char/tpm/tpm-dev.c   |  2 --
 drivers/char/tpm/tpm-sysfs.c | 23 +----------------------
 drivers/char/tpm/tpm.h       |  4 +---
 4 files changed, 8 insertions(+), 36 deletions(-)

diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index df40eee..5d268ac 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -29,6 +29,8 @@
 #include "tpm.h"
 #include "tpm_eventlog.h"
 
+ATTRIBUTE_GROUPS(tpm_dev);
+
 static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
 static LIST_HEAD(tpm_chip_list);
 static DEFINE_SPINLOCK(driver_lock);
@@ -136,6 +138,8 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
 	else
 		chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
 
+	chip->dev.groups = tpm_dev_groups;
+
 	dev_set_name(&chip->dev, chip->devname);
 
 	device_initialize(&chip->dev);
@@ -209,13 +213,9 @@ int tpm_chip_register(struct tpm_chip *chip)
 	if (rc)
 		return rc;
 
-	rc = tpm_sysfs_add_device(chip);
-	if (rc)
-		goto del_misc;
-
 	rc = tpm_add_ppi(chip);
 	if (rc)
-		goto del_sysfs;
+		goto out_err;
 
 	chip->bios_dir = tpm_bios_log_setup(chip->devname);
 
@@ -225,9 +225,7 @@ int tpm_chip_register(struct tpm_chip *chip)
 	spin_unlock(&driver_lock);
 
 	return 0;
-del_sysfs:
-	tpm_sysfs_del_device(chip);
-del_misc:
+out_err:
 	tpm_dev_del_device(chip);
 	return rc;
 }
@@ -250,7 +248,6 @@ void tpm_chip_unregister(struct tpm_chip *chip)
 	spin_unlock(&driver_lock);
 	synchronize_rcu();
 
-	tpm_sysfs_del_device(chip);
 	tpm_remove_ppi(chip);
 
 	if (chip->bios_dir)
diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
index de0337e..f3f073f 100644
--- a/drivers/char/tpm/tpm-dev.c
+++ b/drivers/char/tpm/tpm-dev.c
@@ -179,5 +179,3 @@ const struct file_operations tpm_fops = {
 	.write = tpm_write,
 	.release = tpm_release,
 };
-
-
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index ee66fd4..9f5b85a 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -263,7 +263,7 @@ static ssize_t timeouts_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(timeouts);
 
-static struct attribute *tpm_dev_attrs[] = {
+struct attribute *tpm_dev_attrs[] = {
 	&dev_attr_pubek.attr,
 	&dev_attr_pcrs.attr,
 	&dev_attr_enabled.attr,
@@ -276,24 +276,3 @@ static struct attribute *tpm_dev_attrs[] = {
 	&dev_attr_timeouts.attr,
 	NULL,
 };
-
-static const struct attribute_group tpm_dev_group = {
-	.attrs = tpm_dev_attrs,
-};
-
-int tpm_sysfs_add_device(struct tpm_chip *chip)
-{
-	int err;
-	err = sysfs_create_group(&chip->pdev->kobj,
-				 &tpm_dev_group);
-
-	if (err)
-		dev_err(chip->pdev,
-			"failed to create sysfs attributes, %d\n", err);
-	return err;
-}
-
-void tpm_sysfs_del_device(struct tpm_chip *chip)
-{
-	sysfs_remove_group(&chip->pdev->kobj, &tpm_dev_group);
-}
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 83103e0..9d062e6 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -325,6 +325,7 @@ struct tpm_cmd_t {
 extern struct class *tpm_class;
 extern dev_t tpm_devt;
 extern const struct file_operations tpm_fops;
+extern struct attribute *tpm_dev_attrs[];
 
 ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
 ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
@@ -346,9 +347,6 @@ extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
 extern int tpm_chip_register(struct tpm_chip *chip);
 extern void tpm_chip_unregister(struct tpm_chip *chip);
 
-int tpm_sysfs_add_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);
 
 #ifdef CONFIG_ACPI
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 07/10] tpm: TPM 2.0 baseline support
  2014-11-11 13:45 ` Jarkko Sakkinen
                   ` (6 preceding siblings ...)
  (?)
@ 2014-11-11 13:45 ` Jarkko Sakkinen
  2014-11-26  0:42     ` Stefan Berger
  -1 siblings, 1 reply; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech, Jarkko Sakkinen,
	Will Arthur

TPM 2.0 devices are separated by adding a field 'flags' to struct
tpm_chip and defining a flag TPM_CHIP_FLAG_TPM2 for tagging them.

This patch adds the following internal functions:

- tpm2_get_random()
- tpm2_get_tpm_pt()
- tpm2_pcr_extend()
- tpm2_pcr_read()
- tpm2_startup()

Additionally, the following exported functions are implemented for
implementing TPM 2.0 device drivers:

- tpm2_do_selftest()
- tpm2_calc_ordinal_durations()
- tpm2_gen_interrupt()

The existing functions that are exported for the use for existing
subsystems have been changed to check the flags field in struct
tpm_chip and use appropriate TPM 2.0 counterpart if
TPM_CHIP_FLAG_TPM2 is est.

The code for tpm2_calc_ordinal_duration() and tpm2_startup() were
originally written by Will Arthur.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Will Arthur <will.c.arthur@intel.com>
---
 drivers/char/tpm/Makefile        |   2 +-
 drivers/char/tpm/tpm-chip.c      |  21 +-
 drivers/char/tpm/tpm-interface.c |  24 +-
 drivers/char/tpm/tpm.h           |  67 +++++
 drivers/char/tpm/tpm2-cmd.c      | 566 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 668 insertions(+), 12 deletions(-)
 create mode 100644 drivers/char/tpm/tpm2-cmd.c

diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 837da04..ae56af9 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the kernel tpm device drivers.
 #
 obj-$(CONFIG_TCG_TPM) += tpm.o
-tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o
+tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o
 tpm-$(CONFIG_ACPI) += tpm_ppi.o
 
 ifdef CONFIG_ACPI
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 5d268ac..4d25b24 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -213,11 +213,14 @@ int tpm_chip_register(struct tpm_chip *chip)
 	if (rc)
 		return rc;
 
-	rc = tpm_add_ppi(chip);
-	if (rc)
-		goto out_err;
+	/* Populate sysfs for TPM1 devices. */
+	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+		rc = tpm_add_ppi(chip);
+		if (rc)
+			goto out_err;
 
-	chip->bios_dir = tpm_bios_log_setup(chip->devname);
+		chip->bios_dir = tpm_bios_log_setup(chip->devname);
+	}
 
 	/* Make the chip available. */
 	spin_lock(&driver_lock);
@@ -248,10 +251,12 @@ void tpm_chip_unregister(struct tpm_chip *chip)
 	spin_unlock(&driver_lock);
 	synchronize_rcu();
 
-	tpm_remove_ppi(chip);
-
-	if (chip->bios_dir)
-		tpm_bios_log_teardown(chip->bios_dir);
+	/* Clean up sysfs for TPM1 devices. */
+	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+		if (chip->bios_dir)
+			tpm_bios_log_teardown(chip->bios_dir);
+		tpm_remove_ppi(chip);
+	}
 
 	tpm_dev_del_device(chip);
 }
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 9e4ce4d..e62b835 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -360,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
 	if (chip->vendor.irq)
 		goto out_recv;
 
-	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
+		stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
+	else
+		stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
 	do {
 		u8 status = chip->ops->status(chip);
 		if ((status & chip->ops->req_complete_mask) ==
@@ -483,7 +486,7 @@ static const struct tpm_input_header tpm_startup_header = {
 static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
 {
 	struct tpm_cmd_t start_cmd;
-	start_cmd.header.in = tpm_startup_header;
+
 	start_cmd.params.startup_in.startup_type = startup_type;
 	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
 				"attempting to start the TPM");
@@ -680,7 +683,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
 	chip = tpm_chip_find_get(chip_num);
 	if (chip == NULL)
 		return -ENODEV;
-	rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
+		rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
+	else
+		rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
 	tpm_chip_put(chip);
 	return rc;
 }
@@ -714,6 +720,12 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
 	if (chip == NULL)
 		return -ENODEV;
 
+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+		rc = tpm2_pcr_extend(chip, pcr_idx, hash);
+		tpm_chip_put(chip);
+		return rc;
+	}
+
 	cmd.header.in = pcrextend_header;
 	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
 	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
@@ -974,6 +986,12 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 	if (chip == NULL)
 		return -ENODEV;
 
+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+		err = tpm2_get_random(chip, out, max);
+		tpm_chip_put(chip);
+		return err;
+	}
+
 	do {
 		tpm_cmd.header.in = tpm_getrandom_header;
 		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 9d062e6..8a434d2 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -62,6 +62,57 @@ enum tpm_duration {
 #define TPM_ERR_INVALID_POSTINIT 38
 
 #define TPM_HEADER_SIZE		10
+
+enum tpm2_const {
+	TPM2_PLATFORM_PCR	= 24,
+	TPM2_PCR_SELECT_MIN	= ((TPM2_PLATFORM_PCR + 7) / 8),
+	TPM2_TIMEOUT_A		= 750 * 1000,
+	TPM2_TIMEOUT_B		= 2000 * 1000,
+	TPM2_TIMEOUT_C		= 200 * 1000,
+	TPM2_TIMEOUT_D		= 30 * 1000,
+	TPM2_DURATION_SHORT	= 20 * 1000,
+	TPM2_DURATION_MEDIUM	= 750 * 1000,
+	TPM2_DURATION_LONG	= 2000 * 1000,
+};
+
+enum tpm2_structures {
+	TPM2_ST_NO_SESSIONS	= 0x8001,
+	TPM2_ST_SESSIONS	= 0x8002,
+};
+
+enum tpm2_return_codes {
+	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_GET_CAPABILITY	= 0x017A,
+	TPM2_CC_GET_RANDOM	= 0x017B,
+	TPM2_CC_PCR_READ	= 0x017E,
+	TPM2_CC_PCR_EXTEND	= 0x0182,
+	TPM2_CC_LAST		= 0x018F,
+};
+
+enum tpm2_permanent_handles {
+	TPM2_RS_PW		= 0x40000009,
+};
+
+enum tpm2_capabilities {
+	TPM2_CAP_TPM_PROPERTIES = 6,
+};
+
+enum tpm2_startup_types {
+	TPM2_SU_CLEAR	= 0x0000,
+	TPM2_SU_STATE	= 0x0001,
+};
+
 struct tpm_chip;
 
 struct tpm_vendor_specific {
@@ -96,12 +147,17 @@ struct tpm_vendor_specific {
 
 #define TPM_PPI_VERSION_LEN		3
 
+enum tpm_chip_flags {
+	TPM_CHIP_FLAG_TPM2	= BIT(0),
+};
+
 struct tpm_chip {
 	struct device *pdev;	/* Device stuff */
 	struct device dev;
 	struct cdev cdev;
 
 	const struct tpm_class_ops *ops;
+	unsigned int flags;
 
 	int dev_num;		/* /dev/tpm# */
 	char devname[7];
@@ -362,3 +418,14 @@ static inline void tpm_remove_ppi(struct tpm_chip *chip)
 {
 }
 #endif
+
+int tpm2_startup(struct tpm_chip *chip, __be16 startup_type);
+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);
+
+extern ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
+			       u32 *value, const char *desc);
+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);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
new file mode 100644
index 0000000..458a17d
--- /dev/null
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -0,0 +1,566 @@
+/*
+ * 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 */
+};
+
+static const struct tpm_input_header tpm2_startup_header = {
+	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+	.length = cpu_to_be32(12),
+	.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. When a negative number is
+ * returned it remarks a POSIX error code. When a positive number is returned
+ * it remarks a TPM error.
+ */
+int tpm2_startup(struct tpm_chip *chip, __be16 startup_type)
+{
+	struct tpm2_cmd cmd;
+
+	cmd.header.in = tpm2_startup_header;
+
+	cmd.params.startup_in.startup_type = startup_type;
+	return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+				"attempting to start the TPM");
+}
+
+#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. When a negative number is
+ * returned it remarks a POSIX error code. When 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;
+	int i, j;
+
+	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;
+
+	for (i = 0; i < TPM2_PCR_SELECT_MIN; i++) {
+		j = pcr_idx - i * 8;
+
+		cmd.params.pcrread_in.pcr_select[i] =
+			(j >= 0 && j < 8) ? 1 << j : 0;
+	}
+
+	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;
+}
+
+/**
+ * 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. When a negative number is
+ * returned it remarks a POSIX error code. When a positive number is returned
+ * it remarks a TPM error.
+ */
+static const struct tpm_input_header tpm2_pcrextend_header = {
+	.tag = cpu_to_be16(TPM2_ST_SESSIONS),
+	.length = cpu_to_be32(sizeof(struct tpm_input_header) +
+			      sizeof(struct tpm2_pcr_extend_in)),
+	.ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND)
+};
+
+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;
+}
+
+static const struct tpm_input_header tpm2_getrandom_header = {
+	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+	.length = cpu_to_be32(sizeof(struct tpm_input_header) +
+			      sizeof(struct tpm2_get_random_in)),
+	.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. When a negative number is
+ * returned it remarks a POSIX error code. When 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, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
+	int err, total = 0, retries = 5;
+	u8 *dest = out;
+
+	if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)
+		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 = be16_to_cpu(cmd.params.getrandom_out.size);
+		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. When a negative number is
+ * returned it remarks a POSIX error code. When 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;
+}
+EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
+
+/*
+ * 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. When a negative number is
+ * returned it remarks a POSIX error code. When 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)
+		return 2 * 60 * HZ;
+	else
+		return duration;
+}
+EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration);
+
+static const struct tpm_input_header tpm2_selftest_header = {
+	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+	.length = cpu_to_be32(sizeof(struct tpm_input_header) +
+			      sizeof(struct tpm2_self_test_in)),
+	.ordinal = cpu_to_be32(TPM2_CC_SELF_TEST)
+};
+
+#define TPM2_SELF_TEST_IN_SIZE \
+	(sizeof(struct tpm_input_header) + sizeof(struct tpm2_self_test_in))
+
+/**
+ * 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. When a negative number is
+ * returned it remarks a POSIX error code. When 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");
+
+	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. When a negative number is
+ * returned it remarks a POSIX error code. When 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
+ *
+ * 0 is returned when the operation is successful. When a negative number is
+ * returned it remarks a POSIX error code. When a positive number is returned
+ * it remarks a TPM error.
+ */
+
+int tpm2_gen_interrupt(struct tpm_chip *chip)
+{
+	u32 dummy;
+	int rc;
+
+	rc = tpm2_get_tpm_pt(chip,
+			     TPM2_CAP_TPM_PROPERTIES,
+			     &dummy,
+			     "attempting to generate an interrupt");
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(tpm2_gen_interrupt);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 08/10] tpm: TPM 2.0 CRB Interface
  2014-11-11 13:45 ` Jarkko Sakkinen
                   ` (7 preceding siblings ...)
  (?)
@ 2014-11-11 13:45 ` Jarkko Sakkinen
  2014-11-26 14:06     ` Stefan Berger
  -1 siblings, 1 reply; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech, Jarkko Sakkinen

tpm_crb is a driver for TPM 2.0 Command Response Buffer (CRB) Interface
as defined in PC Client Platform TPM Profile (PTP) Specification.

Only polling and single locality is supported as these are the limitations
of the available hardware, Platform Trust Techonlogy (PTT) in Haswell
CPUs.

The driver always applies CRB with ACPI start because PTT reports using
only ACPI start as start method but as a result of my testing it requires
also CRB start.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/char/tpm/Kconfig   |   9 ++
 drivers/char/tpm/Makefile  |   1 +
 drivers/char/tpm/tpm_crb.c | 323 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 333 insertions(+)
 create mode 100644 drivers/char/tpm/tpm_crb.c

diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index c54cac3..10c9419 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -122,4 +122,13 @@ config TCG_XEN
 	  To compile this driver as a module, choose M here; the module
 	  will be called xen-tpmfront.
 
+config TCG_CRB
+	tristate "TPM 2.0 CRB Interface"
+	depends on X86 && ACPI
+	---help---
+	  If you have a TPM security chip that is compliant with the
+	  TCG CRB 2.0 TPM specification say Yes and it will be accessible
+	  from within Linux.  To compile this driver as a module, choose
+	  M here; the module will be called tpm_crb.
+
 endif # TCG_TPM
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index ae56af9..e6d26dd 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
 obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
 obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o
 obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
+obj-$(CONFIG_TCG_CRB) += tpm_crb.o
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
new file mode 100644
index 0000000..eb221d5
--- /dev/null
+++ b/drivers/char/tpm/tpm_crb.c
@@ -0,0 +1,323 @@
+/*
+ * 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;
+};
+
+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),
+};
+
+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 *cca;
+	unsigned long cca_pa;
+};
+
+#ifdef CONFIG_PM_SLEEP
+int crb_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int crb_resume(struct device *dev)
+{
+	struct tpm_chip *chip = dev_get_drvdata(dev);
+
+	(void) tpm2_do_selftest(chip);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(crb_pm, crb_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(priv->cca->start) & 1) != 1)
+		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;
+	struct crb_control_area *cca;
+	unsigned int expected;
+	unsigned long offset;
+	u8 *resp;
+
+	cca = priv->cca;
+	if (le32_to_cpu(cca->sts) & CRB_CA_STS_ERROR)
+		return -EIO;
+
+	offset = le64_to_cpu(cca->rsp_pa) - priv->cca_pa;
+	resp = (u8 *) ((unsigned long) cca + offset);
+	memcpy(buf, resp, 6);
+	expected = be32_to_cpup((__be32 *) &buf[2]);
+
+	if (expected > count)
+		return -EIO;
+
+	memcpy(&buf[6], &resp[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;
+	struct crb_control_area *cca;
+	u8 *cmd;
+	int rc = 0;
+
+	cca = priv->cca;
+
+	if (len > le32_to_cpu(cca->cmd_size)) {
+		dev_err(&chip->dev,
+			"invalid command count value %x %zx\n",
+			(unsigned int) len,
+			(size_t) le32_to_cpu(cca->cmd_size));
+		return -E2BIG;
+	}
+
+	cmd = (u8 *) ((unsigned long) cca + le64_to_cpu(cca->cmd_pa) -
+		      priv->cca_pa);
+	memcpy(cmd, buf, len);
+
+	/* Make sure that cmd is populated before issuing start. */
+	wmb();
+
+	cca->start = cpu_to_le32(1);
+	rc = crb_do_acpi_start(chip);
+	return rc;
+}
+
+static void crb_cancel(struct tpm_chip *chip)
+{
+	struct crb_priv *priv = chip->vendor.priv;
+	struct crb_control_area *cca;
+
+	cca = priv->cca;
+	cca->cancel = cpu_to_le32(1);
+
+	/* Make sure that cmd is populated before issuing start. */
+	wmb();
+
+	if (crb_do_acpi_start(chip))
+		dev_err(&chip->dev, "ACPI Start failed\n");
+
+	cca->cancel = 0;
+}
+
+static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
+{
+	struct crb_priv *priv = chip->vendor.priv;
+
+	return (le32_to_cpu(priv->cca->cancel) & 1) == 1;
+}
+
+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;
+	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;
+	}
+
+	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);
+
+	if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START)
+		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_pa = le32_to_cpu(buf->control_area_pa);
+	priv->cca = (struct crb_control_area *)
+		devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000);
+	if (!priv->cca) {
+		dev_err(dev, "allocating memory failed\n");
+		return -ENOMEM;
+	}
+
+	chip->vendor.priv = priv;
+
+	/* Default timeouts and durations */
+	chip->vendor.timeout_a = usecs_to_jiffies(TPM2_TIMEOUT_A);
+	chip->vendor.timeout_b = usecs_to_jiffies(TPM2_TIMEOUT_B);
+	chip->vendor.timeout_c = usecs_to_jiffies(TPM2_TIMEOUT_C);
+	chip->vendor.timeout_d = usecs_to_jiffies(TPM2_TIMEOUT_D);
+	chip->vendor.duration[TPM_SHORT] =
+		usecs_to_jiffies(TPM2_DURATION_SHORT);
+	chip->vendor.duration[TPM_MEDIUM] =
+		usecs_to_jiffies(TPM2_DURATION_MEDIUM);
+	chip->vendor.duration[TPM_LONG] =
+		usecs_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);
+}
+
+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");
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 09/10] tpm: TPM 2.0 FIFO Interface
  2014-11-11 13:45 ` Jarkko Sakkinen
                   ` (8 preceding siblings ...)
  (?)
@ 2014-11-11 13:45 ` Jarkko Sakkinen
  2014-11-25 21:52     ` Stefan Berger
  2014-11-27  1:38     ` Stefan Berger
  -1 siblings, 2 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech, Will Arthur,
	Jarkko Sakkinen

From: Will Arthur <will.c.arthur@intel.com>

Detect TPM 2.0 by using the extended STS (STS3) register. For TPM 2.0,
instead of calling tpm_get_timeouts(), assign duration and timeout
values defined in the TPM 2.0 PTP specification.

Signed-off-by: Will Arthur <will.c.arthur@intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/char/tpm/tpm_tis.c | 71 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 56 insertions(+), 15 deletions(-)

diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 7a2c59b..0b3c089 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2005, 2006 IBM Corporation
+ * Copyright (C) 2014 Intel Corporation
  *
  * Authors:
  * Leendert van Doorn <leendert@watson.ibm.com>
@@ -44,6 +45,10 @@ enum tis_status {
 	TPM_STS_DATA_EXPECT = 0x08,
 };
 
+enum tis_status3 {
+	TPM_STS3_TPM2_FAM = 0x04,
+};
+
 enum tis_int_flags {
 	TPM_GLOBAL_INT_ENABLE = 0x80000000,
 	TPM_INTF_BURST_COUNT_STATIC = 0x100,
@@ -70,6 +75,7 @@ enum tis_defaults {
 #define	TPM_INT_STATUS(l)		(0x0010 | ((l) << 12))
 #define	TPM_INTF_CAPS(l)		(0x0014 | ((l) << 12))
 #define	TPM_STS(l)			(0x0018 | ((l) << 12))
+#define	TPM_STS3(l)			(0x001b | ((l) << 12))
 #define	TPM_DATA_FIFO(l)		(0x0024 | ((l) << 12))
 
 #define	TPM_DID_VID(l)			(0x0F00 | ((l) << 12))
@@ -344,6 +350,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
 {
 	int rc;
 	u32 ordinal;
+	unsigned long dur;
 
 	rc = tpm_tis_send_data(chip, buf, len);
 	if (rc < 0)
@@ -355,9 +362,14 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
 
 	if (chip->vendor.irq) {
 		ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
+
+		if (chip->flags & TPM_CHIP_FLAG_TPM2)
+			dur = tpm_calc_ordinal_duration(chip, ordinal);
+		else
+			dur = tpm_calc_ordinal_duration(chip, ordinal);
+
 		if (wait_for_tpm_stat
-		    (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
-		     tpm_calc_ordinal_duration(chip, ordinal),
+		    (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur,
 		     &chip->vendor.read_queue, false) < 0) {
 			rc = -ETIME;
 			goto out_err;
@@ -543,6 +555,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 	u32 vendor, intfcaps, intmask;
 	int rc, i, irq_s, irq_e, probe;
 	struct tpm_chip *chip;
+	u8 sts3;
 
 	chip = tpmm_chip_alloc(dev, &tpm_tis);
 	if (IS_ERR(chip))
@@ -554,11 +567,28 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 	if (!chip->vendor.iobase)
 		return -EIO;
 
+	sts3 = ioread8(chip->vendor.iobase + TPM_STS3(1));
+	if (sts3 & TPM_STS3_TPM2_FAM)
+		chip->flags = TPM_CHIP_FLAG_TPM2;
+
 	/* 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);
+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+		chip->vendor.timeout_a = usecs_to_jiffies(TPM2_TIMEOUT_A);
+		chip->vendor.timeout_b = usecs_to_jiffies(TPM2_TIMEOUT_B);
+		chip->vendor.timeout_c = usecs_to_jiffies(TPM2_TIMEOUT_C);
+		chip->vendor.timeout_d = usecs_to_jiffies(TPM2_TIMEOUT_D);
+		chip->vendor.duration[TPM_SHORT] =
+			usecs_to_jiffies(TPM2_DURATION_SHORT);
+		chip->vendor.duration[TPM_MEDIUM] =
+			usecs_to_jiffies(TPM2_DURATION_MEDIUM);
+		chip->vendor.duration[TPM_LONG] =
+			usecs_to_jiffies(TPM2_DURATION_LONG);
+	} else {
+		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);
+	}
 
 	if (wait_startup(chip, 0) != 0) {
 		rc = -ENODEV;
@@ -573,8 +603,8 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 	vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
 	chip->vendor.manufacturer_id = vendor;
 
-	dev_info(dev,
-		 "1.2 TPM (device-id 0x%X, rev-id %d)\n",
+	dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n",
+		 (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
 		 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
 
 	if (!itpm) {
@@ -616,13 +646,17 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 		dev_dbg(dev, "\tData Avail Int Support\n");
 
 	/* get the timeouts before testing for irqs */
-	if (tpm_get_timeouts(chip)) {
+	if (!(chip->flags & TPM_CHIP_FLAG_TPM2) && 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)) {
+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
+		rc = tpm2_do_selftest(chip);
+	else
+		rc = tpm_do_selftest(chip);
+	if (rc) {
 		dev_err(dev, "TPM self test failed\n");
 		rc = -ENODEV;
 		goto out_err;
@@ -683,7 +717,10 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 			chip->vendor.probed_irq = 0;
 
 			/* Generate Interrupts */
-			tpm_gen_interrupt(chip);
+			if (chip->flags & TPM_CHIP_FLAG_TPM2)
+				tpm2_gen_interrupt(chip);
+			else
+				tpm_gen_interrupt(chip);
 
 			chip->vendor.irq = chip->vendor.probed_irq;
 
@@ -759,14 +796,18 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
 static int tpm_tis_resume(struct device *dev)
 {
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-	int ret;
+	int ret = 0;
 
 	if (chip->vendor.irq)
 		tpm_tis_reenable_interrupts(chip);
 
-	ret = tpm_pm_resume(dev);
-	if (!ret)
-		tpm_do_selftest(chip);
+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
+		tpm2_do_selftest(chip);
+	else {
+		ret = tpm_pm_resume(dev);
+		if (!ret)
+			tpm_do_selftest(chip);
+	}
 
 	return ret;
 }
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 10/10] tpm: TPM 2.0 sysfs attributes
  2014-11-11 13:45 ` Jarkko Sakkinen
                   ` (9 preceding siblings ...)
  (?)
@ 2014-11-11 13:45 ` Jarkko Sakkinen
  2014-11-25 23:55     ` Stefan Berger
  -1 siblings, 1 reply; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-11 13:45 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech, Jarkko Sakkinen

Manadatory sysfs attributes for TPM 2.0 devices so that it is easy
to check whether storage hierarchies are enabled and use PPI
interface.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 Documentation/ABI/stable/sysfs-class-tpm2 |  57 +++++++++++
 drivers/char/tpm/Makefile                 |   2 +-
 drivers/char/tpm/tpm-chip.c               |  21 +++--
 drivers/char/tpm/tpm.h                    |  19 ++++
 drivers/char/tpm/tpm2-sysfs.c             | 152 ++++++++++++++++++++++++++++++
 5 files changed, 241 insertions(+), 10 deletions(-)
 create mode 100644 Documentation/ABI/stable/sysfs-class-tpm2
 create mode 100644 drivers/char/tpm/tpm2-sysfs.c

diff --git a/Documentation/ABI/stable/sysfs-class-tpm2 b/Documentation/ABI/stable/sysfs-class-tpm2
new file mode 100644
index 0000000..301ab2e
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-class-tpm2
@@ -0,0 +1,57 @@
+What:		/sys/class/misc/tpmX/device/
+Date:		October 2014
+KernelVersion:	3.19
+Contact:	tpmdd-devel@lists.sf.net
+Description:	The device/ directory under a specific TPM instance exposes
+		the properties of that TPM chip.
+
+What:		/sys/class/misc/tpmX/device/family
+Date:		October 2014
+KernelVersion:	3.19
+Contact:	tpmdd-devel@lists.sf.net
+Description:	The protocol family in the major.minor format.
+
+What:		/sys/class/misc/tpmX/device/sh_enabled
+Date:		October 2014
+KernelVersion:	3.19
+Contact:	tpmdd-devel@lists.sf.net
+Description:	The "sh_enabled" property prints a '1' if the Storage Hierarchy
+		is enabled, i.e. if PM_PT_STARTUP_CLEAR.shEnable is set.
+
+What:		/sys/class/misc/tpmX/device/sh_owned
+Date:		October 2014
+KernelVersion:	3.19
+Contact:	tpmdd-devel@lists.sf.net
+Description:	The "sh_owned" property prints a '1' if the ownership of the
+		Storage Hierarchy has been taken, i.e. if
+		TPM_PT_PERMANENT.ownerAuthSet is set.
+
+What:		/sys/class/misc/tpmX/device/eh_enabled
+Date:		October 2014
+KernelVersion:	3.19
+Contact:	tpmdd-devel@lists.sf.net
+Description:	The "eh_enabled" property prints a '1' if the Endorsement
+		Hierarchy is enabled, i.e if PM_PT_STARTUP_CLEAR.ehEnable is
+		set.
+
+What:		/sys/class/misc/tpmX/device/eh_owned
+Date:		October 2014
+KernelVersion:	3.19
+Contact:	tpmdd-devel@lists.sf.net
+Description:	The "eh_owned" property prints a '1' if the ownership of the
+		Endrosoment Hierarchy has been taken, i.e if
+		TPM_PT_PERMANENT.endorsementAuthSet is set.
+
+What:		/sys/class/misc/tpmX/device/manufacturer
+Date:		October 2014
+KernelVersion:	3.19
+Contact:	tpmdd-devel@lists.sf.net
+Description:	The "manufacturer" property prints the vendor ID of the TPM
+		manufacturer.
+
+What:		/sys/class/misc/tpmX/device/firmware
+Date:		October 2014
+KernelVersion:	3.19
+Contact:	tpmdd-devel@lists.sf.net
+Description:	The property prints the vendor-specific value indicating the
+		version of the firmware.
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index e6d26dd..15e3b4c 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the kernel tpm device drivers.
 #
 obj-$(CONFIG_TCG_TPM) += tpm.o
-tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o
+tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o tpm2-sysfs.o
 tpm-$(CONFIG_ACPI) += tpm_ppi.o
 
 ifdef CONFIG_ACPI
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 4d25b24..accd408 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -30,6 +30,7 @@
 #include "tpm_eventlog.h"
 
 ATTRIBUTE_GROUPS(tpm_dev);
+ATTRIBUTE_GROUPS(tpm2_dev);
 
 static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
 static LIST_HEAD(tpm_chip_list);
@@ -138,7 +139,10 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
 	else
 		chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
 
-	chip->dev.groups = tpm_dev_groups;
+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
+		chip->dev.groups = tpm2_dev_groups;
+	else
+		chip->dev.groups = tpm_dev_groups;
 
 	dev_set_name(&chip->dev, chip->devname);
 
@@ -213,14 +217,12 @@ int tpm_chip_register(struct tpm_chip *chip)
 	if (rc)
 		return rc;
 
-	/* Populate sysfs for TPM1 devices. */
-	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
-		rc = tpm_add_ppi(chip);
-		if (rc)
-			goto out_err;
+	rc = tpm_add_ppi(chip);
+	if (rc)
+		goto out_err;
 
+	if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
 		chip->bios_dir = tpm_bios_log_setup(chip->devname);
-	}
 
 	/* Make the chip available. */
 	spin_lock(&driver_lock);
@@ -251,8 +253,9 @@ void tpm_chip_unregister(struct tpm_chip *chip)
 	spin_unlock(&driver_lock);
 	synchronize_rcu();
 
-	/* Clean up sysfs for TPM1 devices. */
-	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+		tpm_remove_ppi(chip);
+	} else {
 		if (chip->bios_dir)
 			tpm_bios_log_teardown(chip->bios_dir);
 		tpm_remove_ppi(chip);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 8a434d2..1548182 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -108,6 +108,24 @@ enum tpm2_capabilities {
 	TPM2_CAP_TPM_PROPERTIES = 6,
 };
 
+enum tpm2_tpm_properties {
+	TPM2_PT_MANUFACTURER		= 0x00000105,
+	TPM2_PT_FIRMWARE_VERSION_1	= 0x0000010C,
+	TPM2_PT_FIRMWARE_VERSION_2	= 0x0000010D,
+	TPM2_PT_PERMANENT		= 0x00000200,
+	TPM2_PT_STARTUP_CLEAR		= 0x00000201,
+};
+
+enum tpm2_pt_startup_clear {
+	TPM2_PT_SC_SH_ENABLE	= BIT(1),
+	TPM2_PT_SC_EH_ENABLE	= BIT(2),
+};
+
+enum tpm2_pt_permanent {
+	TPM2_PT_PM_OWNER_AUTH_SET	= BIT(0),
+	TPM2_PT_PM_ENDORSEMENT_AUTH_SET	= BIT(1),
+};
+
 enum tpm2_startup_types {
 	TPM2_SU_CLEAR	= 0x0000,
 	TPM2_SU_STATE	= 0x0001,
@@ -382,6 +400,7 @@ extern struct class *tpm_class;
 extern dev_t tpm_devt;
 extern const struct file_operations tpm_fops;
 extern struct attribute *tpm_dev_attrs[];
+extern struct attribute *tpm2_dev_attrs[];
 
 ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
 ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
diff --git a/drivers/char/tpm/tpm2-sysfs.c b/drivers/char/tpm/tpm2-sysfs.c
new file mode 100644
index 0000000..9e5e2e3
--- /dev/null
+++ b/drivers/char/tpm/tpm2-sysfs.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Authors:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ *
+ * TPM2 sysfs attributes
+ *
+ * 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/device.h>
+#include <linux/slab.h>
+#include "tpm.h"
+
+static ssize_t sh_enabled_show(struct device *dev, struct device_attribute *attr,
+		     char *buf)
+{
+	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+	u32 value;
+	ssize_t rc;
+
+	rc = tpm2_get_tpm_pt(chip, TPM2_PT_STARTUP_CLEAR, &value,
+			     "could not retrieve STARTUP_CLEAR property");
+	if (rc)
+		return 0;
+
+	rc = sprintf(buf, "%d\n", (value & TPM2_PT_SC_SH_ENABLE) > 0);
+	return rc;
+}
+static DEVICE_ATTR_RO(sh_enabled);
+
+static ssize_t sh_owned_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+	u32 value;
+	ssize_t rc;
+
+	rc = tpm2_get_tpm_pt(chip, TPM2_PT_PERMANENT, &value,
+			     "could not retrieve PERMANENT property");
+	if (rc)
+		return 0;
+
+	rc = sprintf(buf, "%d\n", (value & TPM2_PT_PM_OWNER_AUTH_SET) > 0);
+	return rc;
+}
+static DEVICE_ATTR_RO(sh_owned);
+
+static ssize_t eh_enabled_show(struct device *dev, struct device_attribute *attr,
+		     char *buf)
+{
+	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+	u32 value;
+	ssize_t rc;
+
+	rc = tpm2_get_tpm_pt(chip, TPM2_PT_STARTUP_CLEAR, &value,
+			     "could not retrieve STARTUP_CLEAR property");
+	if (rc)
+		return 0;
+
+	rc = sprintf(buf, "%d\n", (value & TPM2_PT_SC_EH_ENABLE) > 0);
+	return rc;
+}
+static DEVICE_ATTR_RO(eh_enabled);
+
+static ssize_t eh_owned_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+	u32 value;
+	ssize_t rc;
+
+	rc = tpm2_get_tpm_pt(chip, TPM2_PT_PERMANENT, &value,
+			     "could not retrieve PERMANENT property");
+	if (rc)
+		return 0;
+
+	rc = sprintf(buf, "%d\n", (value & TPM2_PT_PM_ENDORSEMENT_AUTH_SET) > 0);
+	return rc;
+}
+static DEVICE_ATTR_RO(eh_owned);
+
+static ssize_t manufacturer_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+	u32 manufacturer;
+	ssize_t rc;
+	char *str = buf;
+
+	rc = tpm2_get_tpm_pt(chip, TPM2_PT_MANUFACTURER, (u32 *) &manufacturer,
+			     "could not retrieve MANUFACTURER property");
+	if (rc)
+		return 0;
+
+	str += sprintf(str, "0x%08x\n", be32_to_cpu(manufacturer));
+
+	return str - buf;
+}
+static DEVICE_ATTR_RO(manufacturer);
+
+static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+	u32 firmware1;
+	u32 firmware2;
+	ssize_t rc;
+	char *str = buf;
+
+	rc = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_1, (u32 *) &firmware1,
+			     "could not retrieve FIRMWARE_VERSION_1 property");
+	if (rc)
+		return 0;
+
+	rc = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_2, (u32 *) &firmware2,
+			     "could not retrieve FIRMWARE_VERSION_2 property");
+	if (rc)
+		return 0;
+
+	str += sprintf(str, "0x%08x.0x%08x\n", firmware1, firmware2);
+
+	return str - buf;
+}
+static DEVICE_ATTR_RO(firmware);
+
+static ssize_t family_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	char *str = buf;
+
+	str += sprintf(str, "2.0\n");
+
+	return str - buf;
+}
+static DEVICE_ATTR_RO(family);
+
+struct attribute *tpm2_dev_attrs[] = {
+	&dev_attr_sh_enabled.attr,
+	&dev_attr_sh_owned.attr,
+	&dev_attr_eh_enabled.attr,
+	&dev_attr_eh_owned.attr,
+	&dev_attr_manufacturer.attr,
+	&dev_attr_firmware.attr,
+	&dev_attr_family.attr,
+	NULL,
+};
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 00/10] TPM 2.0 support
  2014-11-11 13:45 ` Jarkko Sakkinen
                   ` (10 preceding siblings ...)
  (?)
@ 2014-11-18  6:33 ` Jarkko Sakkinen
  -1 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-18  6:33 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech

Any feedback?

/Jarkko

On Tue, Nov 11, 2014 at 03:45:03PM +0200, Jarkko Sakkinen wrote:
> This patch set enables TPM2 protocol and provides drivers for FIFO and
> CRB interfaces.
> 
> v2:
> - Improved struct tpm_chip life-cycle by taking advantage of devres
>   API.
> - Refined sysfs attributes as simple key-values thereby not repeating
>   mistakes in TPM1 sysfs attributes.
> - Documented functions in tpm-chip.c and tpm2-cmd.c.
> - Documented sysfs attributes.
> 
> v3:
> - Lots of fixes in calling order in device drivers (thanks to Jason
>   Gunthorpe for pointing these out!).
> - Attach sysfs attributes to the misc device because it represents
>   TPM device to the user space.
> 
> v4:
> - Disable sysfs attibutes for TPM 2.0 for until we can sort out the 
>   best approach for them.
> - Fixed all the style issues found with checkpatch.pl.
> 
> v5:
> - missing EXPORT_SYMBOL_GPL()
> - own class for TPM devices used for TPM 2.0 devices and onwards.
> 
> v6:
> - Non-racy initialization for sysfs attributes using struct device's
>   groups field.
> - The class 'tpm' is used now for all TPM devices. For the first device
>   node major MISC_MAJOR and minor TPM_MINOR is used in order to retain
>   backwards compatability.
> 
> v7:
> - Release device number and free struct tpm_chip memory inside
>   tpm_dev_release callback.
> - Moved code from tpm-interface.c and tpm_dev.c to tpm-chip.c.
> 
> Opens:
> - What we should do with PPI and BIOS log sysfs attributes?
>   Can we associate them with the character device without
>   breaking anything? Can we postpone this issue after
>   this patch set has been pulled?
> 
> Jarkko Sakkinen (9):
>   tpm: merge duplicate transmit_cmd() functions
>   tpm: two-phase chip management functions
>   tpm: fix multiple race conditions in tpm_ppi.c
>   tpm: rename chip->dev to chip->pdev
>   tpm: device class for tpm
>   tpm: fix: move sysfs attributes to the correct place.
>   tpm: TPM 2.0 baseline support
>   tpm: TPM 2.0 CRB Interface
>   tpm: TPM 2.0 sysfs attributes
> 
> Will Arthur (1):
>   tpm: TPM 2.0 FIFO Interface
> 
>  Documentation/ABI/stable/sysfs-class-tpm2 |  57 +++
>  drivers/char/tpm/Kconfig                  |   9 +
>  drivers/char/tpm/Makefile                 |   3 +-
>  drivers/char/tpm/tpm-chip.c               | 266 ++++++++++++++
>  drivers/char/tpm/tpm-dev.c                |  44 +--
>  drivers/char/tpm/tpm-interface.c          | 261 +++++---------
>  drivers/char/tpm/tpm-sysfs.c              |  46 +--
>  drivers/char/tpm/tpm.h                    | 134 ++++++-
>  drivers/char/tpm/tpm2-cmd.c               | 566 ++++++++++++++++++++++++++++++
>  drivers/char/tpm/tpm2-sysfs.c             | 152 ++++++++
>  drivers/char/tpm/tpm_atmel.c              |  25 +-
>  drivers/char/tpm/tpm_crb.c                | 323 +++++++++++++++++
>  drivers/char/tpm/tpm_i2c_atmel.c          |  49 +--
>  drivers/char/tpm/tpm_i2c_infineon.c       |  43 +--
>  drivers/char/tpm/tpm_i2c_nuvoton.c        |  68 ++--
>  drivers/char/tpm/tpm_i2c_stm_st33.c       |  44 +--
>  drivers/char/tpm/tpm_ibmvtpm.c            |  17 +-
>  drivers/char/tpm/tpm_infineon.c           |  51 +--
>  drivers/char/tpm/tpm_nsc.c                |  34 +-
>  drivers/char/tpm/tpm_ppi.c                | 136 ++++---
>  drivers/char/tpm/tpm_tis.c                | 180 ++++++----
>  drivers/char/tpm/xen-tpmfront.c           |  14 +-
>  22 files changed, 1920 insertions(+), 602 deletions(-)
>  create mode 100644 Documentation/ABI/stable/sysfs-class-tpm2
>  create mode 100644 drivers/char/tpm/tpm-chip.c
>  create mode 100644 drivers/char/tpm/tpm2-cmd.c
>  create mode 100644 drivers/char/tpm/tpm2-sysfs.c
>  create mode 100644 drivers/char/tpm/tpm_crb.c
> 
> -- 
> 2.1.0
> 

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 06/10] tpm: fix: move sysfs attributes to the correct place.
@ 2014-11-18  9:29     ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-18  9:29 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel, linux-kernel, josh.triplett, christophe.ricard,
	jason.gunthorpe, linux-api, trousers-tech

On Tue, Nov 11, 2014 at 03:45:09PM +0200, Jarkko Sakkinen wrote:
> The sysfs attributes of the TPM device were created to the platform
> device directory that owns the character device instead of placing
> them correctly to the directory of the character device,
> 
> They were also created in a racy way so that character device might
> become visible before sysfs attributes become available.
> 
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>

For this patch there are at least these open items:

- Paths in Documentation/ABI/stable/sysfs-class-tpm should be updated.
- I moved attributes described in the documentation to the character
  device sysfs-directory from platform device sysfs directory. I don't
  believe this is a mentionable breakage because they weren't machine
  readable anyway. This should be however explicitly stated in the
  commit message.
- What should be done with PPI sysfs attributes? They are also in wrong
  place.
- What should be done with the BIOS log? They are also in wrong place.

I think this patch is really the key change to sort out before pulling the
patch set to the maintainer tree. 

/Jarkko

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 06/10] tpm: fix: move sysfs attributes to the correct place.
@ 2014-11-18  9:29     ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-18  9:29 UTC (permalink / raw)
  To: Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Tue, Nov 11, 2014 at 03:45:09PM +0200, Jarkko Sakkinen wrote:
> The sysfs attributes of the TPM device were created to the platform
> device directory that owns the character device instead of placing
> them correctly to the directory of the character device,
> 
> They were also created in a racy way so that character device might
> become visible before sysfs attributes become available.
> 
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>

For this patch there are at least these open items:

- Paths in Documentation/ABI/stable/sysfs-class-tpm should be updated.
- I moved attributes described in the documentation to the character
  device sysfs-directory from platform device sysfs directory. I don't
  believe this is a mentionable breakage because they weren't machine
  readable anyway. This should be however explicitly stated in the
  commit message.
- What should be done with PPI sysfs attributes? They are also in wrong
  place.
- What should be done with the BIOS log? They are also in wrong place.

I think this patch is really the key change to sort out before pulling the
patch set to the maintainer tree. 

/Jarkko

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 01/10] tpm: merge duplicate transmit_cmd() functions
  2014-11-11 13:45   ` Jarkko Sakkinen
  (?)
@ 2014-11-25 21:18   ` Stefan Berger
  2014-11-27 11:43       ` Jarkko Sakkinen
  -1 siblings, 1 reply; 49+ messages in thread
From: Stefan Berger @ 2014-11-25 21:18 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard, josh.triplett, linux-api, linux-kernel,
	tpmdd-devel, jason.gunthorpe, trousers-tech

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> Merged transmit_cmd() functions in tpm-interface.c and tpm-sysfs.c.
> Added "tpm_" prefix for consistency sake. Changed cmd parameter as
> opaque. This enables to use separate command structures for TPM1
> and TPM2 commands in future. Loose coupling works fine here.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> ---
>   drivers/char/tpm/tpm-interface.c | 49 +++++++++++++++++++++-------------------
>   drivers/char/tpm/tpm-sysfs.c     | 23 ++-----------------
>   drivers/char/tpm/tpm.h           |  3 ++-
>   3 files changed, 30 insertions(+), 45 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> index 6af1700..0150b7c 100644
> --- a/drivers/char/tpm/tpm-interface.c
> +++ b/drivers/char/tpm/tpm-interface.c
> @@ -398,9 +398,10 @@ out:
>   #define TPM_DIGEST_SIZE 20
>   #define TPM_RET_CODE_IDX 6
>
> -static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
> -			    int len, const char *desc)
> +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd,
> +			 int len, const char *desc)
>   {
> +	struct tpm_output_header *header;
>   	int err;
>
>   	len = tpm_transmit(chip, (u8 *) cmd, len);
> @@ -409,7 +410,9 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
>   	else if (len < TPM_HEADER_SIZE)
>   		return -EFAULT;
>
> -	err = be32_to_cpu(cmd->header.out.return_code);
> +	header = (struct tpm_output_header *) cmd;

The cast should not be necessary -- and this change doesn't buy much...

header = &cmd->header.out;

Should do the trick without cast.


> +
> +	err = be32_to_cpu(header->return_code);
>   	if (err != 0 && desc)
>   		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
>
> @@ -448,7 +451,7 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
>   		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
>   		tpm_cmd.params.getcap_in.subcap = subcap_id;
>   	}
> -	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
> +	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
>   	if (!rc)
>   		*cap = tpm_cmd.params.getcap_out.cap;
>   	return rc;
> @@ -464,8 +467,8 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
>   	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
>   	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
>
> -	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> -			"attempting to determine the timeouts");
> +	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> +			      "attempting to determine the timeouts");
>   }
>   EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
>
> @@ -484,8 +487,8 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
>   	struct tpm_cmd_t start_cmd;
>   	start_cmd.header.in = tpm_startup_header;
>   	start_cmd.params.startup_in.startup_type = startup_type;
> -	return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
> -			    "attempting to start the TPM");
> +	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
> +				"attempting to start the TPM");
>   }
>
>   int tpm_get_timeouts(struct tpm_chip *chip)
> @@ -500,7 +503,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
>   	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
>   	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
>   	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
> -	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
> +	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
>
>   	if (rc == TPM_ERR_INVALID_POSTINIT) {
>   		/* The TPM is not started, we are the first to talk to it.
> @@ -513,7 +516,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
>   		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
>   		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
>   		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
> -		rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> +		rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
>   				  NULL);
>   	}
>   	if (rc) {
> @@ -575,8 +578,8 @@ duration:
>   	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
>   	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
>
> -	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> -			"attempting to determine the durations");
> +	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> +			      "attempting to determine the durations");
>   	if (rc)
>   		return rc;
>
> @@ -631,8 +634,8 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
>   	struct tpm_cmd_t cmd;
>
>   	cmd.header.in = continue_selftest_header;
> -	rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
> -			  "continue selftest");
> +	rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
> +			      "continue selftest");
>   	return rc;
>   }
>
> @@ -672,8 +675,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
>
>   	cmd.header.in = pcrread_header;
>   	cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
> -	rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
> -			  "attempting to read a pcr value");
> +	rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
> +			      "attempting to read a pcr value");
>
>   	if (rc == 0)
>   		memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
> @@ -737,8 +740,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
>   	cmd.header.in = pcrextend_header;
>   	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
>   	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
> -	rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> -			  "attempting extend a PCR value");
> +	rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> +			      "attempting extend a PCR value");
>
>   	tpm_chip_put(chip);
>   	return rc;
> @@ -817,7 +820,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
>   	if (chip == NULL)
>   		return -ENODEV;
>
> -	rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
> +	rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
>
>   	tpm_chip_put(chip);
>   	return rc;
> @@ -938,14 +941,14 @@ int tpm_pm_suspend(struct device *dev)
>   		cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
>   		memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
>   		       TPM_DIGEST_SIZE);
> -		rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> -				  "extending dummy pcr before suspend");
> +		rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> +				      "extending dummy pcr before suspend");
>   	}
>
>   	/* now do the actual savestate */
>   	for (try = 0; try < TPM_RETRY; try++) {
>   		cmd.header.in = savestate_header;
> -		rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
> +		rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
>
>   		/*
>   		 * If the TPM indicates that it is too busy to respond to
> @@ -1022,7 +1025,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
>   		tpm_cmd.header.in = tpm_getrandom_header;
>   		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
>
> -		err = transmit_cmd(chip, &tpm_cmd,
> +		err = tpm_transmit_cmd(chip, &tpm_cmd,
>   				   TPM_GETRANDOM_RESULT_SIZE + num_bytes,
>   				   "attempting get random");
>   		if (err)
> diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
> index 01730a2..8ecb052 100644
> --- a/drivers/char/tpm/tpm-sysfs.c
> +++ b/drivers/char/tpm/tpm-sysfs.c
> @@ -20,25 +20,6 @@
>   #include <linux/device.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 TPM_ORD_READPUBEK cpu_to_be32(124)
>   static struct tpm_input_header tpm_readpubek_header = {
> @@ -58,8 +39,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
>   	struct tpm_chip *chip = dev_get_drvdata(dev);
>
>   	tpm_cmd.header.in = tpm_readpubek_header;
> -	err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
> -			   "attempting to read the PUBEK");
> +	err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
> +			       "attempting to read the PUBEK");
>   	if (err)
>   		goto out;
>
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index e4d0888..e638eb0 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -314,9 +314,10 @@ struct tpm_cmd_t {
>   } __packed;
>
>   ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
> -
>   ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
>   		     size_t bufsiz);

Delete this prototype ?

> +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len,
> +			 const char *desc);
>   extern int tpm_get_timeouts(struct tpm_chip *);
>   extern void tpm_gen_interrupt(struct tpm_chip *);
>   extern int tpm_do_selftest(struct tpm_chip *);


    Stefan


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 03/10] tpm: fix multiple race conditions in tpm_ppi.c
  2014-11-11 13:45 ` [PATCH v7 03/10] tpm: fix multiple race conditions in tpm_ppi.c Jarkko Sakkinen
@ 2014-11-25 21:40   ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-25 21:40 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard, josh.triplett, linux-api, linux-kernel,
	tpmdd-devel, jason.gunthorpe, trousers-tech

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> Traversal of the ACPI device tree was not done right. It should lookup
> PPI only under the ACPI device that it is associated. Otherwise, it could
> match to a wrong PPI interface if there are two TPM devices in the device
> tree.
>
> Removed global ACPI handle and version string from tpm_ppi.c as this
> is racy. Instead they should be associated with the chip.
>
> Additionally, added the missing copyright platter to tpm_ppi.c.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> ---
>   drivers/char/tpm/tpm-chip.c |   4 +-
>   drivers/char/tpm/tpm.h      |  16 ++++--
>   drivers/char/tpm/tpm_ppi.c  | 136 +++++++++++++++++++++++++++-----------------
>   drivers/char/tpm/tpm_tis.c  |  15 +++--
>   4 files changed, 108 insertions(+), 63 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index cf3ad24..647867c 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -148,7 +148,7 @@ int tpm_chip_register(struct tpm_chip *chip)
>   	if (rc)
>   		goto del_misc;
>
> -	rc = tpm_add_ppi(&chip->dev->kobj);
> +	rc = tpm_add_ppi(chip);
>   	if (rc)
>   		goto del_sysfs;
>
> @@ -186,7 +186,7 @@ void tpm_chip_unregister(struct tpm_chip *chip)
>   	synchronize_rcu();
>
>   	tpm_sysfs_del_device(chip);
> -	tpm_remove_ppi(&chip->dev->kobj);
> +	tpm_remove_ppi(chip);
>
>   	if (chip->bios_dir)
>   		tpm_bios_log_teardown(chip->bios_dir);
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 9880681..69f4003 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -27,6 +27,7 @@
>   #include <linux/platform_device.h>
>   #include <linux/io.h>
>   #include <linux/tpm.h>
> +#include <linux/acpi.h>
>
>   enum tpm_const {
>   	TPM_MINOR = 224,	/* officially assigned */
> @@ -94,6 +95,8 @@ struct tpm_vendor_specific {
>   #define TPM_VID_WINBOND  0x1050
>   #define TPM_VID_STM      0x104A
>
> +#define TPM_PPI_VERSION_LEN		3
> +
>   struct tpm_chip {
>   	struct device *dev;	/* Device stuff */
>   	const struct tpm_class_ops *ops;
> @@ -109,6 +112,11 @@ struct tpm_chip {
>
>   	struct dentry **bios_dir;
>
> +#ifdef CONFIG_ACPI
> +	acpi_handle acpi_dev_handle;
> +	char ppi_version[TPM_PPI_VERSION_LEN + 1];
> +#endif /* CONFIG_ACPI */
> +
>   	struct list_head list;
>   };
>
> @@ -340,15 +348,15 @@ void tpm_sysfs_del_device(struct tpm_chip *chip);
>   int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
>
>   #ifdef CONFIG_ACPI
> -extern int tpm_add_ppi(struct kobject *);
> -extern void tpm_remove_ppi(struct kobject *);
> +extern int tpm_add_ppi(struct tpm_chip *chip);
> +extern void tpm_remove_ppi(struct tpm_chip *chip);
>   #else
> -static inline int tpm_add_ppi(struct kobject *parent)
> +static inline int tpm_add_ppi(struct tpm_chip *chip)
>   {
>   	return 0;
>   }
>
> -static inline void tpm_remove_ppi(struct kobject *parent)
> +static inline void tpm_remove_ppi(struct tpm_chip *chip)
>   {
>   }
>   #endif
> diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c
> index 61dcc80..6acdb17 100644
> --- a/drivers/char/tpm/tpm_ppi.c
> +++ b/drivers/char/tpm/tpm_ppi.c
> @@ -1,3 +1,22 @@
> +/*
> + * Copyright (C) 2012-2014 Intel Corporation
> + *
> + * Authors:
> + * Xiaoyan Zhang <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 "tpm.h"
>
> @@ -22,45 +41,22 @@ static const u8 tpm_ppi_uuid[] = {
>   	0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
>   };
>
> -static char tpm_ppi_version[PPI_VERSION_LEN + 1];
> -static acpi_handle tpm_ppi_handle;
> -
> -static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context,
> -				void **return_value)
> -{
> -	union acpi_object *obj;
> -
> -	if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
> -			    1 << TPM_PPI_FN_VERSION))
> -		return AE_OK;
> -
> -	/* Cache version string */
> -	obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid,
> -				      TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
> -				      NULL, ACPI_TYPE_STRING);
> -	if (obj) {
> -		strlcpy(tpm_ppi_version, obj->string.pointer,
> -			PPI_VERSION_LEN + 1);
> -		ACPI_FREE(obj);
> -	}
> -
> -	*return_value = handle;
> -
> -	return AE_CTRL_TERMINATE;
> -}
> -
>   static inline union acpi_object *
> -tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4)
> +tpm_eval_dsm(acpi_handle dev_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(!dev_handle);
> +	return acpi_evaluate_dsm_typed(dev_handle, tpm_ppi_uuid,
> +				       TPM_PPI_REVISION_ID,
> +				       func, argv4, type);
>   }
>
>   static ssize_t tpm_show_ppi_version(struct device *dev,
>   				    struct device_attribute *attr, char *buf)
>   {
> -	return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version);
> +	struct tpm_chip *chip = dev_get_drvdata(dev);
> +
> +	return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version);
>   }
>
>   static ssize_t tpm_show_ppi_request(struct device *dev,
> @@ -68,8 +64,10 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
>   {
>   	ssize_t size = -EINVAL;
>   	union acpi_object *obj;
> +	struct tpm_chip *chip = dev_get_drvdata(dev);
>
> -	obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL);
> +	obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
> +			   ACPI_TYPE_PACKAGE, NULL);
>   	if (!obj)
>   		return -ENXIO;
>
> @@ -103,14 +101,15 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
>   	int func = TPM_PPI_FN_SUBREQ;
>   	union acpi_object *obj, tmp;
>   	union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
> +	struct tpm_chip *chip = dev_get_drvdata(dev);
>
>   	/*
>   	 * the function to submit TPM operation request to pre-os environment
>   	 * is updated with function index from SUBREQ to SUBREQ2 since PPI
>   	 * version 1.1
>   	 */
> -	if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
> -			   1 << TPM_PPI_FN_SUBREQ2))
> +	if (acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
> +			   TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2))
>   		func = TPM_PPI_FN_SUBREQ2;
>
>   	/*
> @@ -119,7 +118,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
>   	 * string/package type. For PPI version 1.0 and 1.1, use buffer type
>   	 * for compatibility, and use package type since 1.2 according to spec.
>   	 */
> -	if (strcmp(tpm_ppi_version, "1.2") < 0) {
> +	if (strcmp(chip->ppi_version, "1.2") < 0) {
>   		if (sscanf(buf, "%d", &req) != 1)
>   			return -EINVAL;
>   		argv4.type = ACPI_TYPE_BUFFER;
> @@ -131,7 +130,8 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
>   			return -EINVAL;
>   	}
>
> -	obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4);
> +	obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER,
> +			   &argv4);
>   	if (!obj) {
>   		return -ENXIO;
>   	} else {
> @@ -157,6 +157,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
>   		.buffer.length = 0,
>   		.buffer.pointer = NULL
>   	};
> +	struct tpm_chip *chip = dev_get_drvdata(dev);
>
>   	static char *info[] = {
>   		"None",
> @@ -171,9 +172,10 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
>   	 * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
>   	 * compatibility, define params[3].type as buffer, if PPI version < 1.2
>   	 */
> -	if (strcmp(tpm_ppi_version, "1.2") < 0)
> +	if (strcmp(chip->ppi_version, "1.2") < 0)
>   		obj = &tmp;
> -	obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj);
> +	obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT,
> +			   ACPI_TYPE_INTEGER, obj);
>   	if (!obj) {
>   		return -ENXIO;
>   	} else {
> @@ -196,8 +198,10 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
>   	acpi_status status = -EINVAL;
>   	union acpi_object *obj, *ret_obj;
>   	u64 req, res;
> +	struct tpm_chip *chip = dev_get_drvdata(dev);
>
> -	obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL);
> +	obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
> +			   ACPI_TYPE_PACKAGE, NULL);
>   	if (!obj)
>   		return -ENXIO;
>
> @@ -248,7 +252,8 @@ cleanup:
>   	return status;
>   }
>
> -static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
> +static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
> +				   u32 end)
>   {
>   	int i;
>   	u32 ret;
> @@ -264,14 +269,15 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
>   		"User not required",
>   	};
>
> -	if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
> +	if (!acpi_check_dsm(dev_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
>   			    1 << TPM_PPI_FN_GETOPR))
>   		return -EPERM;
>
>   	tmp.integer.type = ACPI_TYPE_INTEGER;
>   	for (i = start; i <= end; i++) {
>   		tmp.integer.value = i;
> -		obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv);
> +		obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
> +				   ACPI_TYPE_INTEGER, &argv);
>   		if (!obj) {
>   			return -ENOMEM;
>   		} else {
> @@ -291,14 +297,20 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
>   					   struct device_attribute *attr,
>   					   char *buf)
>   {
> -	return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX);
> +	struct tpm_chip *chip = dev_get_drvdata(dev);
> +
> +	return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
> +				   PPI_TPM_REQ_MAX);
>   }
>
>   static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
>   					  struct device_attribute *attr,
>   					  char *buf)
>   {
> -	return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END);
> +	struct tpm_chip *chip = dev_get_drvdata(dev);
> +
> +	return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
> +				   PPI_VS_REQ_END);
>   }
>
>   static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL);
> @@ -323,16 +335,34 @@ static struct attribute_group ppi_attr_grp = {
>   	.attrs = ppi_attrs
>   };
>
> -int tpm_add_ppi(struct kobject *parent)
> +int tpm_add_ppi(struct tpm_chip *chip)
>   {
> -	/* Cache TPM ACPI handle and version string */
> -	acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
> -			    ppi_callback, NULL, NULL, &tpm_ppi_handle);
> -	return tpm_ppi_handle ? sysfs_create_group(parent, &ppi_attr_grp) : 0;
> +	union acpi_object *obj;
> +
> +	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)
> +		return -ENOMEM;
> +
> +	strlcpy(chip->ppi_version, obj->string.pointer,
> +		PPI_VERSION_LEN + 1);

  sizeof(chip->ppi_version) would be better than PPI_VERSION_LEN + 1.

Rest looks ok to me.

     Stefan


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 04/10] tpm: rename chip->dev to chip->pdev
@ 2014-11-25 21:44     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-25 21:44 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard, josh.triplett, linux-api, linux-kernel,
	tpmdd-devel, jason.gunthorpe, trousers-tech

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> Rename chip->dev to chip->pdev to make it explicit that this not the
> character device but actually represents the platform device.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
>


> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 69f4003..b3a7c76 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -98,7 +98,7 @@ struct tpm_vendor_specific {
>   #define TPM_PPI_VERSION_LEN		3
>
>   struct tpm_chip {
> -	struct device *dev;	/* Device stuff */
> +	struct device *pdev;	/* Device stuff */
>   	const struct tpm_class_ops *ops;
>
>   	int dev_num;		/* /dev/tpm# */

So this is the core requiring the renamings.  I assume you got them all 
and none were hidden in #if's or so.

Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 04/10] tpm: rename chip->dev to chip->pdev
@ 2014-11-25 21:44     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-25 21:44 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> Rename chip->dev to chip->pdev to make it explicit that this not the
> character device but actually represents the platform device.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
>


> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 69f4003..b3a7c76 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -98,7 +98,7 @@ struct tpm_vendor_specific {
>   #define TPM_PPI_VERSION_LEN		3
>
>   struct tpm_chip {
> -	struct device *dev;	/* Device stuff */
> +	struct device *pdev;	/* Device stuff */
>   	const struct tpm_class_ops *ops;
>
>   	int dev_num;		/* /dev/tpm# */

So this is the core requiring the renamings.  I assume you got them all 
and none were hidden in #if's or so.

Reviewed-by: Stefan Berger <stefanb-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 09/10] tpm: TPM 2.0 FIFO Interface
@ 2014-11-25 21:52     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-25 21:52 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard, josh.triplett, linux-api, linux-kernel,
	Will Arthur, tpmdd-devel, jason.gunthorpe, trousers-tech

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> From: Will Arthur <will.c.arthur@intel.com>
>
> Detect TPM 2.0 by using the extended STS (STS3) register. For TPM 2.0,
> instead of calling tpm_get_timeouts(), assign duration and timeout
> values defined in the TPM 2.0 PTP specification.
>
> Signed-off-by: Will Arthur <will.c.arthur@intel.com>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> ---
>   drivers/char/tpm/tpm_tis.c | 71 ++++++++++++++++++++++++++++++++++++----------
>   1 file changed, 56 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
> index 7a2c59b..0b3c089 100644
> --- a/drivers/char/tpm/tpm_tis.c
> +++ b/drivers/char/tpm/tpm_tis.c
> @@ -1,5 +1,6 @@
>   /*
>    * Copyright (C) 2005, 2006 IBM Corporation
> + * Copyright (C) 2014 Intel Corporation
>    *
>    * Authors:
>    * Leendert van Doorn <leendert@watson.ibm.com>
> @@ -44,6 +45,10 @@ enum tis_status {
>   	TPM_STS_DATA_EXPECT = 0x08,
>   };
>
> +enum tis_status3 {
> +	TPM_STS3_TPM2_FAM = 0x04,
> +};
> +
>   enum tis_int_flags {
>   	TPM_GLOBAL_INT_ENABLE = 0x80000000,
>   	TPM_INTF_BURST_COUNT_STATIC = 0x100,
> @@ -70,6 +75,7 @@ enum tis_defaults {
>   #define	TPM_INT_STATUS(l)		(0x0010 | ((l) << 12))
>   #define	TPM_INTF_CAPS(l)		(0x0014 | ((l) << 12))
>   #define	TPM_STS(l)			(0x0018 | ((l) << 12))
> +#define	TPM_STS3(l)			(0x001b | ((l) << 12))
>   #define	TPM_DATA_FIFO(l)		(0x0024 | ((l) << 12))
>
>   #define	TPM_DID_VID(l)			(0x0F00 | ((l) << 12))
> @@ -344,6 +350,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
>   {
>   	int rc;
>   	u32 ordinal;
> +	unsigned long dur;
>
>   	rc = tpm_tis_send_data(chip, buf, len);
>   	if (rc < 0)
> @@ -355,9 +362,14 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
>
>   	if (chip->vendor.irq) {
>   		ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
> +
> +		if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +			dur = tpm_calc_ordinal_duration(chip, ordinal);
> +		else
> +			dur = tpm_calc_ordinal_duration(chip, ordinal);
> +

Is this right? Shouldn't you call tpm2_calc_ordinal_duration for TPM2? 
If not don't check the flag but leave comment for why the same function 
can be called for both TPM versions.


>   		if (wait_for_tpm_stat
> -		    (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
> -		     tpm_calc_ordinal_duration(chip, ordinal),
> +		    (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur,
>   		     &chip->vendor.read_queue, false) < 0) {
>   			rc = -ETIME;
>   			goto out_err;
> @@ -543,6 +555,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   	u32 vendor, intfcaps, intmask;
>   	int rc, i, irq_s, irq_e, probe;
>   	struct tpm_chip *chip;
> +	u8 sts3;
>
>   	chip = tpmm_chip_alloc(dev, &tpm_tis);
>   	if (IS_ERR(chip))
> @@ -554,11 +567,28 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   	if (!chip->vendor.iobase)
>   		return -EIO;
>
> +	sts3 = ioread8(chip->vendor.iobase + TPM_STS3(1));
> +	if (sts3 & TPM_STS3_TPM2_FAM)
> +		chip->flags = TPM_CHIP_FLAG_TPM2;
> +
>   	/* 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);
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> +		chip->vendor.timeout_a = usecs_to_jiffies(TPM2_TIMEOUT_A);
> +		chip->vendor.timeout_b = usecs_to_jiffies(TPM2_TIMEOUT_B);
> +		chip->vendor.timeout_c = usecs_to_jiffies(TPM2_TIMEOUT_C);
> +		chip->vendor.timeout_d = usecs_to_jiffies(TPM2_TIMEOUT_D);
> +		chip->vendor.duration[TPM_SHORT] =
> +			usecs_to_jiffies(TPM2_DURATION_SHORT);
> +		chip->vendor.duration[TPM_MEDIUM] =
> +			usecs_to_jiffies(TPM2_DURATION_MEDIUM);
> +		chip->vendor.duration[TPM_LONG] =
> +			usecs_to_jiffies(TPM2_DURATION_LONG);
> +	} else {
> +		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);
> +	}
>
>   	if (wait_startup(chip, 0) != 0) {
>   		rc = -ENODEV;
> @@ -573,8 +603,8 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   	vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
>   	chip->vendor.manufacturer_id = vendor;
>
> -	dev_info(dev,
> -		 "1.2 TPM (device-id 0x%X, rev-id %d)\n",
> +	dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n",
> +		 (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
>   		 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
>
>   	if (!itpm) {
> @@ -616,13 +646,17 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   		dev_dbg(dev, "\tData Avail Int Support\n");
>
>   	/* get the timeouts before testing for irqs */
> -	if (tpm_get_timeouts(chip)) {
> +	if (!(chip->flags & TPM_CHIP_FLAG_TPM2) && 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)) {
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +		rc = tpm2_do_selftest(chip);
> +	else
> +		rc = tpm_do_selftest(chip);
> +	if (rc) {
>   		dev_err(dev, "TPM self test failed\n");
>   		rc = -ENODEV;
>   		goto out_err;
> @@ -683,7 +717,10 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   			chip->vendor.probed_irq = 0;
>
>   			/* Generate Interrupts */
> -			tpm_gen_interrupt(chip);
> +			if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +				tpm2_gen_interrupt(chip);
> +			else
> +				tpm_gen_interrupt(chip);
>
>   			chip->vendor.irq = chip->vendor.probed_irq;
>
> @@ -759,14 +796,18 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
>   static int tpm_tis_resume(struct device *dev)
>   {
>   	struct tpm_chip *chip = dev_get_drvdata(dev);
> -	int ret;
> +	int ret = 0;
>
>   	if (chip->vendor.irq)
>   		tpm_tis_reenable_interrupts(chip);
>
> -	ret = tpm_pm_resume(dev);
> -	if (!ret)
> -		tpm_do_selftest(chip);
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +		tpm2_do_selftest(chip);
> +	else {
> +		ret = tpm_pm_resume(dev);
> +		if (!ret)
> +			tpm_do_selftest(chip);
> +	}

Only a self test necessary for TPM2 if resuming from ACPI sleep?

Other parts look good to me.
    Stefan


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 09/10] tpm: TPM 2.0 FIFO Interface
@ 2014-11-25 21:52     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-25 21:52 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Will Arthur,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> From: Will Arthur <will.c.arthur-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
>
> Detect TPM 2.0 by using the extended STS (STS3) register. For TPM 2.0,
> instead of calling tpm_get_timeouts(), assign duration and timeout
> values defined in the TPM 2.0 PTP specification.
>
> Signed-off-by: Will Arthur <will.c.arthur-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> ---
>   drivers/char/tpm/tpm_tis.c | 71 ++++++++++++++++++++++++++++++++++++----------
>   1 file changed, 56 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
> index 7a2c59b..0b3c089 100644
> --- a/drivers/char/tpm/tpm_tis.c
> +++ b/drivers/char/tpm/tpm_tis.c
> @@ -1,5 +1,6 @@
>   /*
>    * Copyright (C) 2005, 2006 IBM Corporation
> + * Copyright (C) 2014 Intel Corporation
>    *
>    * Authors:
>    * Leendert van Doorn <leendert-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org>
> @@ -44,6 +45,10 @@ enum tis_status {
>   	TPM_STS_DATA_EXPECT = 0x08,
>   };
>
> +enum tis_status3 {
> +	TPM_STS3_TPM2_FAM = 0x04,
> +};
> +
>   enum tis_int_flags {
>   	TPM_GLOBAL_INT_ENABLE = 0x80000000,
>   	TPM_INTF_BURST_COUNT_STATIC = 0x100,
> @@ -70,6 +75,7 @@ enum tis_defaults {
>   #define	TPM_INT_STATUS(l)		(0x0010 | ((l) << 12))
>   #define	TPM_INTF_CAPS(l)		(0x0014 | ((l) << 12))
>   #define	TPM_STS(l)			(0x0018 | ((l) << 12))
> +#define	TPM_STS3(l)			(0x001b | ((l) << 12))
>   #define	TPM_DATA_FIFO(l)		(0x0024 | ((l) << 12))
>
>   #define	TPM_DID_VID(l)			(0x0F00 | ((l) << 12))
> @@ -344,6 +350,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
>   {
>   	int rc;
>   	u32 ordinal;
> +	unsigned long dur;
>
>   	rc = tpm_tis_send_data(chip, buf, len);
>   	if (rc < 0)
> @@ -355,9 +362,14 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
>
>   	if (chip->vendor.irq) {
>   		ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
> +
> +		if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +			dur = tpm_calc_ordinal_duration(chip, ordinal);
> +		else
> +			dur = tpm_calc_ordinal_duration(chip, ordinal);
> +

Is this right? Shouldn't you call tpm2_calc_ordinal_duration for TPM2? 
If not don't check the flag but leave comment for why the same function 
can be called for both TPM versions.


>   		if (wait_for_tpm_stat
> -		    (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
> -		     tpm_calc_ordinal_duration(chip, ordinal),
> +		    (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur,
>   		     &chip->vendor.read_queue, false) < 0) {
>   			rc = -ETIME;
>   			goto out_err;
> @@ -543,6 +555,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   	u32 vendor, intfcaps, intmask;
>   	int rc, i, irq_s, irq_e, probe;
>   	struct tpm_chip *chip;
> +	u8 sts3;
>
>   	chip = tpmm_chip_alloc(dev, &tpm_tis);
>   	if (IS_ERR(chip))
> @@ -554,11 +567,28 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   	if (!chip->vendor.iobase)
>   		return -EIO;
>
> +	sts3 = ioread8(chip->vendor.iobase + TPM_STS3(1));
> +	if (sts3 & TPM_STS3_TPM2_FAM)
> +		chip->flags = TPM_CHIP_FLAG_TPM2;
> +
>   	/* 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);
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> +		chip->vendor.timeout_a = usecs_to_jiffies(TPM2_TIMEOUT_A);
> +		chip->vendor.timeout_b = usecs_to_jiffies(TPM2_TIMEOUT_B);
> +		chip->vendor.timeout_c = usecs_to_jiffies(TPM2_TIMEOUT_C);
> +		chip->vendor.timeout_d = usecs_to_jiffies(TPM2_TIMEOUT_D);
> +		chip->vendor.duration[TPM_SHORT] =
> +			usecs_to_jiffies(TPM2_DURATION_SHORT);
> +		chip->vendor.duration[TPM_MEDIUM] =
> +			usecs_to_jiffies(TPM2_DURATION_MEDIUM);
> +		chip->vendor.duration[TPM_LONG] =
> +			usecs_to_jiffies(TPM2_DURATION_LONG);
> +	} else {
> +		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);
> +	}
>
>   	if (wait_startup(chip, 0) != 0) {
>   		rc = -ENODEV;
> @@ -573,8 +603,8 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   	vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
>   	chip->vendor.manufacturer_id = vendor;
>
> -	dev_info(dev,
> -		 "1.2 TPM (device-id 0x%X, rev-id %d)\n",
> +	dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n",
> +		 (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
>   		 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
>
>   	if (!itpm) {
> @@ -616,13 +646,17 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   		dev_dbg(dev, "\tData Avail Int Support\n");
>
>   	/* get the timeouts before testing for irqs */
> -	if (tpm_get_timeouts(chip)) {
> +	if (!(chip->flags & TPM_CHIP_FLAG_TPM2) && 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)) {
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +		rc = tpm2_do_selftest(chip);
> +	else
> +		rc = tpm_do_selftest(chip);
> +	if (rc) {
>   		dev_err(dev, "TPM self test failed\n");
>   		rc = -ENODEV;
>   		goto out_err;
> @@ -683,7 +717,10 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   			chip->vendor.probed_irq = 0;
>
>   			/* Generate Interrupts */
> -			tpm_gen_interrupt(chip);
> +			if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +				tpm2_gen_interrupt(chip);
> +			else
> +				tpm_gen_interrupt(chip);
>
>   			chip->vendor.irq = chip->vendor.probed_irq;
>
> @@ -759,14 +796,18 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
>   static int tpm_tis_resume(struct device *dev)
>   {
>   	struct tpm_chip *chip = dev_get_drvdata(dev);
> -	int ret;
> +	int ret = 0;
>
>   	if (chip->vendor.irq)
>   		tpm_tis_reenable_interrupts(chip);
>
> -	ret = tpm_pm_resume(dev);
> -	if (!ret)
> -		tpm_do_selftest(chip);
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +		tpm2_do_selftest(chip);
> +	else {
> +		ret = tpm_pm_resume(dev);
> +		if (!ret)
> +			tpm_do_selftest(chip);
> +	}

Only a self test necessary for TPM2 if resuming from ACPI sleep?

Other parts look good to me.
    Stefan

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 10/10] tpm: TPM 2.0 sysfs attributes
@ 2014-11-25 23:55     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-25 23:55 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard, josh.triplett, linux-api, linux-kernel,
	tpmdd-devel, jason.gunthorpe, trousers-tech

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> Manadatory sysfs attributes for TPM 2.0 devices so that it is easy
> to check whether storage hierarchies are enabled and use PPI
> interface.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> ---
>   Documentation/ABI/stable/sysfs-class-tpm2 |  57 +++++++++++
>   drivers/char/tpm/Makefile                 |   2 +-
>   drivers/char/tpm/tpm-chip.c               |  21 +++--
>   drivers/char/tpm/tpm.h                    |  19 ++++
>   drivers/char/tpm/tpm2-sysfs.c             | 152 ++++++++++++++++++++++++++++++
>   5 files changed, 241 insertions(+), 10 deletions(-)
>   create mode 100644 Documentation/ABI/stable/sysfs-class-tpm2
>   create mode 100644 drivers/char/tpm/tpm2-sysfs.c
>
> diff --git a/Documentation/ABI/stable/sysfs-class-tpm2 b/Documentation/ABI/stable/sysfs-class-tpm2
> new file mode 100644
> index 0000000..301ab2e
> --- /dev/null
> +++ b/Documentation/ABI/stable/sysfs-class-tpm2
> @@ -0,0 +1,57 @@
> +What:		/sys/class/misc/tpmX/device/
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel@lists.sf.net
> +Description:	The device/ directory under a specific TPM instance exposes
> +		the properties of that TPM chip.
> +
> +What:		/sys/class/misc/tpmX/device/family
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel@lists.sf.net
> +Description:	The protocol family in the major.minor format.
> +

What protocol ? The TPM protocol family .. ?

> +What:		/sys/class/misc/tpmX/device/sh_enabled
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel@lists.sf.net
> +Description:	The "sh_enabled" property prints a '1' if the Storage Hierarchy
> +		is enabled, i.e. if PM_PT_STARTUP_CLEAR.shEnable is set.

Why capital letters for storage hierarchy?

> +
> +What:		/sys/class/misc/tpmX/device/sh_owned
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel@lists.sf.net
> +Description:	The "sh_owned" property prints a '1' if the ownership of the
> +		Storage Hierarchy has been taken, i.e. if
> +		TPM_PT_PERMANENT.ownerAuthSet is set.
> +

Same her

> +What:		/sys/class/misc/tpmX/device/eh_enabled
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel@lists.sf.net
> +Description:	The "eh_enabled" property prints a '1' if the Endorsement
> +		Hierarchy is enabled, i.e if PM_PT_STARTUP_CLEAR.ehEnable is
> +		set.


> +
> +What:		/sys/class/misc/tpmX/device/eh_owned
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel@lists.sf.net
> +Description:	The "eh_owned" property prints a '1' if the ownership of the
> +		Endrosoment Hierarchy has been taken, i.e if
> +		TPM_PT_PERMANENT.endorsementAuthSet is set.
> +
> +What:		/sys/class/misc/tpmX/device/manufacturer
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel@lists.sf.net
> +Description:	The "manufacturer" property prints the vendor ID of the TPM
> +		manufacturer.
> +
> +What:		/sys/class/misc/tpmX/device/firmware
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel@lists.sf.net
> +Description:	The property prints the vendor-specific value indicating the
> +		version of the firmware.
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> index e6d26dd..15e3b4c 100644
> --- a/drivers/char/tpm/Makefile
> +++ b/drivers/char/tpm/Makefile
> @@ -2,7 +2,7 @@
>   # Makefile for the kernel tpm device drivers.
>   #
>   obj-$(CONFIG_TCG_TPM) += tpm.o
> -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o
> +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o tpm2-sysfs.o
>   tpm-$(CONFIG_ACPI) += tpm_ppi.o
>
>   ifdef CONFIG_ACPI
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 4d25b24..accd408 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -30,6 +30,7 @@
>   #include "tpm_eventlog.h"
>
>   ATTRIBUTE_GROUPS(tpm_dev);
> +ATTRIBUTE_GROUPS(tpm2_dev);
>
>   static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
>   static LIST_HEAD(tpm_chip_list);
> @@ -138,7 +139,10 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
>   	else
>   		chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
>
> -	chip->dev.groups = tpm_dev_groups;
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +		chip->dev.groups = tpm2_dev_groups;
> +	else
> +		chip->dev.groups = tpm_dev_groups;
>
>   	dev_set_name(&chip->dev, chip->devname);
>
> @@ -213,14 +217,12 @@ int tpm_chip_register(struct tpm_chip *chip)
>   	if (rc)
>   		return rc;
>
> -	/* Populate sysfs for TPM1 devices. */
> -	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
> -		rc = tpm_add_ppi(chip);
> -		if (rc)
> -			goto out_err;
> +	rc = tpm_add_ppi(chip);
> +	if (rc)
> +		goto out_err;
>
> +	if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
>   		chip->bios_dir = tpm_bios_log_setup(chip->devname);
> -	}
>
>   	/* Make the chip available. */
>   	spin_lock(&driver_lock);
> @@ -251,8 +253,9 @@ void tpm_chip_unregister(struct tpm_chip *chip)
>   	spin_unlock(&driver_lock);
>   	synchronize_rcu();
>
> -	/* Clean up sysfs for TPM1 devices. */
> -	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> +		tpm_remove_ppi(chip);

Take the tpm_remove_ppi(chip) out of the if and else branches into a 
common path.

> +	} else {
>   		if (chip->bios_dir)
>   			tpm_bios_log_teardown(chip->bios_dir);
>   		tpm_remove_ppi(chip);
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 8a434d2..1548182 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -108,6 +108,24 @@ enum tpm2_capabilities {
>   	TPM2_CAP_TPM_PROPERTIES = 6,
>   };
>
> +enum tpm2_tpm_properties {
> +	TPM2_PT_MANUFACTURER		= 0x00000105,
> +	TPM2_PT_FIRMWARE_VERSION_1	= 0x0000010C,
> +	TPM2_PT_FIRMWARE_VERSION_2	= 0x0000010D,
> +	TPM2_PT_PERMANENT		= 0x00000200,
> +	TPM2_PT_STARTUP_CLEAR		= 0x00000201,
> +};
> +
> +enum tpm2_pt_startup_clear {
> +	TPM2_PT_SC_SH_ENABLE	= BIT(1),
> +	TPM2_PT_SC_EH_ENABLE	= BIT(2),
> +};
> +
> +enum tpm2_pt_permanent {
> +	TPM2_PT_PM_OWNER_AUTH_SET	= BIT(0),
> +	TPM2_PT_PM_ENDORSEMENT_AUTH_SET	= BIT(1),
> +};
> +
>   enum tpm2_startup_types {
>   	TPM2_SU_CLEAR	= 0x0000,
>   	TPM2_SU_STATE	= 0x0001,
> @@ -382,6 +400,7 @@ extern struct class *tpm_class;
>   extern dev_t tpm_devt;
>   extern const struct file_operations tpm_fops;
>   extern struct attribute *tpm_dev_attrs[];
> +extern struct attribute *tpm2_dev_attrs[];
>
>   ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
>   ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
> diff --git a/drivers/char/tpm/tpm2-sysfs.c b/drivers/char/tpm/tpm2-sysfs.c
> new file mode 100644
> index 0000000..9e5e2e3
> --- /dev/null
> +++ b/drivers/char/tpm/tpm2-sysfs.c
> @@ -0,0 +1,152 @@
> +/*
> + * Copyright (C) 2014 Intel Corporation
> + *
> + * Authors:
> + * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> + *
> + * TPM2 sysfs attributes
> + *
> + * 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/device.h>
> +#include <linux/slab.h>
> +#include "tpm.h"
> +
> +static ssize_t sh_enabled_show(struct device *dev, struct device_attribute *attr,
> +		     char *buf)
> +{
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
> +	u32 value;
> +	ssize_t rc;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_STARTUP_CLEAR, &value,
> +			     "could not retrieve STARTUP_CLEAR property");
> +	if (rc)
> +		return 0;
> +
> +	rc = sprintf(buf, "%d\n", (value & TPM2_PT_SC_SH_ENABLE) > 0);
> +	return rc;
> +}
> +static DEVICE_ATTR_RO(sh_enabled);
> +
> +static ssize_t sh_owned_show(struct device *dev, struct device_attribute *attr,
> +			  char *buf)
> +{
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
> +	u32 value;
> +	ssize_t rc;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_PERMANENT, &value,
> +			     "could not retrieve PERMANENT property");
> +	if (rc)
> +		return 0;
> +
> +	rc = sprintf(buf, "%d\n", (value & TPM2_PT_PM_OWNER_AUTH_SET) > 0);
> +	return rc;
> +}
> +static DEVICE_ATTR_RO(sh_owned);
> +
> +static ssize_t eh_enabled_show(struct device *dev, struct device_attribute *attr,
> +		     char *buf)
> +{
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
> +	u32 value;
> +	ssize_t rc;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_STARTUP_CLEAR, &value,
> +			     "could not retrieve STARTUP_CLEAR property");
> +	if (rc)
> +		return 0;
> +
> +	rc = sprintf(buf, "%d\n", (value & TPM2_PT_SC_EH_ENABLE) > 0);
> +	return rc;
> +}
> +static DEVICE_ATTR_RO(eh_enabled);
> +
> +static ssize_t eh_owned_show(struct device *dev, struct device_attribute *attr,
> +			  char *buf)
> +{
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
> +	u32 value;
> +	ssize_t rc;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_PERMANENT, &value,
> +			     "could not retrieve PERMANENT property");
> +	if (rc)
> +		return 0;
> +
> +	rc = sprintf(buf, "%d\n", (value & TPM2_PT_PM_ENDORSEMENT_AUTH_SET) > 0);
> +	return rc;
> +}
> +static DEVICE_ATTR_RO(eh_owned);
> +
> +static ssize_t manufacturer_show(struct device *dev,
> +				 struct device_attribute *attr,
> +				 char *buf)
> +{
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
> +	u32 manufacturer;
> +	ssize_t rc;
> +	char *str = buf;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_MANUFACTURER, (u32 *) &manufacturer,

seems an unnecessary cast.

> +			     "could not retrieve MANUFACTURER property");
> +	if (rc)
> +		return 0;
> +
> +	str += sprintf(str, "0x%08x\n", be32_to_cpu(manufacturer));
> +
rc = sprintf()
return rc;

Like above?
> +	return str - buf;
> +}
> +static DEVICE_ATTR_RO(manufacturer);
> +
> +static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
> +			 char *buf)
> +{
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
> +	u32 firmware1;
> +	u32 firmware2;
> +	ssize_t rc;
> +	char *str = buf;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_1, (u32 *) &firmware1,
> +			     "could not retrieve FIRMWARE_VERSION_1 property");
> +	if (rc)
> +		return 0;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_2, (u32 *) &firmware2,
> +			     "could not retrieve FIRMWARE_VERSION_2 property");
> +	if (rc)
> +		return 0;
> +
> +	str += sprintf(str, "0x%08x.0x%08x\n", firmware1, firmware2);
> +
> +	return str - buf;

Same for here, why not again do rc = sprintf .. return rc; ?

> +}
> +static DEVICE_ATTR_RO(firmware);
> +
> +static ssize_t family_show(struct device *dev, struct device_attribute *attr,
> +			   char *buf)
> +{
> +	char *str = buf;
> +
> +	str += sprintf(str, "2.0\n");
> +
> +	return str - buf;

return sprintf(buf, "2.0\n");

> +}
> +static DEVICE_ATTR_RO(family);
> +
> +struct attribute *tpm2_dev_attrs[] = {
> +	&dev_attr_sh_enabled.attr,
> +	&dev_attr_sh_owned.attr,
> +	&dev_attr_eh_enabled.attr,
> +	&dev_attr_eh_owned.attr,
> +	&dev_attr_manufacturer.attr,
> +	&dev_attr_firmware.attr,
> +	&dev_attr_family.attr,
> +	NULL,
> +};

     Stefan


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 10/10] tpm: TPM 2.0 sysfs attributes
@ 2014-11-25 23:55     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-25 23:55 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> Manadatory sysfs attributes for TPM 2.0 devices so that it is easy
> to check whether storage hierarchies are enabled and use PPI
> interface.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> ---
>   Documentation/ABI/stable/sysfs-class-tpm2 |  57 +++++++++++
>   drivers/char/tpm/Makefile                 |   2 +-
>   drivers/char/tpm/tpm-chip.c               |  21 +++--
>   drivers/char/tpm/tpm.h                    |  19 ++++
>   drivers/char/tpm/tpm2-sysfs.c             | 152 ++++++++++++++++++++++++++++++
>   5 files changed, 241 insertions(+), 10 deletions(-)
>   create mode 100644 Documentation/ABI/stable/sysfs-class-tpm2
>   create mode 100644 drivers/char/tpm/tpm2-sysfs.c
>
> diff --git a/Documentation/ABI/stable/sysfs-class-tpm2 b/Documentation/ABI/stable/sysfs-class-tpm2
> new file mode 100644
> index 0000000..301ab2e
> --- /dev/null
> +++ b/Documentation/ABI/stable/sysfs-class-tpm2
> @@ -0,0 +1,57 @@
> +What:		/sys/class/misc/tpmX/device/
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel-TtF/mJH4Jtrk1uMJSBkQmQ@public.gmane.org
> +Description:	The device/ directory under a specific TPM instance exposes
> +		the properties of that TPM chip.
> +
> +What:		/sys/class/misc/tpmX/device/family
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel-TtF/mJH4Jtrk1uMJSBkQmQ@public.gmane.org
> +Description:	The protocol family in the major.minor format.
> +

What protocol ? The TPM protocol family .. ?

> +What:		/sys/class/misc/tpmX/device/sh_enabled
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel-TtF/mJH4Jtrk1uMJSBkQmQ@public.gmane.org
> +Description:	The "sh_enabled" property prints a '1' if the Storage Hierarchy
> +		is enabled, i.e. if PM_PT_STARTUP_CLEAR.shEnable is set.

Why capital letters for storage hierarchy?

> +
> +What:		/sys/class/misc/tpmX/device/sh_owned
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel-TtF/mJH4Jtrk1uMJSBkQmQ@public.gmane.org
> +Description:	The "sh_owned" property prints a '1' if the ownership of the
> +		Storage Hierarchy has been taken, i.e. if
> +		TPM_PT_PERMANENT.ownerAuthSet is set.
> +

Same her

> +What:		/sys/class/misc/tpmX/device/eh_enabled
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel-TtF/mJH4Jtrk1uMJSBkQmQ@public.gmane.org
> +Description:	The "eh_enabled" property prints a '1' if the Endorsement
> +		Hierarchy is enabled, i.e if PM_PT_STARTUP_CLEAR.ehEnable is
> +		set.


> +
> +What:		/sys/class/misc/tpmX/device/eh_owned
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel-TtF/mJH4Jtrk1uMJSBkQmQ@public.gmane.org
> +Description:	The "eh_owned" property prints a '1' if the ownership of the
> +		Endrosoment Hierarchy has been taken, i.e if
> +		TPM_PT_PERMANENT.endorsementAuthSet is set.
> +
> +What:		/sys/class/misc/tpmX/device/manufacturer
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel-TtF/mJH4Jtrk1uMJSBkQmQ@public.gmane.org
> +Description:	The "manufacturer" property prints the vendor ID of the TPM
> +		manufacturer.
> +
> +What:		/sys/class/misc/tpmX/device/firmware
> +Date:		October 2014
> +KernelVersion:	3.19
> +Contact:	tpmdd-devel-TtF/mJH4Jtrk1uMJSBkQmQ@public.gmane.org
> +Description:	The property prints the vendor-specific value indicating the
> +		version of the firmware.
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> index e6d26dd..15e3b4c 100644
> --- a/drivers/char/tpm/Makefile
> +++ b/drivers/char/tpm/Makefile
> @@ -2,7 +2,7 @@
>   # Makefile for the kernel tpm device drivers.
>   #
>   obj-$(CONFIG_TCG_TPM) += tpm.o
> -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o
> +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o tpm2-sysfs.o
>   tpm-$(CONFIG_ACPI) += tpm_ppi.o
>
>   ifdef CONFIG_ACPI
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 4d25b24..accd408 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -30,6 +30,7 @@
>   #include "tpm_eventlog.h"
>
>   ATTRIBUTE_GROUPS(tpm_dev);
> +ATTRIBUTE_GROUPS(tpm2_dev);
>
>   static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
>   static LIST_HEAD(tpm_chip_list);
> @@ -138,7 +139,10 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
>   	else
>   		chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
>
> -	chip->dev.groups = tpm_dev_groups;
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +		chip->dev.groups = tpm2_dev_groups;
> +	else
> +		chip->dev.groups = tpm_dev_groups;
>
>   	dev_set_name(&chip->dev, chip->devname);
>
> @@ -213,14 +217,12 @@ int tpm_chip_register(struct tpm_chip *chip)
>   	if (rc)
>   		return rc;
>
> -	/* Populate sysfs for TPM1 devices. */
> -	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
> -		rc = tpm_add_ppi(chip);
> -		if (rc)
> -			goto out_err;
> +	rc = tpm_add_ppi(chip);
> +	if (rc)
> +		goto out_err;
>
> +	if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
>   		chip->bios_dir = tpm_bios_log_setup(chip->devname);
> -	}
>
>   	/* Make the chip available. */
>   	spin_lock(&driver_lock);
> @@ -251,8 +253,9 @@ void tpm_chip_unregister(struct tpm_chip *chip)
>   	spin_unlock(&driver_lock);
>   	synchronize_rcu();
>
> -	/* Clean up sysfs for TPM1 devices. */
> -	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> +		tpm_remove_ppi(chip);

Take the tpm_remove_ppi(chip) out of the if and else branches into a 
common path.

> +	} else {
>   		if (chip->bios_dir)
>   			tpm_bios_log_teardown(chip->bios_dir);
>   		tpm_remove_ppi(chip);
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 8a434d2..1548182 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -108,6 +108,24 @@ enum tpm2_capabilities {
>   	TPM2_CAP_TPM_PROPERTIES = 6,
>   };
>
> +enum tpm2_tpm_properties {
> +	TPM2_PT_MANUFACTURER		= 0x00000105,
> +	TPM2_PT_FIRMWARE_VERSION_1	= 0x0000010C,
> +	TPM2_PT_FIRMWARE_VERSION_2	= 0x0000010D,
> +	TPM2_PT_PERMANENT		= 0x00000200,
> +	TPM2_PT_STARTUP_CLEAR		= 0x00000201,
> +};
> +
> +enum tpm2_pt_startup_clear {
> +	TPM2_PT_SC_SH_ENABLE	= BIT(1),
> +	TPM2_PT_SC_EH_ENABLE	= BIT(2),
> +};
> +
> +enum tpm2_pt_permanent {
> +	TPM2_PT_PM_OWNER_AUTH_SET	= BIT(0),
> +	TPM2_PT_PM_ENDORSEMENT_AUTH_SET	= BIT(1),
> +};
> +
>   enum tpm2_startup_types {
>   	TPM2_SU_CLEAR	= 0x0000,
>   	TPM2_SU_STATE	= 0x0001,
> @@ -382,6 +400,7 @@ extern struct class *tpm_class;
>   extern dev_t tpm_devt;
>   extern const struct file_operations tpm_fops;
>   extern struct attribute *tpm_dev_attrs[];
> +extern struct attribute *tpm2_dev_attrs[];
>
>   ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
>   ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
> diff --git a/drivers/char/tpm/tpm2-sysfs.c b/drivers/char/tpm/tpm2-sysfs.c
> new file mode 100644
> index 0000000..9e5e2e3
> --- /dev/null
> +++ b/drivers/char/tpm/tpm2-sysfs.c
> @@ -0,0 +1,152 @@
> +/*
> + * Copyright (C) 2014 Intel Corporation
> + *
> + * Authors:
> + * Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> + *
> + * TPM2 sysfs attributes
> + *
> + * 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/device.h>
> +#include <linux/slab.h>
> +#include "tpm.h"
> +
> +static ssize_t sh_enabled_show(struct device *dev, struct device_attribute *attr,
> +		     char *buf)
> +{
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
> +	u32 value;
> +	ssize_t rc;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_STARTUP_CLEAR, &value,
> +			     "could not retrieve STARTUP_CLEAR property");
> +	if (rc)
> +		return 0;
> +
> +	rc = sprintf(buf, "%d\n", (value & TPM2_PT_SC_SH_ENABLE) > 0);
> +	return rc;
> +}
> +static DEVICE_ATTR_RO(sh_enabled);
> +
> +static ssize_t sh_owned_show(struct device *dev, struct device_attribute *attr,
> +			  char *buf)
> +{
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
> +	u32 value;
> +	ssize_t rc;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_PERMANENT, &value,
> +			     "could not retrieve PERMANENT property");
> +	if (rc)
> +		return 0;
> +
> +	rc = sprintf(buf, "%d\n", (value & TPM2_PT_PM_OWNER_AUTH_SET) > 0);
> +	return rc;
> +}
> +static DEVICE_ATTR_RO(sh_owned);
> +
> +static ssize_t eh_enabled_show(struct device *dev, struct device_attribute *attr,
> +		     char *buf)
> +{
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
> +	u32 value;
> +	ssize_t rc;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_STARTUP_CLEAR, &value,
> +			     "could not retrieve STARTUP_CLEAR property");
> +	if (rc)
> +		return 0;
> +
> +	rc = sprintf(buf, "%d\n", (value & TPM2_PT_SC_EH_ENABLE) > 0);
> +	return rc;
> +}
> +static DEVICE_ATTR_RO(eh_enabled);
> +
> +static ssize_t eh_owned_show(struct device *dev, struct device_attribute *attr,
> +			  char *buf)
> +{
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
> +	u32 value;
> +	ssize_t rc;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_PERMANENT, &value,
> +			     "could not retrieve PERMANENT property");
> +	if (rc)
> +		return 0;
> +
> +	rc = sprintf(buf, "%d\n", (value & TPM2_PT_PM_ENDORSEMENT_AUTH_SET) > 0);
> +	return rc;
> +}
> +static DEVICE_ATTR_RO(eh_owned);
> +
> +static ssize_t manufacturer_show(struct device *dev,
> +				 struct device_attribute *attr,
> +				 char *buf)
> +{
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
> +	u32 manufacturer;
> +	ssize_t rc;
> +	char *str = buf;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_MANUFACTURER, (u32 *) &manufacturer,

seems an unnecessary cast.

> +			     "could not retrieve MANUFACTURER property");
> +	if (rc)
> +		return 0;
> +
> +	str += sprintf(str, "0x%08x\n", be32_to_cpu(manufacturer));
> +
rc = sprintf()
return rc;

Like above?
> +	return str - buf;
> +}
> +static DEVICE_ATTR_RO(manufacturer);
> +
> +static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
> +			 char *buf)
> +{
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
> +	u32 firmware1;
> +	u32 firmware2;
> +	ssize_t rc;
> +	char *str = buf;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_1, (u32 *) &firmware1,
> +			     "could not retrieve FIRMWARE_VERSION_1 property");
> +	if (rc)
> +		return 0;
> +
> +	rc = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_2, (u32 *) &firmware2,
> +			     "could not retrieve FIRMWARE_VERSION_2 property");
> +	if (rc)
> +		return 0;
> +
> +	str += sprintf(str, "0x%08x.0x%08x\n", firmware1, firmware2);
> +
> +	return str - buf;

Same for here, why not again do rc = sprintf .. return rc; ?

> +}
> +static DEVICE_ATTR_RO(firmware);
> +
> +static ssize_t family_show(struct device *dev, struct device_attribute *attr,
> +			   char *buf)
> +{
> +	char *str = buf;
> +
> +	str += sprintf(str, "2.0\n");
> +
> +	return str - buf;

return sprintf(buf, "2.0\n");

> +}
> +static DEVICE_ATTR_RO(family);
> +
> +struct attribute *tpm2_dev_attrs[] = {
> +	&dev_attr_sh_enabled.attr,
> +	&dev_attr_sh_owned.attr,
> +	&dev_attr_eh_enabled.attr,
> +	&dev_attr_eh_owned.attr,
> +	&dev_attr_manufacturer.attr,
> +	&dev_attr_firmware.attr,
> +	&dev_attr_family.attr,
> +	NULL,
> +};

     Stefan

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 07/10] tpm: TPM 2.0 baseline support
@ 2014-11-26  0:42     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-26  0:42 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard, josh.triplett, linux-api, linux-kernel,
	Will Arthur, tpmdd-devel, jason.gunthorpe, trousers-tech

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> TPM 2.0 devices are separated by adding a field 'flags' to struct
> tpm_chip and defining a flag TPM_CHIP_FLAG_TPM2 for tagging them.
>
> This patch adds the following internal functions:
>
> - tpm2_get_random()
> - tpm2_get_tpm_pt()
> - tpm2_pcr_extend()
> - tpm2_pcr_read()
> - tpm2_startup()
>
> Additionally, the following exported functions are implemented for
> implementing TPM 2.0 device drivers:
>
> - tpm2_do_selftest()
> - tpm2_calc_ordinal_durations()
> - tpm2_gen_interrupt()
>
> The existing functions that are exported for the use for existing
> subsystems have been changed to check the flags field in struct
> tpm_chip and use appropriate TPM 2.0 counterpart if
> TPM_CHIP_FLAG_TPM2 is est.
>
> The code for tpm2_calc_ordinal_duration() and tpm2_startup() were
> originally written by Will Arthur.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> Signed-off-by: Will Arthur <will.c.arthur@intel.com>
> ---
>   drivers/char/tpm/Makefile        |   2 +-
>   drivers/char/tpm/tpm-chip.c      |  21 +-
>   drivers/char/tpm/tpm-interface.c |  24 +-
>   drivers/char/tpm/tpm.h           |  67 +++++
>   drivers/char/tpm/tpm2-cmd.c      | 566 +++++++++++++++++++++++++++++++++++++++
>   5 files changed, 668 insertions(+), 12 deletions(-)
>   create mode 100644 drivers/char/tpm/tpm2-cmd.c
>
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> index 837da04..ae56af9 100644
> --- a/drivers/char/tpm/Makefile
> +++ b/drivers/char/tpm/Makefile
> @@ -2,7 +2,7 @@
>   # Makefile for the kernel tpm device drivers.
>   #
>   obj-$(CONFIG_TCG_TPM) += tpm.o
> -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o
> +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o
>   tpm-$(CONFIG_ACPI) += tpm_ppi.o
>
>   ifdef CONFIG_ACPI
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 5d268ac..4d25b24 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -213,11 +213,14 @@ int tpm_chip_register(struct tpm_chip *chip)
>   	if (rc)
>   		return rc;
>
> -	rc = tpm_add_ppi(chip);
> -	if (rc)
> -		goto out_err;
> +	/* Populate sysfs for TPM1 devices. */
> +	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
> +		rc = tpm_add_ppi(chip);
> +		if (rc)
> +			goto out_err;
>
> -	chip->bios_dir = tpm_bios_log_setup(chip->devname);
> +		chip->bios_dir = tpm_bios_log_setup(chip->devname);
> +	}
>
>   	/* Make the chip available. */
>   	spin_lock(&driver_lock);
> @@ -248,10 +251,12 @@ void tpm_chip_unregister(struct tpm_chip *chip)
>   	spin_unlock(&driver_lock);
>   	synchronize_rcu();
>
> -	tpm_remove_ppi(chip);
> -
> -	if (chip->bios_dir)
> -		tpm_bios_log_teardown(chip->bios_dir);
> +	/* Clean up sysfs for TPM1 devices. */
> +	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
> +		if (chip->bios_dir)
> +			tpm_bios_log_teardown(chip->bios_dir);
> +		tpm_remove_ppi(chip);
> +	}
>
>   	tpm_dev_del_device(chip);
>   }
> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> index 9e4ce4d..e62b835 100644
> --- a/drivers/char/tpm/tpm-interface.c
> +++ b/drivers/char/tpm/tpm-interface.c
> @@ -360,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
>   	if (chip->vendor.irq)
>   		goto out_recv;
>
> -	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +		stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
> +	else
> +		stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
>   	do {
>   		u8 status = chip->ops->status(chip);
>   		if ((status & chip->ops->req_complete_mask) ==
> @@ -483,7 +486,7 @@ static const struct tpm_input_header tpm_startup_header = {
>   static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
>   {
>   	struct tpm_cmd_t start_cmd;
> -	start_cmd.header.in = tpm_startup_header;
> +
>   	start_cmd.params.startup_in.startup_type = startup_type;
>   	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
>   				"attempting to start the TPM");
> @@ -680,7 +683,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
>   	chip = tpm_chip_find_get(chip_num);
>   	if (chip == NULL)
>   		return -ENODEV;
> -	rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +		rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
> +	else
> +		rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
>   	tpm_chip_put(chip);
>   	return rc;
>   }
> @@ -714,6 +720,12 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
>   	if (chip == NULL)
>   		return -ENODEV;
>
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> +		rc = tpm2_pcr_extend(chip, pcr_idx, hash);
> +		tpm_chip_put(chip);
> +		return rc;
> +	}
> +
>   	cmd.header.in = pcrextend_header;
>   	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
>   	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
> @@ -974,6 +986,12 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
>   	if (chip == NULL)
>   		return -ENODEV;
>
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> +		err = tpm2_get_random(chip, out, max);
> +		tpm_chip_put(chip);
> +		return err;
> +	}
> +
>   	do {
>   		tpm_cmd.header.in = tpm_getrandom_header;
>   		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 9d062e6..8a434d2 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -62,6 +62,57 @@ enum tpm_duration {
>   #define TPM_ERR_INVALID_POSTINIT 38
>
>   #define TPM_HEADER_SIZE		10
> +
> +enum tpm2_const {
> +	TPM2_PLATFORM_PCR	= 24,
> +	TPM2_PCR_SELECT_MIN	= ((TPM2_PLATFORM_PCR + 7) / 8),
> +	TPM2_TIMEOUT_A		= 750 * 1000,
> +	TPM2_TIMEOUT_B		= 2000 * 1000,
> +	TPM2_TIMEOUT_C		= 200 * 1000,
> +	TPM2_TIMEOUT_D		= 30 * 1000,
> +	TPM2_DURATION_SHORT	= 20 * 1000,
> +	TPM2_DURATION_MEDIUM	= 750 * 1000,
> +	TPM2_DURATION_LONG	= 2000 * 1000,
> +};
> +
> +enum tpm2_structures {
> +	TPM2_ST_NO_SESSIONS	= 0x8001,
> +	TPM2_ST_SESSIONS	= 0x8002,
> +};
> +
> +enum tpm2_return_codes {
> +	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_GET_CAPABILITY	= 0x017A,
> +	TPM2_CC_GET_RANDOM	= 0x017B,
> +	TPM2_CC_PCR_READ	= 0x017E,
> +	TPM2_CC_PCR_EXTEND	= 0x0182,
> +	TPM2_CC_LAST		= 0x018F,
> +};
> +
> +enum tpm2_permanent_handles {
> +	TPM2_RS_PW		= 0x40000009,
> +};
> +
> +enum tpm2_capabilities {
> +	TPM2_CAP_TPM_PROPERTIES = 6,
> +};
> +
> +enum tpm2_startup_types {
> +	TPM2_SU_CLEAR	= 0x0000,
> +	TPM2_SU_STATE	= 0x0001,
> +};
> +
>   struct tpm_chip;
>
>   struct tpm_vendor_specific {
> @@ -96,12 +147,17 @@ struct tpm_vendor_specific {
>
>   #define TPM_PPI_VERSION_LEN		3
>
> +enum tpm_chip_flags {
> +	TPM_CHIP_FLAG_TPM2	= BIT(0),
> +};
> +
>   struct tpm_chip {
>   	struct device *pdev;	/* Device stuff */
>   	struct device dev;
>   	struct cdev cdev;
>
>   	const struct tpm_class_ops *ops;
> +	unsigned int flags;
>
>   	int dev_num;		/* /dev/tpm# */
>   	char devname[7];
> @@ -362,3 +418,14 @@ static inline void tpm_remove_ppi(struct tpm_chip *chip)
>   {
>   }
>   #endif
> +
> +int tpm2_startup(struct tpm_chip *chip, __be16 startup_type);
> +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);
> +
> +extern ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
> +			       u32 *value, const char *desc);
> +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);
> diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
> new file mode 100644
> index 0000000..458a17d
> --- /dev/null
> +++ b/drivers/char/tpm/tpm2-cmd.c
> @@ -0,0 +1,566 @@
> +/*
> + * 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 */
> +};
> +
> +static const struct tpm_input_header tpm2_startup_header = {
> +	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
> +	.length = cpu_to_be32(12),

12 -> sizeof(struct tpm_input_header) + sizeof(struct pm2_startup_in)

> +	.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. When a negative number is
> + * returned it remarks a POSIX error code. When a positive number is returned
> + * it remarks a TPM error.

Replace 'When's with 'If's. (when being 'temporal')

> + */
> +int tpm2_startup(struct tpm_chip *chip, __be16 startup_type)
> +{
> +	struct tpm2_cmd cmd;
> +
> +	cmd.header.in = tpm2_startup_header;
> +
> +	cmd.params.startup_in.startup_type = startup_type;
> +	return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
> +				"attempting to start the TPM");
> +}
> +
> +#define TPM2_PCR_READ_IN_SIZE \
> +	(sizeof(struct tpm_input_header) + \
> +	 sizeof(struct tpm2_pcr_read_in))
> +

Ah! You could also use a #define above!

> +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. When a negative number is
> + * returned it remarks a POSIX error code. When a positive number is returned
> + * it remarks a TPM error.
> + */

Replace 'When's with 'If's. Also further below.

> +int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
> +{
> +	int rc;
> +	struct tpm2_cmd cmd;
> +	u8 *buf;
> +	int i, j;
> +
> +	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;
> +
> +	for (i = 0; i < TPM2_PCR_SELECT_MIN; i++) {
> +		j = pcr_idx - i * 8;
> +
> +		cmd.params.pcrread_in.pcr_select[i] =
> +			(j >= 0 && j < 8) ? 1 << j : 0;
> +	}

Umpf - what's this? You need to set the PCR index as an index in the 
bitfield?

pcr_idx >> 3  gives you the index into the array, assuming that [0] 
holds bits for PCR0 to 7.

1 << (pcr_idx & 0x7) gives you the bit to set, assuming bit 0 is to be 
set for PCR 0
1 << (7- (pcr_idx & 0x7)) gives you the bit to set, assuming bit 7 is to 
be set for PCR 0.

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;
> +}
> +
> +/**
> + * 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. When a negative number is
> + * returned it remarks a POSIX error code. When a positive number is returned
> + * it remarks a TPM error.
> + */
> +static const struct tpm_input_header tpm2_pcrextend_header = {
> +	.tag = cpu_to_be16(TPM2_ST_SESSIONS),
> +	.length = cpu_to_be32(sizeof(struct tpm_input_header) +
> +			      sizeof(struct tpm2_pcr_extend_in)),
> +	.ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND)
> +};
> +
> +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;
> +}
> +
> +static const struct tpm_input_header tpm2_getrandom_header = {
> +	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
> +	.length = cpu_to_be32(sizeof(struct tpm_input_header) +
> +			      sizeof(struct tpm2_get_random_in)),
> +	.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. When a negative number is
> + * returned it remarks a POSIX error code. When 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, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
num_bytes = min_t(u32, max, sizeof(tpm2_cmd.params.getrandom_out.buffer);

This way you tie it to the actual buffer size of the buffer the TPM can fill

> +	int err, total = 0, retries = 5;
> +	u8 *dest = out;
> +
> +	if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)

... || max > sizeof((tpm2_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 = be16_to_cpu(cmd.params.getrandom_out.size);
> +		memcpy(dest, cmd.params.getrandom_out.buffer, recd);

to be on the safe side, I would do

/* never accept more bytes than we asked for */
recd = min(recd, num_bytes);
memcpy(dest, cmd.params.getrandom_out.buffer, recd);

so that the destination buffer can never be overwritten beyond its 
boundaries by a TPM that just ends up sending you more bytes than you 
asked for (firmware bug).

> +
> +		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. When a negative number is
> + * returned it remarks a POSIX error code. When 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;
> +}
> +EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
> +
> +/*
> + * 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. When a negative number is
> + * returned it remarks a POSIX error code. When 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)
> +		return 2 * 60 * HZ;
> +	else
> +		return duration;
> +}
> +EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration);
> +
> +static const struct tpm_input_header tpm2_selftest_header = {
> +	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
> +	.length = cpu_to_be32(sizeof(struct tpm_input_header) +
> +			      sizeof(struct tpm2_self_test_in)),
> +	.ordinal = cpu_to_be32(TPM2_CC_SELF_TEST)
> +};
> +
> +#define TPM2_SELF_TEST_IN_SIZE \
> +	(sizeof(struct tpm_input_header) + sizeof(struct tpm2_self_test_in))
> +
> +/**
> + * 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. When a negative number is
> + * returned it remarks a POSIX error code. When 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");
> +
> +	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. When a negative number is
> + * returned it remarks a POSIX error code. When 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
> + *
> + * 0 is returned when the operation is successful. When a negative number is
> + * returned it remarks a POSIX error code. When a positive number is returned
> + * it remarks a TPM error.
> + */
> +
> +int tpm2_gen_interrupt(struct tpm_chip *chip)
> +{
> +	u32 dummy;
> +	int rc;
> +
> +	rc = tpm2_get_tpm_pt(chip,
> +			     TPM2_CAP_TPM_PROPERTIES,
> +			     &dummy,
> +			     "attempting to generate an interrupt");
> +
> +	return rc;
> +}
> +EXPORT_SYMBOL_GPL(tpm2_gen_interrupt);

      Stefan


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 07/10] tpm: TPM 2.0 baseline support
@ 2014-11-26  0:42     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-26  0:42 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Will Arthur,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> TPM 2.0 devices are separated by adding a field 'flags' to struct
> tpm_chip and defining a flag TPM_CHIP_FLAG_TPM2 for tagging them.
>
> This patch adds the following internal functions:
>
> - tpm2_get_random()
> - tpm2_get_tpm_pt()
> - tpm2_pcr_extend()
> - tpm2_pcr_read()
> - tpm2_startup()
>
> Additionally, the following exported functions are implemented for
> implementing TPM 2.0 device drivers:
>
> - tpm2_do_selftest()
> - tpm2_calc_ordinal_durations()
> - tpm2_gen_interrupt()
>
> The existing functions that are exported for the use for existing
> subsystems have been changed to check the flags field in struct
> tpm_chip and use appropriate TPM 2.0 counterpart if
> TPM_CHIP_FLAG_TPM2 is est.
>
> The code for tpm2_calc_ordinal_duration() and tpm2_startup() were
> originally written by Will Arthur.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Signed-off-by: Will Arthur <will.c.arthur-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> ---
>   drivers/char/tpm/Makefile        |   2 +-
>   drivers/char/tpm/tpm-chip.c      |  21 +-
>   drivers/char/tpm/tpm-interface.c |  24 +-
>   drivers/char/tpm/tpm.h           |  67 +++++
>   drivers/char/tpm/tpm2-cmd.c      | 566 +++++++++++++++++++++++++++++++++++++++
>   5 files changed, 668 insertions(+), 12 deletions(-)
>   create mode 100644 drivers/char/tpm/tpm2-cmd.c
>
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> index 837da04..ae56af9 100644
> --- a/drivers/char/tpm/Makefile
> +++ b/drivers/char/tpm/Makefile
> @@ -2,7 +2,7 @@
>   # Makefile for the kernel tpm device drivers.
>   #
>   obj-$(CONFIG_TCG_TPM) += tpm.o
> -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o
> +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o
>   tpm-$(CONFIG_ACPI) += tpm_ppi.o
>
>   ifdef CONFIG_ACPI
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 5d268ac..4d25b24 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -213,11 +213,14 @@ int tpm_chip_register(struct tpm_chip *chip)
>   	if (rc)
>   		return rc;
>
> -	rc = tpm_add_ppi(chip);
> -	if (rc)
> -		goto out_err;
> +	/* Populate sysfs for TPM1 devices. */
> +	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
> +		rc = tpm_add_ppi(chip);
> +		if (rc)
> +			goto out_err;
>
> -	chip->bios_dir = tpm_bios_log_setup(chip->devname);
> +		chip->bios_dir = tpm_bios_log_setup(chip->devname);
> +	}
>
>   	/* Make the chip available. */
>   	spin_lock(&driver_lock);
> @@ -248,10 +251,12 @@ void tpm_chip_unregister(struct tpm_chip *chip)
>   	spin_unlock(&driver_lock);
>   	synchronize_rcu();
>
> -	tpm_remove_ppi(chip);
> -
> -	if (chip->bios_dir)
> -		tpm_bios_log_teardown(chip->bios_dir);
> +	/* Clean up sysfs for TPM1 devices. */
> +	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
> +		if (chip->bios_dir)
> +			tpm_bios_log_teardown(chip->bios_dir);
> +		tpm_remove_ppi(chip);
> +	}
>
>   	tpm_dev_del_device(chip);
>   }
> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> index 9e4ce4d..e62b835 100644
> --- a/drivers/char/tpm/tpm-interface.c
> +++ b/drivers/char/tpm/tpm-interface.c
> @@ -360,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
>   	if (chip->vendor.irq)
>   		goto out_recv;
>
> -	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +		stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
> +	else
> +		stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
>   	do {
>   		u8 status = chip->ops->status(chip);
>   		if ((status & chip->ops->req_complete_mask) ==
> @@ -483,7 +486,7 @@ static const struct tpm_input_header tpm_startup_header = {
>   static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
>   {
>   	struct tpm_cmd_t start_cmd;
> -	start_cmd.header.in = tpm_startup_header;
> +
>   	start_cmd.params.startup_in.startup_type = startup_type;
>   	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
>   				"attempting to start the TPM");
> @@ -680,7 +683,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
>   	chip = tpm_chip_find_get(chip_num);
>   	if (chip == NULL)
>   		return -ENODEV;
> -	rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> +		rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
> +	else
> +		rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
>   	tpm_chip_put(chip);
>   	return rc;
>   }
> @@ -714,6 +720,12 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
>   	if (chip == NULL)
>   		return -ENODEV;
>
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> +		rc = tpm2_pcr_extend(chip, pcr_idx, hash);
> +		tpm_chip_put(chip);
> +		return rc;
> +	}
> +
>   	cmd.header.in = pcrextend_header;
>   	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
>   	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
> @@ -974,6 +986,12 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
>   	if (chip == NULL)
>   		return -ENODEV;
>
> +	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> +		err = tpm2_get_random(chip, out, max);
> +		tpm_chip_put(chip);
> +		return err;
> +	}
> +
>   	do {
>   		tpm_cmd.header.in = tpm_getrandom_header;
>   		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 9d062e6..8a434d2 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -62,6 +62,57 @@ enum tpm_duration {
>   #define TPM_ERR_INVALID_POSTINIT 38
>
>   #define TPM_HEADER_SIZE		10
> +
> +enum tpm2_const {
> +	TPM2_PLATFORM_PCR	= 24,
> +	TPM2_PCR_SELECT_MIN	= ((TPM2_PLATFORM_PCR + 7) / 8),
> +	TPM2_TIMEOUT_A		= 750 * 1000,
> +	TPM2_TIMEOUT_B		= 2000 * 1000,
> +	TPM2_TIMEOUT_C		= 200 * 1000,
> +	TPM2_TIMEOUT_D		= 30 * 1000,
> +	TPM2_DURATION_SHORT	= 20 * 1000,
> +	TPM2_DURATION_MEDIUM	= 750 * 1000,
> +	TPM2_DURATION_LONG	= 2000 * 1000,
> +};
> +
> +enum tpm2_structures {
> +	TPM2_ST_NO_SESSIONS	= 0x8001,
> +	TPM2_ST_SESSIONS	= 0x8002,
> +};
> +
> +enum tpm2_return_codes {
> +	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_GET_CAPABILITY	= 0x017A,
> +	TPM2_CC_GET_RANDOM	= 0x017B,
> +	TPM2_CC_PCR_READ	= 0x017E,
> +	TPM2_CC_PCR_EXTEND	= 0x0182,
> +	TPM2_CC_LAST		= 0x018F,
> +};
> +
> +enum tpm2_permanent_handles {
> +	TPM2_RS_PW		= 0x40000009,
> +};
> +
> +enum tpm2_capabilities {
> +	TPM2_CAP_TPM_PROPERTIES = 6,
> +};
> +
> +enum tpm2_startup_types {
> +	TPM2_SU_CLEAR	= 0x0000,
> +	TPM2_SU_STATE	= 0x0001,
> +};
> +
>   struct tpm_chip;
>
>   struct tpm_vendor_specific {
> @@ -96,12 +147,17 @@ struct tpm_vendor_specific {
>
>   #define TPM_PPI_VERSION_LEN		3
>
> +enum tpm_chip_flags {
> +	TPM_CHIP_FLAG_TPM2	= BIT(0),
> +};
> +
>   struct tpm_chip {
>   	struct device *pdev;	/* Device stuff */
>   	struct device dev;
>   	struct cdev cdev;
>
>   	const struct tpm_class_ops *ops;
> +	unsigned int flags;
>
>   	int dev_num;		/* /dev/tpm# */
>   	char devname[7];
> @@ -362,3 +418,14 @@ static inline void tpm_remove_ppi(struct tpm_chip *chip)
>   {
>   }
>   #endif
> +
> +int tpm2_startup(struct tpm_chip *chip, __be16 startup_type);
> +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);
> +
> +extern ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
> +			       u32 *value, const char *desc);
> +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);
> diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
> new file mode 100644
> index 0000000..458a17d
> --- /dev/null
> +++ b/drivers/char/tpm/tpm2-cmd.c
> @@ -0,0 +1,566 @@
> +/*
> + * Copyright (C) 2014 Intel Corporation
> + *
> + * Authors:
> + * Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> + *
> + * Maintained by: <tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
> + *
> + * 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 */
> +};
> +
> +static const struct tpm_input_header tpm2_startup_header = {
> +	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
> +	.length = cpu_to_be32(12),

12 -> sizeof(struct tpm_input_header) + sizeof(struct pm2_startup_in)

> +	.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. When a negative number is
> + * returned it remarks a POSIX error code. When a positive number is returned
> + * it remarks a TPM error.

Replace 'When's with 'If's. (when being 'temporal')

> + */
> +int tpm2_startup(struct tpm_chip *chip, __be16 startup_type)
> +{
> +	struct tpm2_cmd cmd;
> +
> +	cmd.header.in = tpm2_startup_header;
> +
> +	cmd.params.startup_in.startup_type = startup_type;
> +	return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
> +				"attempting to start the TPM");
> +}
> +
> +#define TPM2_PCR_READ_IN_SIZE \
> +	(sizeof(struct tpm_input_header) + \
> +	 sizeof(struct tpm2_pcr_read_in))
> +

Ah! You could also use a #define above!

> +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. When a negative number is
> + * returned it remarks a POSIX error code. When a positive number is returned
> + * it remarks a TPM error.
> + */

Replace 'When's with 'If's. Also further below.

> +int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
> +{
> +	int rc;
> +	struct tpm2_cmd cmd;
> +	u8 *buf;
> +	int i, j;
> +
> +	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;
> +
> +	for (i = 0; i < TPM2_PCR_SELECT_MIN; i++) {
> +		j = pcr_idx - i * 8;
> +
> +		cmd.params.pcrread_in.pcr_select[i] =
> +			(j >= 0 && j < 8) ? 1 << j : 0;
> +	}

Umpf - what's this? You need to set the PCR index as an index in the 
bitfield?

pcr_idx >> 3  gives you the index into the array, assuming that [0] 
holds bits for PCR0 to 7.

1 << (pcr_idx & 0x7) gives you the bit to set, assuming bit 0 is to be 
set for PCR 0
1 << (7- (pcr_idx & 0x7)) gives you the bit to set, assuming bit 7 is to 
be set for PCR 0.

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;
> +}
> +
> +/**
> + * 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. When a negative number is
> + * returned it remarks a POSIX error code. When a positive number is returned
> + * it remarks a TPM error.
> + */
> +static const struct tpm_input_header tpm2_pcrextend_header = {
> +	.tag = cpu_to_be16(TPM2_ST_SESSIONS),
> +	.length = cpu_to_be32(sizeof(struct tpm_input_header) +
> +			      sizeof(struct tpm2_pcr_extend_in)),
> +	.ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND)
> +};
> +
> +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;
> +}
> +
> +static const struct tpm_input_header tpm2_getrandom_header = {
> +	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
> +	.length = cpu_to_be32(sizeof(struct tpm_input_header) +
> +			      sizeof(struct tpm2_get_random_in)),
> +	.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. When a negative number is
> + * returned it remarks a POSIX error code. When 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, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
num_bytes = min_t(u32, max, sizeof(tpm2_cmd.params.getrandom_out.buffer);

This way you tie it to the actual buffer size of the buffer the TPM can fill

> +	int err, total = 0, retries = 5;
> +	u8 *dest = out;
> +
> +	if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)

... || max > sizeof((tpm2_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 = be16_to_cpu(cmd.params.getrandom_out.size);
> +		memcpy(dest, cmd.params.getrandom_out.buffer, recd);

to be on the safe side, I would do

/* never accept more bytes than we asked for */
recd = min(recd, num_bytes);
memcpy(dest, cmd.params.getrandom_out.buffer, recd);

so that the destination buffer can never be overwritten beyond its 
boundaries by a TPM that just ends up sending you more bytes than you 
asked for (firmware bug).

> +
> +		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. When a negative number is
> + * returned it remarks a POSIX error code. When 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;
> +}
> +EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
> +
> +/*
> + * 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. When a negative number is
> + * returned it remarks a POSIX error code. When 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)
> +		return 2 * 60 * HZ;
> +	else
> +		return duration;
> +}
> +EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration);
> +
> +static const struct tpm_input_header tpm2_selftest_header = {
> +	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
> +	.length = cpu_to_be32(sizeof(struct tpm_input_header) +
> +			      sizeof(struct tpm2_self_test_in)),
> +	.ordinal = cpu_to_be32(TPM2_CC_SELF_TEST)
> +};
> +
> +#define TPM2_SELF_TEST_IN_SIZE \
> +	(sizeof(struct tpm_input_header) + sizeof(struct tpm2_self_test_in))
> +
> +/**
> + * 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. When a negative number is
> + * returned it remarks a POSIX error code. When 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");
> +
> +	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. When a negative number is
> + * returned it remarks a POSIX error code. When 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
> + *
> + * 0 is returned when the operation is successful. When a negative number is
> + * returned it remarks a POSIX error code. When a positive number is returned
> + * it remarks a TPM error.
> + */
> +
> +int tpm2_gen_interrupt(struct tpm_chip *chip)
> +{
> +	u32 dummy;
> +	int rc;
> +
> +	rc = tpm2_get_tpm_pt(chip,
> +			     TPM2_CAP_TPM_PROPERTIES,
> +			     &dummy,
> +			     "attempting to generate an interrupt");
> +
> +	return rc;
> +}
> +EXPORT_SYMBOL_GPL(tpm2_gen_interrupt);

      Stefan

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 06/10] tpm: fix: move sysfs attributes to the correct place.
@ 2014-11-26  0:48     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-26  0:48 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard, josh.triplett, linux-api, linux-kernel,
	tpmdd-devel, jason.gunthorpe, trousers-tech

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> The sysfs attributes of the TPM device were created to the platform
> device directory that owns the character device instead of placing
> them correctly to the directory of the character device,
>
> They were also created in a racy way so that character device might
> become visible before sysfs attributes become available.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> ---
>   drivers/char/tpm/tpm-chip.c  | 15 ++++++---------
>   drivers/char/tpm/tpm-dev.c   |  2 --
>   drivers/char/tpm/tpm-sysfs.c | 23 +----------------------
>   drivers/char/tpm/tpm.h       |  4 +---
>   4 files changed, 8 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index df40eee..5d268ac 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -29,6 +29,8 @@
>   #include "tpm.h"
>   #include "tpm_eventlog.h"
>
> +ATTRIBUTE_GROUPS(tpm_dev);
> +
>   static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
>   static LIST_HEAD(tpm_chip_list);
>   static DEFINE_SPINLOCK(driver_lock);
> @@ -136,6 +138,8 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
>   	else
>   		chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
>
> +	chip->dev.groups = tpm_dev_groups;
> +
>   	dev_set_name(&chip->dev, chip->devname);
>
>   	device_initialize(&chip->dev);
> @@ -209,13 +213,9 @@ int tpm_chip_register(struct tpm_chip *chip)
>   	if (rc)
>   		return rc;
>
> -	rc = tpm_sysfs_add_device(chip);
> -	if (rc)
> -		goto del_misc;
> -
>   	rc = tpm_add_ppi(chip);
>   	if (rc)
> -		goto del_sysfs;
> +		goto out_err;
>
>   	chip->bios_dir = tpm_bios_log_setup(chip->devname);
>
> @@ -225,9 +225,7 @@ int tpm_chip_register(struct tpm_chip *chip)
>   	spin_unlock(&driver_lock);
>
>   	return 0;
> -del_sysfs:
> -	tpm_sysfs_del_device(chip);
> -del_misc:
> +out_err:
>   	tpm_dev_del_device(chip);
>   	return rc;
>   }
> @@ -250,7 +248,6 @@ void tpm_chip_unregister(struct tpm_chip *chip)
>   	spin_unlock(&driver_lock);
>   	synchronize_rcu();
>
> -	tpm_sysfs_del_device(chip);
>   	tpm_remove_ppi(chip);
>
>   	if (chip->bios_dir)
> diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
> index de0337e..f3f073f 100644
> --- a/drivers/char/tpm/tpm-dev.c
> +++ b/drivers/char/tpm/tpm-dev.c
> @@ -179,5 +179,3 @@ const struct file_operations tpm_fops = {
>   	.write = tpm_write,
>   	.release = tpm_release,
>   };
> -
> -

Unnecessary changes.
> diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
> index ee66fd4..9f5b85a 100644
> --- a/drivers/char/tpm/tpm-sysfs.c
> +++ b/drivers/char/tpm/tpm-sysfs.c
> @@ -263,7 +263,7 @@ static ssize_t timeouts_show(struct device *dev, struct device_attribute *attr,
>   }
>   static DEVICE_ATTR_RO(timeouts);
>
> -static struct attribute *tpm_dev_attrs[] = {
> +struct attribute *tpm_dev_attrs[] = {
>   	&dev_attr_pubek.attr,
>   	&dev_attr_pcrs.attr,
>   	&dev_attr_enabled.attr,
> @@ -276,24 +276,3 @@ static struct attribute *tpm_dev_attrs[] = {
>   	&dev_attr_timeouts.attr,
>   	NULL,
>   };
> -
> -static const struct attribute_group tpm_dev_group = {
> -	.attrs = tpm_dev_attrs,
> -};
> -
> -int tpm_sysfs_add_device(struct tpm_chip *chip)
> -{
> -	int err;
> -	err = sysfs_create_group(&chip->pdev->kobj,
> -				 &tpm_dev_group);
> -
> -	if (err)
> -		dev_err(chip->pdev,
> -			"failed to create sysfs attributes, %d\n", err);
> -	return err;
> -}
> -
> -void tpm_sysfs_del_device(struct tpm_chip *chip)
> -{
> -	sysfs_remove_group(&chip->pdev->kobj, &tpm_dev_group);
> -}
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 83103e0..9d062e6 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -325,6 +325,7 @@ struct tpm_cmd_t {
>   extern struct class *tpm_class;
>   extern dev_t tpm_devt;
>   extern const struct file_operations tpm_fops;
> +extern struct attribute *tpm_dev_attrs[];
>
>   ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
>   ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
> @@ -346,9 +347,6 @@ extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
>   extern int tpm_chip_register(struct tpm_chip *chip);
>   extern void tpm_chip_unregister(struct tpm_chip *chip);
>
> -int tpm_sysfs_add_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);
>
>   #ifdef CONFIG_ACPI

Other than those stray line deletions, it looks good to me.

    Stefan


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 06/10] tpm: fix: move sysfs attributes to the correct place.
@ 2014-11-26  0:48     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-26  0:48 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> The sysfs attributes of the TPM device were created to the platform
> device directory that owns the character device instead of placing
> them correctly to the directory of the character device,
>
> They were also created in a racy way so that character device might
> become visible before sysfs attributes become available.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> ---
>   drivers/char/tpm/tpm-chip.c  | 15 ++++++---------
>   drivers/char/tpm/tpm-dev.c   |  2 --
>   drivers/char/tpm/tpm-sysfs.c | 23 +----------------------
>   drivers/char/tpm/tpm.h       |  4 +---
>   4 files changed, 8 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index df40eee..5d268ac 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -29,6 +29,8 @@
>   #include "tpm.h"
>   #include "tpm_eventlog.h"
>
> +ATTRIBUTE_GROUPS(tpm_dev);
> +
>   static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
>   static LIST_HEAD(tpm_chip_list);
>   static DEFINE_SPINLOCK(driver_lock);
> @@ -136,6 +138,8 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
>   	else
>   		chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
>
> +	chip->dev.groups = tpm_dev_groups;
> +
>   	dev_set_name(&chip->dev, chip->devname);
>
>   	device_initialize(&chip->dev);
> @@ -209,13 +213,9 @@ int tpm_chip_register(struct tpm_chip *chip)
>   	if (rc)
>   		return rc;
>
> -	rc = tpm_sysfs_add_device(chip);
> -	if (rc)
> -		goto del_misc;
> -
>   	rc = tpm_add_ppi(chip);
>   	if (rc)
> -		goto del_sysfs;
> +		goto out_err;
>
>   	chip->bios_dir = tpm_bios_log_setup(chip->devname);
>
> @@ -225,9 +225,7 @@ int tpm_chip_register(struct tpm_chip *chip)
>   	spin_unlock(&driver_lock);
>
>   	return 0;
> -del_sysfs:
> -	tpm_sysfs_del_device(chip);
> -del_misc:
> +out_err:
>   	tpm_dev_del_device(chip);
>   	return rc;
>   }
> @@ -250,7 +248,6 @@ void tpm_chip_unregister(struct tpm_chip *chip)
>   	spin_unlock(&driver_lock);
>   	synchronize_rcu();
>
> -	tpm_sysfs_del_device(chip);
>   	tpm_remove_ppi(chip);
>
>   	if (chip->bios_dir)
> diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
> index de0337e..f3f073f 100644
> --- a/drivers/char/tpm/tpm-dev.c
> +++ b/drivers/char/tpm/tpm-dev.c
> @@ -179,5 +179,3 @@ const struct file_operations tpm_fops = {
>   	.write = tpm_write,
>   	.release = tpm_release,
>   };
> -
> -

Unnecessary changes.
> diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
> index ee66fd4..9f5b85a 100644
> --- a/drivers/char/tpm/tpm-sysfs.c
> +++ b/drivers/char/tpm/tpm-sysfs.c
> @@ -263,7 +263,7 @@ static ssize_t timeouts_show(struct device *dev, struct device_attribute *attr,
>   }
>   static DEVICE_ATTR_RO(timeouts);
>
> -static struct attribute *tpm_dev_attrs[] = {
> +struct attribute *tpm_dev_attrs[] = {
>   	&dev_attr_pubek.attr,
>   	&dev_attr_pcrs.attr,
>   	&dev_attr_enabled.attr,
> @@ -276,24 +276,3 @@ static struct attribute *tpm_dev_attrs[] = {
>   	&dev_attr_timeouts.attr,
>   	NULL,
>   };
> -
> -static const struct attribute_group tpm_dev_group = {
> -	.attrs = tpm_dev_attrs,
> -};
> -
> -int tpm_sysfs_add_device(struct tpm_chip *chip)
> -{
> -	int err;
> -	err = sysfs_create_group(&chip->pdev->kobj,
> -				 &tpm_dev_group);
> -
> -	if (err)
> -		dev_err(chip->pdev,
> -			"failed to create sysfs attributes, %d\n", err);
> -	return err;
> -}
> -
> -void tpm_sysfs_del_device(struct tpm_chip *chip)
> -{
> -	sysfs_remove_group(&chip->pdev->kobj, &tpm_dev_group);
> -}
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 83103e0..9d062e6 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -325,6 +325,7 @@ struct tpm_cmd_t {
>   extern struct class *tpm_class;
>   extern dev_t tpm_devt;
>   extern const struct file_operations tpm_fops;
> +extern struct attribute *tpm_dev_attrs[];
>
>   ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
>   ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
> @@ -346,9 +347,6 @@ extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
>   extern int tpm_chip_register(struct tpm_chip *chip);
>   extern void tpm_chip_unregister(struct tpm_chip *chip);
>
> -int tpm_sysfs_add_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);
>
>   #ifdef CONFIG_ACPI

Other than those stray line deletions, it looks good to me.

    Stefan

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 05/10] tpm: device class for tpm
@ 2014-11-26 12:34     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-26 12:34 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard, josh.triplett, linux-api, linux-kernel,
	tpmdd-devel, jason.gunthorpe, trousers-tech

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> Added own device class for TPM. Uses MISC_MAJOR:TPM_MINOR for the
> first character device in order to retain backwards compatability.
> Added tpm_dev_release() back attached to the character device.
> devm now only calls put_device when the platform device is removed.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> ---
>   drivers/char/tpm/tpm-chip.c        | 81 ++++++++++++++++++++++++++++++++++----
>   drivers/char/tpm/tpm-dev.c         | 36 ++---------------
>   drivers/char/tpm/tpm-interface.c   | 29 ++++++++++++++
>   drivers/char/tpm/tpm.h             | 12 ++++--
>   drivers/char/tpm/tpm_i2c_nuvoton.c |  2 +-
>   drivers/char/tpm/tpm_tis.c         |  4 +-
>   6 files changed, 116 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 96ea8eb..df40eee 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -25,6 +25,7 @@
>   #include <linux/mutex.h>
>   #include <linux/spinlock.h>
>   #include <linux/freezer.h>
> +#include <linux/major.h>
>   #include "tpm.h"
>   #include "tpm_eventlog.h"
>
> @@ -32,6 +33,9 @@ static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
>   static LIST_HEAD(tpm_chip_list);
>   static DEFINE_SPINLOCK(driver_lock);
>
> +struct class *tpm_class;
> +dev_t tpm_devt;
> +
>   /*
>    * tpm_chip_find_get - return tpm_chip for a given chip number
>    * @chip_num the device number for the chip
> @@ -55,16 +59,24 @@ struct tpm_chip *tpm_chip_find_get(int chip_num)
>   }
>
>   /**
> - * tpmm_chip_remove() - free chip memory and device number
> - * @data: points to struct tpm_chip instance
> + * tpmm_put_device() - wrap put_device() for devm
> + * @data: points to the device
> + */
> +static void tpmm_put_device(void *data)
> +{
> +	struct device *dev = (struct device *) data;
> +	put_device(dev);
> +}
> +
> +/**
> + * tpm_dev_release() - free chip memory and the device number
> + * @dev: the character device for the TPM chip
>    *
> - * This is used internally by tpmm_chip_alloc() and called by devres
> - * when the device is released. This function does the opposite of
> - * tpmm_chip_alloc() freeing memory and the device number.
> + * This is used as the release function for the character device.
>    */
> -static void tpmm_chip_remove(void *data)
> +static void tpm_dev_release(struct device *dev)
>   {
> -	struct tpm_chip *chip = (struct tpm_chip *) data;
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
>
>   	spin_lock(&driver_lock);
>   	clear_bit(chip->dev_num, dev_mask);
> @@ -112,13 +124,66 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
>   		  chip->dev_num);
>
>   	chip->pdev = dev;
> -	devm_add_action(dev, tpmm_chip_remove, chip);
> +
>   	dev_set_drvdata(dev, chip);
>
> +	chip->dev.class = tpm_class;
> +	chip->dev.release = tpm_dev_release;
> +	chip->dev.parent = chip->pdev;
> +
> +	if (chip->dev_num == 0)
> +		chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
> +	else
> +		chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
> +
> +	dev_set_name(&chip->dev, chip->devname);
> +
> +	device_initialize(&chip->dev);
> +
> +	chip->cdev.owner = chip->pdev->driver->owner;
> +	cdev_init(&chip->cdev, &tpm_fops);
> +
> +	devm_add_action(dev, tpmm_put_device, chip);
>   	return chip;
>   }
>   EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
>
> +static int tpm_dev_add_device(struct tpm_chip *chip)
> +{
> +	int rc;
> +
> +	rc = device_add(&chip->dev);
> +	if (rc) {
> +		dev_err(&chip->dev,
> +			"unable to device_register %s, major %d, minor %d " \
> +			"err=%d\n",
> +			chip->devname, MAJOR(chip->dev.devt),
> +			MINOR(chip->dev.devt), rc);
> +
> +		return rc;
> +	}
> +
> +	rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
> +	if (rc) {
> +		dev_err(&chip->dev,
> +			"unable to cdev_add %s, major %d, minor %d " \
> +			"err=%d\n",
> +			chip->devname, MAJOR(chip->dev.devt),
> +			MINOR(chip->dev.devt), rc);
> +
> +		device_unregister(&chip->dev);
> +		return rc;
> +	}
> +
> +	return rc;
> +}
> +
> +static void tpm_dev_del_device(struct tpm_chip *chip)
> +{
> +	cdev_del(&chip->cdev);
> +	device_unregister(&chip->dev);
> +}
> +
>   /*
>    * tpm_chip_register() - create a misc driver for the TPM chip
>    * @chip: TPM chip to use.
> diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
> index 3568321..de0337e 100644
> --- a/drivers/char/tpm/tpm-dev.c
> +++ b/drivers/char/tpm/tpm-dev.c
> @@ -17,7 +17,6 @@
>    * License.
>    *
>    */
> -#include <linux/miscdevice.h>
>   #include <linux/slab.h>
>   #include <linux/uaccess.h>
>   #include "tpm.h"
> @@ -54,9 +53,8 @@ static void timeout_work(struct work_struct *work)
>
>   static int tpm_open(struct inode *inode, struct file *file)
>   {
> -	struct miscdevice *misc = file->private_data;
> -	struct tpm_chip *chip = container_of(misc, struct tpm_chip,
> -					     vendor.miscdev);
> +	struct tpm_chip *chip =
> +		container_of(inode->i_cdev, struct tpm_chip, cdev);
>   	struct file_priv *priv;
>
>   	/* It's assured that the chip will be opened just once,
> @@ -173,7 +171,7 @@ static int tpm_release(struct inode *inode, struct file *file)
>   	return 0;
>   }
>
> -static const struct file_operations tpm_fops = {
> +const struct file_operations tpm_fops = {
>   	.owner = THIS_MODULE,
>   	.llseek = no_llseek,
>   	.open = tpm_open,
> @@ -182,32 +180,4 @@ static const struct file_operations tpm_fops = {
>   	.release = tpm_release,
>   };
>
> -int tpm_dev_add_device(struct tpm_chip *chip)
> -{
> -	int rc;
>
> -	chip->vendor.miscdev.fops = &tpm_fops;
> -	if (chip->dev_num == 0)
> -		chip->vendor.miscdev.minor = TPM_MINOR;
> -	else
> -		chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR;
> -
> -	chip->vendor.miscdev.name = chip->devname;
> -	chip->vendor.miscdev.parent = chip->pdev;
> -
> -	rc = misc_register(&chip->vendor.miscdev);
> -	if (rc) {
> -		chip->vendor.miscdev.name = NULL;
> -		dev_err(chip->pdev,
> -			"unable to misc_register %s, minor %d err=%d\n",
> -			chip->vendor.miscdev.name,
> -			chip->vendor.miscdev.minor, rc);
> -	}
> -	return rc;
> -}
> -
> -void tpm_dev_del_device(struct tpm_chip *chip)
> -{
> -	if (chip->vendor.miscdev.name)
> -		misc_deregister(&chip->vendor.miscdev);
> -}
> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> index e6b08bd..9e4ce4d 100644
> --- a/drivers/char/tpm/tpm-interface.c
> +++ b/drivers/char/tpm/tpm-interface.c
> @@ -997,6 +997,35 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
>   }
>   EXPORT_SYMBOL_GPL(tpm_get_random);
>
> +static int __init tpm_init(void)
> +{
> +	int rc;
> +
> +	tpm_class = class_create(THIS_MODULE, "tpm");
> +	if (IS_ERR(tpm_class)) {
> +		pr_err("couldn't create tpm class\n");
> +		return PTR_ERR(tpm_class);
> +	}
> +
> +	rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm");
> +	if (rc < 0) {
> +		pr_err("tpm: failed to allocate char dev region\n");
> +		class_destroy(tpm_class);
> +		return rc;
> +	}
> +
> +	return 0;
> +}
> +
> +static void __exit tpm_exit(void)
> +{
> +	class_destroy(tpm_class);
> +	unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES);
> +}
> +
> +subsys_initcall(tpm_init);
> +module_exit(tpm_exit);
> +
>   MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
>   MODULE_DESCRIPTION("TPM Driver");
>   MODULE_VERSION("2.0");
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index b3a7c76..83103e0 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -23,11 +23,11 @@
>   #include <linux/fs.h>
>   #include <linux/mutex.h>
>   #include <linux/sched.h>
> -#include <linux/miscdevice.h>
>   #include <linux/platform_device.h>
>   #include <linux/io.h>
>   #include <linux/tpm.h>
>   #include <linux/acpi.h>
> +#include <linux/cdev.h>
>
>   enum tpm_const {
>   	TPM_MINOR = 224,	/* officially assigned */
> @@ -74,7 +74,6 @@ struct tpm_vendor_specific {
>   	int region_size;
>   	int have_region;
>
> -	struct miscdevice miscdev;
>   	struct list_head list;
>   	int locality;
>   	unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
> @@ -99,6 +98,9 @@ struct tpm_vendor_specific {
>
>   struct tpm_chip {
>   	struct device *pdev;	/* Device stuff */
> +	struct device dev;
> +	struct cdev cdev;
> +
>   	const struct tpm_class_ops *ops;
>
>   	int dev_num;		/* /dev/tpm# */
> @@ -320,6 +322,10 @@ struct tpm_cmd_t {
>   	tpm_cmd_params	params;
>   } __packed;
>
> +extern struct class *tpm_class;
> +extern dev_t tpm_devt;
> +extern const struct file_operations tpm_fops;
> +
>   ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
>   ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
>   		     size_t bufsiz);
> @@ -340,8 +346,6 @@ extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
>   extern int tpm_chip_register(struct tpm_chip *chip);
>   extern void tpm_chip_unregister(struct tpm_chip *chip);
>
> -int tpm_dev_add_device(struct tpm_chip *chip);
> -void tpm_dev_del_device(struct tpm_chip *chip);
>   int tpm_sysfs_add_device(struct tpm_chip *chip);
>   void tpm_sysfs_del_device(struct tpm_chip *chip);
>
> diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c
> index 92ee9fa..14246e2 100644
> --- a/drivers/char/tpm/tpm_i2c_nuvoton.c
> +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c
> @@ -557,7 +557,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
>   		rc = devm_request_irq(dev, chip->vendor.irq,
>   				      i2c_nuvoton_int_handler,
>   				      IRQF_TRIGGER_LOW,
> -				      chip->vendor.miscdev.name,
> +				      chip->devname,
>   				      chip);
>   		if (rc) {
>   			dev_err(dev, "%s() Unable to request irq: %d for use\n",
> diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
> index 660d9af..7a2c59b 100644
> --- a/drivers/char/tpm/tpm_tis.c
> +++ b/drivers/char/tpm/tpm_tis.c
> @@ -661,7 +661,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   				 TPM_INT_VECTOR(chip->vendor.locality));
>   			if (devm_request_irq
>   			    (dev, i, tis_int_probe, IRQF_SHARED,
> -			     chip->vendor.miscdev.name, chip) != 0) {
> +			     chip->devname, chip) != 0) {
>   				dev_info(chip->pdev,
>   					 "Unable to request irq: %d for probe\n",
>   					 i);
> @@ -708,7 +708,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   			 TPM_INT_VECTOR(chip->vendor.locality));
>   		if (devm_request_irq
>   		    (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
> -		     chip->vendor.miscdev.name, chip) != 0) {
> +		     chip->devname, chip) != 0) {
>   			dev_info(chip->pdev,
>   				 "Unable to request irq: %d for use\n",
>   				 chip->vendor.irq);

This looks ok to me.

Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 05/10] tpm: device class for tpm
@ 2014-11-26 12:34     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-26 12:34 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> Added own device class for TPM. Uses MISC_MAJOR:TPM_MINOR for the
> first character device in order to retain backwards compatability.
> Added tpm_dev_release() back attached to the character device.
> devm now only calls put_device when the platform device is removed.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> ---
>   drivers/char/tpm/tpm-chip.c        | 81 ++++++++++++++++++++++++++++++++++----
>   drivers/char/tpm/tpm-dev.c         | 36 ++---------------
>   drivers/char/tpm/tpm-interface.c   | 29 ++++++++++++++
>   drivers/char/tpm/tpm.h             | 12 ++++--
>   drivers/char/tpm/tpm_i2c_nuvoton.c |  2 +-
>   drivers/char/tpm/tpm_tis.c         |  4 +-
>   6 files changed, 116 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 96ea8eb..df40eee 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -25,6 +25,7 @@
>   #include <linux/mutex.h>
>   #include <linux/spinlock.h>
>   #include <linux/freezer.h>
> +#include <linux/major.h>
>   #include "tpm.h"
>   #include "tpm_eventlog.h"
>
> @@ -32,6 +33,9 @@ static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
>   static LIST_HEAD(tpm_chip_list);
>   static DEFINE_SPINLOCK(driver_lock);
>
> +struct class *tpm_class;
> +dev_t tpm_devt;
> +
>   /*
>    * tpm_chip_find_get - return tpm_chip for a given chip number
>    * @chip_num the device number for the chip
> @@ -55,16 +59,24 @@ struct tpm_chip *tpm_chip_find_get(int chip_num)
>   }
>
>   /**
> - * tpmm_chip_remove() - free chip memory and device number
> - * @data: points to struct tpm_chip instance
> + * tpmm_put_device() - wrap put_device() for devm
> + * @data: points to the device
> + */
> +static void tpmm_put_device(void *data)
> +{
> +	struct device *dev = (struct device *) data;
> +	put_device(dev);
> +}
> +
> +/**
> + * tpm_dev_release() - free chip memory and the device number
> + * @dev: the character device for the TPM chip
>    *
> - * This is used internally by tpmm_chip_alloc() and called by devres
> - * when the device is released. This function does the opposite of
> - * tpmm_chip_alloc() freeing memory and the device number.
> + * This is used as the release function for the character device.
>    */
> -static void tpmm_chip_remove(void *data)
> +static void tpm_dev_release(struct device *dev)
>   {
> -	struct tpm_chip *chip = (struct tpm_chip *) data;
> +	struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
>
>   	spin_lock(&driver_lock);
>   	clear_bit(chip->dev_num, dev_mask);
> @@ -112,13 +124,66 @@ struct tpm_chip *tpmm_chip_alloc(struct device *dev,
>   		  chip->dev_num);
>
>   	chip->pdev = dev;
> -	devm_add_action(dev, tpmm_chip_remove, chip);
> +
>   	dev_set_drvdata(dev, chip);
>
> +	chip->dev.class = tpm_class;
> +	chip->dev.release = tpm_dev_release;
> +	chip->dev.parent = chip->pdev;
> +
> +	if (chip->dev_num == 0)
> +		chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
> +	else
> +		chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
> +
> +	dev_set_name(&chip->dev, chip->devname);
> +
> +	device_initialize(&chip->dev);
> +
> +	chip->cdev.owner = chip->pdev->driver->owner;
> +	cdev_init(&chip->cdev, &tpm_fops);
> +
> +	devm_add_action(dev, tpmm_put_device, chip);
>   	return chip;
>   }
>   EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
>
> +static int tpm_dev_add_device(struct tpm_chip *chip)
> +{
> +	int rc;
> +
> +	rc = device_add(&chip->dev);
> +	if (rc) {
> +		dev_err(&chip->dev,
> +			"unable to device_register %s, major %d, minor %d " \
> +			"err=%d\n",
> +			chip->devname, MAJOR(chip->dev.devt),
> +			MINOR(chip->dev.devt), rc);
> +
> +		return rc;
> +	}
> +
> +	rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
> +	if (rc) {
> +		dev_err(&chip->dev,
> +			"unable to cdev_add %s, major %d, minor %d " \
> +			"err=%d\n",
> +			chip->devname, MAJOR(chip->dev.devt),
> +			MINOR(chip->dev.devt), rc);
> +
> +		device_unregister(&chip->dev);
> +		return rc;
> +	}
> +
> +	return rc;
> +}
> +
> +static void tpm_dev_del_device(struct tpm_chip *chip)
> +{
> +	cdev_del(&chip->cdev);
> +	device_unregister(&chip->dev);
> +}
> +
>   /*
>    * tpm_chip_register() - create a misc driver for the TPM chip
>    * @chip: TPM chip to use.
> diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
> index 3568321..de0337e 100644
> --- a/drivers/char/tpm/tpm-dev.c
> +++ b/drivers/char/tpm/tpm-dev.c
> @@ -17,7 +17,6 @@
>    * License.
>    *
>    */
> -#include <linux/miscdevice.h>
>   #include <linux/slab.h>
>   #include <linux/uaccess.h>
>   #include "tpm.h"
> @@ -54,9 +53,8 @@ static void timeout_work(struct work_struct *work)
>
>   static int tpm_open(struct inode *inode, struct file *file)
>   {
> -	struct miscdevice *misc = file->private_data;
> -	struct tpm_chip *chip = container_of(misc, struct tpm_chip,
> -					     vendor.miscdev);
> +	struct tpm_chip *chip =
> +		container_of(inode->i_cdev, struct tpm_chip, cdev);
>   	struct file_priv *priv;
>
>   	/* It's assured that the chip will be opened just once,
> @@ -173,7 +171,7 @@ static int tpm_release(struct inode *inode, struct file *file)
>   	return 0;
>   }
>
> -static const struct file_operations tpm_fops = {
> +const struct file_operations tpm_fops = {
>   	.owner = THIS_MODULE,
>   	.llseek = no_llseek,
>   	.open = tpm_open,
> @@ -182,32 +180,4 @@ static const struct file_operations tpm_fops = {
>   	.release = tpm_release,
>   };
>
> -int tpm_dev_add_device(struct tpm_chip *chip)
> -{
> -	int rc;
>
> -	chip->vendor.miscdev.fops = &tpm_fops;
> -	if (chip->dev_num == 0)
> -		chip->vendor.miscdev.minor = TPM_MINOR;
> -	else
> -		chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR;
> -
> -	chip->vendor.miscdev.name = chip->devname;
> -	chip->vendor.miscdev.parent = chip->pdev;
> -
> -	rc = misc_register(&chip->vendor.miscdev);
> -	if (rc) {
> -		chip->vendor.miscdev.name = NULL;
> -		dev_err(chip->pdev,
> -			"unable to misc_register %s, minor %d err=%d\n",
> -			chip->vendor.miscdev.name,
> -			chip->vendor.miscdev.minor, rc);
> -	}
> -	return rc;
> -}
> -
> -void tpm_dev_del_device(struct tpm_chip *chip)
> -{
> -	if (chip->vendor.miscdev.name)
> -		misc_deregister(&chip->vendor.miscdev);
> -}
> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> index e6b08bd..9e4ce4d 100644
> --- a/drivers/char/tpm/tpm-interface.c
> +++ b/drivers/char/tpm/tpm-interface.c
> @@ -997,6 +997,35 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
>   }
>   EXPORT_SYMBOL_GPL(tpm_get_random);
>
> +static int __init tpm_init(void)
> +{
> +	int rc;
> +
> +	tpm_class = class_create(THIS_MODULE, "tpm");
> +	if (IS_ERR(tpm_class)) {
> +		pr_err("couldn't create tpm class\n");
> +		return PTR_ERR(tpm_class);
> +	}
> +
> +	rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm");
> +	if (rc < 0) {
> +		pr_err("tpm: failed to allocate char dev region\n");
> +		class_destroy(tpm_class);
> +		return rc;
> +	}
> +
> +	return 0;
> +}
> +
> +static void __exit tpm_exit(void)
> +{
> +	class_destroy(tpm_class);
> +	unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES);
> +}
> +
> +subsys_initcall(tpm_init);
> +module_exit(tpm_exit);
> +
>   MODULE_AUTHOR("Leendert van Doorn (leendert-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org)");
>   MODULE_DESCRIPTION("TPM Driver");
>   MODULE_VERSION("2.0");
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index b3a7c76..83103e0 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -23,11 +23,11 @@
>   #include <linux/fs.h>
>   #include <linux/mutex.h>
>   #include <linux/sched.h>
> -#include <linux/miscdevice.h>
>   #include <linux/platform_device.h>
>   #include <linux/io.h>
>   #include <linux/tpm.h>
>   #include <linux/acpi.h>
> +#include <linux/cdev.h>
>
>   enum tpm_const {
>   	TPM_MINOR = 224,	/* officially assigned */
> @@ -74,7 +74,6 @@ struct tpm_vendor_specific {
>   	int region_size;
>   	int have_region;
>
> -	struct miscdevice miscdev;
>   	struct list_head list;
>   	int locality;
>   	unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
> @@ -99,6 +98,9 @@ struct tpm_vendor_specific {
>
>   struct tpm_chip {
>   	struct device *pdev;	/* Device stuff */
> +	struct device dev;
> +	struct cdev cdev;
> +
>   	const struct tpm_class_ops *ops;
>
>   	int dev_num;		/* /dev/tpm# */
> @@ -320,6 +322,10 @@ struct tpm_cmd_t {
>   	tpm_cmd_params	params;
>   } __packed;
>
> +extern struct class *tpm_class;
> +extern dev_t tpm_devt;
> +extern const struct file_operations tpm_fops;
> +
>   ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
>   ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
>   		     size_t bufsiz);
> @@ -340,8 +346,6 @@ extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
>   extern int tpm_chip_register(struct tpm_chip *chip);
>   extern void tpm_chip_unregister(struct tpm_chip *chip);
>
> -int tpm_dev_add_device(struct tpm_chip *chip);
> -void tpm_dev_del_device(struct tpm_chip *chip);
>   int tpm_sysfs_add_device(struct tpm_chip *chip);
>   void tpm_sysfs_del_device(struct tpm_chip *chip);
>
> diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c
> index 92ee9fa..14246e2 100644
> --- a/drivers/char/tpm/tpm_i2c_nuvoton.c
> +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c
> @@ -557,7 +557,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
>   		rc = devm_request_irq(dev, chip->vendor.irq,
>   				      i2c_nuvoton_int_handler,
>   				      IRQF_TRIGGER_LOW,
> -				      chip->vendor.miscdev.name,
> +				      chip->devname,
>   				      chip);
>   		if (rc) {
>   			dev_err(dev, "%s() Unable to request irq: %d for use\n",
> diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
> index 660d9af..7a2c59b 100644
> --- a/drivers/char/tpm/tpm_tis.c
> +++ b/drivers/char/tpm/tpm_tis.c
> @@ -661,7 +661,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   				 TPM_INT_VECTOR(chip->vendor.locality));
>   			if (devm_request_irq
>   			    (dev, i, tis_int_probe, IRQF_SHARED,
> -			     chip->vendor.miscdev.name, chip) != 0) {
> +			     chip->devname, chip) != 0) {
>   				dev_info(chip->pdev,
>   					 "Unable to request irq: %d for probe\n",
>   					 i);
> @@ -708,7 +708,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   			 TPM_INT_VECTOR(chip->vendor.locality));
>   		if (devm_request_irq
>   		    (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
> -		     chip->vendor.miscdev.name, chip) != 0) {
> +		     chip->devname, chip) != 0) {
>   			dev_info(chip->pdev,
>   				 "Unable to request irq: %d for use\n",
>   				 chip->vendor.irq);

This looks ok to me.

Reviewed-by: Stefan Berger <stefanb-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 08/10] tpm: TPM 2.0 CRB Interface
@ 2014-11-26 14:06     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-26 14:06 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard, josh.triplett, linux-api, linux-kernel,
	tpmdd-devel, jason.gunthorpe, trousers-tech

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> tpm_crb is a driver for TPM 2.0 Command Response Buffer (CRB) Interface
> as defined in PC Client Platform TPM Profile (PTP) Specification.
>
> Only polling and single locality is supported as these are the limitations
> of the available hardware, Platform Trust Techonlogy (PTT) in Haswell
> CPUs.
>
> The driver always applies CRB with ACPI start because PTT reports using
> only ACPI start as start method but as a result of my testing it requires
> also CRB start.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> ---
>   drivers/char/tpm/Kconfig   |   9 ++
>   drivers/char/tpm/Makefile  |   1 +
>   drivers/char/tpm/tpm_crb.c | 323 +++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 333 insertions(+)
>   create mode 100644 drivers/char/tpm/tpm_crb.c
>
> diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
> index c54cac3..10c9419 100644
> --- a/drivers/char/tpm/Kconfig
> +++ b/drivers/char/tpm/Kconfig
> @@ -122,4 +122,13 @@ config TCG_XEN
>   	  To compile this driver as a module, choose M here; the module
>   	  will be called xen-tpmfront.
>
> +config TCG_CRB
> +	tristate "TPM 2.0 CRB Interface"
> +	depends on X86 && ACPI
> +	---help---
> +	  If you have a TPM security chip that is compliant with the
> +	  TCG CRB 2.0 TPM specification say Yes and it will be accessible
> +	  from within Linux.  To compile this driver as a module, choose
> +	  M here; the module will be called tpm_crb.
> +
>   endif # TCG_TPM
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> index ae56af9..e6d26dd 100644
> --- a/drivers/char/tpm/Makefile
> +++ b/drivers/char/tpm/Makefile
> @@ -22,3 +22,4 @@ obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
>   obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
>   obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o
>   obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
> +obj-$(CONFIG_TCG_CRB) += tpm_crb.o
> diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
> new file mode 100644
> index 0000000..eb221d5
> --- /dev/null
> +++ b/drivers/char/tpm/tpm_crb.c
> @@ -0,0 +1,323 @@
> +/*
> + * 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;
> +};
> +
> +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),
> +};
> +
> +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 *cca;
> +	unsigned long cca_pa;
> +};
> +
> +#ifdef CONFIG_PM_SLEEP
> +int crb_suspend(struct device *dev)
> +{
> +	return 0;
> +}
> +
> +static int crb_resume(struct device *dev)
> +{
> +	struct tpm_chip *chip = dev_get_drvdata(dev);
> +
> +	(void) tpm2_do_selftest(chip);
> +
> +	return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(crb_pm, crb_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(priv->cca->start) & 1) != 1)

Use a #define rather than the magic '1'.


> +		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;
> +	struct crb_control_area *cca;
> +	unsigned int expected;
> +	unsigned long offset;
> +	u8 *resp;
> +
> +	cca = priv->cca;
> +	if (le32_to_cpu(cca->sts) & CRB_CA_STS_ERROR)
> +		return -EIO;
> +
> +	offset = le64_to_cpu(cca->rsp_pa) - priv->cca_pa;
> +	resp = (u8 *) ((unsigned long) cca + offset);

make sure that count >= 6?

> +	memcpy(buf, resp, 6);
> +	expected = be32_to_cpup((__be32 *) &buf[2]);
> +
> +	if (expected > count)
> +		return -EIO;
> +
> +	memcpy(&buf[6], &resp[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;
> +	struct crb_control_area *cca;
> +	u8 *cmd;
> +	int rc = 0;
> +
> +	cca = priv->cca;
> +
> +	if (len > le32_to_cpu(cca->cmd_size)) {
> +		dev_err(&chip->dev,
> +			"invalid command count value %x %zx\n",
> +			(unsigned int) len,
> +			(size_t) le32_to_cpu(cca->cmd_size));
> +		return -E2BIG;
> +	}
> +
> +	cmd = (u8 *) ((unsigned long) cca + le64_to_cpu(cca->cmd_pa) -
> +		      priv->cca_pa);

cca = priv->cca per statement above     -> cmd = cca + x - cca = x

-> cmd = le64_to_cpu(cca->cmd_pa);

Should do the trick, no ?

> +	memcpy(cmd, buf, len);
> +
> +	/* Make sure that cmd is populated before issuing start. */
> +	wmb();
> +
> +	cca->start = cpu_to_le32(1);
> +	rc = crb_do_acpi_start(chip);

I had commented on this already. Your TPM seems to no implement the ACPI 
specs properly, or rather the ACPI table is wrong.
You have to check whether the ACPI function needs to be called. The next 
TPM from a different vendor for whom the ACPI start function is not 
necessary will need this check here since it will give a return code 
indicating failure. Then your TPM won't work anymore! I think you should 
add a check into the crb_do_acpi_start for whether this function needs 
to be called or whether your TPM is being used (vendor check?) and run 
this start function then anyway.


> +	return rc;
> +}
> +
> +static void crb_cancel(struct tpm_chip *chip)
> +{
> +	struct crb_priv *priv = chip->vendor.priv;
> +	struct crb_control_area *cca;
> +
> +	cca = priv->cca;
> +	cca->cancel = cpu_to_le32(1);

nit: #define for this ?

> +
> +	/* Make sure that cmd is populated before issuing start. */
> +	wmb();
> +
> +	if (crb_do_acpi_start(chip))
> +		dev_err(&chip->dev, "ACPI Start failed\n");
> +
> +	cca->cancel = 0;
> +}
> +
> +static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
> +{
> +	struct crb_priv *priv = chip->vendor.priv;
> +
> +	return (le32_to_cpu(priv->cca->cancel) & 1) == 1;
> +}
> +
> +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;
> +	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;
> +	}
> +
> +	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);

I wonder whether you should check whether that ACPI table is big enough 
to allow you accessing its start_method.

if (buf->length < sizeof(struct acpi_tpm2) ) {
     return -EXYZ;
}

> +
> +	if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START)
> +		priv->flags |= CRB_FL_CRB_START;

You set this flag but you don't seem to check it anywhere.

> +
> +	if (sm == CRB_SM_ACPI_START || sm == CRB_SM_CRB_WITH_ACPI_START)
> +		priv->flags |= CRB_FL_ACPI_START;


You set this flag but you don't seem to check it anywhere.


> +
> +	priv->cca_pa = le32_to_cpu(buf->control_area_pa);
> +	priv->cca = (struct crb_control_area *)
> +		devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000);
> +	if (!priv->cca) {
> +		dev_err(dev, "allocating memory failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	chip->vendor.priv = priv;
> +
> +	/* Default timeouts and durations */
> +	chip->vendor.timeout_a = usecs_to_jiffies(TPM2_TIMEOUT_A);
> +	chip->vendor.timeout_b = usecs_to_jiffies(TPM2_TIMEOUT_B);
> +	chip->vendor.timeout_c = usecs_to_jiffies(TPM2_TIMEOUT_C);
> +	chip->vendor.timeout_d = usecs_to_jiffies(TPM2_TIMEOUT_D);
> +	chip->vendor.duration[TPM_SHORT] =
> +		usecs_to_jiffies(TPM2_DURATION_SHORT);
> +	chip->vendor.duration[TPM_MEDIUM] =
> +		usecs_to_jiffies(TPM2_DURATION_MEDIUM);
> +	chip->vendor.duration[TPM_LONG] =
> +		usecs_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);
> +}
> +
> +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");

Regards,
     Stefan


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 08/10] tpm: TPM 2.0 CRB Interface
@ 2014-11-26 14:06     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-26 14:06 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> tpm_crb is a driver for TPM 2.0 Command Response Buffer (CRB) Interface
> as defined in PC Client Platform TPM Profile (PTP) Specification.
>
> Only polling and single locality is supported as these are the limitations
> of the available hardware, Platform Trust Techonlogy (PTT) in Haswell
> CPUs.
>
> The driver always applies CRB with ACPI start because PTT reports using
> only ACPI start as start method but as a result of my testing it requires
> also CRB start.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> ---
>   drivers/char/tpm/Kconfig   |   9 ++
>   drivers/char/tpm/Makefile  |   1 +
>   drivers/char/tpm/tpm_crb.c | 323 +++++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 333 insertions(+)
>   create mode 100644 drivers/char/tpm/tpm_crb.c
>
> diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
> index c54cac3..10c9419 100644
> --- a/drivers/char/tpm/Kconfig
> +++ b/drivers/char/tpm/Kconfig
> @@ -122,4 +122,13 @@ config TCG_XEN
>   	  To compile this driver as a module, choose M here; the module
>   	  will be called xen-tpmfront.
>
> +config TCG_CRB
> +	tristate "TPM 2.0 CRB Interface"
> +	depends on X86 && ACPI
> +	---help---
> +	  If you have a TPM security chip that is compliant with the
> +	  TCG CRB 2.0 TPM specification say Yes and it will be accessible
> +	  from within Linux.  To compile this driver as a module, choose
> +	  M here; the module will be called tpm_crb.
> +
>   endif # TCG_TPM
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> index ae56af9..e6d26dd 100644
> --- a/drivers/char/tpm/Makefile
> +++ b/drivers/char/tpm/Makefile
> @@ -22,3 +22,4 @@ obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
>   obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
>   obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o
>   obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
> +obj-$(CONFIG_TCG_CRB) += tpm_crb.o
> diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
> new file mode 100644
> index 0000000..eb221d5
> --- /dev/null
> +++ b/drivers/char/tpm/tpm_crb.c
> @@ -0,0 +1,323 @@
> +/*
> + * Copyright (C) 2014 Intel Corporation
> + *
> + * Authors:
> + * Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> + *
> + * Maintained by: <tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
> + *
> + * 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;
> +};
> +
> +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),
> +};
> +
> +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 *cca;
> +	unsigned long cca_pa;
> +};
> +
> +#ifdef CONFIG_PM_SLEEP
> +int crb_suspend(struct device *dev)
> +{
> +	return 0;
> +}
> +
> +static int crb_resume(struct device *dev)
> +{
> +	struct tpm_chip *chip = dev_get_drvdata(dev);
> +
> +	(void) tpm2_do_selftest(chip);
> +
> +	return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(crb_pm, crb_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(priv->cca->start) & 1) != 1)

Use a #define rather than the magic '1'.


> +		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;
> +	struct crb_control_area *cca;
> +	unsigned int expected;
> +	unsigned long offset;
> +	u8 *resp;
> +
> +	cca = priv->cca;
> +	if (le32_to_cpu(cca->sts) & CRB_CA_STS_ERROR)
> +		return -EIO;
> +
> +	offset = le64_to_cpu(cca->rsp_pa) - priv->cca_pa;
> +	resp = (u8 *) ((unsigned long) cca + offset);

make sure that count >= 6?

> +	memcpy(buf, resp, 6);
> +	expected = be32_to_cpup((__be32 *) &buf[2]);
> +
> +	if (expected > count)
> +		return -EIO;
> +
> +	memcpy(&buf[6], &resp[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;
> +	struct crb_control_area *cca;
> +	u8 *cmd;
> +	int rc = 0;
> +
> +	cca = priv->cca;
> +
> +	if (len > le32_to_cpu(cca->cmd_size)) {
> +		dev_err(&chip->dev,
> +			"invalid command count value %x %zx\n",
> +			(unsigned int) len,
> +			(size_t) le32_to_cpu(cca->cmd_size));
> +		return -E2BIG;
> +	}
> +
> +	cmd = (u8 *) ((unsigned long) cca + le64_to_cpu(cca->cmd_pa) -
> +		      priv->cca_pa);

cca = priv->cca per statement above     -> cmd = cca + x - cca = x

-> cmd = le64_to_cpu(cca->cmd_pa);

Should do the trick, no ?

> +	memcpy(cmd, buf, len);
> +
> +	/* Make sure that cmd is populated before issuing start. */
> +	wmb();
> +
> +	cca->start = cpu_to_le32(1);
> +	rc = crb_do_acpi_start(chip);

I had commented on this already. Your TPM seems to no implement the ACPI 
specs properly, or rather the ACPI table is wrong.
You have to check whether the ACPI function needs to be called. The next 
TPM from a different vendor for whom the ACPI start function is not 
necessary will need this check here since it will give a return code 
indicating failure. Then your TPM won't work anymore! I think you should 
add a check into the crb_do_acpi_start for whether this function needs 
to be called or whether your TPM is being used (vendor check?) and run 
this start function then anyway.


> +	return rc;
> +}
> +
> +static void crb_cancel(struct tpm_chip *chip)
> +{
> +	struct crb_priv *priv = chip->vendor.priv;
> +	struct crb_control_area *cca;
> +
> +	cca = priv->cca;
> +	cca->cancel = cpu_to_le32(1);

nit: #define for this ?

> +
> +	/* Make sure that cmd is populated before issuing start. */
> +	wmb();
> +
> +	if (crb_do_acpi_start(chip))
> +		dev_err(&chip->dev, "ACPI Start failed\n");
> +
> +	cca->cancel = 0;
> +}
> +
> +static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
> +{
> +	struct crb_priv *priv = chip->vendor.priv;
> +
> +	return (le32_to_cpu(priv->cca->cancel) & 1) == 1;
> +}
> +
> +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;
> +	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;
> +	}
> +
> +	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);

I wonder whether you should check whether that ACPI table is big enough 
to allow you accessing its start_method.

if (buf->length < sizeof(struct acpi_tpm2) ) {
     return -EXYZ;
}

> +
> +	if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START)
> +		priv->flags |= CRB_FL_CRB_START;

You set this flag but you don't seem to check it anywhere.

> +
> +	if (sm == CRB_SM_ACPI_START || sm == CRB_SM_CRB_WITH_ACPI_START)
> +		priv->flags |= CRB_FL_ACPI_START;


You set this flag but you don't seem to check it anywhere.


> +
> +	priv->cca_pa = le32_to_cpu(buf->control_area_pa);
> +	priv->cca = (struct crb_control_area *)
> +		devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000);
> +	if (!priv->cca) {
> +		dev_err(dev, "allocating memory failed\n");
> +		return -ENOMEM;
> +	}
> +
> +	chip->vendor.priv = priv;
> +
> +	/* Default timeouts and durations */
> +	chip->vendor.timeout_a = usecs_to_jiffies(TPM2_TIMEOUT_A);
> +	chip->vendor.timeout_b = usecs_to_jiffies(TPM2_TIMEOUT_B);
> +	chip->vendor.timeout_c = usecs_to_jiffies(TPM2_TIMEOUT_C);
> +	chip->vendor.timeout_d = usecs_to_jiffies(TPM2_TIMEOUT_D);
> +	chip->vendor.duration[TPM_SHORT] =
> +		usecs_to_jiffies(TPM2_DURATION_SHORT);
> +	chip->vendor.duration[TPM_MEDIUM] =
> +		usecs_to_jiffies(TPM2_DURATION_MEDIUM);
> +	chip->vendor.duration[TPM_LONG] =
> +		usecs_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);
> +}
> +
> +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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>");
> +MODULE_DESCRIPTION("TPM2 Driver");
> +MODULE_VERSION("0.1");
> +MODULE_LICENSE("GPL");

Regards,
     Stefan

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 02/10] tpm: two-phase chip management functions
@ 2014-11-26 14:38     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-26 14:38 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard, josh.triplett, linux-api, linux-kernel,
	tpmdd-devel, jason.gunthorpe, trousers-tech

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> tpm_register_hardware() and tpm_remove_hardware() are called often
> before initializing the device. This is wrong order since it could
> be that main TPM driver needs a fully initialized chip to be able to
> do its job. For example, now it is impossible to move common startup
> functions such as tpm_do_selftest() to tpm_register_hardware().
>
> Added tpmm_chip_alloc() and tpm_chip_register() where tpm_chip_alloc()
> reserves memory resources and tpm_chip_register() initializes the
> device driver. This way it is possible to alter struct tpm_chip
> attributes and initialize the device driver before passing it to
> tpm_chip_register().
>
> The framework takes care of freeing struct tpm_chip by using devres
> API. The broken release callback has been wiped. For example, ACPI
> drivers do not ever get this callback.
>
> This is a interm step to get proper life-cycle for TPM device drivers.
> The next steps are adding proper ref counting and locking to tpm_chip
> that is used in every place in the TPM driver.
>
> Big thank you to Jason Gunthorpe for carefully reviewing this part
> of the code. Without his contribution reaching the best quality would
> not have been possible.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> ---
>   drivers/char/tpm/Makefile           |   2 +-
>   drivers/char/tpm/tpm-chip.c         | 196 ++++++++++++++++++++++++++++++++++++
>   drivers/char/tpm/tpm-interface.c    | 148 +--------------------------
>   drivers/char/tpm/tpm.h              |  11 +-
>   drivers/char/tpm/tpm_atmel.c        |  11 +-
>   drivers/char/tpm/tpm_i2c_atmel.c    |  33 ++----
>   drivers/char/tpm/tpm_i2c_infineon.c |  37 ++-----
>   drivers/char/tpm/tpm_i2c_nuvoton.c  |  44 +++-----
>   drivers/char/tpm/tpm_i2c_stm_st33.c |  38 +++----
>   drivers/char/tpm/tpm_ibmvtpm.c      |  17 ++--
>   drivers/char/tpm/tpm_infineon.c     |  29 +++---
>   drivers/char/tpm/tpm_nsc.c          |  14 ++-
>   drivers/char/tpm/tpm_tis.c          |  78 ++++++--------
>   drivers/char/tpm/xen-tpmfront.c     |  14 +--
>   14 files changed, 329 insertions(+), 343 deletions(-)
>   create mode 100644 drivers/char/tpm/tpm-chip.c
>
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> index 4d85dd6..837da04 100644
> --- a/drivers/char/tpm/Makefile
> +++ b/drivers/char/tpm/Makefile
> @@ -2,7 +2,7 @@
>   # Makefile for the kernel tpm device drivers.
>   #
>   obj-$(CONFIG_TCG_TPM) += tpm.o
> -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o
> +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o
>   tpm-$(CONFIG_ACPI) += tpm_ppi.o
>
>   ifdef CONFIG_ACPI
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> new file mode 100644
> index 0000000..cf3ad24
> --- /dev/null
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -0,0 +1,196 @@
> +/*
> + * 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 "tpm.h"
> +#include "tpm_eventlog.h"
> +
> +static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
> +static LIST_HEAD(tpm_chip_list);
> +static DEFINE_SPINLOCK(driver_lock);
> +
> +/*
> + * tpm_chip_find_get - return tpm_chip for a given chip number
> + * @chip_num the device number for the chip
> + */
> +struct tpm_chip *tpm_chip_find_get(int chip_num)
> +{
> +	struct tpm_chip *pos, *chip = NULL;
> +
> +	rcu_read_lock();
> +	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
> +		if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
> +			continue;
> +
> +		if (try_module_get(pos->dev->driver->owner)) {
> +			chip = pos;
> +			break;
> +		}
> +	}
> +	rcu_read_unlock();
> +	return chip;
> +}
> +
> +/**
> + * tpmm_chip_remove() - free chip memory and device number
> + * @data: points to struct tpm_chip instance
> + *
> + * This is used internally by tpmm_chip_alloc() and called by devres
> + * when the device is released. This function does the opposite of
> + * tpmm_chip_alloc() freeing memory and the device number.
> + */
> +static void tpmm_chip_remove(void *data)
> +{
> +	struct tpm_chip *chip = (struct tpm_chip *) data;
> +
> +	spin_lock(&driver_lock);
> +	clear_bit(chip->dev_num, dev_mask);
> +	spin_unlock(&driver_lock);
> +	kfree(chip);
> +}
> +
> +/**
> + * tpmm_chip_alloc() - allocate a new struct tpm_chip instance
> + * @dev: device to which the chip is associated
> + * @ops: struct tpm_class_ops instance
> + *
> + * Allocates a new struct tpm_chip instance and assigns a free
> + * device number for it. Caller does not have to worry about
> + * freeing the allocated resources. When the devices is removed
> + * devres calls tpmm_chip_remove() to do the job.
> + */
> +struct tpm_chip *tpmm_chip_alloc(struct device *dev,
> +				 const struct tpm_class_ops *ops)
> +{
> +	struct tpm_chip *chip;
> +
> +	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
> +	if (chip == NULL)
> +		return ERR_PTR(-ENOMEM);
> +
> +	mutex_init(&chip->tpm_mutex);
> +	INIT_LIST_HEAD(&chip->list);
> +
> +	chip->ops = ops;
> +
> +	spin_lock(&driver_lock);
> +	chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
> +	spin_unlock(&driver_lock);
> +
> +	if (chip->dev_num >= TPM_NUM_DEVICES) {
> +		dev_err(dev, "No available tpm device numbers\n");
> +		kfree(chip);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	set_bit(chip->dev_num, dev_mask);
> +
> +	scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm",
> +		  chip->dev_num);

nit picking here: "tpm%d", chip->dev_num would just be good enough

> +
> +	chip->dev = dev;
> +	devm_add_action(dev, tpmm_chip_remove, chip);
> +	dev_set_drvdata(dev, chip);
> +
> +	return chip;
> +}
> +EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
> +
> +/*
> + * tpm_chip_register() - create a misc driver for the TPM chip
> + * @chip: TPM chip to use.
> + *
> + * Creates a misc driver for the TPM chip and adds sysfs interfaces for
> + * the device, PPI and TCPA. As the last step this function adds the
> + * chip to the list of TPM chips available for use.
> + *
> + * NOTE: This function should be only called after the chip initialization
> + * is complete.
> + *
> + * Called from tpm_<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;
> +
> +	rc = tpm_sysfs_add_device(chip);
> +	if (rc)
> +		goto del_misc;
> +
> +	rc = tpm_add_ppi(&chip->dev->kobj);
> +	if (rc)
> +		goto del_sysfs;
> +
> +	chip->bios_dir = tpm_bios_log_setup(chip->devname);
> +
> +	/* Make the chip available. */
> +	spin_lock(&driver_lock);
> +	list_add_rcu(&chip->list, &tpm_chip_list);
> +	spin_unlock(&driver_lock);
> +
> +	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)
> +{
> +	spin_lock(&driver_lock);
> +	list_del_rcu(&chip->list);
> +	spin_unlock(&driver_lock);
> +	synchronize_rcu();
> +
> +	tpm_sysfs_del_device(chip);
> +	tpm_remove_ppi(&chip->dev->kobj);
> +
> +	if (chip->bios_dir)
> +		tpm_bios_log_teardown(chip->bios_dir);
> +
> +	tpm_dev_del_device(chip);
> +}
> +EXPORT_SYMBOL_GPL(tpm_chip_unregister);
> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> index 0150b7c..915c610 100644
> --- a/drivers/char/tpm/tpm-interface.c
> +++ b/drivers/char/tpm/tpm-interface.c
> @@ -1,5 +1,6 @@
>   /*
>    * Copyright (C) 2004 IBM Corporation
> + * Copyright (C) 2014 Intel Corporation
>    *
>    * Authors:
>    * Leendert van Doorn <leendert@watson.ibm.com>
> @@ -47,10 +48,6 @@ module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
>   MODULE_PARM_DESC(suspend_pcr,
>   		 "PCR to use for dummy writes to faciltate flush on suspend.");
>
> -static LIST_HEAD(tpm_chip_list);
> -static DEFINE_SPINLOCK(driver_lock);
> -static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
> -
>   /*
>    * Array with one entry per ordinal defining the maximum amount
>    * of time the chip could take to return the result.  The ordinal
> @@ -639,27 +636,6 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
>   	return rc;
>   }
>
> -/*
> - * tpm_chip_find_get - return tpm_chip for given chip number
> - */
> -static struct tpm_chip *tpm_chip_find_get(int chip_num)
> -{
> -	struct tpm_chip *pos, *chip = NULL;
> -
> -	rcu_read_lock();
> -	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
> -		if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
> -			continue;
> -
> -		if (try_module_get(pos->dev->driver->owner)) {
> -			chip = pos;
> -			break;
> -		}
> -	}
> -	rcu_read_unlock();
> -	return chip;
> -}
> -
>   #define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
>   #define READ_PCR_RESULT_SIZE 30
>   static struct tpm_input_header pcrread_header = {
> @@ -887,30 +863,6 @@ again:
>   }
>   EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
>
> -void tpm_remove_hardware(struct device *dev)
> -{
> -	struct tpm_chip *chip = dev_get_drvdata(dev);
> -
> -	if (chip == NULL) {
> -		dev_err(dev, "No device data found\n");
> -		return;
> -	}
> -
> -	spin_lock(&driver_lock);
> -	list_del_rcu(&chip->list);
> -	spin_unlock(&driver_lock);
> -	synchronize_rcu();
> -
> -	tpm_dev_del_device(chip);
> -	tpm_sysfs_del_device(chip);
> -	tpm_remove_ppi(&dev->kobj);
> -	tpm_bios_log_teardown(chip->bios_dir);
> -
> -	/* write it this way to be explicit (chip->dev == dev) */
> -	put_device(chip->dev);
> -}
> -EXPORT_SYMBOL_GPL(tpm_remove_hardware);
> -
>   #define TPM_ORD_SAVESTATE cpu_to_be32(152)
>   #define SAVESTATE_RESULT_SIZE 10
>
> @@ -1044,104 +996,6 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
>   }
>   EXPORT_SYMBOL_GPL(tpm_get_random);
>
> -/* In case vendor provided release function, call it too.*/
> -
> -void tpm_dev_vendor_release(struct tpm_chip *chip)
> -{
> -	if (!chip)
> -		return;
> -
> -	clear_bit(chip->dev_num, dev_mask);
> -}
> -EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
> -
> -
> -/*
> - * Once all references to platform device are down to 0,
> - * release all allocated structures.
> - */
> -static void tpm_dev_release(struct device *dev)
> -{
> -	struct tpm_chip *chip = dev_get_drvdata(dev);
> -
> -	if (!chip)
> -		return;
> -
> -	tpm_dev_vendor_release(chip);
> -
> -	chip->release(dev);
> -	kfree(chip);
> -}
> -
> -/*
> - * Called from tpm_<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)
> -{
> -	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;
> -}
> -EXPORT_SYMBOL_GPL(tpm_register_hardware);
> -
>   MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
>   MODULE_DESCRIPTION("TPM Driver");
>   MODULE_VERSION("2.0");
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index e638eb0..9880681 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -110,7 +110,6 @@ struct tpm_chip {
>   	struct dentry **bios_dir;
>
>   	struct list_head list;
> -	void (*release) (struct device *);
>   };
>
>   #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
> @@ -322,15 +321,17 @@ extern int tpm_get_timeouts(struct tpm_chip *);
>   extern void tpm_gen_interrupt(struct tpm_chip *);
>   extern int tpm_do_selftest(struct tpm_chip *);
>   extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
> -extern struct tpm_chip* tpm_register_hardware(struct device *,
> -					      const struct tpm_class_ops *ops);
> -extern void tpm_dev_vendor_release(struct tpm_chip *);
> -extern void tpm_remove_hardware(struct device *);
>   extern int tpm_pm_suspend(struct device *);
>   extern int tpm_pm_resume(struct device *);
>   extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
>   			     wait_queue_head_t *, bool);
>
> +struct tpm_chip *tpm_chip_find_get(int chip_num);
> +extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
> +				       const struct tpm_class_ops *ops);
> +extern int tpm_chip_register(struct tpm_chip *chip);
> +extern void tpm_chip_unregister(struct tpm_chip *chip);
> +
>   int tpm_dev_add_device(struct tpm_chip *chip);
>   void tpm_dev_del_device(struct tpm_chip *chip);
>   int tpm_sysfs_add_device(struct tpm_chip *chip);
> diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
> index 6069d13..8e2576a 100644
> --- a/drivers/char/tpm/tpm_atmel.c
> +++ b/drivers/char/tpm/tpm_atmel.c
> @@ -138,11 +138,11 @@ static void atml_plat_remove(void)
>   	struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
>
>   	if (chip) {
> +		tpm_chip_unregister(chip);
>   		if (chip->vendor.have_region)
>   			atmel_release_region(chip->vendor.base,
>   					     chip->vendor.region_size);
>   		atmel_put_base_addr(chip->vendor.iobase);
> -		tpm_remove_hardware(chip->dev);
>   		platform_device_unregister(pdev);
>   	}
>   }
> @@ -184,8 +184,9 @@ static int __init init_atmel(void)
>   		goto err_rel_reg;
>   	}
>
> -	if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) {
> -		rc = -ENODEV;
> +	chip = tpmm_chip_alloc(&pdev->dev, &tpm_atmel);
> +	if (IS_ERR(chip)) {
> +		rc = PTR_ERR(chip);
>   		goto err_unreg_dev;
>   	}
>
> @@ -194,6 +195,10 @@ static int __init init_atmel(void)
>   	chip->vendor.have_region = have_region;
>   	chip->vendor.region_size = region_size;
>
> +	rc = tpm_chip_register(chip);
> +	if (rc)
> +		goto err_unreg_dev;
> +
>   	return 0;
>
>   err_unreg_dev:
> diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c
> index 7727292..8af3b4a 100644
> --- a/drivers/char/tpm/tpm_i2c_atmel.c
> +++ b/drivers/char/tpm/tpm_i2c_atmel.c
> @@ -160,11 +160,9 @@ static int i2c_atmel_probe(struct i2c_client *client,
>   	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
>   		return -ENODEV;
>
> -	chip = tpm_register_hardware(dev, &i2c_atmel);
> -	if (!chip) {
> -		dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
> -		return -ENODEV;
> -	}
> +	chip = tpmm_chip_alloc(dev, &i2c_atmel);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
>   	chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
>   					 GFP_KERNEL);
> @@ -179,21 +177,16 @@ static int i2c_atmel_probe(struct i2c_client *client,
>   	/* There is no known way to probe for this device, and all version
>   	 * information seems to be read via TPM commands. Thus we rely on the
>   	 * TPM startup process in the common code to detect the device. */
> -	if (tpm_get_timeouts(chip)) {
> -		rc = -ENODEV;
> -		goto out_err;
> -	}
> +	if (tpm_get_timeouts(chip))
> +		return -ENODEV;
>
> -	if (tpm_do_selftest(chip)) {
> -		rc = -ENODEV;
> -		goto out_err;
> -	}
> +	if (tpm_do_selftest(chip))
> +		return -ENODEV;
>
> -	return 0;
> +	rc = tpm_chip_register(chip);
> +	if (rc)
> +		return rc;
>
> -out_err:
> -	tpm_dev_vendor_release(chip);
> -	tpm_remove_hardware(chip->dev);
>   	return rc;
>   }
>
> @@ -201,11 +194,7 @@ static int i2c_atmel_remove(struct i2c_client *client)
>   {
>   	struct device *dev = &(client->dev);
>   	struct tpm_chip *chip = dev_get_drvdata(dev);
> -
> -	if (chip)
> -		tpm_dev_vendor_release(chip);
> -	tpm_remove_hardware(dev);
> -	kfree(chip);
> +	tpm_chip_unregister(chip);
>   	return 0;
>   }
>
> diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
> index 472af4b..03708e6 100644
> --- a/drivers/char/tpm/tpm_i2c_infineon.c
> +++ b/drivers/char/tpm/tpm_i2c_infineon.c
> @@ -581,12 +581,9 @@ static int tpm_tis_i2c_init(struct device *dev)
>   	int rc = 0;
>   	struct tpm_chip *chip;
>
> -	chip = tpm_register_hardware(dev, &tpm_tis_i2c);
> -	if (!chip) {
> -		dev_err(dev, "could not register hardware\n");
> -		rc = -ENODEV;
> -		goto out_err;
> -	}
> +	chip = tpmm_chip_alloc(dev, &tpm_tis_i2c);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
>   	/* Disable interrupts */
>   	chip->vendor.irq = 0;
> @@ -600,7 +597,7 @@ static int tpm_tis_i2c_init(struct device *dev)
>   	if (request_locality(chip, 0) != 0) {
>   		dev_err(dev, "could not request locality\n");
>   		rc = -ENODEV;
> -		goto out_vendor;
> +		goto out_err;
>   	}
>
>   	/* read four bytes from DID_VID register */
> @@ -628,21 +625,9 @@ static int tpm_tis_i2c_init(struct device *dev)
>   	tpm_get_timeouts(chip);
>   	tpm_do_selftest(chip);
>
> -	return 0;
> -
> +	return tpm_chip_register(chip);
>   out_release:
>   	release_locality(chip, chip->vendor.locality, 1);
> -
> -out_vendor:
> -	/* close file handles */
> -	tpm_dev_vendor_release(chip);
> -
> -	/* remove hardware */
> -	tpm_remove_hardware(chip->dev);
> -
> -	/* reset these pointers, otherwise we oops */
> -	chip->dev->release = NULL;
> -	chip->release = NULL;
>   	tpm_dev.client = NULL;
>   out_err:
>   	return rc;
> @@ -712,17 +697,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client,
>   static int tpm_tis_i2c_remove(struct i2c_client *client)
>   {
>   	struct tpm_chip *chip = tpm_dev.chip;
> -	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;
>
>   	return 0;
> diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c
> index 7b158ef..09f0c46 100644
> --- a/drivers/char/tpm/tpm_i2c_nuvoton.c
> +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c
> @@ -530,11 +530,9 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
>   	dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid,
>   		 (u8) (vid >> 16), (u8) (vid >> 24));
>
> -	chip = tpm_register_hardware(dev, &tpm_i2c);
> -	if (!chip) {
> -		dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
> -		return -ENODEV;
> -	}
> +	chip = tpmm_chip_alloc(dev, &tpm_i2c);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
>   	chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
>   					 GFP_KERNEL);
> @@ -584,7 +582,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
>   							   TPM_DATA_FIFO_W,
>   							   1, (u8 *) (&rc));
>   				if (rc < 0)
> -					goto out_err;
> +					return rc;
>   				/* TPM_STS <- 0x40 (commandReady) */
>   				i2c_nuvoton_ready(chip);
>   			} else {
> @@ -594,45 +592,33 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
>   				 * only TPM_STS_VALID should be set
>   				 */
>   				if (i2c_nuvoton_read_status(chip) !=
> -				    TPM_STS_VALID) {
> -					rc = -EIO;
> -					goto out_err;
> -				}
> +				    TPM_STS_VALID)
> +					return -EIO;
>   			}
>   		}
>   	}
>
> -	if (tpm_get_timeouts(chip)) {
> -		rc = -ENODEV;
> -		goto out_err;
> -	}
> +	if (tpm_get_timeouts(chip))
> +		return -ENODEV;
>
> -	if (tpm_do_selftest(chip)) {
> -		rc = -ENODEV;
> -		goto out_err;
> -	}
> +	if (tpm_do_selftest(chip))
> +		return -ENODEV;
>
> -	return 0;
> +	rc = tpm_chip_register(chip);
> +	if (rc)
> +		return rc;
>
> -out_err:
> -	tpm_dev_vendor_release(chip);
> -	tpm_remove_hardware(chip->dev);
> -	return rc;
> +	return 0;
>   }
>
>   static int i2c_nuvoton_remove(struct i2c_client *client)
>   {
>   	struct device *dev = &(client->dev);
>   	struct tpm_chip *chip = dev_get_drvdata(dev);
> -
> -	if (chip)
> -		tpm_dev_vendor_release(chip);
> -	tpm_remove_hardware(dev);
> -	kfree(chip);
> +	tpm_chip_unregister(chip);
>   	return 0;
>   }
>
> -
>   static const struct i2c_device_id i2c_nuvoton_id[] = {
>   	{I2C_DRIVER_NAME, 0},
>   	{}
> diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
> index 4669e37..b9d1a38 100644
> --- a/drivers/char/tpm/tpm_i2c_stm_st33.c
> +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
> @@ -609,37 +609,29 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
>   	if (client == NULL) {
>   		pr_info("%s: i2c client is NULL. Device not accessible.\n",
>   			__func__);
> -		err = -ENODEV;
> -		goto end;
> +		return -ENODEV;
>   	}
>
>   	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
>   		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;
> -	}
> +	chip = tpmm_chip_alloc(&client->dev, &st_i2c_tpm);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
>   	platform_data = client->dev.platform_data;
>
>   	if (!platform_data) {
>   		dev_info(&client->dev, "chip not available\n");
> -		err = -ENODEV;
> -		goto _tpm_clean_answer;
> +		return -ENODEV;
>   	}
>
>   	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;
> -	}
> +	if (platform_data->tpm_i2c_buffer[0] == NULL)
> +		return -ENOMEM;
>   	platform_data->tpm_i2c_buffer[1] =
>   	    kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
>   	if (platform_data->tpm_i2c_buffer[1] == NULL) {
> @@ -716,8 +708,10 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
>   	tpm_get_timeouts(chip);
>   	tpm_do_selftest(chip);
>
> -	dev_info(chip->dev, "TPM I2C Initialized\n");
> -	return 0;
> +	err = tpm_chip_register(chip);
> +	if (!err)
> +		return 0;
> +
>   _irq_set:
>   	free_irq(gpio_to_irq(platform_data->io_serirq), (void *)chip);
>   _gpio_init2:
> @@ -732,10 +726,6 @@ _tpm_clean_response2:
>   _tpm_clean_response1:
>   	kzfree(platform_data->tpm_i2c_buffer[0]);
>   	platform_data->tpm_i2c_buffer[0] = NULL;
> -_tpm_clean_answer:
> -	tpm_remove_hardware(chip->dev);
> -end:
> -	pr_info("TPM I2C initialisation fail\n");
>   	return err;
>   }
>
> @@ -752,13 +742,13 @@ static int tpm_st33_i2c_remove(struct i2c_client *client)
>   		((struct i2c_client *)TPM_VPRIV(chip))->dev.platform_data;
>
>   	if (pin_infos != NULL) {
> +		tpm_chip_unregister(chip);
> +
>   		free_irq(pin_infos->io_serirq, chip);
>
>   		gpio_free(pin_infos->io_serirq);
>   		gpio_free(pin_infos->io_lpcpd);
>
> -		tpm_remove_hardware(chip->dev);
> -
>   		if (pin_infos->tpm_i2c_buffer[1] != NULL) {
>   			kzfree(pin_infos->tpm_i2c_buffer[1]);
>   			pin_infos->tpm_i2c_buffer[1] = NULL;
> diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
> index af74c57..eb95796 100644
> --- a/drivers/char/tpm/tpm_ibmvtpm.c
> +++ b/drivers/char/tpm/tpm_ibmvtpm.c
> @@ -270,8 +270,11 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
>   static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
>   {
>   	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
> +	struct tpm_chip *chip = dev_get_drvdata(ibmvtpm->dev);
>   	int rc = 0;
>
> +	tpm_chip_unregister(chip);
> +
>   	free_irq(vdev->irq, ibmvtpm);
>
>   	do {
> @@ -290,8 +293,6 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
>   		kfree(ibmvtpm->rtce_buf);
>   	}
>
> -	tpm_remove_hardware(ibmvtpm->dev);
> -
>   	kfree(ibmvtpm);
>
>   	return 0;
> @@ -555,11 +556,9 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
>   	struct tpm_chip *chip;
>   	int rc = -ENOMEM, rc1;
>
> -	chip = tpm_register_hardware(dev, &tpm_ibmvtpm);
> -	if (!chip) {
> -		dev_err(dev, "tpm_register_hardware failed\n");
> -		return -ENODEV;
> -	}
> +	chip = tpmm_chip_alloc(dev, &tpm_ibmvtpm);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
>   	ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
>   	if (!ibmvtpm) {
> @@ -629,7 +628,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
>   	if (rc)
>   		goto init_irq_cleanup;
>
> -	return rc;
> +	return tpm_chip_register(chip);
>   init_irq_cleanup:
>   	do {
>   		rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
> @@ -644,8 +643,6 @@ cleanup:
>   		kfree(ibmvtpm);
>   	}
>
> -	tpm_remove_hardware(dev);
> -
>   	return rc;
>   }
>
> diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
> index dc0a255..dcdb671 100644
> --- a/drivers/char/tpm/tpm_infineon.c
> +++ b/drivers/char/tpm/tpm_infineon.c
> @@ -546,7 +546,14 @@ static int tpm_inf_pnp_probe(struct pnp_dev *dev,
>   			 vendorid[0], vendorid[1],
>   			 productid[0], productid[1], chipname);
>
> -		if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf)))
> +		chip = tpmm_chip_alloc(&dev->dev, &tpm_inf);
> +		if (IS_ERR(chip)) {
> +			rc = PTR_ERR(chip);
> +			goto err_release_region;
> +		}
> +
> +		rc = tpm_chip_register(chip);
> +		if (rc)
>   			goto err_release_region;
>
>   		return 0;
> @@ -572,17 +579,15 @@ static void tpm_inf_pnp_remove(struct pnp_dev *dev)
>   {
>   	struct tpm_chip *chip = pnp_get_drvdata(dev);
>
> -	if (chip) {
> -		if (tpm_dev.iotype == TPM_INF_IO_PORT) {
> -			release_region(tpm_dev.data_regs, tpm_dev.data_size);
> -			release_region(tpm_dev.config_port,
> -				       tpm_dev.config_size);
> -		} else {
> -			iounmap(tpm_dev.mem_base);
> -			release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
> -		}
> -		tpm_dev_vendor_release(chip);
> -		tpm_remove_hardware(chip->dev);
> +	tpm_chip_unregister(chip);
> +
> +	if (tpm_dev.iotype == TPM_INF_IO_PORT) {
> +		release_region(tpm_dev.data_regs, tpm_dev.data_size);
> +		release_region(tpm_dev.config_port,
> +			       tpm_dev.config_size);
> +	} else {
> +		iounmap(tpm_dev.mem_base);
> +		release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
>   	}
>   }
>
> diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
> index 3179ec9..00c5470 100644
> --- a/drivers/char/tpm/tpm_nsc.c
> +++ b/drivers/char/tpm/tpm_nsc.c
> @@ -247,10 +247,9 @@ static struct platform_device *pdev = NULL;
>   static void tpm_nsc_remove(struct device *dev)
>   {
>   	struct tpm_chip *chip = dev_get_drvdata(dev);
> -	if ( chip ) {
> -		release_region(chip->vendor.base, 2);
> -		tpm_remove_hardware(chip->dev);
> -	}
> +
> +	tpm_chip_unregister(chip);
> +	release_region(chip->vendor.base, 2);
>   }
>
>   static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume);
> @@ -308,11 +307,16 @@ static int __init init_nsc(void)
>   		goto err_del_dev;
>   	}
>
> -	if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) {
> +	chip = tpmm_chip_alloc(&pdev->dev, &tpm_nsc);
> +	if (IS_ERR(chip)) {
>   		rc = -ENODEV;
>   		goto err_rel_reg;
>   	}
>
> +	rc = tpm_chip_register(chip);
> +	if (rc)
> +		goto err_rel_reg;
> +
>   	dev_dbg(&pdev->dev, "NSC TPM detected\n");
>   	dev_dbg(&pdev->dev,
>   		"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
> diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
> index 2c46734..0066b68 100644
> --- a/drivers/char/tpm/tpm_tis.c
> +++ b/drivers/char/tpm/tpm_tis.c
> @@ -75,9 +75,6 @@ enum tis_defaults {
>   #define	TPM_DID_VID(l)			(0x0F00 | ((l) << 12))
>   #define	TPM_RID(l)			(0x0F04 | ((l) << 12))
>
> -static LIST_HEAD(tis_chips);
> -static DEFINE_MUTEX(tis_lock);
> -
>   #if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
>   static int is_itpm(struct pnp_dev *dev)
>   {
> @@ -528,6 +525,17 @@ static bool interrupts = true;
>   module_param(interrupts, bool, 0444);
>   MODULE_PARM_DESC(interrupts, "Enable interrupts");
>
> +static void tpm_tis_remove(struct tpm_chip *chip)
> +{
> +	iowrite32(~TPM_GLOBAL_INT_ENABLE &
> +		  ioread32(chip->vendor.iobase +
> +			   TPM_INT_ENABLE(chip->vendor.
> +					  locality)),
> +		  chip->vendor.iobase +
> +		  TPM_INT_ENABLE(chip->vendor.locality));
> +	release_locality(chip, chip->vendor.locality, 1);
> +}
> +
>   static int tpm_tis_init(struct device *dev, resource_size_t start,
>   			resource_size_t len, unsigned int irq)
>   {
> @@ -535,14 +543,13 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
>   	int rc, i, irq_s, irq_e, probe;
>   	struct tpm_chip *chip;
>
> -	if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
> -		return -ENODEV;
> +	chip = tpmm_chip_alloc(dev, &tpm_tis);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
> -	chip->vendor.iobase = ioremap(start, len);
> -	if (!chip->vendor.iobase) {
> -		rc = -EIO;
> -		goto out_err;
> -	}
> +	chip->vendor.iobase = devm_ioremap(dev, start, len);
> +	if (!chip->vendor.iobase)
> +		return -EIO;
>
>   	/* Default timeouts */
>   	chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
> @@ -649,8 +656,8 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
>   		for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
>   			iowrite8(i, chip->vendor.iobase +
>   				 TPM_INT_VECTOR(chip->vendor.locality));
> -			if (request_irq
> -			    (i, tis_int_probe, IRQF_SHARED,
> +			if (devm_request_irq
> +			    (dev, i, tis_int_probe, IRQF_SHARED,
>   			     chip->vendor.miscdev.name, chip) != 0) {
>   				dev_info(chip->dev,
>   					 "Unable to request irq: %d for probe\n",
> @@ -690,15 +697,14 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
>   			iowrite32(intmask,
>   				  chip->vendor.iobase +
>   				  TPM_INT_ENABLE(chip->vendor.locality));
> -			free_irq(i, chip);
>   		}
>   	}
>   	if (chip->vendor.irq) {
>   		iowrite8(chip->vendor.irq,
>   			 chip->vendor.iobase +
>   			 TPM_INT_VECTOR(chip->vendor.locality));
> -		if (request_irq
> -		    (chip->vendor.irq, tis_int_handler, IRQF_SHARED,
> +		if (devm_request_irq
> +		    (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
>   		     chip->vendor.miscdev.name, chip) != 0) {
>   			dev_info(chip->dev,
>   				 "Unable to request irq: %d for use\n",
> @@ -719,17 +725,9 @@ 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);
> -
> -
> -	return 0;
> +	return tpm_chip_register(chip);
>   out_err:
> -	if (chip->vendor.iobase)
> -		iounmap(chip->vendor.iobase);
> -	tpm_remove_hardware(chip->dev);
> +	tpm_tis_remove(chip);
>   	return rc;
>   }
>
> @@ -811,13 +809,10 @@ MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
>   static void tpm_tis_pnp_remove(struct pnp_dev *dev)
>   {
>   	struct tpm_chip *chip = pnp_get_drvdata(dev);
> -
> -	tpm_dev_vendor_release(chip);
> -
> -	kfree(chip);
> +	tpm_chip_unregister(chip);
> +	tpm_tis_remove(chip);
>   }
>
> -
>   static struct pnp_driver tis_pnp_driver = {
>   	.name = "tpm_tis",
>   	.id_table = tpm_pnp_tbl,
> @@ -836,7 +831,7 @@ MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
>
>   static struct platform_driver tis_drv = {
>   	.driver = {
> -		.name = "tpm_tis",
> +		.name		= "tpm_tis",
>   		.owner		= THIS_MODULE,
>   		.pm		= &tpm_tis_pm,
>   	},
> @@ -876,31 +871,16 @@ err_dev:
>
>   static void __exit cleanup_tis(void)
>   {
> -	struct tpm_vendor_specific *i, *j;
>   	struct tpm_chip *chip;
> -	mutex_lock(&tis_lock);
> -	list_for_each_entry_safe(i, j, &tis_chips, list) {
> -		chip = to_tpm_chip(i);
> -		tpm_remove_hardware(chip->dev);
> -		iowrite32(~TPM_GLOBAL_INT_ENABLE &
> -			  ioread32(chip->vendor.iobase +
> -				   TPM_INT_ENABLE(chip->vendor.
> -						  locality)),
> -			  chip->vendor.iobase +
> -			  TPM_INT_ENABLE(chip->vendor.locality));
> -		release_locality(chip, chip->vendor.locality, 1);
> -		if (chip->vendor.irq)
> -			free_irq(chip->vendor.irq, chip);
> -		iounmap(i->iobase);
> -		list_del(&i->list);
> -	}
> -	mutex_unlock(&tis_lock);
>   #ifdef CONFIG_PNP
>   	if (!force) {
>   		pnp_unregister_driver(&tis_pnp_driver);
>   		return;
>   	}
>   #endif
> +	chip = dev_get_drvdata(&pdev->dev);
> +	tpm_chip_unregister(chip);
> +	tpm_tis_remove(chip);
>   	platform_device_unregister(pdev);
>   	platform_driver_unregister(&tis_drv);
>   }
> diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c
> index 441b44e..c3b4f5a 100644
> --- a/drivers/char/tpm/xen-tpmfront.c
> +++ b/drivers/char/tpm/xen-tpmfront.c
> @@ -175,9 +175,9 @@ static int setup_chip(struct device *dev, struct tpm_private *priv)
>   {
>   	struct tpm_chip *chip;
>
> -	chip = tpm_register_hardware(dev, &tpm_vtpm);
> -	if (!chip)
> -		return -ENODEV;
> +	chip = tpmm_chip_alloc(dev, &tpm_vtpm);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
>   	init_waitqueue_head(&chip->vendor.read_queue);
>
> @@ -286,6 +286,7 @@ static int tpmfront_probe(struct xenbus_device *dev,
>   		const struct xenbus_device_id *id)
>   {
>   	struct tpm_private *priv;
> +	struct tpm_chip *chip;
>   	int rv;
>
>   	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> @@ -302,21 +303,22 @@ static int tpmfront_probe(struct xenbus_device *dev,
>
>   	rv = setup_ring(dev, priv);
>   	if (rv) {
> -		tpm_remove_hardware(&dev->dev);
> +		chip = dev_get_drvdata(&dev->dev);
> +		tpm_chip_unregister(chip);
>   		ring_free(priv);
>   		return rv;
>   	}
>
>   	tpm_get_timeouts(priv->chip);
>
> -	return rv;
> +	return tpm_chip_register(priv->chip);
>   }
>
>   static int tpmfront_remove(struct xenbus_device *dev)
>   {
>   	struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
>   	struct tpm_private *priv = TPM_VPRIV(chip);
> -	tpm_remove_hardware(&dev->dev);
> +	tpm_chip_unregister(chip);
>   	ring_free(priv);
>   	TPM_VPRIV(chip) = NULL;
>   	return 0;



Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>



^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 02/10] tpm: two-phase chip management functions
@ 2014-11-26 14:38     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-26 14:38 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> tpm_register_hardware() and tpm_remove_hardware() are called often
> before initializing the device. This is wrong order since it could
> be that main TPM driver needs a fully initialized chip to be able to
> do its job. For example, now it is impossible to move common startup
> functions such as tpm_do_selftest() to tpm_register_hardware().
>
> Added tpmm_chip_alloc() and tpm_chip_register() where tpm_chip_alloc()
> reserves memory resources and tpm_chip_register() initializes the
> device driver. This way it is possible to alter struct tpm_chip
> attributes and initialize the device driver before passing it to
> tpm_chip_register().
>
> The framework takes care of freeing struct tpm_chip by using devres
> API. The broken release callback has been wiped. For example, ACPI
> drivers do not ever get this callback.
>
> This is a interm step to get proper life-cycle for TPM device drivers.
> The next steps are adding proper ref counting and locking to tpm_chip
> that is used in every place in the TPM driver.
>
> Big thank you to Jason Gunthorpe for carefully reviewing this part
> of the code. Without his contribution reaching the best quality would
> not have been possible.
>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> ---
>   drivers/char/tpm/Makefile           |   2 +-
>   drivers/char/tpm/tpm-chip.c         | 196 ++++++++++++++++++++++++++++++++++++
>   drivers/char/tpm/tpm-interface.c    | 148 +--------------------------
>   drivers/char/tpm/tpm.h              |  11 +-
>   drivers/char/tpm/tpm_atmel.c        |  11 +-
>   drivers/char/tpm/tpm_i2c_atmel.c    |  33 ++----
>   drivers/char/tpm/tpm_i2c_infineon.c |  37 ++-----
>   drivers/char/tpm/tpm_i2c_nuvoton.c  |  44 +++-----
>   drivers/char/tpm/tpm_i2c_stm_st33.c |  38 +++----
>   drivers/char/tpm/tpm_ibmvtpm.c      |  17 ++--
>   drivers/char/tpm/tpm_infineon.c     |  29 +++---
>   drivers/char/tpm/tpm_nsc.c          |  14 ++-
>   drivers/char/tpm/tpm_tis.c          |  78 ++++++--------
>   drivers/char/tpm/xen-tpmfront.c     |  14 +--
>   14 files changed, 329 insertions(+), 343 deletions(-)
>   create mode 100644 drivers/char/tpm/tpm-chip.c
>
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> index 4d85dd6..837da04 100644
> --- a/drivers/char/tpm/Makefile
> +++ b/drivers/char/tpm/Makefile
> @@ -2,7 +2,7 @@
>   # Makefile for the kernel tpm device drivers.
>   #
>   obj-$(CONFIG_TCG_TPM) += tpm.o
> -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o
> +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o
>   tpm-$(CONFIG_ACPI) += tpm_ppi.o
>
>   ifdef CONFIG_ACPI
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> new file mode 100644
> index 0000000..cf3ad24
> --- /dev/null
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -0,0 +1,196 @@
> +/*
> + * Copyright (C) 2004 IBM Corporation
> + * Copyright (C) 2014 Intel Corporation
> + *
> + * Authors:
> + * Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> + * Leendert van Doorn <leendert-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org>
> + * Dave Safford <safford-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org>
> + * Reiner Sailer <sailer-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org>
> + * Kylene Hall <kjhall-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
> + *
> + * Maintained by: <tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
> + *
> + * 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 "tpm.h"
> +#include "tpm_eventlog.h"
> +
> +static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
> +static LIST_HEAD(tpm_chip_list);
> +static DEFINE_SPINLOCK(driver_lock);
> +
> +/*
> + * tpm_chip_find_get - return tpm_chip for a given chip number
> + * @chip_num the device number for the chip
> + */
> +struct tpm_chip *tpm_chip_find_get(int chip_num)
> +{
> +	struct tpm_chip *pos, *chip = NULL;
> +
> +	rcu_read_lock();
> +	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
> +		if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
> +			continue;
> +
> +		if (try_module_get(pos->dev->driver->owner)) {
> +			chip = pos;
> +			break;
> +		}
> +	}
> +	rcu_read_unlock();
> +	return chip;
> +}
> +
> +/**
> + * tpmm_chip_remove() - free chip memory and device number
> + * @data: points to struct tpm_chip instance
> + *
> + * This is used internally by tpmm_chip_alloc() and called by devres
> + * when the device is released. This function does the opposite of
> + * tpmm_chip_alloc() freeing memory and the device number.
> + */
> +static void tpmm_chip_remove(void *data)
> +{
> +	struct tpm_chip *chip = (struct tpm_chip *) data;
> +
> +	spin_lock(&driver_lock);
> +	clear_bit(chip->dev_num, dev_mask);
> +	spin_unlock(&driver_lock);
> +	kfree(chip);
> +}
> +
> +/**
> + * tpmm_chip_alloc() - allocate a new struct tpm_chip instance
> + * @dev: device to which the chip is associated
> + * @ops: struct tpm_class_ops instance
> + *
> + * Allocates a new struct tpm_chip instance and assigns a free
> + * device number for it. Caller does not have to worry about
> + * freeing the allocated resources. When the devices is removed
> + * devres calls tpmm_chip_remove() to do the job.
> + */
> +struct tpm_chip *tpmm_chip_alloc(struct device *dev,
> +				 const struct tpm_class_ops *ops)
> +{
> +	struct tpm_chip *chip;
> +
> +	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
> +	if (chip == NULL)
> +		return ERR_PTR(-ENOMEM);
> +
> +	mutex_init(&chip->tpm_mutex);
> +	INIT_LIST_HEAD(&chip->list);
> +
> +	chip->ops = ops;
> +
> +	spin_lock(&driver_lock);
> +	chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
> +	spin_unlock(&driver_lock);
> +
> +	if (chip->dev_num >= TPM_NUM_DEVICES) {
> +		dev_err(dev, "No available tpm device numbers\n");
> +		kfree(chip);
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	set_bit(chip->dev_num, dev_mask);
> +
> +	scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm",
> +		  chip->dev_num);

nit picking here: "tpm%d", chip->dev_num would just be good enough

> +
> +	chip->dev = dev;
> +	devm_add_action(dev, tpmm_chip_remove, chip);
> +	dev_set_drvdata(dev, chip);
> +
> +	return chip;
> +}
> +EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
> +
> +/*
> + * tpm_chip_register() - create a misc driver for the TPM chip
> + * @chip: TPM chip to use.
> + *
> + * Creates a misc driver for the TPM chip and adds sysfs interfaces for
> + * the device, PPI and TCPA. As the last step this function adds the
> + * chip to the list of TPM chips available for use.
> + *
> + * NOTE: This function should be only called after the chip initialization
> + * is complete.
> + *
> + * Called from tpm_<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;
> +
> +	rc = tpm_sysfs_add_device(chip);
> +	if (rc)
> +		goto del_misc;
> +
> +	rc = tpm_add_ppi(&chip->dev->kobj);
> +	if (rc)
> +		goto del_sysfs;
> +
> +	chip->bios_dir = tpm_bios_log_setup(chip->devname);
> +
> +	/* Make the chip available. */
> +	spin_lock(&driver_lock);
> +	list_add_rcu(&chip->list, &tpm_chip_list);
> +	spin_unlock(&driver_lock);
> +
> +	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)
> +{
> +	spin_lock(&driver_lock);
> +	list_del_rcu(&chip->list);
> +	spin_unlock(&driver_lock);
> +	synchronize_rcu();
> +
> +	tpm_sysfs_del_device(chip);
> +	tpm_remove_ppi(&chip->dev->kobj);
> +
> +	if (chip->bios_dir)
> +		tpm_bios_log_teardown(chip->bios_dir);
> +
> +	tpm_dev_del_device(chip);
> +}
> +EXPORT_SYMBOL_GPL(tpm_chip_unregister);
> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> index 0150b7c..915c610 100644
> --- a/drivers/char/tpm/tpm-interface.c
> +++ b/drivers/char/tpm/tpm-interface.c
> @@ -1,5 +1,6 @@
>   /*
>    * Copyright (C) 2004 IBM Corporation
> + * Copyright (C) 2014 Intel Corporation
>    *
>    * Authors:
>    * Leendert van Doorn <leendert-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org>
> @@ -47,10 +48,6 @@ module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
>   MODULE_PARM_DESC(suspend_pcr,
>   		 "PCR to use for dummy writes to faciltate flush on suspend.");
>
> -static LIST_HEAD(tpm_chip_list);
> -static DEFINE_SPINLOCK(driver_lock);
> -static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
> -
>   /*
>    * Array with one entry per ordinal defining the maximum amount
>    * of time the chip could take to return the result.  The ordinal
> @@ -639,27 +636,6 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
>   	return rc;
>   }
>
> -/*
> - * tpm_chip_find_get - return tpm_chip for given chip number
> - */
> -static struct tpm_chip *tpm_chip_find_get(int chip_num)
> -{
> -	struct tpm_chip *pos, *chip = NULL;
> -
> -	rcu_read_lock();
> -	list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
> -		if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
> -			continue;
> -
> -		if (try_module_get(pos->dev->driver->owner)) {
> -			chip = pos;
> -			break;
> -		}
> -	}
> -	rcu_read_unlock();
> -	return chip;
> -}
> -
>   #define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
>   #define READ_PCR_RESULT_SIZE 30
>   static struct tpm_input_header pcrread_header = {
> @@ -887,30 +863,6 @@ again:
>   }
>   EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
>
> -void tpm_remove_hardware(struct device *dev)
> -{
> -	struct tpm_chip *chip = dev_get_drvdata(dev);
> -
> -	if (chip == NULL) {
> -		dev_err(dev, "No device data found\n");
> -		return;
> -	}
> -
> -	spin_lock(&driver_lock);
> -	list_del_rcu(&chip->list);
> -	spin_unlock(&driver_lock);
> -	synchronize_rcu();
> -
> -	tpm_dev_del_device(chip);
> -	tpm_sysfs_del_device(chip);
> -	tpm_remove_ppi(&dev->kobj);
> -	tpm_bios_log_teardown(chip->bios_dir);
> -
> -	/* write it this way to be explicit (chip->dev == dev) */
> -	put_device(chip->dev);
> -}
> -EXPORT_SYMBOL_GPL(tpm_remove_hardware);
> -
>   #define TPM_ORD_SAVESTATE cpu_to_be32(152)
>   #define SAVESTATE_RESULT_SIZE 10
>
> @@ -1044,104 +996,6 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
>   }
>   EXPORT_SYMBOL_GPL(tpm_get_random);
>
> -/* In case vendor provided release function, call it too.*/
> -
> -void tpm_dev_vendor_release(struct tpm_chip *chip)
> -{
> -	if (!chip)
> -		return;
> -
> -	clear_bit(chip->dev_num, dev_mask);
> -}
> -EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
> -
> -
> -/*
> - * Once all references to platform device are down to 0,
> - * release all allocated structures.
> - */
> -static void tpm_dev_release(struct device *dev)
> -{
> -	struct tpm_chip *chip = dev_get_drvdata(dev);
> -
> -	if (!chip)
> -		return;
> -
> -	tpm_dev_vendor_release(chip);
> -
> -	chip->release(dev);
> -	kfree(chip);
> -}
> -
> -/*
> - * Called from tpm_<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)
> -{
> -	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;
> -}
> -EXPORT_SYMBOL_GPL(tpm_register_hardware);
> -
>   MODULE_AUTHOR("Leendert van Doorn (leendert-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org)");
>   MODULE_DESCRIPTION("TPM Driver");
>   MODULE_VERSION("2.0");
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index e638eb0..9880681 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -110,7 +110,6 @@ struct tpm_chip {
>   	struct dentry **bios_dir;
>
>   	struct list_head list;
> -	void (*release) (struct device *);
>   };
>
>   #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
> @@ -322,15 +321,17 @@ extern int tpm_get_timeouts(struct tpm_chip *);
>   extern void tpm_gen_interrupt(struct tpm_chip *);
>   extern int tpm_do_selftest(struct tpm_chip *);
>   extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
> -extern struct tpm_chip* tpm_register_hardware(struct device *,
> -					      const struct tpm_class_ops *ops);
> -extern void tpm_dev_vendor_release(struct tpm_chip *);
> -extern void tpm_remove_hardware(struct device *);
>   extern int tpm_pm_suspend(struct device *);
>   extern int tpm_pm_resume(struct device *);
>   extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
>   			     wait_queue_head_t *, bool);
>
> +struct tpm_chip *tpm_chip_find_get(int chip_num);
> +extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
> +				       const struct tpm_class_ops *ops);
> +extern int tpm_chip_register(struct tpm_chip *chip);
> +extern void tpm_chip_unregister(struct tpm_chip *chip);
> +
>   int tpm_dev_add_device(struct tpm_chip *chip);
>   void tpm_dev_del_device(struct tpm_chip *chip);
>   int tpm_sysfs_add_device(struct tpm_chip *chip);
> diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
> index 6069d13..8e2576a 100644
> --- a/drivers/char/tpm/tpm_atmel.c
> +++ b/drivers/char/tpm/tpm_atmel.c
> @@ -138,11 +138,11 @@ static void atml_plat_remove(void)
>   	struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
>
>   	if (chip) {
> +		tpm_chip_unregister(chip);
>   		if (chip->vendor.have_region)
>   			atmel_release_region(chip->vendor.base,
>   					     chip->vendor.region_size);
>   		atmel_put_base_addr(chip->vendor.iobase);
> -		tpm_remove_hardware(chip->dev);
>   		platform_device_unregister(pdev);
>   	}
>   }
> @@ -184,8 +184,9 @@ static int __init init_atmel(void)
>   		goto err_rel_reg;
>   	}
>
> -	if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) {
> -		rc = -ENODEV;
> +	chip = tpmm_chip_alloc(&pdev->dev, &tpm_atmel);
> +	if (IS_ERR(chip)) {
> +		rc = PTR_ERR(chip);
>   		goto err_unreg_dev;
>   	}
>
> @@ -194,6 +195,10 @@ static int __init init_atmel(void)
>   	chip->vendor.have_region = have_region;
>   	chip->vendor.region_size = region_size;
>
> +	rc = tpm_chip_register(chip);
> +	if (rc)
> +		goto err_unreg_dev;
> +
>   	return 0;
>
>   err_unreg_dev:
> diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c
> index 7727292..8af3b4a 100644
> --- a/drivers/char/tpm/tpm_i2c_atmel.c
> +++ b/drivers/char/tpm/tpm_i2c_atmel.c
> @@ -160,11 +160,9 @@ static int i2c_atmel_probe(struct i2c_client *client,
>   	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
>   		return -ENODEV;
>
> -	chip = tpm_register_hardware(dev, &i2c_atmel);
> -	if (!chip) {
> -		dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
> -		return -ENODEV;
> -	}
> +	chip = tpmm_chip_alloc(dev, &i2c_atmel);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
>   	chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
>   					 GFP_KERNEL);
> @@ -179,21 +177,16 @@ static int i2c_atmel_probe(struct i2c_client *client,
>   	/* There is no known way to probe for this device, and all version
>   	 * information seems to be read via TPM commands. Thus we rely on the
>   	 * TPM startup process in the common code to detect the device. */
> -	if (tpm_get_timeouts(chip)) {
> -		rc = -ENODEV;
> -		goto out_err;
> -	}
> +	if (tpm_get_timeouts(chip))
> +		return -ENODEV;
>
> -	if (tpm_do_selftest(chip)) {
> -		rc = -ENODEV;
> -		goto out_err;
> -	}
> +	if (tpm_do_selftest(chip))
> +		return -ENODEV;
>
> -	return 0;
> +	rc = tpm_chip_register(chip);
> +	if (rc)
> +		return rc;
>
> -out_err:
> -	tpm_dev_vendor_release(chip);
> -	tpm_remove_hardware(chip->dev);
>   	return rc;
>   }
>
> @@ -201,11 +194,7 @@ static int i2c_atmel_remove(struct i2c_client *client)
>   {
>   	struct device *dev = &(client->dev);
>   	struct tpm_chip *chip = dev_get_drvdata(dev);
> -
> -	if (chip)
> -		tpm_dev_vendor_release(chip);
> -	tpm_remove_hardware(dev);
> -	kfree(chip);
> +	tpm_chip_unregister(chip);
>   	return 0;
>   }
>
> diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
> index 472af4b..03708e6 100644
> --- a/drivers/char/tpm/tpm_i2c_infineon.c
> +++ b/drivers/char/tpm/tpm_i2c_infineon.c
> @@ -581,12 +581,9 @@ static int tpm_tis_i2c_init(struct device *dev)
>   	int rc = 0;
>   	struct tpm_chip *chip;
>
> -	chip = tpm_register_hardware(dev, &tpm_tis_i2c);
> -	if (!chip) {
> -		dev_err(dev, "could not register hardware\n");
> -		rc = -ENODEV;
> -		goto out_err;
> -	}
> +	chip = tpmm_chip_alloc(dev, &tpm_tis_i2c);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
>   	/* Disable interrupts */
>   	chip->vendor.irq = 0;
> @@ -600,7 +597,7 @@ static int tpm_tis_i2c_init(struct device *dev)
>   	if (request_locality(chip, 0) != 0) {
>   		dev_err(dev, "could not request locality\n");
>   		rc = -ENODEV;
> -		goto out_vendor;
> +		goto out_err;
>   	}
>
>   	/* read four bytes from DID_VID register */
> @@ -628,21 +625,9 @@ static int tpm_tis_i2c_init(struct device *dev)
>   	tpm_get_timeouts(chip);
>   	tpm_do_selftest(chip);
>
> -	return 0;
> -
> +	return tpm_chip_register(chip);
>   out_release:
>   	release_locality(chip, chip->vendor.locality, 1);
> -
> -out_vendor:
> -	/* close file handles */
> -	tpm_dev_vendor_release(chip);
> -
> -	/* remove hardware */
> -	tpm_remove_hardware(chip->dev);
> -
> -	/* reset these pointers, otherwise we oops */
> -	chip->dev->release = NULL;
> -	chip->release = NULL;
>   	tpm_dev.client = NULL;
>   out_err:
>   	return rc;
> @@ -712,17 +697,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client,
>   static int tpm_tis_i2c_remove(struct i2c_client *client)
>   {
>   	struct tpm_chip *chip = tpm_dev.chip;
> -	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;
>
>   	return 0;
> diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c
> index 7b158ef..09f0c46 100644
> --- a/drivers/char/tpm/tpm_i2c_nuvoton.c
> +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c
> @@ -530,11 +530,9 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
>   	dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid,
>   		 (u8) (vid >> 16), (u8) (vid >> 24));
>
> -	chip = tpm_register_hardware(dev, &tpm_i2c);
> -	if (!chip) {
> -		dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
> -		return -ENODEV;
> -	}
> +	chip = tpmm_chip_alloc(dev, &tpm_i2c);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
>   	chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
>   					 GFP_KERNEL);
> @@ -584,7 +582,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
>   							   TPM_DATA_FIFO_W,
>   							   1, (u8 *) (&rc));
>   				if (rc < 0)
> -					goto out_err;
> +					return rc;
>   				/* TPM_STS <- 0x40 (commandReady) */
>   				i2c_nuvoton_ready(chip);
>   			} else {
> @@ -594,45 +592,33 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
>   				 * only TPM_STS_VALID should be set
>   				 */
>   				if (i2c_nuvoton_read_status(chip) !=
> -				    TPM_STS_VALID) {
> -					rc = -EIO;
> -					goto out_err;
> -				}
> +				    TPM_STS_VALID)
> +					return -EIO;
>   			}
>   		}
>   	}
>
> -	if (tpm_get_timeouts(chip)) {
> -		rc = -ENODEV;
> -		goto out_err;
> -	}
> +	if (tpm_get_timeouts(chip))
> +		return -ENODEV;
>
> -	if (tpm_do_selftest(chip)) {
> -		rc = -ENODEV;
> -		goto out_err;
> -	}
> +	if (tpm_do_selftest(chip))
> +		return -ENODEV;
>
> -	return 0;
> +	rc = tpm_chip_register(chip);
> +	if (rc)
> +		return rc;
>
> -out_err:
> -	tpm_dev_vendor_release(chip);
> -	tpm_remove_hardware(chip->dev);
> -	return rc;
> +	return 0;
>   }
>
>   static int i2c_nuvoton_remove(struct i2c_client *client)
>   {
>   	struct device *dev = &(client->dev);
>   	struct tpm_chip *chip = dev_get_drvdata(dev);
> -
> -	if (chip)
> -		tpm_dev_vendor_release(chip);
> -	tpm_remove_hardware(dev);
> -	kfree(chip);
> +	tpm_chip_unregister(chip);
>   	return 0;
>   }
>
> -
>   static const struct i2c_device_id i2c_nuvoton_id[] = {
>   	{I2C_DRIVER_NAME, 0},
>   	{}
> diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
> index 4669e37..b9d1a38 100644
> --- a/drivers/char/tpm/tpm_i2c_stm_st33.c
> +++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
> @@ -609,37 +609,29 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
>   	if (client == NULL) {
>   		pr_info("%s: i2c client is NULL. Device not accessible.\n",
>   			__func__);
> -		err = -ENODEV;
> -		goto end;
> +		return -ENODEV;
>   	}
>
>   	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
>   		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;
> -	}
> +	chip = tpmm_chip_alloc(&client->dev, &st_i2c_tpm);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
>   	platform_data = client->dev.platform_data;
>
>   	if (!platform_data) {
>   		dev_info(&client->dev, "chip not available\n");
> -		err = -ENODEV;
> -		goto _tpm_clean_answer;
> +		return -ENODEV;
>   	}
>
>   	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;
> -	}
> +	if (platform_data->tpm_i2c_buffer[0] == NULL)
> +		return -ENOMEM;
>   	platform_data->tpm_i2c_buffer[1] =
>   	    kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
>   	if (platform_data->tpm_i2c_buffer[1] == NULL) {
> @@ -716,8 +708,10 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
>   	tpm_get_timeouts(chip);
>   	tpm_do_selftest(chip);
>
> -	dev_info(chip->dev, "TPM I2C Initialized\n");
> -	return 0;
> +	err = tpm_chip_register(chip);
> +	if (!err)
> +		return 0;
> +
>   _irq_set:
>   	free_irq(gpio_to_irq(platform_data->io_serirq), (void *)chip);
>   _gpio_init2:
> @@ -732,10 +726,6 @@ _tpm_clean_response2:
>   _tpm_clean_response1:
>   	kzfree(platform_data->tpm_i2c_buffer[0]);
>   	platform_data->tpm_i2c_buffer[0] = NULL;
> -_tpm_clean_answer:
> -	tpm_remove_hardware(chip->dev);
> -end:
> -	pr_info("TPM I2C initialisation fail\n");
>   	return err;
>   }
>
> @@ -752,13 +742,13 @@ static int tpm_st33_i2c_remove(struct i2c_client *client)
>   		((struct i2c_client *)TPM_VPRIV(chip))->dev.platform_data;
>
>   	if (pin_infos != NULL) {
> +		tpm_chip_unregister(chip);
> +
>   		free_irq(pin_infos->io_serirq, chip);
>
>   		gpio_free(pin_infos->io_serirq);
>   		gpio_free(pin_infos->io_lpcpd);
>
> -		tpm_remove_hardware(chip->dev);
> -
>   		if (pin_infos->tpm_i2c_buffer[1] != NULL) {
>   			kzfree(pin_infos->tpm_i2c_buffer[1]);
>   			pin_infos->tpm_i2c_buffer[1] = NULL;
> diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
> index af74c57..eb95796 100644
> --- a/drivers/char/tpm/tpm_ibmvtpm.c
> +++ b/drivers/char/tpm/tpm_ibmvtpm.c
> @@ -270,8 +270,11 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
>   static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
>   {
>   	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
> +	struct tpm_chip *chip = dev_get_drvdata(ibmvtpm->dev);
>   	int rc = 0;
>
> +	tpm_chip_unregister(chip);
> +
>   	free_irq(vdev->irq, ibmvtpm);
>
>   	do {
> @@ -290,8 +293,6 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
>   		kfree(ibmvtpm->rtce_buf);
>   	}
>
> -	tpm_remove_hardware(ibmvtpm->dev);
> -
>   	kfree(ibmvtpm);
>
>   	return 0;
> @@ -555,11 +556,9 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
>   	struct tpm_chip *chip;
>   	int rc = -ENOMEM, rc1;
>
> -	chip = tpm_register_hardware(dev, &tpm_ibmvtpm);
> -	if (!chip) {
> -		dev_err(dev, "tpm_register_hardware failed\n");
> -		return -ENODEV;
> -	}
> +	chip = tpmm_chip_alloc(dev, &tpm_ibmvtpm);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
>   	ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
>   	if (!ibmvtpm) {
> @@ -629,7 +628,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
>   	if (rc)
>   		goto init_irq_cleanup;
>
> -	return rc;
> +	return tpm_chip_register(chip);
>   init_irq_cleanup:
>   	do {
>   		rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
> @@ -644,8 +643,6 @@ cleanup:
>   		kfree(ibmvtpm);
>   	}
>
> -	tpm_remove_hardware(dev);
> -
>   	return rc;
>   }
>
> diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
> index dc0a255..dcdb671 100644
> --- a/drivers/char/tpm/tpm_infineon.c
> +++ b/drivers/char/tpm/tpm_infineon.c
> @@ -546,7 +546,14 @@ static int tpm_inf_pnp_probe(struct pnp_dev *dev,
>   			 vendorid[0], vendorid[1],
>   			 productid[0], productid[1], chipname);
>
> -		if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf)))
> +		chip = tpmm_chip_alloc(&dev->dev, &tpm_inf);
> +		if (IS_ERR(chip)) {
> +			rc = PTR_ERR(chip);
> +			goto err_release_region;
> +		}
> +
> +		rc = tpm_chip_register(chip);
> +		if (rc)
>   			goto err_release_region;
>
>   		return 0;
> @@ -572,17 +579,15 @@ static void tpm_inf_pnp_remove(struct pnp_dev *dev)
>   {
>   	struct tpm_chip *chip = pnp_get_drvdata(dev);
>
> -	if (chip) {
> -		if (tpm_dev.iotype == TPM_INF_IO_PORT) {
> -			release_region(tpm_dev.data_regs, tpm_dev.data_size);
> -			release_region(tpm_dev.config_port,
> -				       tpm_dev.config_size);
> -		} else {
> -			iounmap(tpm_dev.mem_base);
> -			release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
> -		}
> -		tpm_dev_vendor_release(chip);
> -		tpm_remove_hardware(chip->dev);
> +	tpm_chip_unregister(chip);
> +
> +	if (tpm_dev.iotype == TPM_INF_IO_PORT) {
> +		release_region(tpm_dev.data_regs, tpm_dev.data_size);
> +		release_region(tpm_dev.config_port,
> +			       tpm_dev.config_size);
> +	} else {
> +		iounmap(tpm_dev.mem_base);
> +		release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
>   	}
>   }
>
> diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
> index 3179ec9..00c5470 100644
> --- a/drivers/char/tpm/tpm_nsc.c
> +++ b/drivers/char/tpm/tpm_nsc.c
> @@ -247,10 +247,9 @@ static struct platform_device *pdev = NULL;
>   static void tpm_nsc_remove(struct device *dev)
>   {
>   	struct tpm_chip *chip = dev_get_drvdata(dev);
> -	if ( chip ) {
> -		release_region(chip->vendor.base, 2);
> -		tpm_remove_hardware(chip->dev);
> -	}
> +
> +	tpm_chip_unregister(chip);
> +	release_region(chip->vendor.base, 2);
>   }
>
>   static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume);
> @@ -308,11 +307,16 @@ static int __init init_nsc(void)
>   		goto err_del_dev;
>   	}
>
> -	if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) {
> +	chip = tpmm_chip_alloc(&pdev->dev, &tpm_nsc);
> +	if (IS_ERR(chip)) {
>   		rc = -ENODEV;
>   		goto err_rel_reg;
>   	}
>
> +	rc = tpm_chip_register(chip);
> +	if (rc)
> +		goto err_rel_reg;
> +
>   	dev_dbg(&pdev->dev, "NSC TPM detected\n");
>   	dev_dbg(&pdev->dev,
>   		"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
> diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
> index 2c46734..0066b68 100644
> --- a/drivers/char/tpm/tpm_tis.c
> +++ b/drivers/char/tpm/tpm_tis.c
> @@ -75,9 +75,6 @@ enum tis_defaults {
>   #define	TPM_DID_VID(l)			(0x0F00 | ((l) << 12))
>   #define	TPM_RID(l)			(0x0F04 | ((l) << 12))
>
> -static LIST_HEAD(tis_chips);
> -static DEFINE_MUTEX(tis_lock);
> -
>   #if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
>   static int is_itpm(struct pnp_dev *dev)
>   {
> @@ -528,6 +525,17 @@ static bool interrupts = true;
>   module_param(interrupts, bool, 0444);
>   MODULE_PARM_DESC(interrupts, "Enable interrupts");
>
> +static void tpm_tis_remove(struct tpm_chip *chip)
> +{
> +	iowrite32(~TPM_GLOBAL_INT_ENABLE &
> +		  ioread32(chip->vendor.iobase +
> +			   TPM_INT_ENABLE(chip->vendor.
> +					  locality)),
> +		  chip->vendor.iobase +
> +		  TPM_INT_ENABLE(chip->vendor.locality));
> +	release_locality(chip, chip->vendor.locality, 1);
> +}
> +
>   static int tpm_tis_init(struct device *dev, resource_size_t start,
>   			resource_size_t len, unsigned int irq)
>   {
> @@ -535,14 +543,13 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
>   	int rc, i, irq_s, irq_e, probe;
>   	struct tpm_chip *chip;
>
> -	if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
> -		return -ENODEV;
> +	chip = tpmm_chip_alloc(dev, &tpm_tis);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
> -	chip->vendor.iobase = ioremap(start, len);
> -	if (!chip->vendor.iobase) {
> -		rc = -EIO;
> -		goto out_err;
> -	}
> +	chip->vendor.iobase = devm_ioremap(dev, start, len);
> +	if (!chip->vendor.iobase)
> +		return -EIO;
>
>   	/* Default timeouts */
>   	chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
> @@ -649,8 +656,8 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
>   		for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
>   			iowrite8(i, chip->vendor.iobase +
>   				 TPM_INT_VECTOR(chip->vendor.locality));
> -			if (request_irq
> -			    (i, tis_int_probe, IRQF_SHARED,
> +			if (devm_request_irq
> +			    (dev, i, tis_int_probe, IRQF_SHARED,
>   			     chip->vendor.miscdev.name, chip) != 0) {
>   				dev_info(chip->dev,
>   					 "Unable to request irq: %d for probe\n",
> @@ -690,15 +697,14 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
>   			iowrite32(intmask,
>   				  chip->vendor.iobase +
>   				  TPM_INT_ENABLE(chip->vendor.locality));
> -			free_irq(i, chip);
>   		}
>   	}
>   	if (chip->vendor.irq) {
>   		iowrite8(chip->vendor.irq,
>   			 chip->vendor.iobase +
>   			 TPM_INT_VECTOR(chip->vendor.locality));
> -		if (request_irq
> -		    (chip->vendor.irq, tis_int_handler, IRQF_SHARED,
> +		if (devm_request_irq
> +		    (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
>   		     chip->vendor.miscdev.name, chip) != 0) {
>   			dev_info(chip->dev,
>   				 "Unable to request irq: %d for use\n",
> @@ -719,17 +725,9 @@ 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);
> -
> -
> -	return 0;
> +	return tpm_chip_register(chip);
>   out_err:
> -	if (chip->vendor.iobase)
> -		iounmap(chip->vendor.iobase);
> -	tpm_remove_hardware(chip->dev);
> +	tpm_tis_remove(chip);
>   	return rc;
>   }
>
> @@ -811,13 +809,10 @@ MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
>   static void tpm_tis_pnp_remove(struct pnp_dev *dev)
>   {
>   	struct tpm_chip *chip = pnp_get_drvdata(dev);
> -
> -	tpm_dev_vendor_release(chip);
> -
> -	kfree(chip);
> +	tpm_chip_unregister(chip);
> +	tpm_tis_remove(chip);
>   }
>
> -
>   static struct pnp_driver tis_pnp_driver = {
>   	.name = "tpm_tis",
>   	.id_table = tpm_pnp_tbl,
> @@ -836,7 +831,7 @@ MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
>
>   static struct platform_driver tis_drv = {
>   	.driver = {
> -		.name = "tpm_tis",
> +		.name		= "tpm_tis",
>   		.owner		= THIS_MODULE,
>   		.pm		= &tpm_tis_pm,
>   	},
> @@ -876,31 +871,16 @@ err_dev:
>
>   static void __exit cleanup_tis(void)
>   {
> -	struct tpm_vendor_specific *i, *j;
>   	struct tpm_chip *chip;
> -	mutex_lock(&tis_lock);
> -	list_for_each_entry_safe(i, j, &tis_chips, list) {
> -		chip = to_tpm_chip(i);
> -		tpm_remove_hardware(chip->dev);
> -		iowrite32(~TPM_GLOBAL_INT_ENABLE &
> -			  ioread32(chip->vendor.iobase +
> -				   TPM_INT_ENABLE(chip->vendor.
> -						  locality)),
> -			  chip->vendor.iobase +
> -			  TPM_INT_ENABLE(chip->vendor.locality));
> -		release_locality(chip, chip->vendor.locality, 1);
> -		if (chip->vendor.irq)
> -			free_irq(chip->vendor.irq, chip);
> -		iounmap(i->iobase);
> -		list_del(&i->list);
> -	}
> -	mutex_unlock(&tis_lock);
>   #ifdef CONFIG_PNP
>   	if (!force) {
>   		pnp_unregister_driver(&tis_pnp_driver);
>   		return;
>   	}
>   #endif
> +	chip = dev_get_drvdata(&pdev->dev);
> +	tpm_chip_unregister(chip);
> +	tpm_tis_remove(chip);
>   	platform_device_unregister(pdev);
>   	platform_driver_unregister(&tis_drv);
>   }
> diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c
> index 441b44e..c3b4f5a 100644
> --- a/drivers/char/tpm/xen-tpmfront.c
> +++ b/drivers/char/tpm/xen-tpmfront.c
> @@ -175,9 +175,9 @@ static int setup_chip(struct device *dev, struct tpm_private *priv)
>   {
>   	struct tpm_chip *chip;
>
> -	chip = tpm_register_hardware(dev, &tpm_vtpm);
> -	if (!chip)
> -		return -ENODEV;
> +	chip = tpmm_chip_alloc(dev, &tpm_vtpm);
> +	if (IS_ERR(chip))
> +		return PTR_ERR(chip);
>
>   	init_waitqueue_head(&chip->vendor.read_queue);
>
> @@ -286,6 +286,7 @@ static int tpmfront_probe(struct xenbus_device *dev,
>   		const struct xenbus_device_id *id)
>   {
>   	struct tpm_private *priv;
> +	struct tpm_chip *chip;
>   	int rv;
>
>   	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> @@ -302,21 +303,22 @@ static int tpmfront_probe(struct xenbus_device *dev,
>
>   	rv = setup_ring(dev, priv);
>   	if (rv) {
> -		tpm_remove_hardware(&dev->dev);
> +		chip = dev_get_drvdata(&dev->dev);
> +		tpm_chip_unregister(chip);
>   		ring_free(priv);
>   		return rv;
>   	}
>
>   	tpm_get_timeouts(priv->chip);
>
> -	return rv;
> +	return tpm_chip_register(priv->chip);
>   }
>
>   static int tpmfront_remove(struct xenbus_device *dev)
>   {
>   	struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
>   	struct tpm_private *priv = TPM_VPRIV(chip);
> -	tpm_remove_hardware(&dev->dev);
> +	tpm_chip_unregister(chip);
>   	ring_free(priv);
>   	TPM_VPRIV(chip) = NULL;
>   	return 0;



Reviewed-by: Stefan Berger <stefanb-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 09/10] tpm: TPM 2.0 FIFO Interface
  2014-11-25 21:52     ` Stefan Berger
  (?)
@ 2014-11-26 18:10     ` Jarkko Sakkinen
  -1 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-26 18:10 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Peter Huewe, Ashley Lai, Marcel Selhorst, christophe.ricard,
	josh.triplett, linux-api, linux-kernel, Will Arthur, tpmdd-devel,
	jason.gunthorpe, trousers-tech

On Tue, Nov 25, 2014 at 04:52:07PM -0500, Stefan Berger wrote:
> On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> >From: Will Arthur <will.c.arthur@intel.com>
> >
> >Detect TPM 2.0 by using the extended STS (STS3) register. For TPM 2.0,
> >instead of calling tpm_get_timeouts(), assign duration and timeout
> >values defined in the TPM 2.0 PTP specification.
> >
> >Signed-off-by: Will Arthur <will.c.arthur@intel.com>
> >Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> >---
> >  drivers/char/tpm/tpm_tis.c | 71 ++++++++++++++++++++++++++++++++++++----------
> >  1 file changed, 56 insertions(+), 15 deletions(-)
> >
> >diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
> >index 7a2c59b..0b3c089 100644
> >--- a/drivers/char/tpm/tpm_tis.c
> >+++ b/drivers/char/tpm/tpm_tis.c
> >@@ -1,5 +1,6 @@
> >  /*
> >   * Copyright (C) 2005, 2006 IBM Corporation
> >+ * Copyright (C) 2014 Intel Corporation
> >   *
> >   * Authors:
> >   * Leendert van Doorn <leendert@watson.ibm.com>
> >@@ -44,6 +45,10 @@ enum tis_status {
> >  	TPM_STS_DATA_EXPECT = 0x08,
> >  };
> >
> >+enum tis_status3 {
> >+	TPM_STS3_TPM2_FAM = 0x04,
> >+};
> >+
> >  enum tis_int_flags {
> >  	TPM_GLOBAL_INT_ENABLE = 0x80000000,
> >  	TPM_INTF_BURST_COUNT_STATIC = 0x100,
> >@@ -70,6 +75,7 @@ enum tis_defaults {
> >  #define	TPM_INT_STATUS(l)		(0x0010 | ((l) << 12))
> >  #define	TPM_INTF_CAPS(l)		(0x0014 | ((l) << 12))
> >  #define	TPM_STS(l)			(0x0018 | ((l) << 12))
> >+#define	TPM_STS3(l)			(0x001b | ((l) << 12))
> >  #define	TPM_DATA_FIFO(l)		(0x0024 | ((l) << 12))
> >
> >  #define	TPM_DID_VID(l)			(0x0F00 | ((l) << 12))
> >@@ -344,6 +350,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
> >  {
> >  	int rc;
> >  	u32 ordinal;
> >+	unsigned long dur;
> >
> >  	rc = tpm_tis_send_data(chip, buf, len);
> >  	if (rc < 0)
> >@@ -355,9 +362,14 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
> >
> >  	if (chip->vendor.irq) {
> >  		ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
> >+
> >+		if (chip->flags & TPM_CHIP_FLAG_TPM2)
> >+			dur = tpm_calc_ordinal_duration(chip, ordinal);
> >+		else
> >+			dur = tpm_calc_ordinal_duration(chip, ordinal);
> >+
> 
> Is this right? Shouldn't you call tpm2_calc_ordinal_duration for TPM2? If
> not don't check the flag but leave comment for why the same function can be
> called for both TPM versions.

No it's not right, it's a mistake. Thanks for noticing this :)

> >  		if (wait_for_tpm_stat
> >-		    (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
> >-		     tpm_calc_ordinal_duration(chip, ordinal),
> >+		    (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur,
> >  		     &chip->vendor.read_queue, false) < 0) {
> >  			rc = -ETIME;
> >  			goto out_err;
> >@@ -543,6 +555,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
> >  	u32 vendor, intfcaps, intmask;
> >  	int rc, i, irq_s, irq_e, probe;
> >  	struct tpm_chip *chip;
> >+	u8 sts3;
> >
> >  	chip = tpmm_chip_alloc(dev, &tpm_tis);
> >  	if (IS_ERR(chip))
> >@@ -554,11 +567,28 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
> >  	if (!chip->vendor.iobase)
> >  		return -EIO;
> >
> >+	sts3 = ioread8(chip->vendor.iobase + TPM_STS3(1));
> >+	if (sts3 & TPM_STS3_TPM2_FAM)
> >+		chip->flags = TPM_CHIP_FLAG_TPM2;
> >+
> >  	/* 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);
> >+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> >+		chip->vendor.timeout_a = usecs_to_jiffies(TPM2_TIMEOUT_A);
> >+		chip->vendor.timeout_b = usecs_to_jiffies(TPM2_TIMEOUT_B);
> >+		chip->vendor.timeout_c = usecs_to_jiffies(TPM2_TIMEOUT_C);
> >+		chip->vendor.timeout_d = usecs_to_jiffies(TPM2_TIMEOUT_D);
> >+		chip->vendor.duration[TPM_SHORT] =
> >+			usecs_to_jiffies(TPM2_DURATION_SHORT);
> >+		chip->vendor.duration[TPM_MEDIUM] =
> >+			usecs_to_jiffies(TPM2_DURATION_MEDIUM);
> >+		chip->vendor.duration[TPM_LONG] =
> >+			usecs_to_jiffies(TPM2_DURATION_LONG);
> >+	} else {
> >+		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);
> >+	}
> >
> >  	if (wait_startup(chip, 0) != 0) {
> >  		rc = -ENODEV;
> >@@ -573,8 +603,8 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
> >  	vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
> >  	chip->vendor.manufacturer_id = vendor;
> >
> >-	dev_info(dev,
> >-		 "1.2 TPM (device-id 0x%X, rev-id %d)\n",
> >+	dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n",
> >+		 (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
> >  		 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
> >
> >  	if (!itpm) {
> >@@ -616,13 +646,17 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
> >  		dev_dbg(dev, "\tData Avail Int Support\n");
> >
> >  	/* get the timeouts before testing for irqs */
> >-	if (tpm_get_timeouts(chip)) {
> >+	if (!(chip->flags & TPM_CHIP_FLAG_TPM2) && 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)) {
> >+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> >+		rc = tpm2_do_selftest(chip);
> >+	else
> >+		rc = tpm_do_selftest(chip);
> >+	if (rc) {
> >  		dev_err(dev, "TPM self test failed\n");
> >  		rc = -ENODEV;
> >  		goto out_err;
> >@@ -683,7 +717,10 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
> >  			chip->vendor.probed_irq = 0;
> >
> >  			/* Generate Interrupts */
> >-			tpm_gen_interrupt(chip);
> >+			if (chip->flags & TPM_CHIP_FLAG_TPM2)
> >+				tpm2_gen_interrupt(chip);
> >+			else
> >+				tpm_gen_interrupt(chip);
> >
> >  			chip->vendor.irq = chip->vendor.probed_irq;
> >
> >@@ -759,14 +796,18 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
> >  static int tpm_tis_resume(struct device *dev)
> >  {
> >  	struct tpm_chip *chip = dev_get_drvdata(dev);
> >-	int ret;
> >+	int ret = 0;
> >
> >  	if (chip->vendor.irq)
> >  		tpm_tis_reenable_interrupts(chip);
> >
> >-	ret = tpm_pm_resume(dev);
> >-	if (!ret)
> >-		tpm_do_selftest(chip);
> >+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> >+		tpm2_do_selftest(chip);
> >+	else {
> >+		ret = tpm_pm_resume(dev);
> >+		if (!ret)
> >+			tpm_do_selftest(chip);
> >+	}
> 
> Only a self test necessary for TPM2 if resuming from ACPI sleep?

AFAIK firmware/BIOS should do TPM2_Startup according to the rules in the
section 12.2.3.2 of the Architecture specification.

> Other parts look good to me.
>    Stefan

/Jarkko

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 09/10] tpm: TPM 2.0 FIFO Interface
@ 2014-11-27  1:38     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-27  1:38 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard, josh.triplett, linux-api, linux-kernel,
	Will Arthur, tpmdd-devel, jason.gunthorpe, trousers-tech

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> From: Will Arthur <will.c.arthur@intel.com>
>
> Detect TPM 2.0 by using the extended STS (STS3) register. For TPM 2.0,
> instead of calling tpm_get_timeouts(), assign duration and timeout
> values defined in the TPM 2.0 PTP specification.


>
> Signed-off-by: Will Arthur <will.c.arthur@intel.com>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> ---
>   drivers/char/tpm/tpm_tis.c | 71 ++++++++++++++++++++++++++++++++++++----------
>   1 file changed, 56 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
> index 7a2c59b..0b3c089 100644
> --- a/drivers/char/tpm/tpm_tis.c
> +++ b/drivers/char/tpm/tpm_tis.c
> @@ -1,5 +1,6 @@
>   /*
>    * Copyright (C) 2005, 2006 IBM Corporation
> + * Copyright (C) 2014 Intel Corporation
>    *
>    * Authors:
>    * Leendert van Doorn <leendert@watson.ibm.com>
> @@ -44,6 +45,10 @@ enum tis_status {
>   	TPM_STS_DATA_EXPECT = 0x08,
>   };
>
> +enum tis_status3 {
> +	TPM_STS3_TPM2_FAM = 0x04,
> +};
> +

I just looked at the specs: You have to define a mask for bits 2 and 3 
-> 0xc0.


> @@ -554,11 +567,28 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   	if (!chip->vendor.iobase)
>   		return -EIO;
>
> +	sts3 = ioread8(chip->vendor.iobase + TPM_STS3(1));
> +	if (sts3 & TPM_STS3_TPM2_FAM)
> +		chip->flags = TPM_CHIP_FLAG_TPM2;

And use the mask here.

((sts3 & XYZ_MASK) == TPM_STS3_TPM2_FAM)
     chip->flags = TPM_CHIP_FLAG_TPM2;

Since the bits 00 indicate TPM 1.2, 01 TPM2 and 10 and 11 are reserved!


    Stefan


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 09/10] tpm: TPM 2.0 FIFO Interface
@ 2014-11-27  1:38     ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-27  1:38 UTC (permalink / raw)
  To: Jarkko Sakkinen, Peter Huewe, Ashley Lai, Marcel Selhorst
  Cc: christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Will Arthur,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> From: Will Arthur <will.c.arthur-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
>
> Detect TPM 2.0 by using the extended STS (STS3) register. For TPM 2.0,
> instead of calling tpm_get_timeouts(), assign duration and timeout
> values defined in the TPM 2.0 PTP specification.


>
> Signed-off-by: Will Arthur <will.c.arthur-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> ---
>   drivers/char/tpm/tpm_tis.c | 71 ++++++++++++++++++++++++++++++++++++----------
>   1 file changed, 56 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
> index 7a2c59b..0b3c089 100644
> --- a/drivers/char/tpm/tpm_tis.c
> +++ b/drivers/char/tpm/tpm_tis.c
> @@ -1,5 +1,6 @@
>   /*
>    * Copyright (C) 2005, 2006 IBM Corporation
> + * Copyright (C) 2014 Intel Corporation
>    *
>    * Authors:
>    * Leendert van Doorn <leendert-aZOuKsOsJu3MbYB6QlFGEg@public.gmane.org>
> @@ -44,6 +45,10 @@ enum tis_status {
>   	TPM_STS_DATA_EXPECT = 0x08,
>   };
>
> +enum tis_status3 {
> +	TPM_STS3_TPM2_FAM = 0x04,
> +};
> +

I just looked at the specs: You have to define a mask for bits 2 and 3 
-> 0xc0.


> @@ -554,11 +567,28 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
>   	if (!chip->vendor.iobase)
>   		return -EIO;
>
> +	sts3 = ioread8(chip->vendor.iobase + TPM_STS3(1));
> +	if (sts3 & TPM_STS3_TPM2_FAM)
> +		chip->flags = TPM_CHIP_FLAG_TPM2;

And use the mask here.

((sts3 & XYZ_MASK) == TPM_STS3_TPM2_FAM)
     chip->flags = TPM_CHIP_FLAG_TPM2;

Since the bits 00 indicate TPM 1.2, 01 TPM2 and 10 and 11 are reserved!


    Stefan

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 01/10] tpm: merge duplicate transmit_cmd() functions
@ 2014-11-27 11:43       ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-27 11:43 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Peter Huewe, Ashley Lai, Marcel Selhorst, christophe.ricard,
	josh.triplett, linux-api, linux-kernel, tpmdd-devel,
	jason.gunthorpe, trousers-tech

On Tue, Nov 25, 2014 at 04:18:39PM -0500, Stefan Berger wrote:
> On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> >Merged transmit_cmd() functions in tpm-interface.c and tpm-sysfs.c.
> >Added "tpm_" prefix for consistency sake. Changed cmd parameter as
> >opaque. This enables to use separate command structures for TPM1
> >and TPM2 commands in future. Loose coupling works fine here.
> >
> >Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> >---
> >  drivers/char/tpm/tpm-interface.c | 49 +++++++++++++++++++++-------------------
> >  drivers/char/tpm/tpm-sysfs.c     | 23 ++-----------------
> >  drivers/char/tpm/tpm.h           |  3 ++-
> >  3 files changed, 30 insertions(+), 45 deletions(-)
> >
> >diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> >index 6af1700..0150b7c 100644
> >--- a/drivers/char/tpm/tpm-interface.c
> >+++ b/drivers/char/tpm/tpm-interface.c
> >@@ -398,9 +398,10 @@ out:
> >  #define TPM_DIGEST_SIZE 20
> >  #define TPM_RET_CODE_IDX 6
> >
> >-static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
> >-			    int len, const char *desc)
> >+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd,
> >+			 int len, const char *desc)
> >  {
> >+	struct tpm_output_header *header;
> >  	int err;
> >
> >  	len = tpm_transmit(chip, (u8 *) cmd, len);
> >@@ -409,7 +410,9 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
> >  	else if (len < TPM_HEADER_SIZE)
> >  		return -EFAULT;
> >
> >-	err = be32_to_cpu(cmd->header.out.return_code);
> >+	header = (struct tpm_output_header *) cmd;
> 
> The cast should not be necessary -- and this change doesn't buy much...
> 
> header = &cmd->header.out;
> 
> Should do the trick without cast.

I changed the cmd parameter opaque to make this function work both with
TPM1 and TPM2 easily so that I do not have to drop everything to 
struct tpm_cmd_t.

I can change this to

header = cmd;

> >+
> >+	err = be32_to_cpu(header->return_code);
> >  	if (err != 0 && desc)
> >  		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
> >
> >@@ -448,7 +451,7 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
> >  		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> >  		tpm_cmd.params.getcap_in.subcap = subcap_id;
> >  	}
> >-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
> >+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
> >  	if (!rc)
> >  		*cap = tpm_cmd.params.getcap_out.cap;
> >  	return rc;
> >@@ -464,8 +467,8 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
> >  	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> >  	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
> >
> >-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> >-			"attempting to determine the timeouts");
> >+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> >+			      "attempting to determine the timeouts");
> >  }
> >  EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
> >
> >@@ -484,8 +487,8 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
> >  	struct tpm_cmd_t start_cmd;
> >  	start_cmd.header.in = tpm_startup_header;
> >  	start_cmd.params.startup_in.startup_type = startup_type;
> >-	return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
> >-			    "attempting to start the TPM");
> >+	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
> >+				"attempting to start the TPM");
> >  }
> >
> >  int tpm_get_timeouts(struct tpm_chip *chip)
> >@@ -500,7 +503,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
> >  	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
> >  	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> >  	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
> >-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
> >+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
> >
> >  	if (rc == TPM_ERR_INVALID_POSTINIT) {
> >  		/* The TPM is not started, we are the first to talk to it.
> >@@ -513,7 +516,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
> >  		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
> >  		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> >  		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
> >-		rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> >+		rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> >  				  NULL);
> >  	}
> >  	if (rc) {
> >@@ -575,8 +578,8 @@ duration:
> >  	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> >  	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
> >
> >-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> >-			"attempting to determine the durations");
> >+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> >+			      "attempting to determine the durations");
> >  	if (rc)
> >  		return rc;
> >
> >@@ -631,8 +634,8 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
> >  	struct tpm_cmd_t cmd;
> >
> >  	cmd.header.in = continue_selftest_header;
> >-	rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
> >-			  "continue selftest");
> >+	rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
> >+			      "continue selftest");
> >  	return rc;
> >  }
> >
> >@@ -672,8 +675,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
> >
> >  	cmd.header.in = pcrread_header;
> >  	cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
> >-	rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
> >-			  "attempting to read a pcr value");
> >+	rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
> >+			      "attempting to read a pcr value");
> >
> >  	if (rc == 0)
> >  		memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
> >@@ -737,8 +740,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
> >  	cmd.header.in = pcrextend_header;
> >  	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
> >  	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
> >-	rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> >-			  "attempting extend a PCR value");
> >+	rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> >+			      "attempting extend a PCR value");
> >
> >  	tpm_chip_put(chip);
> >  	return rc;
> >@@ -817,7 +820,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
> >  	if (chip == NULL)
> >  		return -ENODEV;
> >
> >-	rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
> >+	rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
> >
> >  	tpm_chip_put(chip);
> >  	return rc;
> >@@ -938,14 +941,14 @@ int tpm_pm_suspend(struct device *dev)
> >  		cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
> >  		memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
> >  		       TPM_DIGEST_SIZE);
> >-		rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> >-				  "extending dummy pcr before suspend");
> >+		rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> >+				      "extending dummy pcr before suspend");
> >  	}
> >
> >  	/* now do the actual savestate */
> >  	for (try = 0; try < TPM_RETRY; try++) {
> >  		cmd.header.in = savestate_header;
> >-		rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
> >+		rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
> >
> >  		/*
> >  		 * If the TPM indicates that it is too busy to respond to
> >@@ -1022,7 +1025,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
> >  		tpm_cmd.header.in = tpm_getrandom_header;
> >  		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
> >
> >-		err = transmit_cmd(chip, &tpm_cmd,
> >+		err = tpm_transmit_cmd(chip, &tpm_cmd,
> >  				   TPM_GETRANDOM_RESULT_SIZE + num_bytes,
> >  				   "attempting get random");
> >  		if (err)
> >diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
> >index 01730a2..8ecb052 100644
> >--- a/drivers/char/tpm/tpm-sysfs.c
> >+++ b/drivers/char/tpm/tpm-sysfs.c
> >@@ -20,25 +20,6 @@
> >  #include <linux/device.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 TPM_ORD_READPUBEK cpu_to_be32(124)
> >  static struct tpm_input_header tpm_readpubek_header = {
> >@@ -58,8 +39,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
> >  	struct tpm_chip *chip = dev_get_drvdata(dev);
> >
> >  	tpm_cmd.header.in = tpm_readpubek_header;
> >-	err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
> >-			   "attempting to read the PUBEK");
> >+	err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
> >+			       "attempting to read the PUBEK");
> >  	if (err)
> >  		goto out;
> >
> >diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> >index e4d0888..e638eb0 100644
> >--- a/drivers/char/tpm/tpm.h
> >+++ b/drivers/char/tpm/tpm.h
> >@@ -314,9 +314,10 @@ struct tpm_cmd_t {
> >  } __packed;
> >
> >  ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
> >-
> >  ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
> >  		     size_t bufsiz);
> 
> Delete this prototype ?

tpm-dev.c uses tpm_transmit() and tpm_transmit_cmd() does unnecessary
steps for that use.

> >+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len,
> >+			 const char *desc);
> >  extern int tpm_get_timeouts(struct tpm_chip *);
> >  extern void tpm_gen_interrupt(struct tpm_chip *);
> >  extern int tpm_do_selftest(struct tpm_chip *);
> 
> 
>    Stefan

/Jarkko

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 01/10] tpm: merge duplicate transmit_cmd() functions
@ 2014-11-27 11:43       ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-27 11:43 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Peter Huewe, Ashley Lai, Marcel Selhorst,
	christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Tue, Nov 25, 2014 at 04:18:39PM -0500, Stefan Berger wrote:
> On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> >Merged transmit_cmd() functions in tpm-interface.c and tpm-sysfs.c.
> >Added "tpm_" prefix for consistency sake. Changed cmd parameter as
> >opaque. This enables to use separate command structures for TPM1
> >and TPM2 commands in future. Loose coupling works fine here.
> >
> >Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> >---
> >  drivers/char/tpm/tpm-interface.c | 49 +++++++++++++++++++++-------------------
> >  drivers/char/tpm/tpm-sysfs.c     | 23 ++-----------------
> >  drivers/char/tpm/tpm.h           |  3 ++-
> >  3 files changed, 30 insertions(+), 45 deletions(-)
> >
> >diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> >index 6af1700..0150b7c 100644
> >--- a/drivers/char/tpm/tpm-interface.c
> >+++ b/drivers/char/tpm/tpm-interface.c
> >@@ -398,9 +398,10 @@ out:
> >  #define TPM_DIGEST_SIZE 20
> >  #define TPM_RET_CODE_IDX 6
> >
> >-static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
> >-			    int len, const char *desc)
> >+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd,
> >+			 int len, const char *desc)
> >  {
> >+	struct tpm_output_header *header;
> >  	int err;
> >
> >  	len = tpm_transmit(chip, (u8 *) cmd, len);
> >@@ -409,7 +410,9 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
> >  	else if (len < TPM_HEADER_SIZE)
> >  		return -EFAULT;
> >
> >-	err = be32_to_cpu(cmd->header.out.return_code);
> >+	header = (struct tpm_output_header *) cmd;
> 
> The cast should not be necessary -- and this change doesn't buy much...
> 
> header = &cmd->header.out;
> 
> Should do the trick without cast.

I changed the cmd parameter opaque to make this function work both with
TPM1 and TPM2 easily so that I do not have to drop everything to 
struct tpm_cmd_t.

I can change this to

header = cmd;

> >+
> >+	err = be32_to_cpu(header->return_code);
> >  	if (err != 0 && desc)
> >  		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
> >
> >@@ -448,7 +451,7 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
> >  		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> >  		tpm_cmd.params.getcap_in.subcap = subcap_id;
> >  	}
> >-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
> >+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
> >  	if (!rc)
> >  		*cap = tpm_cmd.params.getcap_out.cap;
> >  	return rc;
> >@@ -464,8 +467,8 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
> >  	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> >  	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
> >
> >-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> >-			"attempting to determine the timeouts");
> >+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> >+			      "attempting to determine the timeouts");
> >  }
> >  EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
> >
> >@@ -484,8 +487,8 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
> >  	struct tpm_cmd_t start_cmd;
> >  	start_cmd.header.in = tpm_startup_header;
> >  	start_cmd.params.startup_in.startup_type = startup_type;
> >-	return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
> >-			    "attempting to start the TPM");
> >+	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
> >+				"attempting to start the TPM");
> >  }
> >
> >  int tpm_get_timeouts(struct tpm_chip *chip)
> >@@ -500,7 +503,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
> >  	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
> >  	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> >  	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
> >-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
> >+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
> >
> >  	if (rc == TPM_ERR_INVALID_POSTINIT) {
> >  		/* The TPM is not started, we are the first to talk to it.
> >@@ -513,7 +516,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
> >  		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
> >  		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> >  		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
> >-		rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> >+		rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> >  				  NULL);
> >  	}
> >  	if (rc) {
> >@@ -575,8 +578,8 @@ duration:
> >  	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
> >  	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
> >
> >-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> >-			"attempting to determine the durations");
> >+	rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> >+			      "attempting to determine the durations");
> >  	if (rc)
> >  		return rc;
> >
> >@@ -631,8 +634,8 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
> >  	struct tpm_cmd_t cmd;
> >
> >  	cmd.header.in = continue_selftest_header;
> >-	rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
> >-			  "continue selftest");
> >+	rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
> >+			      "continue selftest");
> >  	return rc;
> >  }
> >
> >@@ -672,8 +675,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
> >
> >  	cmd.header.in = pcrread_header;
> >  	cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
> >-	rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
> >-			  "attempting to read a pcr value");
> >+	rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
> >+			      "attempting to read a pcr value");
> >
> >  	if (rc == 0)
> >  		memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
> >@@ -737,8 +740,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
> >  	cmd.header.in = pcrextend_header;
> >  	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
> >  	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
> >-	rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> >-			  "attempting extend a PCR value");
> >+	rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> >+			      "attempting extend a PCR value");
> >
> >  	tpm_chip_put(chip);
> >  	return rc;
> >@@ -817,7 +820,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
> >  	if (chip == NULL)
> >  		return -ENODEV;
> >
> >-	rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
> >+	rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
> >
> >  	tpm_chip_put(chip);
> >  	return rc;
> >@@ -938,14 +941,14 @@ int tpm_pm_suspend(struct device *dev)
> >  		cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
> >  		memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
> >  		       TPM_DIGEST_SIZE);
> >-		rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> >-				  "extending dummy pcr before suspend");
> >+		rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
> >+				      "extending dummy pcr before suspend");
> >  	}
> >
> >  	/* now do the actual savestate */
> >  	for (try = 0; try < TPM_RETRY; try++) {
> >  		cmd.header.in = savestate_header;
> >-		rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
> >+		rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
> >
> >  		/*
> >  		 * If the TPM indicates that it is too busy to respond to
> >@@ -1022,7 +1025,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
> >  		tpm_cmd.header.in = tpm_getrandom_header;
> >  		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
> >
> >-		err = transmit_cmd(chip, &tpm_cmd,
> >+		err = tpm_transmit_cmd(chip, &tpm_cmd,
> >  				   TPM_GETRANDOM_RESULT_SIZE + num_bytes,
> >  				   "attempting get random");
> >  		if (err)
> >diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
> >index 01730a2..8ecb052 100644
> >--- a/drivers/char/tpm/tpm-sysfs.c
> >+++ b/drivers/char/tpm/tpm-sysfs.c
> >@@ -20,25 +20,6 @@
> >  #include <linux/device.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 TPM_ORD_READPUBEK cpu_to_be32(124)
> >  static struct tpm_input_header tpm_readpubek_header = {
> >@@ -58,8 +39,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
> >  	struct tpm_chip *chip = dev_get_drvdata(dev);
> >
> >  	tpm_cmd.header.in = tpm_readpubek_header;
> >-	err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
> >-			   "attempting to read the PUBEK");
> >+	err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
> >+			       "attempting to read the PUBEK");
> >  	if (err)
> >  		goto out;
> >
> >diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> >index e4d0888..e638eb0 100644
> >--- a/drivers/char/tpm/tpm.h
> >+++ b/drivers/char/tpm/tpm.h
> >@@ -314,9 +314,10 @@ struct tpm_cmd_t {
> >  } __packed;
> >
> >  ssize_t	tpm_getcap(struct device *, __be32, cap_t *, const char *);
> >-
> >  ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
> >  		     size_t bufsiz);
> 
> Delete this prototype ?

tpm-dev.c uses tpm_transmit() and tpm_transmit_cmd() does unnecessary
steps for that use.

> >+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len,
> >+			 const char *desc);
> >  extern int tpm_get_timeouts(struct tpm_chip *);
> >  extern void tpm_gen_interrupt(struct tpm_chip *);
> >  extern int tpm_do_selftest(struct tpm_chip *);
> 
> 
>    Stefan

/Jarkko

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 04/10] tpm: rename chip->dev to chip->pdev
@ 2014-11-27 14:51       ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-27 14:51 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Peter Huewe, Ashley Lai, Marcel Selhorst, christophe.ricard,
	josh.triplett, linux-api, linux-kernel, tpmdd-devel,
	jason.gunthorpe, trousers-tech

On Tue, Nov 25, 2014 at 04:44:53PM -0500, Stefan Berger wrote:
> On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> >Rename chip->dev to chip->pdev to make it explicit that this not the
> >character device but actually represents the platform device.
> >
> >Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> >
> 
> 
> >diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> >index 69f4003..b3a7c76 100644
> >--- a/drivers/char/tpm/tpm.h
> >+++ b/drivers/char/tpm/tpm.h
> >@@ -98,7 +98,7 @@ struct tpm_vendor_specific {
> >  #define TPM_PPI_VERSION_LEN		3
> >
> >  struct tpm_chip {
> >-	struct device *dev;	/* Device stuff */
> >+	struct device *pdev;	/* Device stuff */
> >  	const struct tpm_class_ops *ops;
> >
> >  	int dev_num;		/* /dev/tpm# */
> 
> So this is the core requiring the renamings.  I assume you got them all and
> none were hidden in #if's or so.

Yup, I basically did :argdo %s/chip->dev/chip->pdev/g for *.[ch].

> Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

/Jarkko

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 04/10] tpm: rename chip->dev to chip->pdev
@ 2014-11-27 14:51       ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-27 14:51 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Peter Huewe, Ashley Lai, Marcel Selhorst,
	christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Tue, Nov 25, 2014 at 04:44:53PM -0500, Stefan Berger wrote:
> On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> >Rename chip->dev to chip->pdev to make it explicit that this not the
> >character device but actually represents the platform device.
> >
> >Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> >
> 
> 
> >diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> >index 69f4003..b3a7c76 100644
> >--- a/drivers/char/tpm/tpm.h
> >+++ b/drivers/char/tpm/tpm.h
> >@@ -98,7 +98,7 @@ struct tpm_vendor_specific {
> >  #define TPM_PPI_VERSION_LEN		3
> >
> >  struct tpm_chip {
> >-	struct device *dev;	/* Device stuff */
> >+	struct device *pdev;	/* Device stuff */
> >  	const struct tpm_class_ops *ops;
> >
> >  	int dev_num;		/* /dev/tpm# */
> 
> So this is the core requiring the renamings.  I assume you got them all and
> none were hidden in #if's or so.

Yup, I basically did :argdo %s/chip->dev/chip->pdev/g for *.[ch].

> Reviewed-by: Stefan Berger <stefanb-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>

/Jarkko

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 08/10] tpm: TPM 2.0 CRB Interface
@ 2014-11-27 15:40       ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-27 15:40 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Peter Huewe, Ashley Lai, Marcel Selhorst, christophe.ricard,
	josh.triplett, linux-api, linux-kernel, tpmdd-devel,
	jason.gunthorpe, trousers-tech

On Wed, Nov 26, 2014 at 09:06:57AM -0500, Stefan Berger wrote:
> On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> >tpm_crb is a driver for TPM 2.0 Command Response Buffer (CRB) Interface
> >as defined in PC Client Platform TPM Profile (PTP) Specification.
> >
> >Only polling and single locality is supported as these are the limitations
> >of the available hardware, Platform Trust Techonlogy (PTT) in Haswell
> >CPUs.
> >
> >The driver always applies CRB with ACPI start because PTT reports using
> >only ACPI start as start method but as a result of my testing it requires
> >also CRB start.
> >
> >Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> >---
> >  drivers/char/tpm/Kconfig   |   9 ++
> >  drivers/char/tpm/Makefile  |   1 +
> >  drivers/char/tpm/tpm_crb.c | 323 +++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 333 insertions(+)
> >  create mode 100644 drivers/char/tpm/tpm_crb.c
> >
> >diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
> >index c54cac3..10c9419 100644
> >--- a/drivers/char/tpm/Kconfig
> >+++ b/drivers/char/tpm/Kconfig
> >@@ -122,4 +122,13 @@ config TCG_XEN
> >  	  To compile this driver as a module, choose M here; the module
> >  	  will be called xen-tpmfront.
> >
> >+config TCG_CRB
> >+	tristate "TPM 2.0 CRB Interface"
> >+	depends on X86 && ACPI
> >+	---help---
> >+	  If you have a TPM security chip that is compliant with the
> >+	  TCG CRB 2.0 TPM specification say Yes and it will be accessible
> >+	  from within Linux.  To compile this driver as a module, choose
> >+	  M here; the module will be called tpm_crb.
> >+
> >  endif # TCG_TPM
> >diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> >index ae56af9..e6d26dd 100644
> >--- a/drivers/char/tpm/Makefile
> >+++ b/drivers/char/tpm/Makefile
> >@@ -22,3 +22,4 @@ obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
> >  obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
> >  obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o
> >  obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
> >+obj-$(CONFIG_TCG_CRB) += tpm_crb.o
> >diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
> >new file mode 100644
> >index 0000000..eb221d5
> >--- /dev/null
> >+++ b/drivers/char/tpm/tpm_crb.c
> >@@ -0,0 +1,323 @@
> >+/*
> >+ * 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;
> >+};
> >+
> >+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),
> >+};
> >+
> >+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 *cca;
> >+	unsigned long cca_pa;
> >+};
> >+
> >+#ifdef CONFIG_PM_SLEEP
> >+int crb_suspend(struct device *dev)
> >+{
> >+	return 0;
> >+}
> >+
> >+static int crb_resume(struct device *dev)
> >+{
> >+	struct tpm_chip *chip = dev_get_drvdata(dev);
> >+
> >+	(void) tpm2_do_selftest(chip);
> >+
> >+	return 0;
> >+}
> >+#endif
> >+
> >+static SIMPLE_DEV_PM_OPS(crb_pm, crb_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(priv->cca->start) & 1) != 1)
> 
> Use a #define rather than the magic '1'.
> 
> 
> >+		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;
> >+	struct crb_control_area *cca;
> >+	unsigned int expected;
> >+	unsigned long offset;
> >+	u8 *resp;
> >+
> >+	cca = priv->cca;
> >+	if (le32_to_cpu(cca->sts) & CRB_CA_STS_ERROR)
> >+		return -EIO;
> >+
> >+	offset = le64_to_cpu(cca->rsp_pa) - priv->cca_pa;
> >+	resp = (u8 *) ((unsigned long) cca + offset);
> 
> make sure that count >= 6?
> 
> >+	memcpy(buf, resp, 6);
> >+	expected = be32_to_cpup((__be32 *) &buf[2]);
> >+
> >+	if (expected > count)
> >+		return -EIO;
> >+
> >+	memcpy(&buf[6], &resp[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;
> >+	struct crb_control_area *cca;
> >+	u8 *cmd;
> >+	int rc = 0;
> >+
> >+	cca = priv->cca;
> >+
> >+	if (len > le32_to_cpu(cca->cmd_size)) {
> >+		dev_err(&chip->dev,
> >+			"invalid command count value %x %zx\n",
> >+			(unsigned int) len,
> >+			(size_t) le32_to_cpu(cca->cmd_size));
> >+		return -E2BIG;
> >+	}
> >+
> >+	cmd = (u8 *) ((unsigned long) cca + le64_to_cpu(cca->cmd_pa) -
> >+		      priv->cca_pa);
> 
> cca = priv->cca per statement above     -> cmd = cca + x - cca = x
> 
> -> cmd = le64_to_cpu(cca->cmd_pa);
> 
> Should do the trick, no ?

Virtual address might be different where CCA is ioremapped.

> >+	memcpy(cmd, buf, len);
> >+
> >+	/* Make sure that cmd is populated before issuing start. */
> >+	wmb();
> >+
> >+	cca->start = cpu_to_le32(1);
> >+	rc = crb_do_acpi_start(chip);
> 
> I had commented on this already. Your TPM seems to no implement the ACPI
> specs properly, or rather the ACPI table is wrong.
> You have to check whether the ACPI function needs to be called. The next TPM
> from a different vendor for whom the ACPI start function is not necessary
> will need this check here since it will give a return code indicating
> failure. Then your TPM won't work anymore! I think you should add a check
> into the crb_do_acpi_start for whether this function needs to be called or
> whether your TPM is being used (vendor check?) and run this start function
> then anyway.

Yes, now that you said I remember you commenting this before.
I'll see what I can do and consider this together with the good remarks
that are below.

> >+	return rc;
> >+}
> >+
> >+static void crb_cancel(struct tpm_chip *chip)
> >+{
> >+	struct crb_priv *priv = chip->vendor.priv;
> >+	struct crb_control_area *cca;
> >+
> >+	cca = priv->cca;
> >+	cca->cancel = cpu_to_le32(1);
> 
> nit: #define for this ?
> 
> >+
> >+	/* Make sure that cmd is populated before issuing start. */
> >+	wmb();
> >+
> >+	if (crb_do_acpi_start(chip))
> >+		dev_err(&chip->dev, "ACPI Start failed\n");
> >+
> >+	cca->cancel = 0;
> >+}
> >+
> >+static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
> >+{
> >+	struct crb_priv *priv = chip->vendor.priv;
> >+
> >+	return (le32_to_cpu(priv->cca->cancel) & 1) == 1;
> >+}
> >+
> >+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;
> >+	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;
> >+	}
> >+
> >+	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);
> 
> I wonder whether you should check whether that ACPI table is big enough to
> allow you accessing its start_method.
> 
> if (buf->length < sizeof(struct acpi_tpm2) ) {
>     return -EXYZ;
> }
> 
> >+
> >+	if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START)
> >+		priv->flags |= CRB_FL_CRB_START;
> 
> You set this flag but you don't seem to check it anywhere.
> 
> >+
> >+	if (sm == CRB_SM_ACPI_START || sm == CRB_SM_CRB_WITH_ACPI_START)
> >+		priv->flags |= CRB_FL_ACPI_START;
> 
> 
> You set this flag but you don't seem to check it anywhere.
> 
> 
> >+
> >+	priv->cca_pa = le32_to_cpu(buf->control_area_pa);
> >+	priv->cca = (struct crb_control_area *)
> >+		devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000);
> >+	if (!priv->cca) {
> >+		dev_err(dev, "allocating memory failed\n");
> >+		return -ENOMEM;
> >+	}
> >+
> >+	chip->vendor.priv = priv;
> >+
> >+	/* Default timeouts and durations */
> >+	chip->vendor.timeout_a = usecs_to_jiffies(TPM2_TIMEOUT_A);
> >+	chip->vendor.timeout_b = usecs_to_jiffies(TPM2_TIMEOUT_B);
> >+	chip->vendor.timeout_c = usecs_to_jiffies(TPM2_TIMEOUT_C);
> >+	chip->vendor.timeout_d = usecs_to_jiffies(TPM2_TIMEOUT_D);
> >+	chip->vendor.duration[TPM_SHORT] =
> >+		usecs_to_jiffies(TPM2_DURATION_SHORT);
> >+	chip->vendor.duration[TPM_MEDIUM] =
> >+		usecs_to_jiffies(TPM2_DURATION_MEDIUM);
> >+	chip->vendor.duration[TPM_LONG] =
> >+		usecs_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);
> >+}
> >+
> >+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");
> 
> Regards,
>     Stefan

/Jarkko

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 08/10] tpm: TPM 2.0 CRB Interface
@ 2014-11-27 15:40       ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-11-27 15:40 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Peter Huewe, Ashley Lai, Marcel Selhorst,
	christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Wed, Nov 26, 2014 at 09:06:57AM -0500, Stefan Berger wrote:
> On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> >tpm_crb is a driver for TPM 2.0 Command Response Buffer (CRB) Interface
> >as defined in PC Client Platform TPM Profile (PTP) Specification.
> >
> >Only polling and single locality is supported as these are the limitations
> >of the available hardware, Platform Trust Techonlogy (PTT) in Haswell
> >CPUs.
> >
> >The driver always applies CRB with ACPI start because PTT reports using
> >only ACPI start as start method but as a result of my testing it requires
> >also CRB start.
> >
> >Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> >---
> >  drivers/char/tpm/Kconfig   |   9 ++
> >  drivers/char/tpm/Makefile  |   1 +
> >  drivers/char/tpm/tpm_crb.c | 323 +++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 333 insertions(+)
> >  create mode 100644 drivers/char/tpm/tpm_crb.c
> >
> >diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
> >index c54cac3..10c9419 100644
> >--- a/drivers/char/tpm/Kconfig
> >+++ b/drivers/char/tpm/Kconfig
> >@@ -122,4 +122,13 @@ config TCG_XEN
> >  	  To compile this driver as a module, choose M here; the module
> >  	  will be called xen-tpmfront.
> >
> >+config TCG_CRB
> >+	tristate "TPM 2.0 CRB Interface"
> >+	depends on X86 && ACPI
> >+	---help---
> >+	  If you have a TPM security chip that is compliant with the
> >+	  TCG CRB 2.0 TPM specification say Yes and it will be accessible
> >+	  from within Linux.  To compile this driver as a module, choose
> >+	  M here; the module will be called tpm_crb.
> >+
> >  endif # TCG_TPM
> >diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> >index ae56af9..e6d26dd 100644
> >--- a/drivers/char/tpm/Makefile
> >+++ b/drivers/char/tpm/Makefile
> >@@ -22,3 +22,4 @@ obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
> >  obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
> >  obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o
> >  obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
> >+obj-$(CONFIG_TCG_CRB) += tpm_crb.o
> >diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
> >new file mode 100644
> >index 0000000..eb221d5
> >--- /dev/null
> >+++ b/drivers/char/tpm/tpm_crb.c
> >@@ -0,0 +1,323 @@
> >+/*
> >+ * Copyright (C) 2014 Intel Corporation
> >+ *
> >+ * Authors:
> >+ * Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> >+ *
> >+ * Maintained by: <tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
> >+ *
> >+ * 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;
> >+};
> >+
> >+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),
> >+};
> >+
> >+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 *cca;
> >+	unsigned long cca_pa;
> >+};
> >+
> >+#ifdef CONFIG_PM_SLEEP
> >+int crb_suspend(struct device *dev)
> >+{
> >+	return 0;
> >+}
> >+
> >+static int crb_resume(struct device *dev)
> >+{
> >+	struct tpm_chip *chip = dev_get_drvdata(dev);
> >+
> >+	(void) tpm2_do_selftest(chip);
> >+
> >+	return 0;
> >+}
> >+#endif
> >+
> >+static SIMPLE_DEV_PM_OPS(crb_pm, crb_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(priv->cca->start) & 1) != 1)
> 
> Use a #define rather than the magic '1'.
> 
> 
> >+		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;
> >+	struct crb_control_area *cca;
> >+	unsigned int expected;
> >+	unsigned long offset;
> >+	u8 *resp;
> >+
> >+	cca = priv->cca;
> >+	if (le32_to_cpu(cca->sts) & CRB_CA_STS_ERROR)
> >+		return -EIO;
> >+
> >+	offset = le64_to_cpu(cca->rsp_pa) - priv->cca_pa;
> >+	resp = (u8 *) ((unsigned long) cca + offset);
> 
> make sure that count >= 6?
> 
> >+	memcpy(buf, resp, 6);
> >+	expected = be32_to_cpup((__be32 *) &buf[2]);
> >+
> >+	if (expected > count)
> >+		return -EIO;
> >+
> >+	memcpy(&buf[6], &resp[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;
> >+	struct crb_control_area *cca;
> >+	u8 *cmd;
> >+	int rc = 0;
> >+
> >+	cca = priv->cca;
> >+
> >+	if (len > le32_to_cpu(cca->cmd_size)) {
> >+		dev_err(&chip->dev,
> >+			"invalid command count value %x %zx\n",
> >+			(unsigned int) len,
> >+			(size_t) le32_to_cpu(cca->cmd_size));
> >+		return -E2BIG;
> >+	}
> >+
> >+	cmd = (u8 *) ((unsigned long) cca + le64_to_cpu(cca->cmd_pa) -
> >+		      priv->cca_pa);
> 
> cca = priv->cca per statement above     -> cmd = cca + x - cca = x
> 
> -> cmd = le64_to_cpu(cca->cmd_pa);
> 
> Should do the trick, no ?

Virtual address might be different where CCA is ioremapped.

> >+	memcpy(cmd, buf, len);
> >+
> >+	/* Make sure that cmd is populated before issuing start. */
> >+	wmb();
> >+
> >+	cca->start = cpu_to_le32(1);
> >+	rc = crb_do_acpi_start(chip);
> 
> I had commented on this already. Your TPM seems to no implement the ACPI
> specs properly, or rather the ACPI table is wrong.
> You have to check whether the ACPI function needs to be called. The next TPM
> from a different vendor for whom the ACPI start function is not necessary
> will need this check here since it will give a return code indicating
> failure. Then your TPM won't work anymore! I think you should add a check
> into the crb_do_acpi_start for whether this function needs to be called or
> whether your TPM is being used (vendor check?) and run this start function
> then anyway.

Yes, now that you said I remember you commenting this before.
I'll see what I can do and consider this together with the good remarks
that are below.

> >+	return rc;
> >+}
> >+
> >+static void crb_cancel(struct tpm_chip *chip)
> >+{
> >+	struct crb_priv *priv = chip->vendor.priv;
> >+	struct crb_control_area *cca;
> >+
> >+	cca = priv->cca;
> >+	cca->cancel = cpu_to_le32(1);
> 
> nit: #define for this ?
> 
> >+
> >+	/* Make sure that cmd is populated before issuing start. */
> >+	wmb();
> >+
> >+	if (crb_do_acpi_start(chip))
> >+		dev_err(&chip->dev, "ACPI Start failed\n");
> >+
> >+	cca->cancel = 0;
> >+}
> >+
> >+static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
> >+{
> >+	struct crb_priv *priv = chip->vendor.priv;
> >+
> >+	return (le32_to_cpu(priv->cca->cancel) & 1) == 1;
> >+}
> >+
> >+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;
> >+	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;
> >+	}
> >+
> >+	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);
> 
> I wonder whether you should check whether that ACPI table is big enough to
> allow you accessing its start_method.
> 
> if (buf->length < sizeof(struct acpi_tpm2) ) {
>     return -EXYZ;
> }
> 
> >+
> >+	if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START)
> >+		priv->flags |= CRB_FL_CRB_START;
> 
> You set this flag but you don't seem to check it anywhere.
> 
> >+
> >+	if (sm == CRB_SM_ACPI_START || sm == CRB_SM_CRB_WITH_ACPI_START)
> >+		priv->flags |= CRB_FL_ACPI_START;
> 
> 
> You set this flag but you don't seem to check it anywhere.
> 
> 
> >+
> >+	priv->cca_pa = le32_to_cpu(buf->control_area_pa);
> >+	priv->cca = (struct crb_control_area *)
> >+		devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000);
> >+	if (!priv->cca) {
> >+		dev_err(dev, "allocating memory failed\n");
> >+		return -ENOMEM;
> >+	}
> >+
> >+	chip->vendor.priv = priv;
> >+
> >+	/* Default timeouts and durations */
> >+	chip->vendor.timeout_a = usecs_to_jiffies(TPM2_TIMEOUT_A);
> >+	chip->vendor.timeout_b = usecs_to_jiffies(TPM2_TIMEOUT_B);
> >+	chip->vendor.timeout_c = usecs_to_jiffies(TPM2_TIMEOUT_C);
> >+	chip->vendor.timeout_d = usecs_to_jiffies(TPM2_TIMEOUT_D);
> >+	chip->vendor.duration[TPM_SHORT] =
> >+		usecs_to_jiffies(TPM2_DURATION_SHORT);
> >+	chip->vendor.duration[TPM_MEDIUM] =
> >+		usecs_to_jiffies(TPM2_DURATION_MEDIUM);
> >+	chip->vendor.duration[TPM_LONG] =
> >+		usecs_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);
> >+}
> >+
> >+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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>");
> >+MODULE_DESCRIPTION("TPM2 Driver");
> >+MODULE_VERSION("0.1");
> >+MODULE_LICENSE("GPL");
> 
> Regards,
>     Stefan

/Jarkko

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 08/10] tpm: TPM 2.0 CRB Interface
@ 2014-11-28 17:23         ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-28 17:23 UTC (permalink / raw)
  To: Jarkko Sakkinen
  Cc: Peter Huewe, Ashley Lai, Marcel Selhorst, christophe.ricard,
	josh.triplett, linux-api, linux-kernel, tpmdd-devel,
	jason.gunthorpe, trousers-tech

On 11/27/2014 10:40 AM, Jarkko Sakkinen wrote:
> On Wed, Nov 26, 2014 at 09:06:57AM -0500, Stefan Berger wrote:
>> On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
>>> tpm_crb is a driver for TPM 2.0 Command Response Buffer (CRB) Interface
>>> as defined in PC Client Platform TPM Profile (PTP) Specification.
>>>
>>> Only polling and single locality is supported as these are the limitations
>>> of the available hardware, Platform Trust Techonlogy (PTT) in Haswell
>>> CPUs.
>>>
>>> The driver always applies CRB with ACPI start because PTT reports using
>>> only ACPI start as start method but as a result of my testing it requires
>>> also CRB start.
>>>
>>> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
>>> ---
>>>
[...]
>>> +static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
>>> +{
>>> +	struct crb_priv *priv = chip->vendor.priv;
>>> +	struct crb_control_area *cca;
>>> +	u8 *cmd;
>>> +	int rc = 0;
>>> +
>>> +	cca = priv->cca;
>>> +
>>> +	if (len > le32_to_cpu(cca->cmd_size)) {
>>> +		dev_err(&chip->dev,
>>> +			"invalid command count value %x %zx\n",
>>> +			(unsigned int) len,
>>> +			(size_t) le32_to_cpu(cca->cmd_size));
>>> +		return -E2BIG;
>>> +	}
>>> +
>>> +	cmd = (u8 *) ((unsigned long) cca + le64_to_cpu(cca->cmd_pa) -
>>> +		      priv->cca_pa);
>> cca = priv->cca per statement above     -> cmd = cca + x - cca = x
>>
>> -> cmd = le64_to_cpu(cca->cmd_pa);
>>
>> Should do the trick, no ?
> Virtual address might be different where CCA is ioremapped.

My bad. Is the 'Command Address' then guaranteed to lie within the 
remapped area of the 'Control Area' or should there be a check whether 
you would need a separate remapping? It's not clear from the specs where 
it lies (2.1 4th paragraph: "They can all be in system RAM, or all be in 
device memory, or any combination"). Same is true for the 'Response 
Address'.  Maybe you should have the ioremapped address for the 'Command 
Address' calculated elsewhere and simplify the address calculation here 
to basically cmd = priv->command_address.

Make the address calculations in cbr_recv and crb_send look the same.

[So, (cca - priv->cca_pa)  calculates the offset of the remapping. 
Adding to this the address of the command buffer gives the ioremapped 
address of the command buffer, assuming it lies within that remapped area. ]


     Stefan

>
>>> +	memcpy(cmd, buf, len);
>>> +
>>> +	/* Make sure that cmd is populated before issuing start. */
>>> +	wmb();
>>> +
>>> +	cca->start = cpu_to_le32(1);
>>> +	rc = crb_do_acpi_start(chip);


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 08/10] tpm: TPM 2.0 CRB Interface
@ 2014-11-28 17:23         ` Stefan Berger
  0 siblings, 0 replies; 49+ messages in thread
From: Stefan Berger @ 2014-11-28 17:23 UTC (permalink / raw)
  To: Jarkko Sakkinen
  Cc: Peter Huewe, Ashley Lai, Marcel Selhorst,
	christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On 11/27/2014 10:40 AM, Jarkko Sakkinen wrote:
> On Wed, Nov 26, 2014 at 09:06:57AM -0500, Stefan Berger wrote:
>> On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
>>> tpm_crb is a driver for TPM 2.0 Command Response Buffer (CRB) Interface
>>> as defined in PC Client Platform TPM Profile (PTP) Specification.
>>>
>>> Only polling and single locality is supported as these are the limitations
>>> of the available hardware, Platform Trust Techonlogy (PTT) in Haswell
>>> CPUs.
>>>
>>> The driver always applies CRB with ACPI start because PTT reports using
>>> only ACPI start as start method but as a result of my testing it requires
>>> also CRB start.
>>>
>>> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
>>> ---
>>>
[...]
>>> +static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
>>> +{
>>> +	struct crb_priv *priv = chip->vendor.priv;
>>> +	struct crb_control_area *cca;
>>> +	u8 *cmd;
>>> +	int rc = 0;
>>> +
>>> +	cca = priv->cca;
>>> +
>>> +	if (len > le32_to_cpu(cca->cmd_size)) {
>>> +		dev_err(&chip->dev,
>>> +			"invalid command count value %x %zx\n",
>>> +			(unsigned int) len,
>>> +			(size_t) le32_to_cpu(cca->cmd_size));
>>> +		return -E2BIG;
>>> +	}
>>> +
>>> +	cmd = (u8 *) ((unsigned long) cca + le64_to_cpu(cca->cmd_pa) -
>>> +		      priv->cca_pa);
>> cca = priv->cca per statement above     -> cmd = cca + x - cca = x
>>
>> -> cmd = le64_to_cpu(cca->cmd_pa);
>>
>> Should do the trick, no ?
> Virtual address might be different where CCA is ioremapped.

My bad. Is the 'Command Address' then guaranteed to lie within the 
remapped area of the 'Control Area' or should there be a check whether 
you would need a separate remapping? It's not clear from the specs where 
it lies (2.1 4th paragraph: "They can all be in system RAM, or all be in 
device memory, or any combination"). Same is true for the 'Response 
Address'.  Maybe you should have the ioremapped address for the 'Command 
Address' calculated elsewhere and simplify the address calculation here 
to basically cmd = priv->command_address.

Make the address calculations in cbr_recv and crb_send look the same.

[So, (cca - priv->cca_pa)  calculates the offset of the remapping. 
Adding to this the address of the command buffer gives the ioremapped 
address of the command buffer, assuming it lies within that remapped area. ]


     Stefan

>
>>> +	memcpy(cmd, buf, len);
>>> +
>>> +	/* Make sure that cmd is populated before issuing start. */
>>> +	wmb();
>>> +
>>> +	cca->start = cpu_to_le32(1);
>>> +	rc = crb_do_acpi_start(chip);

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 08/10] tpm: TPM 2.0 CRB Interface
  2014-11-26 14:06     ` Stefan Berger
  (?)
  (?)
@ 2014-12-01 13:26     ` Jarkko Sakkinen
  -1 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-12-01 13:26 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Peter Huewe, Ashley Lai, Marcel Selhorst, christophe.ricard,
	josh.triplett, linux-api, linux-kernel, tpmdd-devel,
	jason.gunthorpe, trousers-tech

On Wed, Nov 26, 2014 at 09:06:57AM -0500, Stefan Berger wrote:
> On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> >tpm_crb is a driver for TPM 2.0 Command Response Buffer (CRB) Interface
> >as defined in PC Client Platform TPM Profile (PTP) Specification.
> >
> >Only polling and single locality is supported as these are the limitations
> >of the available hardware, Platform Trust Techonlogy (PTT) in Haswell
> >CPUs.
> >
> >The driver always applies CRB with ACPI start because PTT reports using
> >only ACPI start as start method but as a result of my testing it requires
> >also CRB start.
> >
> >Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> >---
> >  drivers/char/tpm/Kconfig   |   9 ++
> >  drivers/char/tpm/Makefile  |   1 +
> >  drivers/char/tpm/tpm_crb.c | 323 +++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 333 insertions(+)
> >  create mode 100644 drivers/char/tpm/tpm_crb.c
> >
> >diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
> >index c54cac3..10c9419 100644
> >--- a/drivers/char/tpm/Kconfig
> >+++ b/drivers/char/tpm/Kconfig
> >@@ -122,4 +122,13 @@ config TCG_XEN
> >  	  To compile this driver as a module, choose M here; the module
> >  	  will be called xen-tpmfront.
> >
> >+config TCG_CRB
> >+	tristate "TPM 2.0 CRB Interface"
> >+	depends on X86 && ACPI
> >+	---help---
> >+	  If you have a TPM security chip that is compliant with the
> >+	  TCG CRB 2.0 TPM specification say Yes and it will be accessible
> >+	  from within Linux.  To compile this driver as a module, choose
> >+	  M here; the module will be called tpm_crb.
> >+
> >  endif # TCG_TPM
> >diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> >index ae56af9..e6d26dd 100644
> >--- a/drivers/char/tpm/Makefile
> >+++ b/drivers/char/tpm/Makefile
> >@@ -22,3 +22,4 @@ obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
> >  obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
> >  obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o
> >  obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
> >+obj-$(CONFIG_TCG_CRB) += tpm_crb.o
> >diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
> >new file mode 100644
> >index 0000000..eb221d5
> >--- /dev/null
> >+++ b/drivers/char/tpm/tpm_crb.c
> >@@ -0,0 +1,323 @@
> >+/*
> >+ * 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;
> >+};
> >+
> >+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),
> >+};
> >+
> >+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 *cca;
> >+	unsigned long cca_pa;
> >+};
> >+
> >+#ifdef CONFIG_PM_SLEEP
> >+int crb_suspend(struct device *dev)
> >+{
> >+	return 0;
> >+}
> >+
> >+static int crb_resume(struct device *dev)
> >+{
> >+	struct tpm_chip *chip = dev_get_drvdata(dev);
> >+
> >+	(void) tpm2_do_selftest(chip);
> >+
> >+	return 0;
> >+}
> >+#endif
> >+
> >+static SIMPLE_DEV_PM_OPS(crb_pm, crb_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(priv->cca->start) & 1) != 1)
> 
> Use a #define rather than the magic '1'.
> 
> 
> >+		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;
> >+	struct crb_control_area *cca;
> >+	unsigned int expected;
> >+	unsigned long offset;
> >+	u8 *resp;
> >+
> >+	cca = priv->cca;
> >+	if (le32_to_cpu(cca->sts) & CRB_CA_STS_ERROR)
> >+		return -EIO;
> >+
> >+	offset = le64_to_cpu(cca->rsp_pa) - priv->cca_pa;
> >+	resp = (u8 *) ((unsigned long) cca + offset);
> 
> make sure that count >= 6?
> 
> >+	memcpy(buf, resp, 6);
> >+	expected = be32_to_cpup((__be32 *) &buf[2]);
> >+
> >+	if (expected > count)
> >+		return -EIO;
> >+
> >+	memcpy(&buf[6], &resp[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;
> >+	struct crb_control_area *cca;
> >+	u8 *cmd;
> >+	int rc = 0;
> >+
> >+	cca = priv->cca;
> >+
> >+	if (len > le32_to_cpu(cca->cmd_size)) {
> >+		dev_err(&chip->dev,
> >+			"invalid command count value %x %zx\n",
> >+			(unsigned int) len,
> >+			(size_t) le32_to_cpu(cca->cmd_size));
> >+		return -E2BIG;
> >+	}
> >+
> >+	cmd = (u8 *) ((unsigned long) cca + le64_to_cpu(cca->cmd_pa) -
> >+		      priv->cca_pa);
> 
> cca = priv->cca per statement above     -> cmd = cca + x - cca = x
> 
> -> cmd = le64_to_cpu(cca->cmd_pa);
> 
> Should do the trick, no ?
> 
> >+	memcpy(cmd, buf, len);
> >+
> >+	/* Make sure that cmd is populated before issuing start. */
> >+	wmb();
> >+
> >+	cca->start = cpu_to_le32(1);
> >+	rc = crb_do_acpi_start(chip);
> 
> I had commented on this already. Your TPM seems to no implement the ACPI
> specs properly, or rather the ACPI table is wrong.
> You have to check whether the ACPI function needs to be called. The next TPM
> from a different vendor for whom the ACPI start function is not necessary
> will need this check here since it will give a return code indicating
> failure. Then your TPM won't work anymore! I think you should add a check
> into the crb_do_acpi_start for whether this function needs to be called or
> whether your TPM is being used (vendor check?) and run this start function
> then anyway.

PTT (4th Core CRB implementation) seems to report needing ACPI start only but
in practice requires both. I fixed this now by flagging ACPI start with
CRB_FL_ACPI_START always doing cca->start assignment. I added comment to 
document this issue.

Maybe it would good idea to check for MSFT0101 and do assignment of 
CRB_FL_CRB_START if that holds? Then all the quirks would be in the
initialization code.

> >+	return rc;
> >+}
> >+
> >+static void crb_cancel(struct tpm_chip *chip)
> >+{
> >+	struct crb_priv *priv = chip->vendor.priv;
> >+	struct crb_control_area *cca;
> >+
> >+	cca = priv->cca;
> >+	cca->cancel = cpu_to_le32(1);
> 
> nit: #define for this ?
> 
> >+
> >+	/* Make sure that cmd is populated before issuing start. */
> >+	wmb();
> >+
> >+	if (crb_do_acpi_start(chip))
> >+		dev_err(&chip->dev, "ACPI Start failed\n");
> >+
> >+	cca->cancel = 0;
> >+}
> >+
> >+static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
> >+{
> >+	struct crb_priv *priv = chip->vendor.priv;
> >+
> >+	return (le32_to_cpu(priv->cca->cancel) & 1) == 1;
> >+}
> >+
> >+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;
> >+	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;
> >+	}
> >+
> >+	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);
> 
> I wonder whether you should check whether that ACPI table is big enough to
> allow you accessing its start_method.
> 
> if (buf->length < sizeof(struct acpi_tpm2) ) {
>     return -EXYZ;
> }
> 
> >+
> >+	if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START)
> >+		priv->flags |= CRB_FL_CRB_START;
> 
> You set this flag but you don't seem to check it anywhere.
> 
> >+
> >+	if (sm == CRB_SM_ACPI_START || sm == CRB_SM_CRB_WITH_ACPI_START)
> >+		priv->flags |= CRB_FL_ACPI_START;
> 
> 
> You set this flag but you don't seem to check it anywhere.
> >+
> >+	priv->cca_pa = le32_to_cpu(buf->control_area_pa);
> >+	priv->cca = (struct crb_control_area *)
> >+		devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000);
> >+	if (!priv->cca) {
> >+		dev_err(dev, "allocating memory failed\n");
> >+		return -ENOMEM;
> >+	}
> >+
> >+	chip->vendor.priv = priv;
> >+
> >+	/* Default timeouts and durations */
> >+	chip->vendor.timeout_a = usecs_to_jiffies(TPM2_TIMEOUT_A);
> >+	chip->vendor.timeout_b = usecs_to_jiffies(TPM2_TIMEOUT_B);
> >+	chip->vendor.timeout_c = usecs_to_jiffies(TPM2_TIMEOUT_C);
> >+	chip->vendor.timeout_d = usecs_to_jiffies(TPM2_TIMEOUT_D);
> >+	chip->vendor.duration[TPM_SHORT] =
> >+		usecs_to_jiffies(TPM2_DURATION_SHORT);
> >+	chip->vendor.duration[TPM_MEDIUM] =
> >+		usecs_to_jiffies(TPM2_DURATION_MEDIUM);
> >+	chip->vendor.duration[TPM_LONG] =
> >+		usecs_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);
> >+}
> >+
> >+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");
> 
> Regards,
>     Stefan
> 

/Jarkko

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 07/10] tpm: TPM 2.0 baseline support
@ 2014-12-01 17:55       ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-12-01 17:55 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Peter Huewe, Ashley Lai, Marcel Selhorst, christophe.ricard,
	josh.triplett, linux-api, linux-kernel, Will Arthur, tpmdd-devel,
	jason.gunthorpe, trousers-tech

On Tue, Nov 25, 2014 at 07:42:25PM -0500, Stefan Berger wrote:
> On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> >TPM 2.0 devices are separated by adding a field 'flags' to struct
> >tpm_chip and defining a flag TPM_CHIP_FLAG_TPM2 for tagging them.
> >
> >This patch adds the following internal functions:
> >
> >- tpm2_get_random()
> >- tpm2_get_tpm_pt()
> >- tpm2_pcr_extend()
> >- tpm2_pcr_read()
> >- tpm2_startup()
> >
> >Additionally, the following exported functions are implemented for
> >implementing TPM 2.0 device drivers:
> >
> >- tpm2_do_selftest()
> >- tpm2_calc_ordinal_durations()
> >- tpm2_gen_interrupt()
> >
> >The existing functions that are exported for the use for existing
> >subsystems have been changed to check the flags field in struct
> >tpm_chip and use appropriate TPM 2.0 counterpart if
> >TPM_CHIP_FLAG_TPM2 is est.
> >
> >The code for tpm2_calc_ordinal_duration() and tpm2_startup() were
> >originally written by Will Arthur.
> >
> >Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
> >Signed-off-by: Will Arthur <will.c.arthur@intel.com>
> >---
> >  drivers/char/tpm/Makefile        |   2 +-
> >  drivers/char/tpm/tpm-chip.c      |  21 +-
> >  drivers/char/tpm/tpm-interface.c |  24 +-
> >  drivers/char/tpm/tpm.h           |  67 +++++
> >  drivers/char/tpm/tpm2-cmd.c      | 566 +++++++++++++++++++++++++++++++++++++++
> >  5 files changed, 668 insertions(+), 12 deletions(-)
> >  create mode 100644 drivers/char/tpm/tpm2-cmd.c
> >
> >diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> >index 837da04..ae56af9 100644
> >--- a/drivers/char/tpm/Makefile
> >+++ b/drivers/char/tpm/Makefile
> >@@ -2,7 +2,7 @@
> >  # Makefile for the kernel tpm device drivers.
> >  #
> >  obj-$(CONFIG_TCG_TPM) += tpm.o
> >-tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o
> >+tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o
> >  tpm-$(CONFIG_ACPI) += tpm_ppi.o
> >
> >  ifdef CONFIG_ACPI
> >diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> >index 5d268ac..4d25b24 100644
> >--- a/drivers/char/tpm/tpm-chip.c
> >+++ b/drivers/char/tpm/tpm-chip.c
> >@@ -213,11 +213,14 @@ int tpm_chip_register(struct tpm_chip *chip)
> >  	if (rc)
> >  		return rc;
> >
> >-	rc = tpm_add_ppi(chip);
> >-	if (rc)
> >-		goto out_err;
> >+	/* Populate sysfs for TPM1 devices. */
> >+	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
> >+		rc = tpm_add_ppi(chip);
> >+		if (rc)
> >+			goto out_err;
> >
> >-	chip->bios_dir = tpm_bios_log_setup(chip->devname);
> >+		chip->bios_dir = tpm_bios_log_setup(chip->devname);
> >+	}
> >
> >  	/* Make the chip available. */
> >  	spin_lock(&driver_lock);
> >@@ -248,10 +251,12 @@ void tpm_chip_unregister(struct tpm_chip *chip)
> >  	spin_unlock(&driver_lock);
> >  	synchronize_rcu();
> >
> >-	tpm_remove_ppi(chip);
> >-
> >-	if (chip->bios_dir)
> >-		tpm_bios_log_teardown(chip->bios_dir);
> >+	/* Clean up sysfs for TPM1 devices. */
> >+	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
> >+		if (chip->bios_dir)
> >+			tpm_bios_log_teardown(chip->bios_dir);
> >+		tpm_remove_ppi(chip);
> >+	}
> >
> >  	tpm_dev_del_device(chip);
> >  }
> >diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> >index 9e4ce4d..e62b835 100644
> >--- a/drivers/char/tpm/tpm-interface.c
> >+++ b/drivers/char/tpm/tpm-interface.c
> >@@ -360,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
> >  	if (chip->vendor.irq)
> >  		goto out_recv;
> >
> >-	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
> >+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> >+		stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
> >+	else
> >+		stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
> >  	do {
> >  		u8 status = chip->ops->status(chip);
> >  		if ((status & chip->ops->req_complete_mask) ==
> >@@ -483,7 +486,7 @@ static const struct tpm_input_header tpm_startup_header = {
> >  static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
> >  {
> >  	struct tpm_cmd_t start_cmd;
> >-	start_cmd.header.in = tpm_startup_header;
> >+
> >  	start_cmd.params.startup_in.startup_type = startup_type;
> >  	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
> >  				"attempting to start the TPM");
> >@@ -680,7 +683,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
> >  	chip = tpm_chip_find_get(chip_num);
> >  	if (chip == NULL)
> >  		return -ENODEV;
> >-	rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
> >+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> >+		rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
> >+	else
> >+		rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
> >  	tpm_chip_put(chip);
> >  	return rc;
> >  }
> >@@ -714,6 +720,12 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
> >  	if (chip == NULL)
> >  		return -ENODEV;
> >
> >+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> >+		rc = tpm2_pcr_extend(chip, pcr_idx, hash);
> >+		tpm_chip_put(chip);
> >+		return rc;
> >+	}
> >+
> >  	cmd.header.in = pcrextend_header;
> >  	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
> >  	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
> >@@ -974,6 +986,12 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
> >  	if (chip == NULL)
> >  		return -ENODEV;
> >
> >+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> >+		err = tpm2_get_random(chip, out, max);
> >+		tpm_chip_put(chip);
> >+		return err;
> >+	}
> >+
> >  	do {
> >  		tpm_cmd.header.in = tpm_getrandom_header;
> >  		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
> >diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> >index 9d062e6..8a434d2 100644
> >--- a/drivers/char/tpm/tpm.h
> >+++ b/drivers/char/tpm/tpm.h
> >@@ -62,6 +62,57 @@ enum tpm_duration {
> >  #define TPM_ERR_INVALID_POSTINIT 38
> >
> >  #define TPM_HEADER_SIZE		10
> >+
> >+enum tpm2_const {
> >+	TPM2_PLATFORM_PCR	= 24,
> >+	TPM2_PCR_SELECT_MIN	= ((TPM2_PLATFORM_PCR + 7) / 8),
> >+	TPM2_TIMEOUT_A		= 750 * 1000,
> >+	TPM2_TIMEOUT_B		= 2000 * 1000,
> >+	TPM2_TIMEOUT_C		= 200 * 1000,
> >+	TPM2_TIMEOUT_D		= 30 * 1000,
> >+	TPM2_DURATION_SHORT	= 20 * 1000,
> >+	TPM2_DURATION_MEDIUM	= 750 * 1000,
> >+	TPM2_DURATION_LONG	= 2000 * 1000,
> >+};
> >+
> >+enum tpm2_structures {
> >+	TPM2_ST_NO_SESSIONS	= 0x8001,
> >+	TPM2_ST_SESSIONS	= 0x8002,
> >+};
> >+
> >+enum tpm2_return_codes {
> >+	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_GET_CAPABILITY	= 0x017A,
> >+	TPM2_CC_GET_RANDOM	= 0x017B,
> >+	TPM2_CC_PCR_READ	= 0x017E,
> >+	TPM2_CC_PCR_EXTEND	= 0x0182,
> >+	TPM2_CC_LAST		= 0x018F,
> >+};
> >+
> >+enum tpm2_permanent_handles {
> >+	TPM2_RS_PW		= 0x40000009,
> >+};
> >+
> >+enum tpm2_capabilities {
> >+	TPM2_CAP_TPM_PROPERTIES = 6,
> >+};
> >+
> >+enum tpm2_startup_types {
> >+	TPM2_SU_CLEAR	= 0x0000,
> >+	TPM2_SU_STATE	= 0x0001,
> >+};
> >+
> >  struct tpm_chip;
> >
> >  struct tpm_vendor_specific {
> >@@ -96,12 +147,17 @@ struct tpm_vendor_specific {
> >
> >  #define TPM_PPI_VERSION_LEN		3
> >
> >+enum tpm_chip_flags {
> >+	TPM_CHIP_FLAG_TPM2	= BIT(0),
> >+};
> >+
> >  struct tpm_chip {
> >  	struct device *pdev;	/* Device stuff */
> >  	struct device dev;
> >  	struct cdev cdev;
> >
> >  	const struct tpm_class_ops *ops;
> >+	unsigned int flags;
> >
> >  	int dev_num;		/* /dev/tpm# */
> >  	char devname[7];
> >@@ -362,3 +418,14 @@ static inline void tpm_remove_ppi(struct tpm_chip *chip)
> >  {
> >  }
> >  #endif
> >+
> >+int tpm2_startup(struct tpm_chip *chip, __be16 startup_type);
> >+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);
> >+
> >+extern ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
> >+			       u32 *value, const char *desc);
> >+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);
> >diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
> >new file mode 100644
> >index 0000000..458a17d
> >--- /dev/null
> >+++ b/drivers/char/tpm/tpm2-cmd.c
> >@@ -0,0 +1,566 @@
> >+/*
> >+ * 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 */
> >+};
> >+
> >+static const struct tpm_input_header tpm2_startup_header = {
> >+	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
> >+	.length = cpu_to_be32(12),
> 
> 12 -> sizeof(struct tpm_input_header) + sizeof(struct pm2_startup_in)
> 
> >+	.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. When a negative number is
> >+ * returned it remarks a POSIX error code. When a positive number is returned
> >+ * it remarks a TPM error.
> 
> Replace 'When's with 'If's. (when being 'temporal')
> 
> >+ */
> >+int tpm2_startup(struct tpm_chip *chip, __be16 startup_type)
> >+{
> >+	struct tpm2_cmd cmd;
> >+
> >+	cmd.header.in = tpm2_startup_header;
> >+
> >+	cmd.params.startup_in.startup_type = startup_type;
> >+	return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
> >+				"attempting to start the TPM");
> >+}
> >+
> >+#define TPM2_PCR_READ_IN_SIZE \
> >+	(sizeof(struct tpm_input_header) + \
> >+	 sizeof(struct tpm2_pcr_read_in))
> >+
> 
> Ah! You could also use a #define above!
> 
> >+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. When a negative number is
> >+ * returned it remarks a POSIX error code. When a positive number is returned
> >+ * it remarks a TPM error.
> >+ */
> 
> Replace 'When's with 'If's. Also further below.
> 
> >+int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
> >+{
> >+	int rc;
> >+	struct tpm2_cmd cmd;
> >+	u8 *buf;
> >+	int i, j;
> >+
> >+	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;
> >+
> >+	for (i = 0; i < TPM2_PCR_SELECT_MIN; i++) {
> >+		j = pcr_idx - i * 8;
> >+
> >+		cmd.params.pcrread_in.pcr_select[i] =
> >+			(j >= 0 && j < 8) ? 1 << j : 0;
> >+	}
> 
> Umpf - what's this? You need to set the PCR index as an index in the
> bitfield?
> 
> pcr_idx >> 3  gives you the index into the array, assuming that [0] holds
> bits for PCR0 to 7.
> 
> 1 << (pcr_idx & 0x7) gives you the bit to set, assuming bit 0 is to be set
> for PCR 0
> 1 << (7- (pcr_idx & 0x7)) gives you the bit to set, assuming bit 7 is to be
> set for PCR 0.
> 
> 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);

Just sloppy and ugly code that nobody has commented so far and since it has
worked I haven't really give it much thought :) Will definitely clean
that mess, thanks.

/Jarkko

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [tpmdd-devel] [PATCH v7 07/10] tpm: TPM 2.0 baseline support
@ 2014-12-01 17:55       ` Jarkko Sakkinen
  0 siblings, 0 replies; 49+ messages in thread
From: Jarkko Sakkinen @ 2014-12-01 17:55 UTC (permalink / raw)
  To: Stefan Berger
  Cc: Peter Huewe, Ashley Lai, Marcel Selhorst,
	christophe.ricard-Re5JQEeQqe8AvxtiuMwx3w,
	josh.triplett-ral2JQCrhuEAvxtiuMwx3w,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Will Arthur,
	tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	jason.gunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
	trousers-tech-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Tue, Nov 25, 2014 at 07:42:25PM -0500, Stefan Berger wrote:
> On 11/11/2014 08:45 AM, Jarkko Sakkinen wrote:
> >TPM 2.0 devices are separated by adding a field 'flags' to struct
> >tpm_chip and defining a flag TPM_CHIP_FLAG_TPM2 for tagging them.
> >
> >This patch adds the following internal functions:
> >
> >- tpm2_get_random()
> >- tpm2_get_tpm_pt()
> >- tpm2_pcr_extend()
> >- tpm2_pcr_read()
> >- tpm2_startup()
> >
> >Additionally, the following exported functions are implemented for
> >implementing TPM 2.0 device drivers:
> >
> >- tpm2_do_selftest()
> >- tpm2_calc_ordinal_durations()
> >- tpm2_gen_interrupt()
> >
> >The existing functions that are exported for the use for existing
> >subsystems have been changed to check the flags field in struct
> >tpm_chip and use appropriate TPM 2.0 counterpart if
> >TPM_CHIP_FLAG_TPM2 is est.
> >
> >The code for tpm2_calc_ordinal_duration() and tpm2_startup() were
> >originally written by Will Arthur.
> >
> >Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> >Signed-off-by: Will Arthur <will.c.arthur-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> >---
> >  drivers/char/tpm/Makefile        |   2 +-
> >  drivers/char/tpm/tpm-chip.c      |  21 +-
> >  drivers/char/tpm/tpm-interface.c |  24 +-
> >  drivers/char/tpm/tpm.h           |  67 +++++
> >  drivers/char/tpm/tpm2-cmd.c      | 566 +++++++++++++++++++++++++++++++++++++++
> >  5 files changed, 668 insertions(+), 12 deletions(-)
> >  create mode 100644 drivers/char/tpm/tpm2-cmd.c
> >
> >diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> >index 837da04..ae56af9 100644
> >--- a/drivers/char/tpm/Makefile
> >+++ b/drivers/char/tpm/Makefile
> >@@ -2,7 +2,7 @@
> >  # Makefile for the kernel tpm device drivers.
> >  #
> >  obj-$(CONFIG_TCG_TPM) += tpm.o
> >-tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o
> >+tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o
> >  tpm-$(CONFIG_ACPI) += tpm_ppi.o
> >
> >  ifdef CONFIG_ACPI
> >diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> >index 5d268ac..4d25b24 100644
> >--- a/drivers/char/tpm/tpm-chip.c
> >+++ b/drivers/char/tpm/tpm-chip.c
> >@@ -213,11 +213,14 @@ int tpm_chip_register(struct tpm_chip *chip)
> >  	if (rc)
> >  		return rc;
> >
> >-	rc = tpm_add_ppi(chip);
> >-	if (rc)
> >-		goto out_err;
> >+	/* Populate sysfs for TPM1 devices. */
> >+	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
> >+		rc = tpm_add_ppi(chip);
> >+		if (rc)
> >+			goto out_err;
> >
> >-	chip->bios_dir = tpm_bios_log_setup(chip->devname);
> >+		chip->bios_dir = tpm_bios_log_setup(chip->devname);
> >+	}
> >
> >  	/* Make the chip available. */
> >  	spin_lock(&driver_lock);
> >@@ -248,10 +251,12 @@ void tpm_chip_unregister(struct tpm_chip *chip)
> >  	spin_unlock(&driver_lock);
> >  	synchronize_rcu();
> >
> >-	tpm_remove_ppi(chip);
> >-
> >-	if (chip->bios_dir)
> >-		tpm_bios_log_teardown(chip->bios_dir);
> >+	/* Clean up sysfs for TPM1 devices. */
> >+	if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
> >+		if (chip->bios_dir)
> >+			tpm_bios_log_teardown(chip->bios_dir);
> >+		tpm_remove_ppi(chip);
> >+	}
> >
> >  	tpm_dev_del_device(chip);
> >  }
> >diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> >index 9e4ce4d..e62b835 100644
> >--- a/drivers/char/tpm/tpm-interface.c
> >+++ b/drivers/char/tpm/tpm-interface.c
> >@@ -360,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
> >  	if (chip->vendor.irq)
> >  		goto out_recv;
> >
> >-	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
> >+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> >+		stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
> >+	else
> >+		stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
> >  	do {
> >  		u8 status = chip->ops->status(chip);
> >  		if ((status & chip->ops->req_complete_mask) ==
> >@@ -483,7 +486,7 @@ static const struct tpm_input_header tpm_startup_header = {
> >  static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
> >  {
> >  	struct tpm_cmd_t start_cmd;
> >-	start_cmd.header.in = tpm_startup_header;
> >+
> >  	start_cmd.params.startup_in.startup_type = startup_type;
> >  	return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
> >  				"attempting to start the TPM");
> >@@ -680,7 +683,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
> >  	chip = tpm_chip_find_get(chip_num);
> >  	if (chip == NULL)
> >  		return -ENODEV;
> >-	rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
> >+	if (chip->flags & TPM_CHIP_FLAG_TPM2)
> >+		rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
> >+	else
> >+		rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
> >  	tpm_chip_put(chip);
> >  	return rc;
> >  }
> >@@ -714,6 +720,12 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
> >  	if (chip == NULL)
> >  		return -ENODEV;
> >
> >+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> >+		rc = tpm2_pcr_extend(chip, pcr_idx, hash);
> >+		tpm_chip_put(chip);
> >+		return rc;
> >+	}
> >+
> >  	cmd.header.in = pcrextend_header;
> >  	cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
> >  	memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
> >@@ -974,6 +986,12 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
> >  	if (chip == NULL)
> >  		return -ENODEV;
> >
> >+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
> >+		err = tpm2_get_random(chip, out, max);
> >+		tpm_chip_put(chip);
> >+		return err;
> >+	}
> >+
> >  	do {
> >  		tpm_cmd.header.in = tpm_getrandom_header;
> >  		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
> >diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> >index 9d062e6..8a434d2 100644
> >--- a/drivers/char/tpm/tpm.h
> >+++ b/drivers/char/tpm/tpm.h
> >@@ -62,6 +62,57 @@ enum tpm_duration {
> >  #define TPM_ERR_INVALID_POSTINIT 38
> >
> >  #define TPM_HEADER_SIZE		10
> >+
> >+enum tpm2_const {
> >+	TPM2_PLATFORM_PCR	= 24,
> >+	TPM2_PCR_SELECT_MIN	= ((TPM2_PLATFORM_PCR + 7) / 8),
> >+	TPM2_TIMEOUT_A		= 750 * 1000,
> >+	TPM2_TIMEOUT_B		= 2000 * 1000,
> >+	TPM2_TIMEOUT_C		= 200 * 1000,
> >+	TPM2_TIMEOUT_D		= 30 * 1000,
> >+	TPM2_DURATION_SHORT	= 20 * 1000,
> >+	TPM2_DURATION_MEDIUM	= 750 * 1000,
> >+	TPM2_DURATION_LONG	= 2000 * 1000,
> >+};
> >+
> >+enum tpm2_structures {
> >+	TPM2_ST_NO_SESSIONS	= 0x8001,
> >+	TPM2_ST_SESSIONS	= 0x8002,
> >+};
> >+
> >+enum tpm2_return_codes {
> >+	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_GET_CAPABILITY	= 0x017A,
> >+	TPM2_CC_GET_RANDOM	= 0x017B,
> >+	TPM2_CC_PCR_READ	= 0x017E,
> >+	TPM2_CC_PCR_EXTEND	= 0x0182,
> >+	TPM2_CC_LAST		= 0x018F,
> >+};
> >+
> >+enum tpm2_permanent_handles {
> >+	TPM2_RS_PW		= 0x40000009,
> >+};
> >+
> >+enum tpm2_capabilities {
> >+	TPM2_CAP_TPM_PROPERTIES = 6,
> >+};
> >+
> >+enum tpm2_startup_types {
> >+	TPM2_SU_CLEAR	= 0x0000,
> >+	TPM2_SU_STATE	= 0x0001,
> >+};
> >+
> >  struct tpm_chip;
> >
> >  struct tpm_vendor_specific {
> >@@ -96,12 +147,17 @@ struct tpm_vendor_specific {
> >
> >  #define TPM_PPI_VERSION_LEN		3
> >
> >+enum tpm_chip_flags {
> >+	TPM_CHIP_FLAG_TPM2	= BIT(0),
> >+};
> >+
> >  struct tpm_chip {
> >  	struct device *pdev;	/* Device stuff */
> >  	struct device dev;
> >  	struct cdev cdev;
> >
> >  	const struct tpm_class_ops *ops;
> >+	unsigned int flags;
> >
> >  	int dev_num;		/* /dev/tpm# */
> >  	char devname[7];
> >@@ -362,3 +418,14 @@ static inline void tpm_remove_ppi(struct tpm_chip *chip)
> >  {
> >  }
> >  #endif
> >+
> >+int tpm2_startup(struct tpm_chip *chip, __be16 startup_type);
> >+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);
> >+
> >+extern ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
> >+			       u32 *value, const char *desc);
> >+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);
> >diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
> >new file mode 100644
> >index 0000000..458a17d
> >--- /dev/null
> >+++ b/drivers/char/tpm/tpm2-cmd.c
> >@@ -0,0 +1,566 @@
> >+/*
> >+ * Copyright (C) 2014 Intel Corporation
> >+ *
> >+ * Authors:
> >+ * Jarkko Sakkinen <jarkko.sakkinen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> >+ *
> >+ * Maintained by: <tpmdd-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
> >+ *
> >+ * 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 */
> >+};
> >+
> >+static const struct tpm_input_header tpm2_startup_header = {
> >+	.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
> >+	.length = cpu_to_be32(12),
> 
> 12 -> sizeof(struct tpm_input_header) + sizeof(struct pm2_startup_in)
> 
> >+	.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. When a negative number is
> >+ * returned it remarks a POSIX error code. When a positive number is returned
> >+ * it remarks a TPM error.
> 
> Replace 'When's with 'If's. (when being 'temporal')
> 
> >+ */
> >+int tpm2_startup(struct tpm_chip *chip, __be16 startup_type)
> >+{
> >+	struct tpm2_cmd cmd;
> >+
> >+	cmd.header.in = tpm2_startup_header;
> >+
> >+	cmd.params.startup_in.startup_type = startup_type;
> >+	return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
> >+				"attempting to start the TPM");
> >+}
> >+
> >+#define TPM2_PCR_READ_IN_SIZE \
> >+	(sizeof(struct tpm_input_header) + \
> >+	 sizeof(struct tpm2_pcr_read_in))
> >+
> 
> Ah! You could also use a #define above!
> 
> >+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. When a negative number is
> >+ * returned it remarks a POSIX error code. When a positive number is returned
> >+ * it remarks a TPM error.
> >+ */
> 
> Replace 'When's with 'If's. Also further below.
> 
> >+int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
> >+{
> >+	int rc;
> >+	struct tpm2_cmd cmd;
> >+	u8 *buf;
> >+	int i, j;
> >+
> >+	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;
> >+
> >+	for (i = 0; i < TPM2_PCR_SELECT_MIN; i++) {
> >+		j = pcr_idx - i * 8;
> >+
> >+		cmd.params.pcrread_in.pcr_select[i] =
> >+			(j >= 0 && j < 8) ? 1 << j : 0;
> >+	}
> 
> Umpf - what's this? You need to set the PCR index as an index in the
> bitfield?
> 
> pcr_idx >> 3  gives you the index into the array, assuming that [0] holds
> bits for PCR0 to 7.
> 
> 1 << (pcr_idx & 0x7) gives you the bit to set, assuming bit 0 is to be set
> for PCR 0
> 1 << (7- (pcr_idx & 0x7)) gives you the bit to set, assuming bit 7 is to be
> set for PCR 0.
> 
> 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);

Just sloppy and ugly code that nobody has commented so far and since it has
worked I haven't really give it much thought :) Will definitely clean
that mess, thanks.

/Jarkko

^ permalink raw reply	[flat|nested] 49+ messages in thread

end of thread, other threads:[~2014-12-01 17:55 UTC | newest]

Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-11 13:45 [PATCH v7 00/10] TPM 2.0 support Jarkko Sakkinen
2014-11-11 13:45 ` Jarkko Sakkinen
2014-11-11 13:45 ` [PATCH v7 01/10] tpm: merge duplicate transmit_cmd() functions Jarkko Sakkinen
2014-11-11 13:45   ` Jarkko Sakkinen
2014-11-25 21:18   ` [tpmdd-devel] " Stefan Berger
2014-11-27 11:43     ` Jarkko Sakkinen
2014-11-27 11:43       ` Jarkko Sakkinen
2014-11-11 13:45 ` [PATCH v7 02/10] tpm: two-phase chip management functions Jarkko Sakkinen
2014-11-11 13:45   ` Jarkko Sakkinen
2014-11-26 14:38   ` [tpmdd-devel] " Stefan Berger
2014-11-26 14:38     ` Stefan Berger
2014-11-11 13:45 ` [PATCH v7 03/10] tpm: fix multiple race conditions in tpm_ppi.c Jarkko Sakkinen
2014-11-25 21:40   ` [tpmdd-devel] " Stefan Berger
2014-11-11 13:45 ` [PATCH v7 04/10] tpm: rename chip->dev to chip->pdev Jarkko Sakkinen
2014-11-25 21:44   ` [tpmdd-devel] " Stefan Berger
2014-11-25 21:44     ` Stefan Berger
2014-11-27 14:51     ` Jarkko Sakkinen
2014-11-27 14:51       ` Jarkko Sakkinen
2014-11-11 13:45 ` [PATCH v7 05/10] tpm: device class for tpm Jarkko Sakkinen
2014-11-26 12:34   ` [tpmdd-devel] " Stefan Berger
2014-11-26 12:34     ` Stefan Berger
2014-11-11 13:45 ` [PATCH v7 06/10] tpm: fix: move sysfs attributes to the correct place Jarkko Sakkinen
2014-11-18  9:29   ` Jarkko Sakkinen
2014-11-18  9:29     ` Jarkko Sakkinen
2014-11-26  0:48   ` [tpmdd-devel] " Stefan Berger
2014-11-26  0:48     ` Stefan Berger
2014-11-11 13:45 ` [PATCH v7 07/10] tpm: TPM 2.0 baseline support Jarkko Sakkinen
2014-11-26  0:42   ` [tpmdd-devel] " Stefan Berger
2014-11-26  0:42     ` Stefan Berger
2014-12-01 17:55     ` Jarkko Sakkinen
2014-12-01 17:55       ` Jarkko Sakkinen
2014-11-11 13:45 ` [PATCH v7 08/10] tpm: TPM 2.0 CRB Interface Jarkko Sakkinen
2014-11-26 14:06   ` [tpmdd-devel] " Stefan Berger
2014-11-26 14:06     ` Stefan Berger
2014-11-27 15:40     ` Jarkko Sakkinen
2014-11-27 15:40       ` Jarkko Sakkinen
2014-11-28 17:23       ` Stefan Berger
2014-11-28 17:23         ` Stefan Berger
2014-12-01 13:26     ` Jarkko Sakkinen
2014-11-11 13:45 ` [PATCH v7 09/10] tpm: TPM 2.0 FIFO Interface Jarkko Sakkinen
2014-11-25 21:52   ` [tpmdd-devel] " Stefan Berger
2014-11-25 21:52     ` Stefan Berger
2014-11-26 18:10     ` Jarkko Sakkinen
2014-11-27  1:38   ` Stefan Berger
2014-11-27  1:38     ` Stefan Berger
2014-11-11 13:45 ` [PATCH v7 10/10] tpm: TPM 2.0 sysfs attributes Jarkko Sakkinen
2014-11-25 23:55   ` [tpmdd-devel] " Stefan Berger
2014-11-25 23:55     ` Stefan Berger
2014-11-18  6:33 ` [PATCH v7 00/10] TPM 2.0 support Jarkko Sakkinen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.