Commit 1d70fe9d authored by Maciej S. Szmigiero's avatar Maciej S. Szmigiero Committed by Jarkko Sakkinen

tpm_tis: use default timeout value if chip reports it as zero

Since commit 1107d065 ("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 8e54caf4 ("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: 1107d065 ("tpm_tis: Introduce intermediate layer for TPM access")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarMaciej S. Szmigiero <mail@maciej.szmigiero.name>
Reviewed-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
parent 62bfdacb
...@@ -522,8 +522,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) ...@@ -522,8 +522,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
int tpm_get_timeouts(struct tpm_chip *chip) int tpm_get_timeouts(struct tpm_chip *chip)
{ {
cap_t cap; cap_t cap;
unsigned long new_timeout[4]; unsigned long timeout_old[4], timeout_chip[4], timeout_eff[4];
unsigned long old_timeout[4];
ssize_t rc; ssize_t rc;
if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS) if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS)
...@@ -564,11 +563,15 @@ int tpm_get_timeouts(struct tpm_chip *chip) ...@@ -564,11 +563,15 @@ int tpm_get_timeouts(struct tpm_chip *chip)
return rc; return rc;
} }
old_timeout[0] = be32_to_cpu(cap.timeout.a); timeout_old[0] = jiffies_to_usecs(chip->timeout_a);
old_timeout[1] = be32_to_cpu(cap.timeout.b); timeout_old[1] = jiffies_to_usecs(chip->timeout_b);
old_timeout[2] = be32_to_cpu(cap.timeout.c); timeout_old[2] = jiffies_to_usecs(chip->timeout_c);
old_timeout[3] = be32_to_cpu(cap.timeout.d); timeout_old[3] = jiffies_to_usecs(chip->timeout_d);
memcpy(new_timeout, old_timeout, sizeof(new_timeout)); 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 * Provide ability for vendor overrides of timeout values in case
...@@ -576,16 +579,24 @@ int tpm_get_timeouts(struct tpm_chip *chip) ...@@ -576,16 +579,24 @@ int tpm_get_timeouts(struct tpm_chip *chip)
*/ */
if (chip->ops->update_timeouts != NULL) if (chip->ops->update_timeouts != NULL)
chip->timeout_adjusted = chip->timeout_adjusted =
chip->ops->update_timeouts(chip, new_timeout); chip->ops->update_timeouts(chip, timeout_eff);
if (!chip->timeout_adjusted) { if (!chip->timeout_adjusted) {
/* Don't overwrite default if value is 0 */ /* Restore default if chip reported 0 */
if (new_timeout[0] != 0 && new_timeout[0] < 1000) { int i;
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 */ /* timeouts in msec rather usec */
for (i = 0; i != ARRAY_SIZE(new_timeout); i++) for (i = 0; i != ARRAY_SIZE(timeout_eff); i++)
new_timeout[i] *= 1000; timeout_eff[i] *= 1000;
chip->timeout_adjusted = true; chip->timeout_adjusted = true;
} }
} }
...@@ -594,16 +605,16 @@ int tpm_get_timeouts(struct tpm_chip *chip) ...@@ -594,16 +605,16 @@ int tpm_get_timeouts(struct tpm_chip *chip)
if (chip->timeout_adjusted) { if (chip->timeout_adjusted) {
dev_info(&chip->dev, dev_info(&chip->dev,
HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n", HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
old_timeout[0], new_timeout[0], timeout_chip[0], timeout_eff[0],
old_timeout[1], new_timeout[1], timeout_chip[1], timeout_eff[1],
old_timeout[2], new_timeout[2], timeout_chip[2], timeout_eff[2],
old_timeout[3], new_timeout[3]); timeout_chip[3], timeout_eff[3]);
} }
chip->timeout_a = usecs_to_jiffies(new_timeout[0]); chip->timeout_a = usecs_to_jiffies(timeout_eff[0]);
chip->timeout_b = usecs_to_jiffies(new_timeout[1]); chip->timeout_b = usecs_to_jiffies(timeout_eff[1]);
chip->timeout_c = usecs_to_jiffies(new_timeout[2]); chip->timeout_c = usecs_to_jiffies(timeout_eff[2]);
chip->timeout_d = usecs_to_jiffies(new_timeout[3]); chip->timeout_d = usecs_to_jiffies(timeout_eff[3]);
rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap, rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap,
"attempting to determine the durations"); "attempting to determine the durations");
......
...@@ -159,7 +159,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info, ...@@ -159,7 +159,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
irq = tpm_info->irq; irq = tpm_info->irq;
if (itpm) 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, return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg,
acpi_dev_handle); acpi_dev_handle);
......
...@@ -264,7 +264,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -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); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int rc, status, burstcnt; int rc, status, burstcnt;
size_t count = 0; 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) if (request_locality(chip, 0) < 0)
return -EBUSY; return -EBUSY;
...@@ -740,7 +740,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, ...@@ -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", (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
vendor >> 16, rid); vendor >> 16, rid);
if (!(priv->flags & TPM_TIS_ITPM_POSSIBLE)) { if (!(priv->flags & TPM_TIS_ITPM_WORKAROUND)) {
probe = probe_itpm(chip); probe = probe_itpm(chip);
if (probe < 0) { if (probe < 0) {
rc = -ENODEV; rc = -ENODEV;
...@@ -748,7 +748,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, ...@@ -748,7 +748,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
} }
if (!!probe) if (!!probe)
priv->flags |= TPM_TIS_ITPM_POSSIBLE; priv->flags |= TPM_TIS_ITPM_WORKAROUND;
} }
/* Figure out the capabilities */ /* Figure out the capabilities */
......
...@@ -80,7 +80,7 @@ enum tis_defaults { ...@@ -80,7 +80,7 @@ enum tis_defaults {
#define TPM_RID(l) (0x0F04 | ((l) << 12)) #define TPM_RID(l) (0x0F04 | ((l) << 12))
enum tpm_tis_flags { enum tpm_tis_flags {
TPM_TIS_ITPM_POSSIBLE = BIT(0), TPM_TIS_ITPM_WORKAROUND = BIT(0),
}; };
struct tpm_tis_data { struct tpm_tis_data {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment