tpm_tis: use default timeout value if chip reports it as zero
authorMaciej S. Szmigiero <mail@maciej.szmigiero.name>
Fri, 13 Jan 2017 21:37:00 +0000 (22:37 +0100)
committerJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Mon, 23 Jan 2017 16:28:18 +0000 (18:28 +0200)
Since commit 1107d065fdf1 ("tpm_tis: Introduce intermediate layer for
TPM access") Atmel 3203 TPM on ThinkPad X61S (TPM firmware version 13.9)
no longer works.  The initialization proceeds fine until we get and
start using chip-reported timeouts - and the chip reports C and D
timeouts of zero.

It turns out that until commit 8e54caf407b98e ("tpm: Provide a generic
means to override the chip returned timeouts") we had actually let
default timeout values remain in this case, so let's bring back this
behavior to make chips like Atmel 3203 work again.

Use a common code that was introduced by that commit so a warning is
printed in this case and /sys/class/tpm/tpm*/timeouts correctly says the
timeouts aren't chip-original.

Fixes: 1107d065fdf1 ("tpm_tis: Introduce intermediate layer for TPM access")
Cc: stable@vger.kernel.org
Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
drivers/char/tpm/tpm-interface.c
drivers/char/tpm/tpm_tis.c
drivers/char/tpm/tpm_tis_core.c
drivers/char/tpm/tpm_tis_core.h

index fecdd3fa8126a17b7ea9c3c8d0dc415bdfc17290..a3461cbdde5fa37acf0f925ee3708f8ea162c5f0 100644 (file)
@@ -522,8 +522,7 @@ 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];
+       unsigned long timeout_old[4], timeout_chip[4], timeout_eff[4];
        ssize_t rc;
 
        if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS)
@@ -564,11 +563,15 @@ int tpm_get_timeouts(struct tpm_chip *chip)
                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));
+       timeout_old[0] = jiffies_to_usecs(chip->timeout_a);
+       timeout_old[1] = jiffies_to_usecs(chip->timeout_b);
+       timeout_old[2] = jiffies_to_usecs(chip->timeout_c);
+       timeout_old[3] = jiffies_to_usecs(chip->timeout_d);
+       timeout_chip[0] = be32_to_cpu(cap.timeout.a);
+       timeout_chip[1] = be32_to_cpu(cap.timeout.b);
+       timeout_chip[2] = be32_to_cpu(cap.timeout.c);
+       timeout_chip[3] = be32_to_cpu(cap.timeout.d);
+       memcpy(timeout_eff, timeout_chip, sizeof(timeout_eff));
 
        /*
         * Provide ability for vendor overrides of timeout values in case
@@ -576,16 +579,24 @@ int tpm_get_timeouts(struct tpm_chip *chip)
         */
        if (chip->ops->update_timeouts != NULL)
                chip->timeout_adjusted =
-                       chip->ops->update_timeouts(chip, new_timeout);
+                       chip->ops->update_timeouts(chip, timeout_eff);
 
        if (!chip->timeout_adjusted) {
-               /* Don't overwrite default if value is 0 */
-               if (new_timeout[0] != 0 && new_timeout[0] < 1000) {
-                       int i;
+               /* Restore default if chip reported 0 */
+               int i;
 
+               for (i = 0; i < ARRAY_SIZE(timeout_eff); i++) {
+                       if (timeout_eff[i])
+                               continue;
+
+                       timeout_eff[i] = timeout_old[i];
+                       chip->timeout_adjusted = true;
+               }
+
+               if (timeout_eff[0] != 0 && timeout_eff[0] < 1000) {
                        /* timeouts in msec rather usec */
-                       for (i = 0; i != ARRAY_SIZE(new_timeout); i++)
-                               new_timeout[i] *= 1000;
+                       for (i = 0; i != ARRAY_SIZE(timeout_eff); i++)
+                               timeout_eff[i] *= 1000;
                        chip->timeout_adjusted = true;
                }
        }
@@ -594,16 +605,16 @@ int tpm_get_timeouts(struct tpm_chip *chip)
        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]);
+                        timeout_chip[0], timeout_eff[0],
+                        timeout_chip[1], timeout_eff[1],
+                        timeout_chip[2], timeout_eff[2],
+                        timeout_chip[3], timeout_eff[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]);
+       chip->timeout_a = usecs_to_jiffies(timeout_eff[0]);
+       chip->timeout_b = usecs_to_jiffies(timeout_eff[1]);
+       chip->timeout_c = usecs_to_jiffies(timeout_eff[2]);
+       chip->timeout_d = usecs_to_jiffies(timeout_eff[3]);
 
        rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap,
                        "attempting to determine the durations");
index 0127af130cb12eef911e0f296e8b885e1f391723..7912dadc39be5cee5c9d2a4cce9bace9c0704f0e 100644 (file)
@@ -159,7 +159,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
                irq = tpm_info->irq;
 
        if (itpm)
-               phy->priv.flags |= TPM_TIS_ITPM_POSSIBLE;
+               phy->priv.flags |= TPM_TIS_ITPM_WORKAROUND;
 
        return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg,
                                 acpi_dev_handle);
index 7993678954a2b7c2910233f77c6af1b5070af9cc..0cfc0eed8525c73c4b147177e8b7059f6d8cf196 100644 (file)
@@ -264,7 +264,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
        struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
        int rc, status, burstcnt;
        size_t count = 0;
-       bool itpm = priv->flags & TPM_TIS_ITPM_POSSIBLE;
+       bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND;
 
        if (request_locality(chip, 0) < 0)
                return -EBUSY;
@@ -740,7 +740,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                 (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
                 vendor >> 16, rid);
 
-       if (!(priv->flags & TPM_TIS_ITPM_POSSIBLE)) {
+       if (!(priv->flags & TPM_TIS_ITPM_WORKAROUND)) {
                probe = probe_itpm(chip);
                if (probe < 0) {
                        rc = -ENODEV;
@@ -748,7 +748,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                }
 
                if (!!probe)
-                       priv->flags |= TPM_TIS_ITPM_POSSIBLE;
+                       priv->flags |= TPM_TIS_ITPM_WORKAROUND;
        }
 
        /* Figure out the capabilities */
index 9191aabbf9c2d9031fae874d720c7510480a59fb..e2212f021a02eb67db9be8bf479edaa97d8b516d 100644 (file)
@@ -80,7 +80,7 @@ enum tis_defaults {
 #define        TPM_RID(l)                      (0x0F04 | ((l) << 12))
 
 enum tpm_tis_flags {
-       TPM_TIS_ITPM_POSSIBLE           = BIT(0),
+       TPM_TIS_ITPM_WORKAROUND         = BIT(0),
 };
 
 struct tpm_tis_data {