Skip to content

Commit b400f9d

Browse files
webmeisterjarkkojs
authored andcommitted
tpm_tis: Use responseRetry to recover from data transfer errors
TPM responses may become damaged during transmission, for example due to bit flips on the wire. Instead of aborting when detecting such issues, the responseRetry functionality can be used to make the TPM retransmit its response and receive it again without errors. Signed-off-by: Alexander Steffen <Alexander.Steffen@infineon.com> Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org> Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
1 parent 32a0c86 commit b400f9d

2 files changed

Lines changed: 30 additions & 8 deletions

File tree

drivers/char/tpm/tpm_tis_core.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -340,19 +340,14 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
340340
return size;
341341
}
342342

343-
static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
343+
static int tpm_tis_try_recv(struct tpm_chip *chip, u8 *buf, size_t count)
344344
{
345345
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
346346
int size = 0;
347347
int status;
348348
u32 expected;
349349
int rc;
350350

351-
if (count < TPM_HEADER_SIZE) {
352-
size = -EIO;
353-
goto out;
354-
}
355-
356351
size = recv_data(chip, buf, TPM_HEADER_SIZE);
357352
/* read first 10 bytes, including tag, paramsize, and result */
358353
if (size < TPM_HEADER_SIZE) {
@@ -385,7 +380,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
385380
goto out;
386381
}
387382
status = tpm_tis_status(chip);
388-
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
383+
if (status & TPM_STS_DATA_AVAIL) {
389384
dev_err(&chip->dev, "Error left over data\n");
390385
size = -EIO;
391386
goto out;
@@ -399,10 +394,36 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
399394
}
400395

401396
out:
402-
tpm_tis_ready(chip);
403397
return size;
404398
}
405399

400+
static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
401+
{
402+
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
403+
unsigned int try;
404+
int rc = 0;
405+
406+
if (count < TPM_HEADER_SIZE)
407+
return -EIO;
408+
409+
for (try = 0; try < TPM_RETRY; try++) {
410+
rc = tpm_tis_try_recv(chip, buf, count);
411+
412+
if (rc == -EIO)
413+
/* Data transfer errors, indicated by EIO, can be
414+
* recovered by rereading the response.
415+
*/
416+
tpm_tis_write8(priv, TPM_STS(priv->locality),
417+
TPM_STS_RESPONSE_RETRY);
418+
else
419+
break;
420+
}
421+
422+
tpm_tis_ready(chip);
423+
424+
return rc;
425+
}
426+
406427
/*
407428
* If interrupts are used (signaled by an irq set in the vendor structure)
408429
* tpm.c can skip polling for the data to be available as the interrupt is

drivers/char/tpm/tpm_tis_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ enum tis_status {
3434
TPM_STS_GO = 0x20,
3535
TPM_STS_DATA_AVAIL = 0x10,
3636
TPM_STS_DATA_EXPECT = 0x08,
37+
TPM_STS_RESPONSE_RETRY = 0x02,
3738
TPM_STS_READ_ZERO = 0x23, /* bits that must be zero on read */
3839
};
3940

0 commit comments

Comments
 (0)