Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alexander Steffen and committed by
Jarkko Sakkinen
b400f9d3 32a0c860

+30 -8
+29 -8
drivers/char/tpm/tpm_tis_core.c
··· 340 340 return size; 341 341 } 342 342 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) 344 344 { 345 345 struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); 346 346 int size = 0; 347 347 int status; 348 348 u32 expected; 349 349 int rc; 350 - 351 - if (count < TPM_HEADER_SIZE) { 352 - size = -EIO; 353 - goto out; 354 - } 355 350 356 351 size = recv_data(chip, buf, TPM_HEADER_SIZE); 357 352 /* read first 10 bytes, including tag, paramsize, and result */ ··· 380 385 goto out; 381 386 } 382 387 status = tpm_tis_status(chip); 383 - if (status & TPM_STS_DATA_AVAIL) { /* retry? */ 388 + if (status & TPM_STS_DATA_AVAIL) { 384 389 dev_err(&chip->dev, "Error left over data\n"); 385 390 size = -EIO; 386 391 goto out; ··· 394 399 } 395 400 396 401 out: 397 - tpm_tis_ready(chip); 398 402 return size; 403 + } 404 + 405 + static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) 406 + { 407 + struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); 408 + unsigned int try; 409 + int rc = 0; 410 + 411 + if (count < TPM_HEADER_SIZE) 412 + return -EIO; 413 + 414 + for (try = 0; try < TPM_RETRY; try++) { 415 + rc = tpm_tis_try_recv(chip, buf, count); 416 + 417 + if (rc == -EIO) 418 + /* Data transfer errors, indicated by EIO, can be 419 + * recovered by rereading the response. 420 + */ 421 + tpm_tis_write8(priv, TPM_STS(priv->locality), 422 + TPM_STS_RESPONSE_RETRY); 423 + else 424 + break; 425 + } 426 + 427 + tpm_tis_ready(chip); 428 + 429 + return rc; 399 430 } 400 431 401 432 /*
+1
drivers/char/tpm/tpm_tis_core.h
··· 34 34 TPM_STS_GO = 0x20, 35 35 TPM_STS_DATA_AVAIL = 0x10, 36 36 TPM_STS_DATA_EXPECT = 0x08, 37 + TPM_STS_RESPONSE_RETRY = 0x02, 37 38 TPM_STS_READ_ZERO = 0x23, /* bits that must be zero on read */ 38 39 }; 39 40