Skip to content

Commit de9e33d

Browse files
u1f35cjarkkojs
authored andcommitted
tpm, tpm_tis: Workaround failed command reception on Infineon devices
Some Infineon devices have a issue where the status register will get stuck with a quick REQUEST_USE / COMMAND_READY sequence. This is not simply a matter of requiring a longer timeout; the work around is to retry the command submission. Add appropriate logic to do this in the send path. This is fixed in later firmware revisions, but those are not always available, and cannot generally be easily updated from outside a firmware environment. Testing has been performed with a simple repeated loop of doing a TPM2_CC_GET_CAPABILITY for TPM_CAP_PROP_MANUFACTURER using the Go code at: https://the.earth.li/~noodles/tpm-stuff/timeout-reproducer-simple.go It can take several hours to reproduce, and several million operations. Signed-off-by: Jonathan McDowell <[email protected]> Reviewed-by: Jarkko Sakkinen <[email protected]> Signed-off-by: Jarkko Sakkinen <[email protected]>
1 parent 7146dff commit de9e33d

File tree

3 files changed

+16
-3
lines changed

3 files changed

+16
-3
lines changed

drivers/char/tpm/tpm_tis_core.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,10 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
463463

464464
if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
465465
&priv->int_queue, false) < 0) {
466-
rc = -ETIME;
466+
if (test_bit(TPM_TIS_STATUS_VALID_RETRY, &priv->flags))
467+
rc = -EAGAIN;
468+
else
469+
rc = -ETIME;
467470
goto out_err;
468471
}
469472
status = tpm_tis_status(chip);
@@ -480,7 +483,10 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
480483

481484
if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
482485
&priv->int_queue, false) < 0) {
483-
rc = -ETIME;
486+
if (test_bit(TPM_TIS_STATUS_VALID_RETRY, &priv->flags))
487+
rc = -EAGAIN;
488+
else
489+
rc = -ETIME;
484490
goto out_err;
485491
}
486492
status = tpm_tis_status(chip);
@@ -545,9 +551,11 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
545551
if (rc >= 0)
546552
/* Data transfer done successfully */
547553
break;
548-
else if (rc != -EIO)
554+
else if (rc != -EAGAIN && rc != -EIO)
549555
/* Data transfer failed, not recoverable */
550556
return rc;
557+
558+
usleep_range(priv->timeout_min, priv->timeout_max);
551559
}
552560

553561
/* go and do it */
@@ -1143,6 +1151,9 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
11431151
priv->timeout_max = TIS_TIMEOUT_MAX_ATML;
11441152
}
11451153

1154+
if (priv->manufacturer_id == TPM_VID_IFX)
1155+
set_bit(TPM_TIS_STATUS_VALID_RETRY, &priv->flags);
1156+
11461157
if (is_bsw()) {
11471158
priv->ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR,
11481159
ILB_REMAP_SIZE);

drivers/char/tpm/tpm_tis_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ enum tpm_tis_flags {
8989
TPM_TIS_INVALID_STATUS = 1,
9090
TPM_TIS_DEFAULT_CANCELLATION = 2,
9191
TPM_TIS_IRQ_TESTED = 3,
92+
TPM_TIS_STATUS_VALID_RETRY = 4,
9293
};
9394

9495
struct tpm_tis_data {

include/linux/tpm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ enum tpm2_cc_attrs {
335335
#define TPM_VID_WINBOND 0x1050
336336
#define TPM_VID_STM 0x104A
337337
#define TPM_VID_ATML 0x1114
338+
#define TPM_VID_IFX 0x15D1
338339

339340
enum tpm_chip_flags {
340341
TPM_CHIP_FLAG_BOOTSTRAPPED = BIT(0),

0 commit comments

Comments
 (0)