]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
tpm: tpm_tis_spi: Use wait_woken() in wait_for_tmp_stat()
authorJarkko Sakkinen <jarkko@kernel.org>
Sat, 9 May 2026 18:51:07 +0000 (21:51 +0300)
committerJarkko Sakkinen <jarkko@kernel.org>
Sun, 21 Jun 2026 01:25:28 +0000 (04:25 +0300)
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: 1a339b658d9d ("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>
drivers/char/tpm/tpm_tis_core.c

index 21d79ad3b164e731fddef3da1c75ae942ca30b1d..153a57c7924005ee3c5b32f1520f526b2bf5d7b4 100644 (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)