Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1427206 > unrolled thread
| Started by | Ed Swierk <eswierk@skyportsystems.com> |
|---|---|
| First post | 2016-06-21 04:10 +0200 |
| Last post | 2016-06-22 03:20 +0200 |
| Articles | 12 — 2 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[PATCH v7 0/5] tpm: Command duration logging and chip-specific override Ed Swierk <eswierk@skyportsystems.com> - 2016-06-21 04:10 +0200
[PATCH v7 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk <eswierk@skyportsystems.com> - 2016-06-21 04:10 +0200
[PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk <eswierk@skyportsystems.com> - 2016-06-21 05:00 +0200
Re: [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> - 2016-06-21 23:40 +0200
Re: [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk <eswierk@skyportsystems.com> - 2016-06-22 02:30 +0200
Re: [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> - 2016-06-22 13:00 +0200
[PATCH v8 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk <eswierk@skyportsystems.com> - 2016-06-22 03:20 +0200
[PATCH v8 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk <eswierk@skyportsystems.com> - 2016-06-22 03:20 +0200
[PATCH v8 2/5] tpm: Add optional logging of TPM command durations Ed Swierk <eswierk@skyportsystems.com> - 2016-06-22 03:20 +0200
[PATCH v8 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk <eswierk@skyportsystems.com> - 2016-06-22 03:20 +0200
[PATCH v8 0/5] tpm: Command duration logging and chip-specific override Ed Swierk <eswierk@skyportsystems.com> - 2016-06-22 03:20 +0200
[PATCH v8 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk <eswierk@skyportsystems.com> - 2016-06-22 03:20 +0200
| From | Ed Swierk <eswierk@skyportsystems.com> |
|---|---|
| Date | 2016-06-21 04:10 +0200 |
| Subject | [PATCH v7 0/5] tpm: Command duration logging and chip-specific override |
| Message-ID | <rMj8R-7Dk-3@gated-at.bofh.it> |
v7: Use tpm_getcap() instead of a redundant new function. v6: Split tpm_get_cap_prop() out of tpm_get_timeouts(); always return error on TPM command failure. v5: Use msecs_to_jiffies() instead of * HZ / 1000. v4: Rework tpm_get_timeouts() to allow overriding both timeouts and durations via a single callback. This series - improves TPM command error reporting - adds optional logging of TPM command durations - allows chip-specific override of command durations as well as protocol timeouts - overrides ST19NP18 TPM command duration to avoid lockups Ed Swierk (5): tpm_tis: Improve reporting of IO errors tpm: Add optional logging of TPM command durations tpm: Clean up reading of timeout and duration capabilities tpm: Allow TPM chip drivers to override reported command durations tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup drivers/char/tpm/tpm-interface.c | 212 ++++++++++++++++++++------------------- drivers/char/tpm/tpm_tis.c | 49 ++++----- include/linux/tpm.h | 3 +- 3 files changed, 130 insertions(+), 134 deletions(-) -- 1.9.1
[toc] | [next] | [standalone]
| From | Ed Swierk <eswierk@skyportsystems.com> |
|---|---|
| Date | 2016-06-21 04:10 +0200 |
| Subject | [PATCH v7 1/5] tpm_tis: Improve reporting of IO errors |
| Message-ID | <rMjiy-7VH-5@gated-at.bofh.it> |
| In reply to | #1427206 |
Mysterious TPM behavior can be difficult to track down through all the
layers of software. Add error messages for conditions that should
never happen. Also include the manufacturer ID along with other chip
data printed during init.
Signed-off-by: Ed Swierk <eswierk@skyportsystems.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
drivers/char/tpm/tpm_tis.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 65f7eec..088fa86 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -299,6 +299,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
expected = be32_to_cpu(*(__be32 *) (buf + 2));
if (expected > count) {
+ dev_err(chip->pdev, "Response too long (wanted %zd, got %d)\n",
+ count, expected);
size = -EIO;
goto out;
}
@@ -366,6 +368,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
&chip->vendor.int_queue, false);
status = tpm_tis_status(chip);
if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
+ dev_err(chip->pdev, "Chip not accepting %zd bytes\n",
+ len - count);
rc = -EIO;
goto out_err;
}
@@ -378,6 +382,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
&chip->vendor.int_queue, false);
status = tpm_tis_status(chip);
if ((status & TPM_STS_DATA_EXPECT) != 0) {
+ dev_err(chip->pdev, "Chip not accepting last byte\n");
rc = -EIO;
goto out_err;
}
@@ -689,8 +694,9 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
chip->vendor.manufacturer_id = vendor;
- dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n",
+ dev_info(dev, "%s TPM (manufacturer-id 0x%X, device-id 0x%X, rev-id %d)\n",
(chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
+ chip->vendor.manufacturer_id,
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
if (!itpm) {
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Ed Swierk <eswierk@skyportsystems.com> |
|---|---|
| Date | 2016-06-21 05:00 +0200 |
| Subject | [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities |
| Message-ID | <rMk4W-8hO-3@gated-at.bofh.it> |
| In reply to | #1427206 |
Call tpm_getcap() from tpm_get_timeouts() to eliminate redundant
code. Return all errors to the caller rather than swallowing them
(e.g. when tpm_transmit_cmd() returns nonzero).
Signed-off-by: Ed Swierk <eswierk@skyportsystems.com>
---
drivers/char/tpm/tpm-interface.c | 74 +++++++++++++++-------------------------
1 file changed, 27 insertions(+), 47 deletions(-)
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index cc1e5bc..73c3ee0 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -461,9 +461,19 @@ 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 = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
+
+ if (!rc &&
+ ((subcap_id == TPM_CAP_PROP_TIS_TIMEOUT &&
+ be32_to_cpu(tpm_cmd.header.out.length) != TPM_HEADER_SIZE + 5) ||
+ (subcap_id == TPM_CAP_PROP_TIS_DURATION &&
+ be32_to_cpu(tpm_cmd.header.out.length) != TPM_HEADER_SIZE + 4)))
+ rc = -EINVAL;
+
if (!rc)
*cap = tpm_cmd.params.getcap_out.cap;
+
return rc;
}
@@ -504,48 +514,30 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
int tpm_get_timeouts(struct tpm_chip *chip)
{
- struct tpm_cmd_t tpm_cmd;
+ cap_t cap;
unsigned long new_timeout[4];
unsigned long old_timeout[4];
- struct duration_t *duration_cap;
ssize_t rc;
- tpm_cmd.header.in = tpm_getcap_header;
- 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 = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
-
+ rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
+ "attempting to determine the timeouts");
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->pdev, "Issuing TPM_STARTUP");
+ dev_info(chip->pdev, "Issuing TPM_STARTUP\n");
if (tpm_startup(chip, TPM_ST_CLEAR))
return rc;
- tpm_cmd.header.in = tpm_getcap_header;
- 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 = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
- NULL);
- }
- if (rc) {
- dev_err(chip->pdev,
- "A TPM error (%zd) occurred attempting to determine the timeouts\n",
- rc);
- goto duration;
+ rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
+ "attempting to determine the timeouts");
}
+ if (rc)
+ return rc;
- if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
- be32_to_cpu(tpm_cmd.header.out.length)
- != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
- return -EINVAL;
-
- old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a);
- old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b);
- old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c);
- old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d);
+ old_timeout[0] = be32_to_cpu(cap.timeout.a);
+ old_timeout[1] = be32_to_cpu(cap.timeout.b);
+ old_timeout[2] = be32_to_cpu(cap.timeout.c);
+ old_timeout[3] = be32_to_cpu(cap.timeout.d);
memcpy(new_timeout, old_timeout, sizeof(new_timeout));
/*
@@ -583,29 +575,17 @@ int tpm_get_timeouts(struct tpm_chip *chip)
chip->vendor.timeout_c = usecs_to_jiffies(new_timeout[2]);
chip->vendor.timeout_d = usecs_to_jiffies(new_timeout[3]);
-duration:
- tpm_cmd.header.in = tpm_getcap_header;
- 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_DURATION;
-
- rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
- "attempting to determine the durations");
+ rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_DURATION, &cap,
+ "attempting to determine the durations");
if (rc)
return rc;
- if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
- be32_to_cpu(tpm_cmd.header.out.length)
- != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32))
- return -EINVAL;
-
- duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
chip->vendor.duration[TPM_SHORT] =
- usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
+ usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short));
chip->vendor.duration[TPM_MEDIUM] =
- usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
+ usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium));
chip->vendor.duration[TPM_LONG] =
- usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
+ usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_long));
/* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
* value wrong and apparently reports msecs rather than usecs. So we
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> |
|---|---|
| Date | 2016-06-21 23:40 +0200 |
| Subject | Re: [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities |
| Message-ID | <rMByO-2NM-35@gated-at.bofh.it> |
| In reply to | #1427223 |
On Mon, Jun 20, 2016 at 06:54:00PM -0700, Ed Swierk wrote:
> Call tpm_getcap() from tpm_get_timeouts() to eliminate redundant
> code. Return all errors to the caller rather than swallowing them
> (e.g. when tpm_transmit_cmd() returns nonzero).
>
> Signed-off-by: Ed Swierk <eswierk@skyportsystems.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
/Jarkko
> ---
> drivers/char/tpm/tpm-interface.c | 74 +++++++++++++++-------------------------
> 1 file changed, 27 insertions(+), 47 deletions(-)
>
> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> index cc1e5bc..73c3ee0 100644
> --- a/drivers/char/tpm/tpm-interface.c
> +++ b/drivers/char/tpm/tpm-interface.c
> @@ -461,9 +461,19 @@ 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 = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
> +
> + if (!rc &&
> + ((subcap_id == TPM_CAP_PROP_TIS_TIMEOUT &&
> + be32_to_cpu(tpm_cmd.header.out.length) != TPM_HEADER_SIZE + 5) ||
> + (subcap_id == TPM_CAP_PROP_TIS_DURATION &&
> + be32_to_cpu(tpm_cmd.header.out.length) != TPM_HEADER_SIZE + 4)))
> + rc = -EINVAL;
> +
> if (!rc)
> *cap = tpm_cmd.params.getcap_out.cap;
> +
> return rc;
> }
>
> @@ -504,48 +514,30 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
>
> int tpm_get_timeouts(struct tpm_chip *chip)
> {
> - struct tpm_cmd_t tpm_cmd;
> + cap_t cap;
> unsigned long new_timeout[4];
> unsigned long old_timeout[4];
> - struct duration_t *duration_cap;
> ssize_t rc;
>
> - tpm_cmd.header.in = tpm_getcap_header;
> - 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 = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
> -
> + rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
> + "attempting to determine the timeouts");
> 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->pdev, "Issuing TPM_STARTUP");
> + dev_info(chip->pdev, "Issuing TPM_STARTUP\n");
> if (tpm_startup(chip, TPM_ST_CLEAR))
> return rc;
>
> - tpm_cmd.header.in = tpm_getcap_header;
> - 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 = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> - NULL);
> - }
> - if (rc) {
> - dev_err(chip->pdev,
> - "A TPM error (%zd) occurred attempting to determine the timeouts\n",
> - rc);
> - goto duration;
> + rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
> + "attempting to determine the timeouts");
> }
> + if (rc)
> + return rc;
>
> - if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
> - be32_to_cpu(tpm_cmd.header.out.length)
> - != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
> - return -EINVAL;
> -
> - old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a);
> - old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b);
> - old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c);
> - old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d);
> + old_timeout[0] = be32_to_cpu(cap.timeout.a);
> + old_timeout[1] = be32_to_cpu(cap.timeout.b);
> + old_timeout[2] = be32_to_cpu(cap.timeout.c);
> + old_timeout[3] = be32_to_cpu(cap.timeout.d);
> memcpy(new_timeout, old_timeout, sizeof(new_timeout));
>
> /*
> @@ -583,29 +575,17 @@ int tpm_get_timeouts(struct tpm_chip *chip)
> chip->vendor.timeout_c = usecs_to_jiffies(new_timeout[2]);
> chip->vendor.timeout_d = usecs_to_jiffies(new_timeout[3]);
>
> -duration:
> - tpm_cmd.header.in = tpm_getcap_header;
> - 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_DURATION;
> -
> - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
> - "attempting to determine the durations");
> + rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_DURATION, &cap,
> + "attempting to determine the durations");
> if (rc)
> return rc;
>
> - if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
> - be32_to_cpu(tpm_cmd.header.out.length)
> - != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32))
> - return -EINVAL;
> -
> - duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
> chip->vendor.duration[TPM_SHORT] =
> - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
> + usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short));
> chip->vendor.duration[TPM_MEDIUM] =
> - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
> + usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium));
> chip->vendor.duration[TPM_LONG] =
> - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
> + usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_long));
>
> /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
> * value wrong and apparently reports msecs rather than usecs. So we
> --
> 1.9.1
>
[toc] | [prev] | [next] | [standalone]
| From | Ed Swierk <eswierk@skyportsystems.com> |
|---|---|
| Date | 2016-06-22 02:30 +0200 |
| Subject | Re: [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities |
| Message-ID | <rMEdj-4x1-1@gated-at.bofh.it> |
| In reply to | #1427223 |
On Mon, Jun 20, 2016 at 6:54 PM, Ed Swierk <eswierk@skyportsystems.com> wrote: > --- a/drivers/char/tpm/tpm-interface.c > +++ b/drivers/char/tpm/tpm-interface.c > @@ -461,9 +461,19 @@ 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 = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); > + > + if (!rc && > + ((subcap_id == TPM_CAP_PROP_TIS_TIMEOUT && > + be32_to_cpu(tpm_cmd.header.out.length) != TPM_HEADER_SIZE + 5) || > + (subcap_id == TPM_CAP_PROP_TIS_DURATION && > + be32_to_cpu(tpm_cmd.header.out.length) != TPM_HEADER_SIZE + 4))) > + rc = -EINVAL; > + Woops, a totally innocuous last-minute (post-testing) cleanup broke this code; should be TPM_HEADER_SIZE + 20 and + 16. I'll push out v8 as soon as I redo my tests. --Ed
[toc] | [prev] | [next] | [standalone]
| From | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> |
|---|---|
| Date | 2016-06-22 13:00 +0200 |
| Subject | Re: [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities |
| Message-ID | <rMO30-2iH-19@gated-at.bofh.it> |
| In reply to | #1428275 |
On Tue, Jun 21, 2016 at 05:21:27PM -0700, Ed Swierk wrote: > On Mon, Jun 20, 2016 at 6:54 PM, Ed Swierk <eswierk@skyportsystems.com> wrote: > > --- a/drivers/char/tpm/tpm-interface.c > > +++ b/drivers/char/tpm/tpm-interface.c > > @@ -461,9 +461,19 @@ 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 = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); > > + > > + if (!rc && > > + ((subcap_id == TPM_CAP_PROP_TIS_TIMEOUT && > > + be32_to_cpu(tpm_cmd.header.out.length) != TPM_HEADER_SIZE + 5) || > > + (subcap_id == TPM_CAP_PROP_TIS_DURATION && > > + be32_to_cpu(tpm_cmd.header.out.length) != TPM_HEADER_SIZE + 4))) > > + rc = -EINVAL; > > + > > Woops, a totally innocuous last-minute (post-testing) cleanup broke > this code; should be TPM_HEADER_SIZE + 20 and + 16. I'll push out v8 > as soon as I redo my tests. OK, that's cool. Haven't yet got into testing it anyway. 1. This is too late for 4.8 release. 2. I'm on four week leave starting from week after next week but before I go to my leave I will apply these commits to my master branch so that they get exposure. 3. I try to do testing for my part before going to the leave. > --Ed /Jarkko
[toc] | [prev] | [next] | [standalone]
| From | Ed Swierk <eswierk@skyportsystems.com> |
|---|---|
| Date | 2016-06-22 03:20 +0200 |
| Subject | [PATCH v8 4/5] tpm: Allow TPM chip drivers to override reported command durations |
| Message-ID | <rMEZI-54t-3@gated-at.bofh.it> |
| In reply to | #1427206 |
Some TPM chips report bogus command durations in their capabilities,
just as others report incorrect timeouts. Rework tpm_get_timeouts() to
allow chip drivers to override either via a single callback. Also
clean up handling of TPMs that report milliseconds instead of
microseconds.
Signed-off-by: Ed Swierk <eswierk@skyportsystems.com>
---
drivers/char/tpm/tpm-interface.c | 143 +++++++++++++++++++++------------------
drivers/char/tpm/tpm_tis.c | 35 +++-------
include/linux/tpm.h | 3 +-
3 files changed, 88 insertions(+), 93 deletions(-)
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index b65c139..5f98488 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -514,12 +514,11 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
int tpm_get_timeouts(struct tpm_chip *chip)
{
- cap_t cap;
- unsigned long new_timeout[4];
- unsigned long old_timeout[4];
- ssize_t rc;
+ cap_t cap1, cap2;
+ int rc;
+ struct tpm_vendor_specific orig_vendor;
- rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
+ rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_TIMEOUT, &cap1,
"attempting to determine the timeouts");
if (rc == TPM_ERR_INVALID_POSTINIT) {
/* The TPM is not started, we are the first to talk to it.
@@ -528,77 +527,91 @@ int tpm_get_timeouts(struct tpm_chip *chip)
if (tpm_startup(chip, TPM_ST_CLEAR))
return rc;
- rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
+ rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_TIMEOUT, &cap1,
"attempting to determine the timeouts");
}
if (rc)
return rc;
- old_timeout[0] = be32_to_cpu(cap.timeout.a);
- old_timeout[1] = be32_to_cpu(cap.timeout.b);
- old_timeout[2] = be32_to_cpu(cap.timeout.c);
- old_timeout[3] = be32_to_cpu(cap.timeout.d);
- memcpy(new_timeout, old_timeout, sizeof(new_timeout));
-
- /*
- * Provide ability for vendor overrides of timeout values in case
- * of misreporting.
- */
- if (chip->ops->update_timeouts != NULL)
- chip->vendor.timeout_adjusted =
- chip->ops->update_timeouts(chip, new_timeout);
-
- if (!chip->vendor.timeout_adjusted) {
- /* Don't overwrite default if value is 0 */
- if (new_timeout[0] != 0 && new_timeout[0] < 1000) {
- int i;
-
- /* timeouts in msec rather usec */
- for (i = 0; i != ARRAY_SIZE(new_timeout); i++)
- new_timeout[i] *= 1000;
- chip->vendor.timeout_adjusted = true;
- }
- }
-
- /* Report adjusted timeouts */
- if (chip->vendor.timeout_adjusted) {
- 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],
- old_timeout[2], new_timeout[2],
- old_timeout[3], new_timeout[3]);
- }
-
- chip->vendor.timeout_a = usecs_to_jiffies(new_timeout[0]);
- chip->vendor.timeout_b = usecs_to_jiffies(new_timeout[1]);
- chip->vendor.timeout_c = usecs_to_jiffies(new_timeout[2]);
- chip->vendor.timeout_d = usecs_to_jiffies(new_timeout[3]);
-
- rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_DURATION, &cap,
+ rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_DURATION, &cap2,
"attempting to determine the durations");
if (rc)
return rc;
- chip->vendor.duration[TPM_SHORT] =
- usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short));
- chip->vendor.duration[TPM_MEDIUM] =
- usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium));
- chip->vendor.duration[TPM_LONG] =
- usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_long));
+ be32_to_cpus(&cap1.timeout.a);
+ be32_to_cpus(&cap1.timeout.b);
+ be32_to_cpus(&cap1.timeout.c);
+ be32_to_cpus(&cap1.timeout.d);
+ chip->vendor.timeout_a = usecs_to_jiffies(cap1.timeout.a);
+ chip->vendor.timeout_b = usecs_to_jiffies(cap1.timeout.b);
+ chip->vendor.timeout_c = usecs_to_jiffies(cap1.timeout.c);
+ chip->vendor.timeout_d = usecs_to_jiffies(cap1.timeout.d);
- /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
- * value wrong and apparently reports msecs rather than usecs. So we
- * fix up the resulting too-small TPM_SHORT value to make things work.
- * We also scale the TPM_MEDIUM and -_LONG values by 1000.
- */
- if (chip->vendor.duration[TPM_SHORT] < (HZ / 100)) {
- chip->vendor.duration[TPM_SHORT] = HZ;
- chip->vendor.duration[TPM_MEDIUM] *= 1000;
- chip->vendor.duration[TPM_LONG] *= 1000;
- chip->vendor.duration_adjusted = true;
- dev_info(chip->pdev, "Adjusting TPM timeout parameters.");
+ /* Some TPMs report timeouts in milliseconds rather than
+ microseconds. Use a value between 1 and 1000 as an
+ indication that this is the case. */
+ if (cap1.timeout.a > 0 && cap1.timeout.a < 1000) {
+ chip->vendor.timeout_a = msecs_to_jiffies(cap1.timeout.a);
+ chip->vendor.timeout_b = msecs_to_jiffies(cap1.timeout.b);
+ chip->vendor.timeout_c = msecs_to_jiffies(cap1.timeout.c);
+ chip->vendor.timeout_d = msecs_to_jiffies(cap1.timeout.d);
+ chip->vendor.timeout_adjusted = true;
}
+
+ be32_to_cpus(&cap2.duration.tpm_short);
+ be32_to_cpus(&cap2.duration.tpm_medium);
+ be32_to_cpus(&cap2.duration.tpm_long);
+ chip->vendor.duration[TPM_SHORT] =
+ usecs_to_jiffies(cap2.duration.tpm_short);
+ chip->vendor.duration[TPM_MEDIUM] =
+ usecs_to_jiffies(cap2.duration.tpm_medium);
+ chip->vendor.duration[TPM_LONG] =
+ usecs_to_jiffies(cap2.duration.tpm_long);
+
+ memcpy(&orig_vendor, &chip->vendor, sizeof(orig_vendor));
+
+ /* Interpret duration values between 1 and 10000 as
+ milliseconds to deal with TPMs like the Broadcom BCM0102 in
+ the Dell Latitude D820. */
+ if (cap2.duration.tpm_short > 0 && cap2.duration.tpm_short < 10000) {
+ chip->vendor.duration[TPM_SHORT] =
+ msecs_to_jiffies(cap2.duration.tpm_short);
+ chip->vendor.duration[TPM_MEDIUM] =
+ msecs_to_jiffies(cap2.duration.tpm_medium);
+ chip->vendor.duration[TPM_LONG] =
+ msecs_to_jiffies(cap2.duration.tpm_long);
+ chip->vendor.duration_adjusted = true;
+ }
+
+ if (chip->ops->update_timeouts != NULL)
+ chip->ops->update_timeouts(chip);
+
+ if (chip->vendor.timeout_adjusted) {
+ dev_info(chip->pdev,
+ HW_ERR "Adjusted timeouts: A %u->%uus B %u->%uus"
+ " C %u->%uus D %u->%uus\n",
+ jiffies_to_usecs(orig_vendor.timeout_a),
+ jiffies_to_usecs(chip->vendor.timeout_a),
+ jiffies_to_usecs(orig_vendor.timeout_b),
+ jiffies_to_usecs(chip->vendor.timeout_b),
+ jiffies_to_usecs(orig_vendor.timeout_c),
+ jiffies_to_usecs(chip->vendor.timeout_c),
+ jiffies_to_usecs(orig_vendor.timeout_d),
+ jiffies_to_usecs(chip->vendor.timeout_d));
+ }
+
+ if (chip->vendor.duration_adjusted) {
+ dev_info(chip->pdev,
+ HW_ERR "Adjusted durations: short %u->%uus"
+ " medium %u->%uus long %u->%uus\n",
+ jiffies_to_usecs(orig_vendor.duration[TPM_SHORT]),
+ jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]),
+ jiffies_to_usecs(orig_vendor.duration[TPM_MEDIUM]),
+ jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]),
+ jiffies_to_usecs(orig_vendor.duration[TPM_LONG]),
+ jiffies_to_usecs(chip->vendor.duration[TPM_LONG]));
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(tpm_get_timeouts);
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 088fa86..caf7278 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -475,34 +475,17 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
return rc;
}
-struct tis_vendor_timeout_override {
- u32 did_vid;
- unsigned long timeout_us[4];
-};
-
-static const struct tis_vendor_timeout_override vendor_timeout_overrides[] = {
- /* Atmel 3204 */
- { 0x32041114, { (TIS_SHORT_TIMEOUT*1000), (TIS_LONG_TIMEOUT*1000),
- (TIS_SHORT_TIMEOUT*1000), (TIS_SHORT_TIMEOUT*1000) } },
-};
-
-static bool tpm_tis_update_timeouts(struct tpm_chip *chip,
- unsigned long *timeout_cap)
+static void tpm_tis_update_timeouts(struct tpm_chip *chip)
{
- int i;
- u32 did_vid;
-
- did_vid = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
-
- for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) {
- if (vendor_timeout_overrides[i].did_vid != did_vid)
- continue;
- memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us,
- sizeof(vendor_timeout_overrides[i].timeout_us));
- return true;
+ switch (ioread32(chip->vendor.iobase + TPM_DID_VID(0))) {
+ case 0x32041114: /* Atmel 3204 */
+ 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);
+ chip->vendor.timeout_adjusted = true;
+ break;
}
-
- return false;
}
/*
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 706e63e..2380ebf 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -41,8 +41,7 @@ struct tpm_class_ops {
int (*send) (struct tpm_chip *chip, u8 *buf, size_t len);
void (*cancel) (struct tpm_chip *chip);
u8 (*status) (struct tpm_chip *chip);
- bool (*update_timeouts)(struct tpm_chip *chip,
- unsigned long *timeout_cap);
+ void (*update_timeouts)(struct tpm_chip *chip);
};
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Ed Swierk <eswierk@skyportsystems.com> |
|---|---|
| Date | 2016-06-22 03:20 +0200 |
| Subject | [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors |
| Message-ID | <rMEZI-54t-7@gated-at.bofh.it> |
| In reply to | #1427206 |
Mysterious TPM behavior can be difficult to track down through all the
layers of software. Add error messages for conditions that should
never happen. Also include the manufacturer ID along with other chip
data printed during init.
Signed-off-by: Ed Swierk <eswierk@skyportsystems.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
drivers/char/tpm/tpm_tis.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 65f7eec..088fa86 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -299,6 +299,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
expected = be32_to_cpu(*(__be32 *) (buf + 2));
if (expected > count) {
+ dev_err(chip->pdev, "Response too long (wanted %zd, got %d)\n",
+ count, expected);
size = -EIO;
goto out;
}
@@ -366,6 +368,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
&chip->vendor.int_queue, false);
status = tpm_tis_status(chip);
if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
+ dev_err(chip->pdev, "Chip not accepting %zd bytes\n",
+ len - count);
rc = -EIO;
goto out_err;
}
@@ -378,6 +382,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
&chip->vendor.int_queue, false);
status = tpm_tis_status(chip);
if ((status & TPM_STS_DATA_EXPECT) != 0) {
+ dev_err(chip->pdev, "Chip not accepting last byte\n");
rc = -EIO;
goto out_err;
}
@@ -689,8 +694,9 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
chip->vendor.manufacturer_id = vendor;
- dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n",
+ dev_info(dev, "%s TPM (manufacturer-id 0x%X, device-id 0x%X, rev-id %d)\n",
(chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
+ chip->vendor.manufacturer_id,
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
if (!itpm) {
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Ed Swierk <eswierk@skyportsystems.com> |
|---|---|
| Date | 2016-06-22 03:20 +0200 |
| Subject | [PATCH v8 2/5] tpm: Add optional logging of TPM command durations |
| Message-ID | <rMEZI-54t-13@gated-at.bofh.it> |
| In reply to | #1427206 |
Some TPMs violate their own advertised command durations. This is much
easier to debug with data about how long each command actually takes
to complete. Add debug messages that can be enabled by running
echo -n 'module tpm +p' >/sys/kernel/debug/dynamic_debug/control
on a kernel configured with DYNAMIC_DEBUG=y.
Signed-off-by: Ed Swierk <eswierk@skyportsystems.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
drivers/char/tpm/tpm-interface.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index c50637d..cc1e5bc 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -333,13 +333,14 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
{
ssize_t rc;
u32 count, ordinal;
- unsigned long stop;
+ unsigned long start, stop;
if (bufsiz > TPM_BUFSIZE)
bufsiz = TPM_BUFSIZE;
count = be32_to_cpu(*((__be32 *) (buf + 2)));
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
+ dev_dbg(chip->pdev, "starting command %d count %d\n", ordinal, count);
if (count == 0)
return -ENODATA;
if (count > bufsiz) {
@@ -360,18 +361,24 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
if (chip->vendor.irq)
goto out_recv;
+ start = jiffies;
if (chip->flags & TPM_CHIP_FLAG_TPM2)
- stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
+ stop = start + tpm2_calc_ordinal_duration(chip, ordinal);
else
- stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
+ stop = start + tpm_calc_ordinal_duration(chip, ordinal);
do {
u8 status = chip->ops->status(chip);
if ((status & chip->ops->req_complete_mask) ==
- chip->ops->req_complete_val)
+ chip->ops->req_complete_val) {
+ dev_dbg(chip->pdev, "completed command %d in %d ms\n",
+ ordinal, jiffies_to_msecs(jiffies - start));
goto out_recv;
+ }
if (chip->ops->req_canceled(chip, status)) {
dev_err(chip->pdev, "Operation Canceled\n");
+ dev_dbg(chip->pdev, "canceled command %d after %d ms\n",
+ ordinal, jiffies_to_msecs(jiffies - start));
rc = -ECANCELED;
goto out;
}
@@ -382,6 +389,8 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
chip->ops->cancel(chip);
dev_err(chip->pdev, "Operation Timed out\n");
+ dev_dbg(chip->pdev, "command %d timed out after %d ms\n", ordinal,
+ jiffies_to_msecs(jiffies - start));
rc = -ETIME;
goto out;
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Ed Swierk <eswierk@skyportsystems.com> |
|---|---|
| Date | 2016-06-22 03:20 +0200 |
| Subject | [PATCH v8 3/5] tpm: Clean up reading of timeout and duration capabilities |
| Message-ID | <rMEZI-54t-17@gated-at.bofh.it> |
| In reply to | #1427206 |
Call tpm_getcap() from tpm_get_timeouts() to eliminate redundant
code. Return all errors to the caller rather than swallowing them
(e.g. when tpm_transmit_cmd() returns nonzero).
Signed-off-by: Ed Swierk <eswierk@skyportsystems.com>
---
drivers/char/tpm/tpm-interface.c | 74 +++++++++++++++-------------------------
1 file changed, 27 insertions(+), 47 deletions(-)
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index cc1e5bc..b65c139 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -461,9 +461,19 @@ 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 = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
+
+ if (!rc &&
+ ((subcap_id == TPM_CAP_PROP_TIS_TIMEOUT &&
+ be32_to_cpu(tpm_cmd.header.out.length) != TPM_HEADER_SIZE + 20) ||
+ (subcap_id == TPM_CAP_PROP_TIS_DURATION &&
+ be32_to_cpu(tpm_cmd.header.out.length) != TPM_HEADER_SIZE + 16)))
+ rc = -EINVAL;
+
if (!rc)
*cap = tpm_cmd.params.getcap_out.cap;
+
return rc;
}
@@ -504,48 +514,30 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
int tpm_get_timeouts(struct tpm_chip *chip)
{
- struct tpm_cmd_t tpm_cmd;
+ cap_t cap;
unsigned long new_timeout[4];
unsigned long old_timeout[4];
- struct duration_t *duration_cap;
ssize_t rc;
- tpm_cmd.header.in = tpm_getcap_header;
- 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 = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
-
+ rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
+ "attempting to determine the timeouts");
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->pdev, "Issuing TPM_STARTUP");
+ dev_info(chip->pdev, "Issuing TPM_STARTUP\n");
if (tpm_startup(chip, TPM_ST_CLEAR))
return rc;
- tpm_cmd.header.in = tpm_getcap_header;
- 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 = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
- NULL);
- }
- if (rc) {
- dev_err(chip->pdev,
- "A TPM error (%zd) occurred attempting to determine the timeouts\n",
- rc);
- goto duration;
+ rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
+ "attempting to determine the timeouts");
}
+ if (rc)
+ return rc;
- if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
- be32_to_cpu(tpm_cmd.header.out.length)
- != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
- return -EINVAL;
-
- old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a);
- old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b);
- old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c);
- old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d);
+ old_timeout[0] = be32_to_cpu(cap.timeout.a);
+ old_timeout[1] = be32_to_cpu(cap.timeout.b);
+ old_timeout[2] = be32_to_cpu(cap.timeout.c);
+ old_timeout[3] = be32_to_cpu(cap.timeout.d);
memcpy(new_timeout, old_timeout, sizeof(new_timeout));
/*
@@ -583,29 +575,17 @@ int tpm_get_timeouts(struct tpm_chip *chip)
chip->vendor.timeout_c = usecs_to_jiffies(new_timeout[2]);
chip->vendor.timeout_d = usecs_to_jiffies(new_timeout[3]);
-duration:
- tpm_cmd.header.in = tpm_getcap_header;
- 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_DURATION;
-
- rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
- "attempting to determine the durations");
+ rc = tpm_getcap(chip->pdev, TPM_CAP_PROP_TIS_DURATION, &cap,
+ "attempting to determine the durations");
if (rc)
return rc;
- if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
- be32_to_cpu(tpm_cmd.header.out.length)
- != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32))
- return -EINVAL;
-
- duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
chip->vendor.duration[TPM_SHORT] =
- usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
+ usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short));
chip->vendor.duration[TPM_MEDIUM] =
- usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
+ usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium));
chip->vendor.duration[TPM_LONG] =
- usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
+ usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_long));
/* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
* value wrong and apparently reports msecs rather than usecs. So we
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Ed Swierk <eswierk@skyportsystems.com> |
|---|---|
| Date | 2016-06-22 03:20 +0200 |
| Subject | [PATCH v8 0/5] tpm: Command duration logging and chip-specific override |
| Message-ID | <rMEZI-54t-5@gated-at.bofh.it> |
| In reply to | #1427206 |
v8: Fix v7 goof-up in tpm_getcap(). v7: Use tpm_getcap() instead of a redundant new function. v6: Split tpm_get_cap_prop() out of tpm_get_timeouts(); always return error on TPM command failure. v5: Use msecs_to_jiffies() instead of * HZ / 1000. v4: Rework tpm_get_timeouts() to allow overriding both timeouts and durations via a single callback. This series - improves TPM command error reporting - adds optional logging of TPM command durations - allows chip-specific override of command durations as well as protocol timeouts - overrides ST19NP18 TPM command duration to avoid lockups Ed Swierk (5): tpm_tis: Improve reporting of IO errors tpm: Add optional logging of TPM command durations tpm: Clean up reading of timeout and duration capabilities tpm: Allow TPM chip drivers to override reported command durations tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup drivers/char/tpm/tpm-interface.c | 212 ++++++++++++++++++++------------------- drivers/char/tpm/tpm_tis.c | 49 ++++----- include/linux/tpm.h | 3 +- 3 files changed, 130 insertions(+), 134 deletions(-) -- 1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Ed Swierk <eswierk@skyportsystems.com> |
|---|---|
| Date | 2016-06-22 03:20 +0200 |
| Subject | [PATCH v8 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup |
| Message-ID | <rMEZI-54t-21@gated-at.bofh.it> |
| In reply to | #1428309 |
The STMicro ST19NP18-TPM sometimes takes much longer to execute commands than it reports in its capabilities. For example, command 186 (TPM_FlushSpecific) has been observed to take 14560 msec to complete, far longer than the 3000 msec limit for "short" commands reported by the chip. The behavior has also been seen with command 101 (TPM_GetCapability). Worse, when the tpm_tis driver attempts to cancel the current command (by writing commandReady = 1 to TPM_STS_x), the chip locks up completely, returning all-1s from all memory-mapped register reads. The lockup can be cleared only by resetting the system. The occurrence of this excessive command duration depends on the sequence of commands preceding it. One sequence is creating at least 2 new keys via TPM_CreateWrapKey, then letting the TPM idle for at least 30 seconds, then loading a key via TPM_LoadKey2. The next TPM_FlushSpecific occasionally takes tens of seconds to complete. Another sequence is creating many keys in a row without pause. The TPM_CreateWrapKey operation gets much slower after the first few iterations, as one would expect when the pool of precomputed keys is exhausted. Then after a 35-second pause, the same TPM_LoadKey2 followed by TPM_FlushSpecific sequence triggers the behavior. Our working theory is that this older TPM sometimes pauses to precompute keys, which modern chips implement as a background process. Without access to the chip's implementation details it's impossible to know whether any commands are immune to being blocked by this process. So it seems safest to ignore the chip's reported command durations, and use a value much higher than any observed duration, like 180 sec (which is the duration this chip reports for "long" commands). Signed-off-by: Ed Swierk <eswierk@skyportsystems.com> --- drivers/char/tpm/tpm_tis.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index caf7278..8355b45 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -485,6 +485,12 @@ static void tpm_tis_update_timeouts(struct tpm_chip *chip) chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->vendor.timeout_adjusted = true; break; + case 0x0000104a: /* STMicro ST19NP18-TPM */ + chip->vendor.duration[TPM_SHORT] = 180 * HZ; + chip->vendor.duration[TPM_MEDIUM] = 180 * HZ; + chip->vendor.duration[TPM_LONG] = 180 * HZ; + chip->vendor.duration_adjusted = true; + break; } } -- 1.9.1
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web