* [PATCH v4 0/4] tpm: Command duration logging and chip-specific override @ 2016-06-08 0:45 Ed Swierk 2016-06-08 0:45 ` [PATCH v4 1/4] tpm_tis: Improve reporting of IO errors Ed Swierk ` (4 more replies) 0 siblings, 5 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-08 0:45 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module 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 (4): tpm_tis: Improve reporting of IO errors tpm: Add optional logging of TPM command durations 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 | 194 ++++++++++++++++++++++----------------- drivers/char/tpm/tpm_tis.c | 48 +++++----- include/linux/tpm.h | 3 +- 3 files changed, 131 insertions(+), 114 deletions(-) -- 1.9.1 ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v4 1/4] tpm_tis: Improve reporting of IO errors 2016-06-08 0:45 [PATCH v4 0/4] tpm: Command duration logging and chip-specific override Ed Swierk @ 2016-06-08 0:45 ` Ed Swierk 2016-06-08 0:45 ` [PATCH v4 2/4] tpm: Add optional logging of TPM command durations Ed Swierk ` (3 subsequent siblings) 4 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-08 0:45 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v4 2/4] tpm: Add optional logging of TPM command durations 2016-06-08 0:45 [PATCH v4 0/4] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-08 0:45 ` [PATCH v4 1/4] tpm_tis: Improve reporting of IO errors Ed Swierk @ 2016-06-08 0:45 ` Ed Swierk 2016-06-08 0:45 ` [PATCH v4 3/4] tpm: Allow TPM chip drivers to override reported " Ed Swierk ` (2 subsequent siblings) 4 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-08 0:45 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v4 3/4] tpm: Allow TPM chip drivers to override reported command durations 2016-06-08 0:45 [PATCH v4 0/4] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-08 0:45 ` [PATCH v4 1/4] tpm_tis: Improve reporting of IO errors Ed Swierk 2016-06-08 0:45 ` [PATCH v4 2/4] tpm: Add optional logging of TPM command durations Ed Swierk @ 2016-06-08 0:45 ` Ed Swierk 2016-06-08 19:05 ` [tpmdd-devel] " Jason Gunthorpe 2016-06-08 0:45 ` [PATCH v4 4/4] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk 2016-06-08 23:00 ` [PATCH v5 0/4] tpm: Command duration logging and chip-specific override Ed Swierk 4 siblings, 1 reply; 68+ messages in thread From: Ed Swierk @ 2016-06-08 0:45 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module 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 | 177 +++++++++++++++++++++------------------ drivers/char/tpm/tpm_tis.c | 35 ++------ include/linux/tpm.h | 3 +- 3 files changed, 106 insertions(+), 109 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index cc1e5bc..b8a08bb 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -502,123 +502,138 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) "attempting to start the TPM"); } -int tpm_get_timeouts(struct tpm_chip *chip) +static int tpm_get_cap_prop(struct tpm_chip *chip, __be32 type, int size, + cap_t *cap, char *desc) { struct tpm_cmd_t tpm_cmd; - 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; + tpm_cmd.params.getcap_in.subcap = type; 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. 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; + tpm_cmd.params.getcap_in.subcap = type; 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; + "Error %zd reading %s\n", rc, desc); + return -EINVAL; } 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)) + != sizeof(tpm_cmd.header.out) + sizeof(u32) + size * sizeof(u32)) { + dev_err(chip->pdev, + "Bad return code or length reading %s\n", desc); 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); - 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]); - } + memcpy(cap, &tpm_cmd.params.getcap_out.cap, sizeof(cap_t)); - 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]); + return 0; +} -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; +int tpm_get_timeouts(struct tpm_chip *chip) +{ + cap_t cap1, cap2; + int rc1, rc2; + struct tpm_vendor_specific orig_vendor; + + rc1 = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_TIMEOUT, 4, &cap1, + "timeouts"); + if (rc1 == 0) { + 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); + } + rc2 = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_DURATION, 3, &cap2, + "durations"); + if (rc2 == 0) { + 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); + } - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the durations"); - if (rc) - return rc; + memcpy(&orig_vendor, &chip->vendor, sizeof(orig_vendor)); + + /* 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 (rc1 == 0 && 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; + } + /* Interpret duration values between 1 and 10000 as + milliseconds to deal with TPMs like the Broadcom BCM0102 in + the Dell Latitude D820. */ + if (rc2 == 0 && 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 (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; + if (chip->ops->update_timeouts != NULL) + chip->ops->update_timeouts(chip); - duration_cap = &tpm_cmd.params.getcap_out.cap.duration; - chip->vendor.duration[TPM_SHORT] = - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); - chip->vendor.duration[TPM_MEDIUM] = - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); - chip->vendor.duration[TPM_LONG] = - usecs_to_jiffies(be32_to_cpu(duration_cap->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 - * 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."); + 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..5c74980 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 = TIS_SHORT_TIMEOUT * HZ / 1000; + chip->vendor.timeout_b = TIS_LONG_TIMEOUT * HZ / 1000; + chip->vendor.timeout_c = TIS_SHORT_TIMEOUT * HZ / 1000; + chip->vendor.timeout_d = TIS_SHORT_TIMEOUT * HZ / 1000; + 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* Re: [tpmdd-devel] [PATCH v4 3/4] tpm: Allow TPM chip drivers to override reported command durations 2016-06-08 0:45 ` [PATCH v4 3/4] tpm: Allow TPM chip drivers to override reported " Ed Swierk @ 2016-06-08 19:05 ` Jason Gunthorpe 2016-06-08 20:41 ` Ed Swierk 0 siblings, 1 reply; 68+ messages in thread From: Jason Gunthorpe @ 2016-06-08 19:05 UTC (permalink / raw) To: Ed Swierk; +Cc: tpmdd-devel, linux-security-module, linux-kernel On Tue, Jun 07, 2016 at 05:45:39PM -0700, Ed Swierk wrote: > + case 0x32041114: /* Atmel 3204 */ > + chip->vendor.timeout_a = TIS_SHORT_TIMEOUT * HZ / 1000; > + chip->vendor.timeout_b = TIS_LONG_TIMEOUT * HZ / 1000; > + chip->vendor.timeout_c = TIS_SHORT_TIMEOUT * HZ / 1000; > + chip->vendor.timeout_d = TIS_SHORT_TIMEOUT * HZ / 1000; Shouldn't these use msec_to_jiffies? Jason ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [tpmdd-devel] [PATCH v4 3/4] tpm: Allow TPM chip drivers to override reported command durations 2016-06-08 19:05 ` [tpmdd-devel] " Jason Gunthorpe @ 2016-06-08 20:41 ` Ed Swierk 0 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-08 20:41 UTC (permalink / raw) To: Jason Gunthorpe; +Cc: tpmdd-devel, linux-security-module, linux-kernel On Wed, Jun 8, 2016 at 12:05 PM, Jason Gunthorpe <jgunthorpe@obsidianresearch.com> wrote: > On Tue, Jun 07, 2016 at 05:45:39PM -0700, Ed Swierk wrote: >> + case 0x32041114: /* Atmel 3204 */ >> + chip->vendor.timeout_a = TIS_SHORT_TIMEOUT * HZ / 1000; >> + chip->vendor.timeout_b = TIS_LONG_TIMEOUT * HZ / 1000; >> + chip->vendor.timeout_c = TIS_SHORT_TIMEOUT * HZ / 1000; >> + chip->vendor.timeout_d = TIS_SHORT_TIMEOUT * HZ / 1000; > > Shouldn't these use msec_to_jiffies? Indeed * HZ / 1000 can be one jiffy less than msec_to_jiffies(), depending on HZ. I'll change it. --Ed ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v4 4/4] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup 2016-06-08 0:45 [PATCH v4 0/4] tpm: Command duration logging and chip-specific override Ed Swierk ` (2 preceding siblings ...) 2016-06-08 0:45 ` [PATCH v4 3/4] tpm: Allow TPM chip drivers to override reported " Ed Swierk @ 2016-06-08 0:45 ` Ed Swierk 2016-06-08 23:00 ` [PATCH v5 0/4] tpm: Command duration logging and chip-specific override Ed Swierk 4 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-08 0:45 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module 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 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 5c74980..0041622 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -485,6 +485,11 @@ static void tpm_tis_update_timeouts(struct tpm_chip *chip) chip->vendor.timeout_d = TIS_SHORT_TIMEOUT * HZ / 1000; 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; } } -- 1.9.1 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v5 0/4] tpm: Command duration logging and chip-specific override 2016-06-08 0:45 [PATCH v4 0/4] tpm: Command duration logging and chip-specific override Ed Swierk ` (3 preceding siblings ...) 2016-06-08 0:45 ` [PATCH v4 4/4] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk @ 2016-06-08 23:00 ` Ed Swierk 2016-06-08 23:00 ` [PATCH v5 1/4] tpm_tis: Improve reporting of IO errors Ed Swierk ` (4 more replies) 4 siblings, 5 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-08 23:00 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module, jgunthorpe 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 (4): tpm_tis: Improve reporting of IO errors tpm: Add optional logging of TPM command durations 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 | 194 ++++++++++++++++++++++----------------- drivers/char/tpm/tpm_tis.c | 48 +++++----- include/linux/tpm.h | 3 +- 3 files changed, 131 insertions(+), 114 deletions(-) -- 1.9.1 ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v5 1/4] tpm_tis: Improve reporting of IO errors 2016-06-08 23:00 ` [PATCH v5 0/4] tpm: Command duration logging and chip-specific override Ed Swierk @ 2016-06-08 23:00 ` Ed Swierk 2016-06-08 23:00 ` [PATCH v5 2/4] tpm: Add optional logging of TPM command durations Ed Swierk ` (3 subsequent siblings) 4 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-08 23:00 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module, jgunthorpe 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v5 2/4] tpm: Add optional logging of TPM command durations 2016-06-08 23:00 ` [PATCH v5 0/4] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-08 23:00 ` [PATCH v5 1/4] tpm_tis: Improve reporting of IO errors Ed Swierk @ 2016-06-08 23:00 ` Ed Swierk 2016-06-08 23:00 ` [PATCH v5 3/4] tpm: Allow TPM chip drivers to override reported " Ed Swierk ` (2 subsequent siblings) 4 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-08 23:00 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module, jgunthorpe 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v5 3/4] tpm: Allow TPM chip drivers to override reported command durations 2016-06-08 23:00 ` [PATCH v5 0/4] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-08 23:00 ` [PATCH v5 1/4] tpm_tis: Improve reporting of IO errors Ed Swierk 2016-06-08 23:00 ` [PATCH v5 2/4] tpm: Add optional logging of TPM command durations Ed Swierk @ 2016-06-08 23:00 ` Ed Swierk 2016-06-10 12:19 ` Jarkko Sakkinen 2016-06-08 23:00 ` [PATCH v5 4/4] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk 2016-06-11 1:55 ` [PATCH v6 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 4 siblings, 1 reply; 68+ messages in thread From: Ed Swierk @ 2016-06-08 23:00 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module, jgunthorpe 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 | 177 +++++++++++++++++++++------------------ drivers/char/tpm/tpm_tis.c | 35 ++------ include/linux/tpm.h | 3 +- 3 files changed, 106 insertions(+), 109 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index cc1e5bc..b8a08bb 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -502,123 +502,138 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) "attempting to start the TPM"); } -int tpm_get_timeouts(struct tpm_chip *chip) +static int tpm_get_cap_prop(struct tpm_chip *chip, __be32 type, int size, + cap_t *cap, char *desc) { struct tpm_cmd_t tpm_cmd; - 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; + tpm_cmd.params.getcap_in.subcap = type; 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. 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; + tpm_cmd.params.getcap_in.subcap = type; 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; + "Error %zd reading %s\n", rc, desc); + return -EINVAL; } 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)) + != sizeof(tpm_cmd.header.out) + sizeof(u32) + size * sizeof(u32)) { + dev_err(chip->pdev, + "Bad return code or length reading %s\n", desc); 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); - 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]); - } + memcpy(cap, &tpm_cmd.params.getcap_out.cap, sizeof(cap_t)); - 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]); + return 0; +} -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; +int tpm_get_timeouts(struct tpm_chip *chip) +{ + cap_t cap1, cap2; + int rc1, rc2; + struct tpm_vendor_specific orig_vendor; + + rc1 = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_TIMEOUT, 4, &cap1, + "timeouts"); + if (rc1 == 0) { + 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); + } + rc2 = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_DURATION, 3, &cap2, + "durations"); + if (rc2 == 0) { + 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); + } - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the durations"); - if (rc) - return rc; + memcpy(&orig_vendor, &chip->vendor, sizeof(orig_vendor)); + + /* 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 (rc1 == 0 && 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; + } + /* Interpret duration values between 1 and 10000 as + milliseconds to deal with TPMs like the Broadcom BCM0102 in + the Dell Latitude D820. */ + if (rc2 == 0 && 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 (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; + if (chip->ops->update_timeouts != NULL) + chip->ops->update_timeouts(chip); - duration_cap = &tpm_cmd.params.getcap_out.cap.duration; - chip->vendor.duration[TPM_SHORT] = - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); - chip->vendor.duration[TPM_MEDIUM] = - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); - chip->vendor.duration[TPM_LONG] = - usecs_to_jiffies(be32_to_cpu(duration_cap->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 - * 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."); + 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* Re: [PATCH v5 3/4] tpm: Allow TPM chip drivers to override reported command durations 2016-06-08 23:00 ` [PATCH v5 3/4] tpm: Allow TPM chip drivers to override reported " Ed Swierk @ 2016-06-10 12:19 ` Jarkko Sakkinen 2016-06-10 17:34 ` Ed Swierk 0 siblings, 1 reply; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-10 12:19 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, stefanb, linux-kernel, linux-security-module, jgunthorpe On Wed, Jun 08, 2016 at 04:00:17PM -0700, Ed Swierk wrote: > 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 | 177 +++++++++++++++++++++------------------ > drivers/char/tpm/tpm_tis.c | 35 ++------ > include/linux/tpm.h | 3 +- > 3 files changed, 106 insertions(+), 109 deletions(-) > > diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c > index cc1e5bc..b8a08bb 100644 > --- a/drivers/char/tpm/tpm-interface.c > +++ b/drivers/char/tpm/tpm-interface.c > @@ -502,123 +502,138 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) > "attempting to start the TPM"); > } > > -int tpm_get_timeouts(struct tpm_chip *chip) > +static int tpm_get_cap_prop(struct tpm_chip *chip, __be32 type, int size, > + cap_t *cap, char *desc) > { > struct tpm_cmd_t tpm_cmd; > - 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; > + tpm_cmd.params.getcap_in.subcap = type; > 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. > 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; > + tpm_cmd.params.getcap_in.subcap = type; > 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; > + "Error %zd reading %s\n", rc, desc); > + return -EINVAL; > } > > 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)) > + != sizeof(tpm_cmd.header.out) + sizeof(u32) + size * sizeof(u32)) { > + dev_err(chip->pdev, > + "Bad return code or length reading %s\n", desc); > 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); > - 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]); > - } > + memcpy(cap, &tpm_cmd.params.getcap_out.cap, sizeof(cap_t)); > > - 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]); > + return 0; > +} > > -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; > +int tpm_get_timeouts(struct tpm_chip *chip) > +{ > + cap_t cap1, cap2; > + int rc1, rc2; > + struct tpm_vendor_specific orig_vendor; > + > + rc1 = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_TIMEOUT, 4, &cap1, > + "timeouts"); > + if (rc1 == 0) { > + 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); > + } > + rc2 = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_DURATION, 3, &cap2, > + "durations"); > + if (rc2 == 0) { > + 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); > + } This is major change to the semantics. Before -EINVAL would have been return on error condition. PS If you want to encapsulate tpm_get_cap_prop(), that step should be a separate commit (prepend this one). /Jarkko ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v5 3/4] tpm: Allow TPM chip drivers to override reported command durations 2016-06-10 12:19 ` Jarkko Sakkinen @ 2016-06-10 17:34 ` Ed Swierk 2016-06-10 19:42 ` Jarkko Sakkinen 0 siblings, 1 reply; 68+ messages in thread From: Ed Swierk @ 2016-06-10 17:34 UTC (permalink / raw) To: Jarkko Sakkinen Cc: tpmdd-devel, Stefan Berger, linux-kernel, linux-security-module, Jason Gunthorpe On Fri, Jun 10, 2016 at 5:19 AM, Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> wrote: > On Wed, Jun 08, 2016 at 04:00:17PM -0700, Ed Swierk wrote: >> 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 | 177 +++++++++++++++++++++------------------ >> drivers/char/tpm/tpm_tis.c | 35 ++------ >> include/linux/tpm.h | 3 +- >> 3 files changed, 106 insertions(+), 109 deletions(-) >> >> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c >> index cc1e5bc..b8a08bb 100644 >> --- a/drivers/char/tpm/tpm-interface.c >> +++ b/drivers/char/tpm/tpm-interface.c >> @@ -502,123 +502,138 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) >> "attempting to start the TPM"); >> } >> >> -int tpm_get_timeouts(struct tpm_chip *chip) >> +static int tpm_get_cap_prop(struct tpm_chip *chip, __be32 type, int size, >> + cap_t *cap, char *desc) >> { >> struct tpm_cmd_t tpm_cmd; >> - 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; >> + tpm_cmd.params.getcap_in.subcap = type; >> 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. >> 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; >> + tpm_cmd.params.getcap_in.subcap = type; >> 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; >> + "Error %zd reading %s\n", rc, desc); >> + return -EINVAL; >> } >> >> 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)) >> + != sizeof(tpm_cmd.header.out) + sizeof(u32) + size * sizeof(u32)) { >> + dev_err(chip->pdev, >> + "Bad return code or length reading %s\n", desc); >> 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); >> - 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]); >> - } >> + memcpy(cap, &tpm_cmd.params.getcap_out.cap, sizeof(cap_t)); >> >> - 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]); >> + return 0; >> +} >> >> -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; >> +int tpm_get_timeouts(struct tpm_chip *chip) >> +{ >> + cap_t cap1, cap2; >> + int rc1, rc2; >> + struct tpm_vendor_specific orig_vendor; >> + >> + rc1 = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_TIMEOUT, 4, &cap1, >> + "timeouts"); >> + if (rc1 == 0) { >> + 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); >> + } >> + rc2 = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_DURATION, 3, &cap2, >> + "durations"); >> + if (rc2 == 0) { >> + 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); >> + } > > This is major change to the semantics. Before -EINVAL would have been > return on error condition. > > PS If you want to encapsulate tpm_get_cap_prop(), that step should be > a separate commit (prepend this one). Good points. I'm confused about the error semantics in the first (timeouts) part of tpm_get_timeouts(). If tpm_transmit_cmd() returns zero and a header check fails, it returns -EINVAL. But if tpm_transmit_cmd() returns nonzero, it swallows the error. In contrast, in the second (durations) part, an error is returned in either case. Is this difference intentional, or should tpm_get_timeouts() return errors immediately in all cases? --Ed ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v5 3/4] tpm: Allow TPM chip drivers to override reported command durations 2016-06-10 17:34 ` Ed Swierk @ 2016-06-10 19:42 ` Jarkko Sakkinen 2016-06-11 1:54 ` Ed Swierk 0 siblings, 1 reply; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-10 19:42 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, Stefan Berger, linux-kernel, linux-security-module, Jason Gunthorpe On Fri, Jun 10, 2016 at 10:34:15AM -0700, Ed Swierk wrote: > On Fri, Jun 10, 2016 at 5:19 AM, Jarkko Sakkinen > <jarkko.sakkinen@linux.intel.com> wrote: > > On Wed, Jun 08, 2016 at 04:00:17PM -0700, Ed Swierk wrote: > >> 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 | 177 +++++++++++++++++++++------------------ > >> drivers/char/tpm/tpm_tis.c | 35 ++------ > >> include/linux/tpm.h | 3 +- > >> 3 files changed, 106 insertions(+), 109 deletions(-) > >> > >> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c > >> index cc1e5bc..b8a08bb 100644 > >> --- a/drivers/char/tpm/tpm-interface.c > >> +++ b/drivers/char/tpm/tpm-interface.c > >> @@ -502,123 +502,138 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) > >> "attempting to start the TPM"); > >> } > >> > >> -int tpm_get_timeouts(struct tpm_chip *chip) > >> +static int tpm_get_cap_prop(struct tpm_chip *chip, __be32 type, int size, > >> + cap_t *cap, char *desc) > >> { > >> struct tpm_cmd_t tpm_cmd; > >> - 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; > >> + tpm_cmd.params.getcap_in.subcap = type; > >> 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. > >> 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; > >> + tpm_cmd.params.getcap_in.subcap = type; > >> 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; > >> + "Error %zd reading %s\n", rc, desc); > >> + return -EINVAL; > >> } > >> > >> 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)) > >> + != sizeof(tpm_cmd.header.out) + sizeof(u32) + size * sizeof(u32)) { > >> + dev_err(chip->pdev, > >> + "Bad return code or length reading %s\n", desc); > >> 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); > >> - 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]); > >> - } > >> + memcpy(cap, &tpm_cmd.params.getcap_out.cap, sizeof(cap_t)); > >> > >> - 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]); > >> + return 0; > >> +} > >> > >> -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; > >> +int tpm_get_timeouts(struct tpm_chip *chip) > >> +{ > >> + cap_t cap1, cap2; > >> + int rc1, rc2; > >> + struct tpm_vendor_specific orig_vendor; > >> + > >> + rc1 = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_TIMEOUT, 4, &cap1, > >> + "timeouts"); > >> + if (rc1 == 0) { > >> + 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); > >> + } > >> + rc2 = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_DURATION, 3, &cap2, > >> + "durations"); > >> + if (rc2 == 0) { > >> + 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); > >> + } > > > > This is major change to the semantics. Before -EINVAL would have been > > return on error condition. > > > > PS If you want to encapsulate tpm_get_cap_prop(), that step should be > > a separate commit (prepend this one). > > Good points. > > I'm confused about the error semantics in the first (timeouts) part of > tpm_get_timeouts(). If tpm_transmit_cmd() returns zero and a header > check fails, it returns -EINVAL. But if tpm_transmit_cmd() returns > nonzero, it swallows the error. > > In contrast, in the second (durations) part, an error is returned in > either case. > > Is this difference intentional, or should tpm_get_timeouts() return > errors immediately in all cases? Sometimes these kinds of things are just "evolutional" :) There are also couple of other things that don't look right: * tpm_transmit_cmd() already prints the TPM error * If you use dev_err(), you must fail. If we ought to continue, it should be at most dev_warn(). In my opinion it is just plain wrong to continue to the durations part in the case of TPM error. I would like to hear a second opinion, though. > --Ed /Jarkko ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v5 3/4] tpm: Allow TPM chip drivers to override reported command durations 2016-06-10 19:42 ` Jarkko Sakkinen @ 2016-06-11 1:54 ` Ed Swierk 0 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-11 1:54 UTC (permalink / raw) To: Jarkko Sakkinen Cc: tpmdd-devel, Stefan Berger, linux-kernel, linux-security-module, Jason Gunthorpe On Fri, Jun 10, 2016 at 12:42 PM, Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> wrote: > On Fri, Jun 10, 2016 at 10:34:15AM -0700, Ed Swierk wrote: >> On Fri, Jun 10, 2016 at 5:19 AM, Jarkko Sakkinen >> <jarkko.sakkinen@linux.intel.com> wrote: >> > On Wed, Jun 08, 2016 at 04:00:17PM -0700, Ed Swierk wrote: >> >> 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 | 177 +++++++++++++++++++++------------------ >> >> drivers/char/tpm/tpm_tis.c | 35 ++------ >> >> include/linux/tpm.h | 3 +- >> >> 3 files changed, 106 insertions(+), 109 deletions(-) >> >> >> >> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c >> >> index cc1e5bc..b8a08bb 100644 >> >> --- a/drivers/char/tpm/tpm-interface.c >> >> +++ b/drivers/char/tpm/tpm-interface.c >> >> @@ -502,123 +502,138 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) >> >> "attempting to start the TPM"); >> >> } >> >> >> >> -int tpm_get_timeouts(struct tpm_chip *chip) >> >> +static int tpm_get_cap_prop(struct tpm_chip *chip, __be32 type, int size, >> >> + cap_t *cap, char *desc) >> >> { >> >> struct tpm_cmd_t tpm_cmd; >> >> - 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; >> >> + tpm_cmd.params.getcap_in.subcap = type; >> >> 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. >> >> 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; >> >> + tpm_cmd.params.getcap_in.subcap = type; >> >> 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; >> >> + "Error %zd reading %s\n", rc, desc); >> >> + return -EINVAL; >> >> } >> >> >> >> 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)) >> >> + != sizeof(tpm_cmd.header.out) + sizeof(u32) + size * sizeof(u32)) { >> >> + dev_err(chip->pdev, >> >> + "Bad return code or length reading %s\n", desc); >> >> 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); >> >> - 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]); >> >> - } >> >> + memcpy(cap, &tpm_cmd.params.getcap_out.cap, sizeof(cap_t)); >> >> >> >> - 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]); >> >> + return 0; >> >> +} >> >> >> >> -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; >> >> +int tpm_get_timeouts(struct tpm_chip *chip) >> >> +{ >> >> + cap_t cap1, cap2; >> >> + int rc1, rc2; >> >> + struct tpm_vendor_specific orig_vendor; >> >> + >> >> + rc1 = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_TIMEOUT, 4, &cap1, >> >> + "timeouts"); >> >> + if (rc1 == 0) { >> >> + 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); >> >> + } >> >> + rc2 = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_DURATION, 3, &cap2, >> >> + "durations"); >> >> + if (rc2 == 0) { >> >> + 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); >> >> + } >> > >> > This is major change to the semantics. Before -EINVAL would have been >> > return on error condition. >> > >> > PS If you want to encapsulate tpm_get_cap_prop(), that step should be >> > a separate commit (prepend this one). >> >> Good points. >> >> I'm confused about the error semantics in the first (timeouts) part of >> tpm_get_timeouts(). If tpm_transmit_cmd() returns zero and a header >> check fails, it returns -EINVAL. But if tpm_transmit_cmd() returns >> nonzero, it swallows the error. >> >> In contrast, in the second (durations) part, an error is returned in >> either case. >> >> Is this difference intentional, or should tpm_get_timeouts() return >> errors immediately in all cases? > > Sometimes these kinds of things are just "evolutional" :) > > There are also couple of other things that don't look right: > > * tpm_transmit_cmd() already prints the TPM error > * If you use dev_err(), you must fail. If we ought to continue, it > should be at most dev_warn(). > > In my opinion it is just plain wrong to continue to the durations part > in the case of TPM error. I would like to hear a second opinion, though. > >> --Ed > > /Jarkko I'll split tpm_get_cap_prop() out from tpm_get_timeouts() in a separate commit, and adjust the error handling on the assumption that TPM errors should always be propagated. --Ed ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v5 4/4] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup 2016-06-08 23:00 ` [PATCH v5 0/4] tpm: Command duration logging and chip-specific override Ed Swierk ` (2 preceding siblings ...) 2016-06-08 23:00 ` [PATCH v5 3/4] tpm: Allow TPM chip drivers to override reported " Ed Swierk @ 2016-06-08 23:00 ` Ed Swierk 2016-06-11 1:55 ` [PATCH v6 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 4 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-08 23:00 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module, jgunthorpe 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 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index caf7278..862c502 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -485,6 +485,11 @@ 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; } } -- 1.9.1 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v6 0/5] tpm: Command duration logging and chip-specific override 2016-06-08 23:00 ` [PATCH v5 0/4] tpm: Command duration logging and chip-specific override Ed Swierk ` (3 preceding siblings ...) 2016-06-08 23:00 ` [PATCH v5 4/4] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk @ 2016-06-11 1:55 ` Ed Swierk 2016-06-11 1:55 ` [PATCH v6 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk ` (5 more replies) 4 siblings, 6 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-11 1:55 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module, jgunthorpe 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: Factor out 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 | 192 ++++++++++++++++++++++----------------- drivers/char/tpm/tpm_tis.c | 48 +++++----- include/linux/tpm.h | 3 +- 3 files changed, 132 insertions(+), 111 deletions(-) -- 1.9.1 ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v6 1/5] tpm_tis: Improve reporting of IO errors 2016-06-11 1:55 ` [PATCH v6 0/5] tpm: Command duration logging and chip-specific override Ed Swierk @ 2016-06-11 1:55 ` Ed Swierk 2016-06-11 1:55 ` [PATCH v6 2/5] tpm: Add optional logging of TPM command durations Ed Swierk ` (4 subsequent siblings) 5 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-11 1:55 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module, jgunthorpe 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v6 2/5] tpm: Add optional logging of TPM command durations 2016-06-11 1:55 ` [PATCH v6 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-11 1:55 ` [PATCH v6 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk @ 2016-06-11 1:55 ` Ed Swierk 2016-06-11 1:55 ` [PATCH v6 3/5] tpm: Factor out reading of timeout and duration capabilities Ed Swierk ` (3 subsequent siblings) 5 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-11 1:55 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module, jgunthorpe 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v6 3/5] tpm: Factor out reading of timeout and duration capabilities 2016-06-11 1:55 ` [PATCH v6 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-11 1:55 ` [PATCH v6 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk 2016-06-11 1:55 ` [PATCH v6 2/5] tpm: Add optional logging of TPM command durations Ed Swierk @ 2016-06-11 1:55 ` Ed Swierk 2016-06-16 20:20 ` Jarkko Sakkinen 2016-06-19 12:12 ` Jarkko Sakkinen 2016-06-11 1:55 ` [PATCH v6 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk ` (2 subsequent siblings) 5 siblings, 2 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-11 1:55 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module, jgunthorpe Factor sending the TPM_GetCapability command and validating the result from tpm_get_timeouts() into a new function. 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 | 96 ++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index cc1e5bc..4d1f62c 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -502,6 +502,52 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) "attempting to start the TPM"); } +static int tpm_get_cap_prop(struct tpm_chip *chip, __be32 type, int size, + cap_t *cap, char *desc) +{ + struct tpm_cmd_t tpm_cmd; + 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 = type; + 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. + Execute a startup command. */ + 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 = type; + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + NULL); + } + + if (rc) { + dev_err(chip->pdev, + "Error %zd reading %s\n", rc, desc); + 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) + size * sizeof(u32)) { + dev_err(chip->pdev, + "Bad return code or length reading %s\n", desc); + return -EINVAL; + } + + memcpy(cap, &tpm_cmd.params.getcap_out.cap, sizeof(cap_t)); + + return 0; +} + int tpm_get_timeouts(struct tpm_chip *chip) { struct tpm_cmd_t tpm_cmd; @@ -510,37 +556,10 @@ int tpm_get_timeouts(struct tpm_chip *chip) 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); - - 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"); - 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; - } - - 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; + rc = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_TIMEOUT, 4, + &tpm_cmd.params.getcap_out.cap, "timeouts"); + if (rc) + return rc; 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); @@ -583,22 +602,11 @@ 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_get_cap_prop(chip, TPM_CAP_PROP_TIS_DURATION, 3, + &tpm_cmd.params.getcap_out.cap, "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)); -- 1.9.1 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* Re: [PATCH v6 3/5] tpm: Factor out reading of timeout and duration capabilities 2016-06-11 1:55 ` [PATCH v6 3/5] tpm: Factor out reading of timeout and duration capabilities Ed Swierk @ 2016-06-16 20:20 ` Jarkko Sakkinen 2016-06-19 12:12 ` Jarkko Sakkinen 1 sibling, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-16 20:20 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, stefanb, linux-kernel, linux-security-module, jgunthorpe On Fri, Jun 10, 2016 at 06:55:05PM -0700, Ed Swierk wrote: > Factor sending the TPM_GetCapability command and validating the result > from tpm_get_timeouts() into a new function. Return all errors to the > caller rather than swallowing them (e.g. when tpm_transmit_cmd() > returns nonzero). LGTM but I have to test this on next week. I'll give final Reviewed/Tested-by after that. Thanks for the good work. > Signed-off-by: Ed Swierk <eswierk@skyportsystems.com> > --- > drivers/char/tpm/tpm-interface.c | 96 ++++++++++++++++++++++------------------ > 1 file changed, 52 insertions(+), 44 deletions(-) /Jarkko ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v6 3/5] tpm: Factor out reading of timeout and duration capabilities 2016-06-11 1:55 ` [PATCH v6 3/5] tpm: Factor out reading of timeout and duration capabilities Ed Swierk 2016-06-16 20:20 ` Jarkko Sakkinen @ 2016-06-19 12:12 ` Jarkko Sakkinen 1 sibling, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-19 12:12 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, stefanb, linux-kernel, linux-security-module, jgunthorpe On Fri, Jun 10, 2016 at 06:55:05PM -0700, Ed Swierk wrote: > Factor sending the TPM_GetCapability command and validating the result > from tpm_get_timeouts() into a new function. 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 | 96 ++++++++++++++++++++++------------------ > 1 file changed, 52 insertions(+), 44 deletions(-) I'm sorry but just now that I started applying these patches this patch started to bother me. > diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c > index cc1e5bc..4d1f62c 100644 > --- a/drivers/char/tpm/tpm-interface.c > +++ b/drivers/char/tpm/tpm-interface.c > @@ -502,6 +502,52 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) > "attempting to start the TPM"); > } > > +static int tpm_get_cap_prop(struct tpm_chip *chip, __be32 type, int size, > + cap_t *cap, char *desc) > +{ > + struct tpm_cmd_t tpm_cmd; > + 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 = type; > + 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. > + Execute a startup command. */ > + 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 = type; > + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, > + NULL); > + } I think inside tpm_get_timeouts() I'd rather something along the lines (with error handling and such details taken away): rc = tpm_getcap(...); if (rc == TPM_ERR_INVALID_POSTINIT) { tpm_startup(...); tpm_getca(...); } > + if (rc) { > + dev_err(chip->pdev, > + "Error %zd reading %s\n", rc, desc); > + 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) + size * sizeof(u32)) { > + dev_err(chip->pdev, > + "Bad return code or length reading %s\n", desc); > + return -EINVAL; > + } This is bogus code. All this kind of checks should be contained in tpm_transmit_cmd(). This is easily "fixed" by moving tpm_getcap() :) /Jarkko ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v6 4/5] tpm: Allow TPM chip drivers to override reported command durations 2016-06-11 1:55 ` [PATCH v6 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (2 preceding siblings ...) 2016-06-11 1:55 ` [PATCH v6 3/5] tpm: Factor out reading of timeout and duration capabilities Ed Swierk @ 2016-06-11 1:55 ` Ed Swierk 2016-06-16 20:26 ` Jarkko Sakkinen 2016-06-11 1:55 ` [PATCH v6 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk 2016-06-21 1:53 ` [PATCH v7 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 5 siblings, 1 reply; 68+ messages in thread From: Ed Swierk @ 2016-06-11 1:55 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module, jgunthorpe 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 | 139 +++++++++++++++++++++------------------ drivers/char/tpm/tpm_tis.c | 35 +++------- include/linux/tpm.h | 3 +- 3 files changed, 85 insertions(+), 92 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 4d1f62c..a14adfd 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -550,83 +550,94 @@ static int tpm_get_cap_prop(struct tpm_chip *chip, __be32 type, int size, int tpm_get_timeouts(struct tpm_chip *chip) { - struct tpm_cmd_t tpm_cmd; - unsigned long new_timeout[4]; - unsigned long old_timeout[4]; - struct duration_t *duration_cap; - ssize_t rc; + cap_t cap1, cap2; + int rc; + struct tpm_vendor_specific orig_vendor; - rc = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_TIMEOUT, 4, - &tpm_cmd.params.getcap_out.cap, "timeouts"); + rc = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_TIMEOUT, 4, &cap1, + "timeouts"); if (rc) return rc; - 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); - memcpy(new_timeout, old_timeout, sizeof(new_timeout)); + rc = tpm_get_cap_prop(chip, TPM_CAP_PROP_TIS_DURATION, 3, &cap2, + "durations"); + if (rc) + return rc; - /* - * 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); + 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); - 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; - } + /* 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; } - /* Report adjusted timeouts */ + 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 "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]); + 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)); } - 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_get_cap_prop(chip, TPM_CAP_PROP_TIS_DURATION, 3, - &tpm_cmd.params.getcap_out.cap, "durations"); - if (rc) - return rc; - - duration_cap = &tpm_cmd.params.getcap_out.cap.duration; - chip->vendor.duration[TPM_SHORT] = - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); - chip->vendor.duration[TPM_MEDIUM] = - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); - chip->vendor.duration[TPM_LONG] = - usecs_to_jiffies(be32_to_cpu(duration_cap->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 - * 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."); + 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* Re: [PATCH v6 4/5] tpm: Allow TPM chip drivers to override reported command durations 2016-06-11 1:55 ` [PATCH v6 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk @ 2016-06-16 20:26 ` Jarkko Sakkinen 0 siblings, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-16 20:26 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, stefanb, linux-kernel, linux-security-module, jgunthorpe On Fri, Jun 10, 2016 at 06:55:06PM -0700, Ed Swierk wrote: > 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> Again, LGTM but have to test :) > --- > drivers/char/tpm/tpm-interface.c | 139 +++++++++++++++++++++------------------ > drivers/char/tpm/tpm_tis.c | 35 +++------- > include/linux/tpm.h | 3 +- > 3 files changed, 85 insertions(+), 92 deletions(-) /Jarkko ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v6 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup 2016-06-11 1:55 ` [PATCH v6 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (3 preceding siblings ...) 2016-06-11 1:55 ` [PATCH v6 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk @ 2016-06-11 1:55 ` Ed Swierk 2016-06-21 1:53 ` [PATCH v7 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 5 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-11 1:55 UTC (permalink / raw) To: tpmdd-devel Cc: eswierk, stefanb, jarkko.sakkinen, linux-kernel, linux-security-module, jgunthorpe 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 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index caf7278..862c502 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -485,6 +485,11 @@ 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; } } -- 1.9.1 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v7 0/5] tpm: Command duration logging and chip-specific override 2016-06-11 1:55 ` [PATCH v6 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (4 preceding siblings ...) 2016-06-11 1:55 ` [PATCH v6 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk @ 2016-06-21 1:53 ` Ed Swierk 2016-06-21 1:53 ` [PATCH v7 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk ` (5 more replies) 5 siblings, 6 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-21 1:53 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v7 1/5] tpm_tis: Improve reporting of IO errors 2016-06-21 1:53 ` [PATCH v7 0/5] tpm: Command duration logging and chip-specific override Ed Swierk @ 2016-06-21 1:53 ` Ed Swierk 2016-06-21 1:53 ` [PATCH v7 2/5] tpm: Add optional logging of TPM command durations Ed Swierk ` (4 subsequent siblings) 5 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-21 1:53 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v7 2/5] tpm: Add optional logging of TPM command durations 2016-06-21 1:53 ` [PATCH v7 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-21 1:53 ` [PATCH v7 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk @ 2016-06-21 1:53 ` Ed Swierk 2016-06-21 1:54 ` [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk ` (3 subsequent siblings) 5 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-21 1:53 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities 2016-06-21 1:53 ` [PATCH v7 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-21 1:53 ` [PATCH v7 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk 2016-06-21 1:53 ` [PATCH v7 2/5] tpm: Add optional logging of TPM command durations Ed Swierk @ 2016-06-21 1:54 ` Ed Swierk 2016-06-21 20:52 ` Jarkko Sakkinen 2016-06-22 0:21 ` Ed Swierk 2016-06-21 1:54 ` [PATCH v7 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk ` (2 subsequent siblings) 5 siblings, 2 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-21 1:54 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* Re: [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities 2016-06-21 1:54 ` [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk @ 2016-06-21 20:52 ` Jarkko Sakkinen 2016-06-22 0:21 ` Ed Swierk 1 sibling, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-21 20:52 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, jgunthorpe, stefanb 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 > ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities 2016-06-21 1:54 ` [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk 2016-06-21 20:52 ` Jarkko Sakkinen @ 2016-06-22 0:21 ` Ed Swierk 2016-06-22 10:46 ` Jarkko Sakkinen 1 sibling, 1 reply; 68+ messages in thread From: Ed Swierk @ 2016-06-22 0:21 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: Jarkko Sakkinen, Jason Gunthorpe, Stefan Berger, Ed Swierk 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 ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities 2016-06-22 0:21 ` Ed Swierk @ 2016-06-22 10:46 ` Jarkko Sakkinen 0 siblings, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-22 10:46 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, Jason Gunthorpe, Stefan Berger 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 ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v7 4/5] tpm: Allow TPM chip drivers to override reported command durations 2016-06-21 1:53 ` [PATCH v7 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (2 preceding siblings ...) 2016-06-21 1:54 ` [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk @ 2016-06-21 1:54 ` Ed Swierk 2016-06-21 20:54 ` Jarkko Sakkinen 2016-06-21 1:54 ` [PATCH v7 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk 2016-06-22 1:10 ` [PATCH v8 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 5 siblings, 1 reply; 68+ messages in thread From: Ed Swierk @ 2016-06-21 1:54 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 73c3ee0..36a6861 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* Re: [PATCH v7 4/5] tpm: Allow TPM chip drivers to override reported command durations 2016-06-21 1:54 ` [PATCH v7 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk @ 2016-06-21 20:54 ` Jarkko Sakkinen 0 siblings, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-21 20:54 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, jgunthorpe, stefanb On Mon, Jun 20, 2016 at 06:54:01PM -0700, Ed Swierk wrote: > 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> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> /Jarkko > --- > 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 73c3ee0..36a6861 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 > ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v7 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup 2016-06-21 1:53 ` [PATCH v7 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (3 preceding siblings ...) 2016-06-21 1:54 ` [PATCH v7 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk @ 2016-06-21 1:54 ` Ed Swierk 2016-06-21 20:55 ` Jarkko Sakkinen 2016-06-22 1:10 ` [PATCH v8 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 5 siblings, 1 reply; 68+ messages in thread From: Ed Swierk @ 2016-06-21 1:54 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* Re: [PATCH v7 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup 2016-06-21 1:54 ` [PATCH v7 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk @ 2016-06-21 20:55 ` Jarkko Sakkinen 0 siblings, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-21 20:55 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, jgunthorpe, stefanb On Mon, Jun 20, 2016 at 06:54:02PM -0700, Ed Swierk wrote: > 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> I think this fine but I would like to hear other opinions on this. Stefan? /Jarkko > --- > 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 > ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v8 0/5] tpm: Command duration logging and chip-specific override 2016-06-21 1:53 ` [PATCH v7 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (4 preceding siblings ...) 2016-06-21 1:54 ` [PATCH v7 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk @ 2016-06-22 1:10 ` Ed Swierk 2016-06-22 1:10 ` [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk ` (5 more replies) 5 siblings, 6 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-22 1:10 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors 2016-06-22 1:10 ` [PATCH v8 0/5] tpm: Command duration logging and chip-specific override Ed Swierk @ 2016-06-22 1:10 ` Ed Swierk 2016-06-24 18:25 ` Jason Gunthorpe 2016-06-22 1:10 ` [PATCH v8 2/5] tpm: Add optional logging of TPM command durations Ed Swierk ` (4 subsequent siblings) 5 siblings, 1 reply; 68+ messages in thread From: Ed Swierk @ 2016-06-22 1:10 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* Re: [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors 2016-06-22 1:10 ` [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk @ 2016-06-24 18:25 ` Jason Gunthorpe 2016-06-24 20:21 ` Jarkko Sakkinen 0 siblings, 1 reply; 68+ messages in thread From: Jason Gunthorpe @ 2016-06-24 18:25 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, jarkko.sakkinen, stefanb > expected = be32_to_cpu(*(__be32 *) (buf + 2)); > if (expected > count) { > + dev_err(chip->pdev, "Response too long (wanted %zd, got %d)\n", > + count, expected); This all needs to be rebased on Jarkko's tree I guess, chip->pdev is gone now. http://git.infradead.org/users/jjs/linux-tpmdd.git/shortlog/refs/heads/master Jarkko, did you miss a pull request for 4.7 or something? This is 4 month old stuff??? Jason ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors 2016-06-24 18:25 ` Jason Gunthorpe @ 2016-06-24 20:21 ` Jarkko Sakkinen 2016-06-24 20:23 ` Jarkko Sakkinen 2016-06-24 20:26 ` Jason Gunthorpe 0 siblings, 2 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-24 20:21 UTC (permalink / raw) To: Jason Gunthorpe Cc: Ed Swierk, tpmdd-devel, linux-kernel, linux-security-module, stefanb Hi Jason, On Fri, Jun 24, 2016 at 12:25:15PM -0600, Jason Gunthorpe wrote: > > expected = be32_to_cpu(*(__be32 *) (buf + 2)); > > if (expected > count) { > > + dev_err(chip->pdev, "Response too long (wanted %zd, got %d)\n", > > + count, expected); > > This all needs to be rebased on Jarkko's tree I guess, chip->pdev is > gone now. > > http://git.infradead.org/users/jjs/linux-tpmdd.git/shortlog/refs/heads/master > > Jarkko, did you miss a pull request for 4.7 or something? This is > 4 month old stuff??? Hmm... Do you mean by 4 month old stuff the stuff that is in mainline and not in my master branch? I'm not sure what happened with 4.7. I merged the changes for in about 4.6-rc5. There was one issue that I fixed that Stephen reported. At the moment linux-next seems contain the stuff that I have in my next. > Jason /Jarkko ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors 2016-06-24 20:21 ` Jarkko Sakkinen @ 2016-06-24 20:23 ` Jarkko Sakkinen 2016-06-24 20:26 ` Jason Gunthorpe 1 sibling, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-24 20:23 UTC (permalink / raw) To: Jason Gunthorpe Cc: Ed Swierk, tpmdd-devel, linux-kernel, linux-security-module, stefanb On Fri, Jun 24, 2016 at 11:21:31PM +0300, Jarkko Sakkinen wrote: > Hi Jason, > > On Fri, Jun 24, 2016 at 12:25:15PM -0600, Jason Gunthorpe wrote: > > > expected = be32_to_cpu(*(__be32 *) (buf + 2)); > > > if (expected > count) { > > > + dev_err(chip->pdev, "Response too long (wanted %zd, got %d)\n", > > > + count, expected); > > > > This all needs to be rebased on Jarkko's tree I guess, chip->pdev is > > gone now. > > > > http://git.infradead.org/users/jjs/linux-tpmdd.git/shortlog/refs/heads/master > > > > Jarkko, did you miss a pull request for 4.7 or something? This is > > 4 month old stuff??? > > Hmm... Do you mean by 4 month old stuff the stuff that is in mainline > and not in my master branch? > > I'm not sure what happened with 4.7. I merged the changes for in about > 4.6-rc5. There was one issue that I fixed that Stephen reported. > > At the moment linux-next seems contain the stuff that I have in my > next. Ed: I was planning to applying these patches to my master next week and run tests on them. If they do not apply it would be good if you could rebase your series to apply to my master. /Jarkko ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors 2016-06-24 20:21 ` Jarkko Sakkinen 2016-06-24 20:23 ` Jarkko Sakkinen @ 2016-06-24 20:26 ` Jason Gunthorpe 2016-06-25 15:24 ` Jarkko Sakkinen 1 sibling, 1 reply; 68+ messages in thread From: Jason Gunthorpe @ 2016-06-24 20:26 UTC (permalink / raw) To: Jarkko Sakkinen Cc: Ed Swierk, tpmdd-devel, linux-kernel, linux-security-module, stefanb On Fri, Jun 24, 2016 at 11:21:31PM +0300, Jarkko Sakkinen wrote: > Hmm... Do you mean by 4 month old stuff the stuff that is in mainline > and not in my master branch? I mean the stuff that is in your branch but not in mainline. $ git log --pretty=oneline jarkko/master ^v4.7-rc3 | wc -l 73 > I'm not sure what happened with 4.7. I merged the changes for in about > 4.6-rc5. There was one issue that I fixed that Stephen reported. > > At the moment linux-next seems contain the stuff that I have in my > next. linux-next is just pulling directly from your tree, you still have to ensure that James gets and processes your pull request during the merge window. If he dropped a pull request you should follow up and ask why, if you never sent one then ... oops :) Jason ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors 2016-06-24 20:26 ` Jason Gunthorpe @ 2016-06-25 15:24 ` Jarkko Sakkinen 2016-06-25 15:47 ` Jarkko Sakkinen 0 siblings, 1 reply; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-25 15:24 UTC (permalink / raw) To: Jason Gunthorpe Cc: Ed Swierk, tpmdd-devel, linux-kernel, linux-security-module, stefanb On Fri, Jun 24, 2016 at 02:26:15PM -0600, Jason Gunthorpe wrote: > On Fri, Jun 24, 2016 at 11:21:31PM +0300, Jarkko Sakkinen wrote: > > Hmm... Do you mean by 4 month old stuff the stuff that is in mainline > > and not in my master branch? > > I mean the stuff that is in your branch but not in mainline. > > $ git log --pretty=oneline jarkko/master ^v4.7-rc3 | wc -l > 73 > > > I'm not sure what happened with 4.7. I merged the changes for in about > > 4.6-rc5. There was one issue that I fixed that Stephen reported. > > > > At the moment linux-next seems contain the stuff that I have in my > > next. > > linux-next is just pulling directly from your tree, you still have to > ensure that James gets and processes your pull request during the > merge window. If he dropped a pull request you should follow up and > ask why, if you never sent one then ... oops :) For 4.6 I used pull request with a signed tag and everything went quite well. For 4.7 I did re-read the whole development process documentation but it only speaks about pull requests and does not clearly state what you just stated. To summarize I screwed this one up but I guess the only big harm is that vTPM support will skip to 4.8. I guess not big harm done? My master is now rebased and this is what I get: $ git log --oneline security/next...master | wc -l 67 I don't think that is too bad. > Jason /Jarkko ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors 2016-06-25 15:24 ` Jarkko Sakkinen @ 2016-06-25 15:47 ` Jarkko Sakkinen 2016-06-27 17:55 ` Jason Gunthorpe 0 siblings, 1 reply; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-25 15:47 UTC (permalink / raw) To: Jason Gunthorpe Cc: Ed Swierk, tpmdd-devel, linux-kernel, linux-security-module, stefanb On Sat, Jun 25, 2016 at 06:24:30PM +0300, Jarkko Sakkinen wrote: > On Fri, Jun 24, 2016 at 02:26:15PM -0600, Jason Gunthorpe wrote: > > On Fri, Jun 24, 2016 at 11:21:31PM +0300, Jarkko Sakkinen wrote: > > > Hmm... Do you mean by 4 month old stuff the stuff that is in mainline > > > and not in my master branch? > > > > I mean the stuff that is in your branch but not in mainline. > > > > $ git log --pretty=oneline jarkko/master ^v4.7-rc3 | wc -l > > 73 > > > > > I'm not sure what happened with 4.7. I merged the changes for in about > > > 4.6-rc5. There was one issue that I fixed that Stephen reported. > > > > > > At the moment linux-next seems contain the stuff that I have in my > > > next. > > > > linux-next is just pulling directly from your tree, you still have to > > ensure that James gets and processes your pull request during the > > merge window. If he dropped a pull request you should follow up and > > ask why, if you never sent one then ... oops :) > > For 4.6 I used pull request with a signed tag and everything went quite > well. > > For 4.7 I did re-read the whole development process documentation but it > only speaks about pull requests and does not clearly state what you just > stated. > > To summarize I screwed this one up but I guess the only big harm is that > vTPM support will skip to 4.8. I guess not big harm done? > > My master is now rebased and this is what I get: > > $ git log --oneline security/next...master | wc -l > 67 > > I don't think that is too bad. My repositories are ready for next pull request. The master has been rebased to James' tree and merged to next. I won't add any new commits expect critical bug fixes for 4.8 release content. /Jarkko ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors 2016-06-25 15:47 ` Jarkko Sakkinen @ 2016-06-27 17:55 ` Jason Gunthorpe 0 siblings, 0 replies; 68+ messages in thread From: Jason Gunthorpe @ 2016-06-27 17:55 UTC (permalink / raw) To: Jarkko Sakkinen Cc: Ed Swierk, tpmdd-devel, linux-kernel, linux-security-module, stefanb On Sat, Jun 25, 2016 at 06:47:45PM +0300, Jarkko Sakkinen wrote: > My repositories are ready for next pull request. The master has been > rebased to James' tree and merged to next. This seems fine.. Generally you shouldn't rebase to create pull requests, but this seemed needed.. Organize your git tree so that it is always pullable and just use merges/resets/etc in the -next branch There is no reason to hold off on more stuff for 4.8, if another batch is ready before the merge window then send it, James already took the stuff you sent. Jason ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v8 2/5] tpm: Add optional logging of TPM command durations 2016-06-22 1:10 ` [PATCH v8 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-22 1:10 ` [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk @ 2016-06-22 1:10 ` Ed Swierk 2016-06-24 18:27 ` Jason Gunthorpe 2016-06-22 1:10 ` [PATCH v8 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk ` (3 subsequent siblings) 5 siblings, 1 reply; 68+ messages in thread From: Ed Swierk @ 2016-06-22 1:10 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* Re: [PATCH v8 2/5] tpm: Add optional logging of TPM command durations 2016-06-22 1:10 ` [PATCH v8 2/5] tpm: Add optional logging of TPM command durations Ed Swierk @ 2016-06-24 18:27 ` Jason Gunthorpe 2016-06-24 20:24 ` Jarkko Sakkinen 0 siblings, 1 reply; 68+ messages in thread From: Jason Gunthorpe @ 2016-06-24 18:27 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, jarkko.sakkinen, stefanb On Tue, Jun 21, 2016 at 06:10:28PM -0700, Ed Swierk wrote: > 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)); [..] > 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)); No sense in logging twice, just enhance the existingerror message. Jason ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v8 2/5] tpm: Add optional logging of TPM command durations 2016-06-24 18:27 ` Jason Gunthorpe @ 2016-06-24 20:24 ` Jarkko Sakkinen 0 siblings, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-06-24 20:24 UTC (permalink / raw) To: Jason Gunthorpe Cc: Ed Swierk, tpmdd-devel, linux-kernel, linux-security-module, stefanb On Fri, Jun 24, 2016 at 12:27:27PM -0600, Jason Gunthorpe wrote: > On Tue, Jun 21, 2016 at 06:10:28PM -0700, Ed Swierk wrote: > > > 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)); > > [..] > > > 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)); > > No sense in logging twice, just enhance the existingerror message. Absolutely agree. Jason, thanks for pointing this out! /Jarkko ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v8 3/5] tpm: Clean up reading of timeout and duration capabilities 2016-06-22 1:10 ` [PATCH v8 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-22 1:10 ` [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk 2016-06-22 1:10 ` [PATCH v8 2/5] tpm: Add optional logging of TPM command durations Ed Swierk @ 2016-06-22 1:10 ` Ed Swierk 2016-06-22 1:10 ` [PATCH v8 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk ` (2 subsequent siblings) 5 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-22 1:10 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v8 4/5] tpm: Allow TPM chip drivers to override reported command durations 2016-06-22 1:10 ` [PATCH v8 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (2 preceding siblings ...) 2016-06-22 1:10 ` [PATCH v8 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk @ 2016-06-22 1:10 ` Ed Swierk 2016-06-22 1:10 ` [PATCH v8 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk 2016-07-13 16:19 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 5 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-22 1:10 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v8 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup 2016-06-22 1:10 ` [PATCH v8 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (3 preceding siblings ...) 2016-06-22 1:10 ` [PATCH v8 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk @ 2016-06-22 1:10 ` Ed Swierk 2016-07-13 16:19 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 5 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-06-22 1:10 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v9 0/5] tpm: Command duration logging and chip-specific override 2016-06-22 1:10 ` [PATCH v8 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (4 preceding siblings ...) 2016-06-22 1:10 ` [PATCH v8 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk @ 2016-07-13 16:19 ` Ed Swierk 2016-07-13 16:19 ` [PATCH v9 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk ` (6 more replies) 5 siblings, 7 replies; 68+ messages in thread From: Ed Swierk @ 2016-07-13 16:19 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk v9: Include command duration in existing error messages rather than logging an extra debug message. Rebase onto Jarkko's tree. 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 | 219 ++++++++++++++++++++------------------- drivers/char/tpm/tpm_tis_core.c | 46 ++++---- include/linux/tpm.h | 3 +- 3 files changed, 136 insertions(+), 132 deletions(-) -- 1.9.1 ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v9 1/5] tpm_tis: Improve reporting of IO errors 2016-07-13 16:19 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk @ 2016-07-13 16:19 ` Ed Swierk 2016-07-13 16:19 ` [PATCH v9 2/5] tpm: Add optional logging of TPM command durations Ed Swierk ` (5 subsequent siblings) 6 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-07-13 16:19 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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_core.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 8110b52..e62fdeb 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -217,6 +217,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->dev, "Response too long (wanted %zd, got %d)\n", + count, expected); size = -EIO; goto out; } @@ -283,6 +285,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) &priv->int_queue, false); status = tpm_tis_status(chip); if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) { + dev_err(&chip->dev, "Chip not accepting %zd bytes\n", + len - count); rc = -EIO; goto out_err; } @@ -297,6 +301,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) &priv->int_queue, false); status = tpm_tis_status(chip); if (!itpm && (status & TPM_STS_DATA_EXPECT) != 0) { + dev_err(&chip->dev, "Chip not accepting last byte\n"); rc = -EIO; goto out_err; } @@ -707,8 +712,9 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, if (rc < 0) goto out_err; - 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", + priv->manufacturer_id, vendor >> 16, rid); if (!(priv->flags & TPM_TIS_ITPM_POSSIBLE)) { -- 1.9.1 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v9 2/5] tpm: Add optional logging of TPM command durations 2016-07-13 16:19 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-07-13 16:19 ` [PATCH v9 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk @ 2016-07-13 16:19 ` Ed Swierk 2016-07-13 16:19 ` [PATCH v9 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk ` (4 subsequent siblings) 6 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-07-13 16:19 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 5e3c1b6..a4beb53 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -335,13 +335,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->dev, "starting command %d count %d\n", ordinal, count); if (count == 0) return -ENODATA; if (count > bufsiz) { @@ -362,18 +363,23 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, if (chip->flags & TPM_CHIP_FLAG_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->dev, "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->dev, "Operation Canceled\n"); + dev_err(&chip->dev, "canceled command %d after %d ms\n", + ordinal, jiffies_to_msecs(jiffies - start)); rc = -ECANCELED; goto out; } @@ -383,7 +389,8 @@ 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->dev, "command %d timed out after %d ms\n", ordinal, + jiffies_to_msecs(jiffies - start)); rc = -ETIME; goto out; -- 1.9.1 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* [PATCH v9 3/5] tpm: Clean up reading of timeout and duration capabilities 2016-07-13 16:19 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-07-13 16:19 ` [PATCH v9 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk 2016-07-13 16:19 ` [PATCH v9 2/5] tpm: Add optional logging of TPM command durations Ed Swierk @ 2016-07-13 16:19 ` Ed Swierk 2016-07-18 18:15 ` Jarkko Sakkinen 2016-07-18 18:19 ` Jarkko Sakkinen 2016-07-13 16:19 ` [PATCH v9 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk ` (3 subsequent siblings) 6 siblings, 2 replies; 68+ messages in thread From: Ed Swierk @ 2016-07-13 16:19 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 a4beb53..dc492ee 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -460,9 +460,19 @@ ssize_t tpm_getcap(struct tpm_chip *chip, __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; } @@ -503,10 +513,9 @@ 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; if (chip->flags & TPM_CHIP_FLAG_TPM2) { @@ -524,42 +533,25 @@ int tpm_get_timeouts(struct tpm_chip *chip) return 0; } - 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, 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->dev, "Issuing TPM_STARTUP"); + dev_info(&chip->dev, "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->dev, - "A TPM error (%zd) occurred attempting to determine the timeouts\n", - rc); - goto duration; + rc = tpm_getcap(chip, 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)); /* @@ -597,29 +589,17 @@ int tpm_get_timeouts(struct tpm_chip *chip) chip->timeout_c = usecs_to_jiffies(new_timeout[2]); chip->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, 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->duration[TPM_SHORT] = - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); + usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short)); chip->duration[TPM_MEDIUM] = - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); + usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium)); chip->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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* Re: [PATCH v9 3/5] tpm: Clean up reading of timeout and duration capabilities 2016-07-13 16:19 ` [PATCH v9 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk @ 2016-07-18 18:15 ` Jarkko Sakkinen 2016-07-18 18:19 ` Jarkko Sakkinen 1 sibling, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-07-18 18:15 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, jgunthorpe, stefanb On Wed, Jul 13, 2016 at 09:19:34AM -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 a4beb53..dc492ee 100644 > --- a/drivers/char/tpm/tpm-interface.c > +++ b/drivers/char/tpm/tpm-interface.c > @@ -460,9 +460,19 @@ ssize_t tpm_getcap(struct tpm_chip *chip, __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; > } > > @@ -503,10 +513,9 @@ 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; > > if (chip->flags & TPM_CHIP_FLAG_TPM2) { > @@ -524,42 +533,25 @@ int tpm_get_timeouts(struct tpm_chip *chip) > return 0; > } > > - 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, 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->dev, "Issuing TPM_STARTUP"); > + dev_info(&chip->dev, "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->dev, > - "A TPM error (%zd) occurred attempting to determine the timeouts\n", > - rc); > - goto duration; > + rc = tpm_getcap(chip, 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)); > > /* > @@ -597,29 +589,17 @@ int tpm_get_timeouts(struct tpm_chip *chip) > chip->timeout_c = usecs_to_jiffies(new_timeout[2]); > chip->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, 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->duration[TPM_SHORT] = > - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); > + usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short)); > chip->duration[TPM_MEDIUM] = > - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); > + usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium)); > chip->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 > ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v9 3/5] tpm: Clean up reading of timeout and duration capabilities 2016-07-13 16:19 ` [PATCH v9 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk 2016-07-18 18:15 ` Jarkko Sakkinen @ 2016-07-18 18:19 ` Jarkko Sakkinen 2016-07-18 18:20 ` Jarkko Sakkinen 1 sibling, 1 reply; 68+ messages in thread From: Jarkko Sakkinen @ 2016-07-18 18:19 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, jgunthorpe, stefanb On Wed, Jul 13, 2016 at 09:19:34AM -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> You have to fix the reported kbuild errors. /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 a4beb53..dc492ee 100644 > --- a/drivers/char/tpm/tpm-interface.c > +++ b/drivers/char/tpm/tpm-interface.c > @@ -460,9 +460,19 @@ ssize_t tpm_getcap(struct tpm_chip *chip, __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; > } > > @@ -503,10 +513,9 @@ 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; > > if (chip->flags & TPM_CHIP_FLAG_TPM2) { > @@ -524,42 +533,25 @@ int tpm_get_timeouts(struct tpm_chip *chip) > return 0; > } > > - 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, 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->dev, "Issuing TPM_STARTUP"); > + dev_info(&chip->dev, "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->dev, > - "A TPM error (%zd) occurred attempting to determine the timeouts\n", > - rc); > - goto duration; > + rc = tpm_getcap(chip, 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)); > > /* > @@ -597,29 +589,17 @@ int tpm_get_timeouts(struct tpm_chip *chip) > chip->timeout_c = usecs_to_jiffies(new_timeout[2]); > chip->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, 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->duration[TPM_SHORT] = > - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); > + usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short)); > chip->duration[TPM_MEDIUM] = > - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); > + usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium)); > chip->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 > ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v9 3/5] tpm: Clean up reading of timeout and duration capabilities 2016-07-18 18:19 ` Jarkko Sakkinen @ 2016-07-18 18:20 ` Jarkko Sakkinen 0 siblings, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-07-18 18:20 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, jgunthorpe, stefanb On Mon, Jul 18, 2016 at 09:19:53PM +0300, Jarkko Sakkinen wrote: > On Wed, Jul 13, 2016 at 09:19:34AM -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> > > You have to fix the reported kbuild errors. Please ignore this :) Pressed send button by mistake in mutt. /Jarkko ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v9 4/5] tpm: Allow TPM chip drivers to override reported command durations 2016-07-13 16:19 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (2 preceding siblings ...) 2016-07-13 16:19 ` [PATCH v9 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk @ 2016-07-13 16:19 ` Ed Swierk 2016-07-13 17:04 ` kbuild test robot 2016-07-18 18:40 ` Jarkko Sakkinen 2016-07-13 16:19 ` [PATCH v9 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk ` (2 subsequent siblings) 6 siblings, 2 replies; 68+ messages in thread From: Ed Swierk @ 2016-07-13 16:19 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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 | 148 ++++++++++++++++++++++----------------- drivers/char/tpm/tpm_tis_core.c | 32 +++------ include/linux/tpm.h | 3 +- 3 files changed, 94 insertions(+), 89 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index dc492ee..9dafc25 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -513,10 +513,10 @@ 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; + unsigned long orig_timeout_a, orig_timeout_b, orig_timeout_c, + orig_timeout_d, orig_duration[3]; if (chip->flags & TPM_CHIP_FLAG_TPM2) { /* Fixed timeouts for TPM2 */ @@ -533,7 +533,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) return 0; } - rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, + rc = tpm_getcap(chip, 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. @@ -542,77 +542,95 @@ int tpm_get_timeouts(struct tpm_chip *chip) if (tpm_startup(chip, TPM_ST_CLEAR)) return rc; - rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, + rc = tpm_getcap(chip, 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->timeout_adjusted = - chip->ops->update_timeouts(chip, new_timeout); - - if (!chip->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->timeout_adjusted = true; - } - } - - /* Report adjusted timeouts */ - if (chip->timeout_adjusted) { - dev_info(&chip->dev, - 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->timeout_a = usecs_to_jiffies(new_timeout[0]); - chip->timeout_b = usecs_to_jiffies(new_timeout[1]); - chip->timeout_c = usecs_to_jiffies(new_timeout[2]); - chip->timeout_d = usecs_to_jiffies(new_timeout[3]); - - rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap, + rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap2, "attempting to determine the durations"); if (rc) return rc; - chip->duration[TPM_SHORT] = - usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short)); - chip->duration[TPM_MEDIUM] = - usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium)); - chip->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->timeout_a = usecs_to_jiffies(cap1.timeout.a); + chip->timeout_b = usecs_to_jiffies(cap1.timeout.b); + chip->timeout_c = usecs_to_jiffies(cap1.timeout.c); + chip->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->duration[TPM_SHORT] < (HZ / 100)) { - chip->duration[TPM_SHORT] = HZ; - chip->duration[TPM_MEDIUM] *= 1000; - chip->duration[TPM_LONG] *= 1000; - chip->duration_adjusted = true; - dev_info(&chip->dev, "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->timeout_a = msecs_to_jiffies(cap1.timeout.a); + chip->timeout_b = msecs_to_jiffies(cap1.timeout.b); + chip->timeout_c = msecs_to_jiffies(cap1.timeout.c); + chip->timeout_d = msecs_to_jiffies(cap1.timeout.d); + chip->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->duration[TPM_SHORT] = + usecs_to_jiffies(cap2.duration.tpm_short); + chip->duration[TPM_MEDIUM] = + usecs_to_jiffies(cap2.duration.tpm_medium); + chip->duration[TPM_LONG] = + usecs_to_jiffies(cap2.duration.tpm_long); + + orig_timeout_a = chip->timeout_a; + orig_timeout_b = chip->timeout_b; + orig_timeout_c = chip->timeout_c; + orig_timeout_d = chip->timeout_d; + memcpy(orig_duration, chip->duration, 3 * sizeof(unsigned long)); + + /* 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->duration[TPM_SHORT] = + msecs_to_jiffies(cap2.duration.tpm_short); + chip->duration[TPM_MEDIUM] = + msecs_to_jiffies(cap2.duration.tpm_medium); + chip->duration[TPM_LONG] = + msecs_to_jiffies(cap2.duration.tpm_long); + chip->duration_adjusted = true; + } + + if (chip->ops->update_timeouts != NULL) + chip->ops->update_timeouts(chip); + + if (chip->timeout_adjusted) { + dev_info(&chip->dev, + HW_ERR "Adjusted timeouts: A %u->%uus B %u->%uus" + " C %u->%uus D %u->%uus\n", + jiffies_to_usecs(orig_timeout_a), + jiffies_to_usecs(chip->timeout_a), + jiffies_to_usecs(orig_timeout_b), + jiffies_to_usecs(chip->timeout_b), + jiffies_to_usecs(orig_timeout_c), + jiffies_to_usecs(chip->timeout_c), + jiffies_to_usecs(orig_timeout_d), + jiffies_to_usecs(chip->timeout_d)); + } + + if (chip->duration_adjusted) { + dev_info(&chip->dev, + HW_ERR "Adjusted durations: short %u->%uus" + " medium %u->%uus long %u->%uus\n", + jiffies_to_usecs(orig_duration[TPM_SHORT]), + jiffies_to_usecs(chip->duration[TPM_SHORT]), + jiffies_to_usecs(orig_duration[TPM_MEDIUM]), + jiffies_to_usecs(chip->duration[TPM_MEDIUM]), + jiffies_to_usecs(orig_duration[TPM_LONG]), + jiffies_to_usecs(chip->duration[TPM_LONG])); + } + return 0; } EXPORT_SYMBOL_GPL(tpm_get_timeouts); diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index e62fdeb..f013664 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -398,37 +398,25 @@ 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) { struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); - int i, rc; + int rc; u32 did_vid; rc = tpm_tis_read32(priv, TPM_DID_VID(0), &did_vid); if (rc < 0) return rc; - 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 (did_vid) { + case 0x32041114: /* Atmel 3204 */ + chip->timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); + chip->timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); + chip->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 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* Re: [PATCH v9 4/5] tpm: Allow TPM chip drivers to override reported command durations 2016-07-13 16:19 ` [PATCH v9 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk @ 2016-07-13 17:04 ` kbuild test robot 2016-07-18 18:40 ` Jarkko Sakkinen 1 sibling, 0 replies; 68+ messages in thread From: kbuild test robot @ 2016-07-13 17:04 UTC (permalink / raw) To: Ed Swierk Cc: kbuild-all, tpmdd-devel, linux-kernel, linux-security-module, jarkko.sakkinen, jgunthorpe, stefanb, eswierk [-- Attachment #1: Type: text/plain, Size: 3257 bytes --] Hi, [auto build test WARNING on next-20160712] [cannot apply to char-misc/char-misc-testing v4.7-rc7 v4.7-rc6 v4.7-rc5 v4.7-rc7] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Ed-Swierk/tpm-Command-duration-logging-and-chip-specific-override/20160714-002547 config: i386-randconfig-s1-201628 (attached as .config) compiler: gcc-6 (Debian 6.1.1-1) 6.1.1 20160430 reproduce: # save the attached .config to linux build tree make ARCH=i386 All warnings (new ones prefixed by >>): drivers/char/tpm/tpm_tis_core.c: In function 'tpm_tis_update_timeouts': >> drivers/char/tpm/tpm_tis_core.c:414:10: warning: 'return' with a value, in function returning void return rc; ^~ drivers/char/tpm/tpm_tis_core.c:406:13: note: declared here static void tpm_tis_update_timeouts(struct tpm_chip *chip) ^~~~~~~~~~~~~~~~~~~~~~~ vim +/return +414 drivers/char/tpm/tpm_tis_core.c 41a5e1cf Christophe Ricard 2016-05-19 398 if (!priv->irq_tested) 41a5e1cf Christophe Ricard 2016-05-19 399 msleep(1); 41a5e1cf Christophe Ricard 2016-05-19 400 if (!priv->irq_tested) 41a5e1cf Christophe Ricard 2016-05-19 401 disable_interrupts(chip); 41a5e1cf Christophe Ricard 2016-05-19 402 priv->irq_tested = true; 41a5e1cf Christophe Ricard 2016-05-19 403 return rc; 41a5e1cf Christophe Ricard 2016-05-19 404 } 41a5e1cf Christophe Ricard 2016-05-19 405 a7da7fe7 Ed Swierk 2016-07-13 406 static void tpm_tis_update_timeouts(struct tpm_chip *chip) 41a5e1cf Christophe Ricard 2016-05-19 407 { 41a5e1cf Christophe Ricard 2016-05-19 408 struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); a7da7fe7 Ed Swierk 2016-07-13 409 int rc; 41a5e1cf Christophe Ricard 2016-05-19 410 u32 did_vid; 41a5e1cf Christophe Ricard 2016-05-19 411 41a5e1cf Christophe Ricard 2016-05-19 412 rc = tpm_tis_read32(priv, TPM_DID_VID(0), &did_vid); 41a5e1cf Christophe Ricard 2016-05-19 413 if (rc < 0) 41a5e1cf Christophe Ricard 2016-05-19 @414 return rc; 41a5e1cf Christophe Ricard 2016-05-19 415 a7da7fe7 Ed Swierk 2016-07-13 416 switch (did_vid) { a7da7fe7 Ed Swierk 2016-07-13 417 case 0x32041114: /* Atmel 3204 */ a7da7fe7 Ed Swierk 2016-07-13 418 chip->timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); a7da7fe7 Ed Swierk 2016-07-13 419 chip->timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); a7da7fe7 Ed Swierk 2016-07-13 420 chip->timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); a7da7fe7 Ed Swierk 2016-07-13 421 chip->timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); a7da7fe7 Ed Swierk 2016-07-13 422 chip->timeout_adjusted = true; :::::: The code at line 414 was first introduced by commit :::::: 41a5e1cf1fe151ed48b4b3106c748d03a85133ce tpm/tpm_tis: Split tpm_tis driver into a core and TCG TIS compliant phy :::::: TO: Christophe Ricard <christophe.ricard@gmail.com> :::::: CC: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/octet-stream, Size: 22818 bytes --] ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v9 4/5] tpm: Allow TPM chip drivers to override reported command durations 2016-07-13 16:19 ` [PATCH v9 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk 2016-07-13 17:04 ` kbuild test robot @ 2016-07-18 18:40 ` Jarkko Sakkinen 1 sibling, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-07-18 18:40 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, jgunthorpe, stefanb On Wed, Jul 13, 2016 at 09:19:35AM -0700, Ed Swierk wrote: > 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. I don't really undestand why you need to turn things so much over. There's too much noise in this commit to reasonably evaluate it. > Signed-off-by: Ed Swierk <eswierk@skyportsystems.com> > --- > drivers/char/tpm/tpm-interface.c | 148 ++++++++++++++++++++++----------------- > drivers/char/tpm/tpm_tis_core.c | 32 +++------ > include/linux/tpm.h | 3 +- > 3 files changed, 94 insertions(+), 89 deletions(-) > > diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c > index dc492ee..9dafc25 100644 > --- a/drivers/char/tpm/tpm-interface.c > +++ b/drivers/char/tpm/tpm-interface.c > @@ -513,10 +513,10 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) > > int tpm_get_timeouts(struct tpm_chip *chip) > { > - cap_t cap; cap_t cap2; > - unsigned long new_timeout[4]; > - unsigned long old_timeout[4]; > - ssize_t rc; > + cap_t cap1, cap2; Do not use cap1. > + int rc; > + unsigned long orig_timeout_a, orig_timeout_b, orig_timeout_c, > + orig_timeout_d, orig_duration[3]; Use old_timeout array just to reduce the diff. > > if (chip->flags & TPM_CHIP_FLAG_TPM2) { > /* Fixed timeouts for TPM2 */ > @@ -533,7 +533,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) > return 0; > } > > - rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, > + rc = tpm_getcap(chip, 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. > @@ -542,77 +542,95 @@ int tpm_get_timeouts(struct tpm_chip *chip) > if (tpm_startup(chip, TPM_ST_CLEAR)) > return rc; > > - rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, > + rc = tpm_getcap(chip, 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->timeout_adjusted = > - chip->ops->update_timeouts(chip, new_timeout); > - > - if (!chip->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->timeout_adjusted = true; > - } > - } > - > - /* Report adjusted timeouts */ > - if (chip->timeout_adjusted) { > - dev_info(&chip->dev, > - 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->timeout_a = usecs_to_jiffies(new_timeout[0]); > - chip->timeout_b = usecs_to_jiffies(new_timeout[1]); > - chip->timeout_c = usecs_to_jiffies(new_timeout[2]); > - chip->timeout_d = usecs_to_jiffies(new_timeout[3]); > - > - rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap, > + rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap2, > "attempting to determine the durations"); > if (rc) > return rc; > > - chip->duration[TPM_SHORT] = > - usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short)); > - chip->duration[TPM_MEDIUM] = > - usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium)); > - chip->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->timeout_a = usecs_to_jiffies(cap1.timeout.a); > + chip->timeout_b = usecs_to_jiffies(cap1.timeout.b); > + chip->timeout_c = usecs_to_jiffies(cap1.timeout.c); > + chip->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->duration[TPM_SHORT] < (HZ / 100)) { > - chip->duration[TPM_SHORT] = HZ; > - chip->duration[TPM_MEDIUM] *= 1000; > - chip->duration[TPM_LONG] *= 1000; > - chip->duration_adjusted = true; > - dev_info(&chip->dev, "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->timeout_a = msecs_to_jiffies(cap1.timeout.a); > + chip->timeout_b = msecs_to_jiffies(cap1.timeout.b); > + chip->timeout_c = msecs_to_jiffies(cap1.timeout.c); > + chip->timeout_d = msecs_to_jiffies(cap1.timeout.d); > + chip->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->duration[TPM_SHORT] = > + usecs_to_jiffies(cap2.duration.tpm_short); > + chip->duration[TPM_MEDIUM] = > + usecs_to_jiffies(cap2.duration.tpm_medium); > + chip->duration[TPM_LONG] = > + usecs_to_jiffies(cap2.duration.tpm_long); > + > + orig_timeout_a = chip->timeout_a; > + orig_timeout_b = chip->timeout_b; > + orig_timeout_c = chip->timeout_c; > + orig_timeout_d = chip->timeout_d; > + memcpy(orig_duration, chip->duration, 3 * sizeof(unsigned long)); > + > + /* 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->duration[TPM_SHORT] = > + msecs_to_jiffies(cap2.duration.tpm_short); > + chip->duration[TPM_MEDIUM] = > + msecs_to_jiffies(cap2.duration.tpm_medium); > + chip->duration[TPM_LONG] = > + msecs_to_jiffies(cap2.duration.tpm_long); > + chip->duration_adjusted = true; > + } > + > + if (chip->ops->update_timeouts != NULL) > + chip->ops->update_timeouts(chip); > + > + if (chip->timeout_adjusted) { > + dev_info(&chip->dev, > + HW_ERR "Adjusted timeouts: A %u->%uus B %u->%uus" > + " C %u->%uus D %u->%uus\n", > + jiffies_to_usecs(orig_timeout_a), > + jiffies_to_usecs(chip->timeout_a), > + jiffies_to_usecs(orig_timeout_b), > + jiffies_to_usecs(chip->timeout_b), > + jiffies_to_usecs(orig_timeout_c), > + jiffies_to_usecs(chip->timeout_c), > + jiffies_to_usecs(orig_timeout_d), > + jiffies_to_usecs(chip->timeout_d)); > + } > + > + if (chip->duration_adjusted) { > + dev_info(&chip->dev, > + HW_ERR "Adjusted durations: short %u->%uus" > + " medium %u->%uus long %u->%uus\n", > + jiffies_to_usecs(orig_duration[TPM_SHORT]), > + jiffies_to_usecs(chip->duration[TPM_SHORT]), > + jiffies_to_usecs(orig_duration[TPM_MEDIUM]), > + jiffies_to_usecs(chip->duration[TPM_MEDIUM]), > + jiffies_to_usecs(orig_duration[TPM_LONG]), > + jiffies_to_usecs(chip->duration[TPM_LONG])); > + } > + > return 0; > } > EXPORT_SYMBOL_GPL(tpm_get_timeouts); > diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c > index e62fdeb..f013664 100644 > --- a/drivers/char/tpm/tpm_tis_core.c > +++ b/drivers/char/tpm/tpm_tis_core.c > @@ -398,37 +398,25 @@ 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) > { > struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); > - int i, rc; > + int rc; > u32 did_vid; > > rc = tpm_tis_read32(priv, TPM_DID_VID(0), &did_vid); > if (rc < 0) > return rc; > > - 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 (did_vid) { > + case 0x32041114: /* Atmel 3204 */ > + chip->timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); > + chip->timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); > + chip->timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); > + chip->timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); > + chip->timeout_adjusted = true; > + break; Is this needed if we have the special case for milliseconds in tpm_get_timeouts? > } > - > - 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 > /Jarkko ^ permalink raw reply [flat|nested] 68+ messages in thread
* [PATCH v9 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup 2016-07-13 16:19 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (3 preceding siblings ...) 2016-07-13 16:19 ` [PATCH v9 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk @ 2016-07-13 16:19 ` Ed Swierk 2016-07-13 16:44 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-07-18 18:07 ` Jarkko Sakkinen 6 siblings, 0 replies; 68+ messages in thread From: Ed Swierk @ 2016-07-13 16:19 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: jarkko.sakkinen, jgunthorpe, stefanb, eswierk 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_core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index f013664..84d6008 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -416,6 +416,12 @@ static void tpm_tis_update_timeouts(struct tpm_chip *chip) chip->timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); chip->timeout_adjusted = true; break; + case 0x0000104a: /* STMicro ST19NP18-TPM */ + chip->duration[TPM_SHORT] = 180 * HZ; + chip->duration[TPM_MEDIUM] = 180 * HZ; + chip->duration[TPM_LONG] = 180 * HZ; + chip->duration_adjusted = true; + break; } } -- 1.9.1 ^ permalink raw reply related [flat|nested] 68+ messages in thread
* Re: [PATCH v9 0/5] tpm: Command duration logging and chip-specific override 2016-07-13 16:19 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (4 preceding siblings ...) 2016-07-13 16:19 ` [PATCH v9 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk @ 2016-07-13 16:44 ` Ed Swierk 2016-07-13 17:36 ` Jason Gunthorpe 2016-07-18 18:07 ` Jarkko Sakkinen 6 siblings, 1 reply; 68+ messages in thread From: Ed Swierk @ 2016-07-13 16:44 UTC (permalink / raw) To: tpmdd-devel, linux-kernel, linux-security-module Cc: Jarkko Sakkinen, Jason Gunthorpe, Stefan Berger, Ed Swierk On Wed, Jul 13, 2016 at 9:19 AM, Ed Swierk <eswierk@skyportsystems.com> wrote: > v9: Include command duration in existing error messages rather than > logging an extra debug message. Rebase onto Jarkko's tree. Incidentally, with Jarkko's tree the tpm_tis module refuses to initialize (with or without force=1): tpm_tis 00:03: can't request region for resource [mem 0xfed40000-0xfed44fff] tpm_tis: probe of 00:03 failed with error -16 The memory region is not marked reserved by the BIOS: e820: BIOS-provided physical RAM map: Xen: [mem 0x0000000000000000-0x000000000005ffff] usable Xen: [mem 0x0000000000060000-0x0000000000067fff] reserved Xen: [mem 0x0000000000068000-0x000000000009afff] usable Xen: [mem 0x00000000000a0000-0x00000000000fffff] reserved Xen: [mem 0x0000000000100000-0x0000000075b01fff] usable Xen: [mem 0x0000000075baf000-0x000000007a1f5fff] usable Xen: [mem 0x000000007b7d7000-0x000000007b7fffff] usable Xen: [mem 0x000000007bf00000-0x000000007bffffff] usable Xen: [mem 0x00000000c7ffc000-0x00000000c7ffcfff] reserved Xen: [mem 0x00000000fbffc000-0x00000000fbffcfff] reserved Xen: [mem 0x00000000fec00000-0x00000000fec01fff] reserved Xen: [mem 0x00000000fec40000-0x00000000fec40fff] reserved Xen: [mem 0x00000000fed20000-0x00000000fed2ffff] usable Xen: [mem 0x00000000fee00000-0x00000000feefffff] reserved Xen: [mem 0x0000000100000000-0x0000000505deafff] usable With force=1, /proc/iomem shows: fed30000-fedfffff : RAM buffer fed40000-fed44fff : tpm_tis I can work around this problem by passing memmap=0x5000$0xfed40000 on the kernel command line. --Ed ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v9 0/5] tpm: Command duration logging and chip-specific override 2016-07-13 16:44 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk @ 2016-07-13 17:36 ` Jason Gunthorpe 2016-07-13 20:00 ` Ed Swierk 0 siblings, 1 reply; 68+ messages in thread From: Jason Gunthorpe @ 2016-07-13 17:36 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, Jarkko Sakkinen, Stefan Berger On Wed, Jul 13, 2016 at 09:44:05AM -0700, Ed Swierk wrote: > On Wed, Jul 13, 2016 at 9:19 AM, Ed Swierk <eswierk@skyportsystems.com> wrote: > > v9: Include command duration in existing error messages rather than > > logging an extra debug message. Rebase onto Jarkko's tree. > > Incidentally, with Jarkko's tree the tpm_tis module refuses to > initialize (with or without force=1): > > tpm_tis 00:03: can't request region for resource [mem 0xfed40000-0xfed44fff] > tpm_tis: probe of 00:03 failed with error -16 > > The memory region is not marked reserved by the BIOS: > fed30000-fedfffff : RAM buffer I think your bios is broken? A working BIOS will look like this: $ cat /proc/iomem | grep -i fed400 fed40000-fed44fff : pnp 00:00 It sets aside the struct resource during pnp: [ 0.097318] pnp: PnP ACPI init [ 0.097366] system 00:00: [mem 0xfed40000-0xfed44fff] has been reserved What did your system do? You should see prints like this: printk(KERN_DEBUG "e820: reserve RAM buffer [mem %#010llx-%#010llx]\n", start, end); Which only happen if E820_RAM is set, which is certainly not right for TPM memory. I don't know what kernel convention is to handle these sorts of defects? Is the use of the memmap kernel command line an appropriate work around? Jason ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v9 0/5] tpm: Command duration logging and chip-specific override 2016-07-13 17:36 ` Jason Gunthorpe @ 2016-07-13 20:00 ` Ed Swierk 2016-07-13 20:58 ` Eric W. Biederman 2016-07-13 20:59 ` Jason Gunthorpe 0 siblings, 2 replies; 68+ messages in thread From: Ed Swierk @ 2016-07-13 20:00 UTC (permalink / raw) To: Jason Gunthorpe Cc: tpmdd-devel, linux-kernel, linux-security-module, Jarkko Sakkinen, Stefan Berger On Wed, Jul 13, 2016 at 10:36 AM, Jason Gunthorpe <jgunthorpe@obsidianresearch.com> wrote: > I think your bios is broken? The BIOS is broken in many ways. I already have to pass memmap=256M$0x80000000, otherwise PCIe extended config space (MMCONFIG) is inaccessible. Also I found memmap=0x7000$0x7a7d0000 works around "APEI: Can not request [mem 0x7a7d0018-0x7a7d0067] for APEI ERST registers", as the BIOS seems to be mistakenly reserving 0x7b7d0000-7b7d7000 instead. > A working BIOS will look like this: > > $ cat /proc/iomem | grep -i fed400 > fed40000-fed44fff : pnp 00:00 > > It sets aside the struct resource during pnp: > > [ 0.097318] pnp: PnP ACPI init > [ 0.097366] system 00:00: [mem 0xfed40000-0xfed44fff] has been reserved > > What did your system do? > > You should see prints like this: > > printk(KERN_DEBUG > "e820: reserve RAM buffer [mem %#010llx-%#010llx]\n", > start, end); > > Which only happen if E820_RAM is set, which is certainly not right for > TPM memory. On my system I see e820: reserve RAM buffer [mem 0x0009b000-0x0009ffff] e820: reserve RAM buffer [mem 0x75b02000-0x77ffffff] e820: reserve RAM buffer [mem 0x7a1f6000-0x7bffffff] e820: reserve RAM buffer [mem 0x7b800000-0x7bffffff] e820: reserve RAM buffer [mem 0xfed30000-0xffffffff] e820: reserve RAM buffer [mem 0x505deb000-0x507ffffff] which doesn't make a whole lot of sense, as several of those areas overlap each other, never mind devices. > I don't know what kernel convention is to handle these sorts of > defects? > > Is the use of the memmap kernel command line an appropriate work > around? It works for me, though I would like to know if there's another approach. --Ed ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v9 0/5] tpm: Command duration logging and chip-specific override 2016-07-13 20:00 ` Ed Swierk @ 2016-07-13 20:58 ` Eric W. Biederman 2016-07-13 20:59 ` Jason Gunthorpe 1 sibling, 0 replies; 68+ messages in thread From: Eric W. Biederman @ 2016-07-13 20:58 UTC (permalink / raw) To: Ed Swierk Cc: Jason Gunthorpe, tpmdd-devel, linux-kernel, linux-security-module, Jarkko Sakkinen, Stefan Berger Ed Swierk <eswierk@skyportsystems.com> writes: > On Wed, Jul 13, 2016 at 10:36 AM, Jason Gunthorpe > <jgunthorpe@obsidianresearch.com> wrote: >> I think your bios is broken? > > The BIOS is broken in many ways. I already have to pass > memmap=256M$0x80000000, otherwise PCIe extended config space > (MMCONFIG) is inaccessible. Also I found memmap=0x7000$0x7a7d0000 > works around "APEI: Can not request [mem 0x7a7d0018-0x7a7d0067] for > APEI ERST registers", as the BIOS seems to be mistakenly reserving > 0x7b7d0000-7b7d7000 instead. > >> A working BIOS will look like this: >> >> $ cat /proc/iomem | grep -i fed400 >> fed40000-fed44fff : pnp 00:00 >> >> It sets aside the struct resource during pnp: >> >> [ 0.097318] pnp: PnP ACPI init >> [ 0.097366] system 00:00: [mem 0xfed40000-0xfed44fff] has been reserved >> >> What did your system do? >> >> You should see prints like this: >> >> printk(KERN_DEBUG >> "e820: reserve RAM buffer [mem %#010llx-%#010llx]\n", >> start, end); >> >> Which only happen if E820_RAM is set, which is certainly not right for >> TPM memory. > > On my system I see > > e820: reserve RAM buffer [mem 0x0009b000-0x0009ffff] > e820: reserve RAM buffer [mem 0x75b02000-0x77ffffff] > e820: reserve RAM buffer [mem 0x7a1f6000-0x7bffffff] > e820: reserve RAM buffer [mem 0x7b800000-0x7bffffff] > e820: reserve RAM buffer [mem 0xfed30000-0xffffffff] > e820: reserve RAM buffer [mem 0x505deb000-0x507ffffff] > > which doesn't make a whole lot of sense, as several of those areas > overlap each other, never mind devices. > >> I don't know what kernel convention is to handle these sorts of >> defects? >> >> Is the use of the memmap kernel command line an appropriate work >> around? > > It works for me, though I would like to know if there's another > approach. There is always poke your BIOS vendor until they deliver code that is not so b0rked it can not be used. You can also add a quirk based on the BIOS's mainboard identification string that fixes up the data provided by the BIOS. I remember a fair number of those dealing with reboot behavior and the like. Eric ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v9 0/5] tpm: Command duration logging and chip-specific override 2016-07-13 20:00 ` Ed Swierk 2016-07-13 20:58 ` Eric W. Biederman @ 2016-07-13 20:59 ` Jason Gunthorpe 1 sibling, 0 replies; 68+ messages in thread From: Jason Gunthorpe @ 2016-07-13 20:59 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, Jarkko Sakkinen, Stefan Berger On Wed, Jul 13, 2016 at 01:00:28PM -0700, Ed Swierk wrote: > On Wed, Jul 13, 2016 at 10:36 AM, Jason Gunthorpe > <jgunthorpe@obsidianresearch.com> wrote: > > I think your bios is broken? > > The BIOS is broken in many ways. I already have to pass > memmap=256M$0x80000000, otherwise PCIe extended config space > (MMCONFIG) is inaccessible. Also I found memmap=0x7000$0x7a7d0000 > works around "APEI: Can not request [mem 0x7a7d0018-0x7a7d0067] for > APEI ERST registers", as the BIOS seems to be mistakenly reserving > 0x7b7d0000-7b7d7000 instead. Is it is possible whatever causes the 'reserve RAM buffer' behavior in the kernel is wonky with your BIOS? That seems to be a special Linux action.. Could it be Xen related? The Xen hypervisor replaces the physical ram map for the dom0 guest, which is why you get these sorts of prints: Xen: [mem 0x0000000000000000-0x000000000005ffff] usable and not: [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x0000000000057fff] usable Jason ^ permalink raw reply [flat|nested] 68+ messages in thread
* Re: [PATCH v9 0/5] tpm: Command duration logging and chip-specific override 2016-07-13 16:19 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk ` (5 preceding siblings ...) 2016-07-13 16:44 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk @ 2016-07-18 18:07 ` Jarkko Sakkinen 6 siblings, 0 replies; 68+ messages in thread From: Jarkko Sakkinen @ 2016-07-18 18:07 UTC (permalink / raw) To: Ed Swierk Cc: tpmdd-devel, linux-kernel, linux-security-module, jgunthorpe, stefanb On Wed, Jul 13, 2016 at 09:19:31AM -0700, Ed Swierk wrote: > v9: Include command duration in existing error messages rather than > logging an extra debug message. Rebase onto Jarkko's tree. > > 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 For the next version please write something more readable. Describe the motivation and solution in big picture, why and how. This list does no good because it just mimics the list of patches. /Jarkko > 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 | 219 ++++++++++++++++++++------------------- > drivers/char/tpm/tpm_tis_core.c | 46 ++++---- > include/linux/tpm.h | 3 +- > 3 files changed, 136 insertions(+), 132 deletions(-) > > -- > 1.9.1 > ^ permalink raw reply [flat|nested] 68+ messages in thread
end of thread, other threads:[~2016-07-18 18:40 UTC | newest] Thread overview: 68+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-06-08 0:45 [PATCH v4 0/4] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-08 0:45 ` [PATCH v4 1/4] tpm_tis: Improve reporting of IO errors Ed Swierk 2016-06-08 0:45 ` [PATCH v4 2/4] tpm: Add optional logging of TPM command durations Ed Swierk 2016-06-08 0:45 ` [PATCH v4 3/4] tpm: Allow TPM chip drivers to override reported " Ed Swierk 2016-06-08 19:05 ` [tpmdd-devel] " Jason Gunthorpe 2016-06-08 20:41 ` Ed Swierk 2016-06-08 0:45 ` [PATCH v4 4/4] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk 2016-06-08 23:00 ` [PATCH v5 0/4] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-08 23:00 ` [PATCH v5 1/4] tpm_tis: Improve reporting of IO errors Ed Swierk 2016-06-08 23:00 ` [PATCH v5 2/4] tpm: Add optional logging of TPM command durations Ed Swierk 2016-06-08 23:00 ` [PATCH v5 3/4] tpm: Allow TPM chip drivers to override reported " Ed Swierk 2016-06-10 12:19 ` Jarkko Sakkinen 2016-06-10 17:34 ` Ed Swierk 2016-06-10 19:42 ` Jarkko Sakkinen 2016-06-11 1:54 ` Ed Swierk 2016-06-08 23:00 ` [PATCH v5 4/4] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk 2016-06-11 1:55 ` [PATCH v6 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-11 1:55 ` [PATCH v6 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk 2016-06-11 1:55 ` [PATCH v6 2/5] tpm: Add optional logging of TPM command durations Ed Swierk 2016-06-11 1:55 ` [PATCH v6 3/5] tpm: Factor out reading of timeout and duration capabilities Ed Swierk 2016-06-16 20:20 ` Jarkko Sakkinen 2016-06-19 12:12 ` Jarkko Sakkinen 2016-06-11 1:55 ` [PATCH v6 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk 2016-06-16 20:26 ` Jarkko Sakkinen 2016-06-11 1:55 ` [PATCH v6 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk 2016-06-21 1:53 ` [PATCH v7 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-21 1:53 ` [PATCH v7 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk 2016-06-21 1:53 ` [PATCH v7 2/5] tpm: Add optional logging of TPM command durations Ed Swierk 2016-06-21 1:54 ` [PATCH v7 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk 2016-06-21 20:52 ` Jarkko Sakkinen 2016-06-22 0:21 ` Ed Swierk 2016-06-22 10:46 ` Jarkko Sakkinen 2016-06-21 1:54 ` [PATCH v7 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk 2016-06-21 20:54 ` Jarkko Sakkinen 2016-06-21 1:54 ` [PATCH v7 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk 2016-06-21 20:55 ` Jarkko Sakkinen 2016-06-22 1:10 ` [PATCH v8 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-06-22 1:10 ` [PATCH v8 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk 2016-06-24 18:25 ` Jason Gunthorpe 2016-06-24 20:21 ` Jarkko Sakkinen 2016-06-24 20:23 ` Jarkko Sakkinen 2016-06-24 20:26 ` Jason Gunthorpe 2016-06-25 15:24 ` Jarkko Sakkinen 2016-06-25 15:47 ` Jarkko Sakkinen 2016-06-27 17:55 ` Jason Gunthorpe 2016-06-22 1:10 ` [PATCH v8 2/5] tpm: Add optional logging of TPM command durations Ed Swierk 2016-06-24 18:27 ` Jason Gunthorpe 2016-06-24 20:24 ` Jarkko Sakkinen 2016-06-22 1:10 ` [PATCH v8 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk 2016-06-22 1:10 ` [PATCH v8 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk 2016-06-22 1:10 ` [PATCH v8 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk 2016-07-13 16:19 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-07-13 16:19 ` [PATCH v9 1/5] tpm_tis: Improve reporting of IO errors Ed Swierk 2016-07-13 16:19 ` [PATCH v9 2/5] tpm: Add optional logging of TPM command durations Ed Swierk 2016-07-13 16:19 ` [PATCH v9 3/5] tpm: Clean up reading of timeout and duration capabilities Ed Swierk 2016-07-18 18:15 ` Jarkko Sakkinen 2016-07-18 18:19 ` Jarkko Sakkinen 2016-07-18 18:20 ` Jarkko Sakkinen 2016-07-13 16:19 ` [PATCH v9 4/5] tpm: Allow TPM chip drivers to override reported command durations Ed Swierk 2016-07-13 17:04 ` kbuild test robot 2016-07-18 18:40 ` Jarkko Sakkinen 2016-07-13 16:19 ` [PATCH v9 5/5] tpm_tis: Increase ST19NP18 TPM command duration to avoid chip lockup Ed Swierk 2016-07-13 16:44 ` [PATCH v9 0/5] tpm: Command duration logging and chip-specific override Ed Swierk 2016-07-13 17:36 ` Jason Gunthorpe 2016-07-13 20:00 ` Ed Swierk 2016-07-13 20:58 ` Eric W. Biederman 2016-07-13 20:59 ` Jason Gunthorpe 2016-07-18 18:07 ` Jarkko Sakkinen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).