On Tue, 2023-06-13 at 20:02 +0200, Alexander Steffen wrote: > 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@xxxxxxxxxxxx> > --- > drivers/char/tpm/tpm_tis_core.c | 37 ++++++++++++++++++++++++++------- > drivers/char/tpm/tpm_tis_core.h | 1 + > 2 files changed, 30 insertions(+), 8 deletions(-) > > diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c > index 5ddaf24518be..a6d1396413a7 100644 > --- a/drivers/char/tpm/tpm_tis_core.c > +++ b/drivers/char/tpm/tpm_tis_core.c > @@ -337,7 +337,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) > return size; > } > > -static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) > +static int tpm_tis_try_recv(struct tpm_chip *chip, u8 *buf, size_t count) > { > struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); > int size = 0; > @@ -345,11 +345,6 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) > u32 expected; > int rc; > > - if (count < TPM_HEADER_SIZE) { > - size = -EIO; > - goto out; > - } > - > size = recv_data(chip, buf, TPM_HEADER_SIZE); > /* read first 10 bytes, including tag, paramsize, and result */ > if (size < TPM_HEADER_SIZE) { > @@ -382,7 +377,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) > goto out; > } > status = tpm_tis_status(chip); > - if (status & TPM_STS_DATA_AVAIL) { /* retry? */ > + if (status & TPM_STS_DATA_AVAIL) { > dev_err(&chip->dev, "Error left over data\n"); > size = -EIO; > goto out; > @@ -396,10 +391,36 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) > } > > out: > - tpm_tis_ready(chip); > return size; > } > > +static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) > +{ > + struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); > + unsigned int try; > + int rc = 0; > + > + if (count < TPM_HEADER_SIZE) > + return -EIO; > + > + for (try = 0; try < TPM_RETRY; try++) { > + rc = tpm_tis_try_recv(chip, buf, count); > + > + if (rc == -EIO) > + /* Data transfer errors, indicated by EIO, can be > + * recovered by rereading the response. > + */ > + tpm_tis_write8(priv, TPM_STS(priv->locality), > + TPM_STS_RESPONSE_RETRY); > + else > + break; > + } > + > + tpm_tis_ready(chip); > + > + return rc; > +} > + > /* > * If interrupts are used (signaled by an irq set in the vendor structure) > * tpm.c can skip polling for the data to be available as the interrupt is > diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h > index 610bfadb6acf..3a6b600d22ba 100644 > --- a/drivers/char/tpm/tpm_tis_core.h > +++ b/drivers/char/tpm/tpm_tis_core.h > @@ -34,6 +34,7 @@ enum tis_status { > TPM_STS_GO = 0x20, > TPM_STS_DATA_AVAIL = 0x10, > TPM_STS_DATA_EXPECT = 0x08, > + TPM_STS_RESPONSE_RETRY = 0x02, > TPM_STS_READ_ZERO = 0x23, /* bits that must be zero on read */ > }; > Reviewed-by: Jarkko Sakkinen <jarkko@xxxxxxxxxx> BR, Jarkko