Re: [PATCH] tpm: Fix the timeout & use ktime

From: Jonathan McDowell
Date: Fri Jun 20 2025 - 10:03:48 EST


On Wed, Jun 11, 2025 at 04:25:24PM +0000, Orlov, Ivan wrote:
The current implementation of timeout detection works in the following
way:

1. Read completion status. If completed, return the data
2. Sleep for some time (usleep_range)
3. Check for timeout using current jiffies value. Return an error if
timed out
4. Goto 1

usleep_range doesn't guarantee it's always going to wake up strictly in
(min, max) range, so such a situation is possible:

1. Driver reads completion status. No completion yet
2. Process sleeps indefinitely. In the meantime, TPM responds
3. We check for timeout without checking for the completion again.
Result is lost.

This looks similar to the issue I fixed in 7146dffa875c ('Fix timeout
handling when waiting for TPM status'), I assume you're actually seeing
it in your systems? I think we're starting to see it (rarely) now the
other issues are fixed in our builds. As a similar approach does the
following work?

diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 8d7e4da6ed53..18ae0767fa60 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -127,7 +127,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
goto out_recv;
stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
- do {
+ while (true) {
u8 status = tpm_chip_status(chip);
if ((status & chip->ops->req_complete_mask) ==
chip->ops->req_complete_val)
@@ -138,9 +138,12 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
return -ECANCELED;
}
+ if (time_after(jiffies, stop))
+ break;
+
tpm_msleep(TPM_TIMEOUT_POLL);
rmb();
- } while (time_before(jiffies, stop));
+ }
tpm_chip_cancel(chip);
dev_err(&chip->dev, "Operation Timed out\n");