tpm: tpm_tis_spi: Use wait_woken() in wait_for_tmp_stat()

wait_event_interruptible_timeout() evaluates its condition after setting
the current task state to TASK_INTERRUPTIBLE.

With CONFIG_DEBUG_ATOMIC_SLEEP this triggers a warning when the IRQ wait
path is used:

    tpm_tis_status()
      tpm_tis_spi_read_bytes()
        tpm_tis_spi_transfer_full()
          spi_bus_lock()
            mutex_lock()

Address this with the following measures:

1. Call wait_tpm_stat_cond() only while tasking is running.
2. Use wait_woken() to wait for changes.

Cc: stable@vger.kernel.org # v4.19+
Cc: Linus Walleij <linusw@kernel.org>
Reported-by: Stefan Wahren <wahrenst@gmx.net>
Closes: https://lore.kernel.org/linux-integrity/6964bec7-3dbb-453b-89ef-9b990217a8b9@gmx.net/
Fixes: 1a339b658d ("tpm_tis_spi: Pass the SPI IRQ down to the driver")
Reviewed-by: Linus Walleij <linusw@kernel.org>
Tested-by: Stefan Wahren <wahrenst@gmx.net>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
This commit is contained in:
Jarkko Sakkinen 2026-05-09 21:51:07 +03:00
parent 595ca21f79
commit c0c9cfb3b7

View File

@ -66,8 +66,8 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
bool check_cancel)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
DEFINE_WAIT_FUNC(wait, woken_wake_function);
unsigned long stop;
long rc;
u8 status;
bool canceled = false;
u8 sts_mask;
@ -87,23 +87,30 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
/* process status changes with irq support */
if (sts_mask) {
ret = -ETIME;
add_wait_queue(queue, &wait);
again:
if (wait_for_tpm_stat_cond(chip, sts_mask, check_cancel,
&canceled)) {
ret = canceled ? -ECANCELED : 0;
goto out;
}
timeout = stop - jiffies;
if ((long)timeout <= 0)
return -ETIME;
rc = wait_event_interruptible_timeout(*queue,
wait_for_tpm_stat_cond(chip, sts_mask, check_cancel,
&canceled),
timeout);
if (rc > 0) {
if (canceled)
return -ECANCELED;
ret = 0;
}
if (rc == -ERESTARTSYS && freezing(current)) {
clear_thread_flag(TIF_SIGPENDING);
goto again;
goto out;
if (signal_pending(current)) {
if (freezing(current)) {
clear_thread_flag(TIF_SIGPENDING);
goto again;
}
goto out;
}
wait_woken(&wait, TASK_INTERRUPTIBLE, timeout);
goto again;
out:
remove_wait_queue(queue, &wait);
}
if (ret)