analogdevicesinc / linux

Linux kernel variant from Analog Devices; see README.md for details

Home Page:https://github.com/analogdevicesinc/linux

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

axi-spi-engine driver watchdog timer still calls back after being canceled

dlech opened this issue · comments

          Unrelated, but I noticed another odd thing when everything is working properly (no timeout): the watchdog timer doesn't seem to be canceled on successful completion and still fires 5 seconds afterwards.
        iio_attr-1170    [000] d.h2.   129.119232: spi_engine_read_rx_fifo <-spi_engine_irq
        iio_attr-1170    [000] d.h2.   129.119233: spi_engine_read_buff <-spi_engine_read_rx_fifo
        iio_attr-1170    [000] d.h2.   129.119235: spi_engine_rx_next <-spi_engine_read_rx_fifo
        iio_attr-1170    [000] d.h2.   129.119236: spi_engine_xfer_next <-spi_engine_rx_next
        iio_attr-1170    [000] d.h2.   129.119238: spi_engine_complete_message <-spi_engine_irq
          <idle>-0       [000] ..s2.   134.152771: spi_engine_timeout <-call_timer_fn

del_timer() is called immediately before spi_engine_complete_message() so I would expect it to be canceled and not call the callback.

Originally posted by @dlech in #2287 (comment)

Sooo, I had to deal with this thing and saw the same behavior. As it turns out the problem is not as crazy or in core code as we were thinking... Note the below log (additional printk placed by me):

[  110.207544] Transfer one spi message... c1c9bda8
[  110.207578] Del watchdog timer (0)
[  110.207585] complete spi message c1c9bda8
[  110.207620] Modify Timer base...
root@analog:~# dmesg -c
[  115.280465] SPI ENGINE TIMEOUT

From the above it's clear that we're being faster in processing the spi transfer than calling mod_timer(). That's also visible by the return code from del_timer() which is 0 - > deactivated timer. So, if we move the mod_timer() call before activating the interrupts, we get:

[  382.201474] Transfer one spi message... c6919da8
[  382.201503] Modify Timer base...
[  382.201520] Del watchdog timer (1)
[  382.201532] complete spi message c6919da8

and no spurious soft interrupt. This was actually causing a kernel panic in a usecase where we play with overlays and a loop with load + unloading the overlay would eventually panic as we would end up (at some point) in the timer callback with the spi controller unbound...

So, a simple patch for this would be:

diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
index 050096874afe..44cbc40abde3 100644
--- a/drivers/spi/spi-axi-spi-engine.c
+++ b/drivers/spi/spi-axi-spi-engine.c
@@ -651,12 +651,13 @@ static int spi_engine_transfer_one_message(struct spi_master *master,

        int_enable |= SPI_ENGINE_INT_SYNC;

+       mod_timer(&spi_engine->watchdog_timer, jiffies + 5 * HZ);
+
        writel_relaxed(int_enable,
                spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
        spi_engine->int_enable = int_enable;
        spin_unlock_irqrestore(&spi_engine->lock, flags);

-       mod_timer(&spi_engine->watchdog_timer, jiffies + 5*HZ);

        return 0;
 }

Now we are calling mod_timer() with the spin lock held but AFAICT, it should not be an issue... Do you see any issue with it @dlech?

I just checked and this should not be an issue in the upstream version of the driver but we will probably only sync the upstream version of the controller in the main branch and not in 2022_R2 where we also need a fix and that is why I'm asking if this looks sane to you :).

I can also just call mod_timer() right before acquiring the spin...

I think it is fine in the spinlock since the timer should have the TIMER_IRQSAFE flag. But if you want to be consistent with the upstream driver, I just put it before the spinlock since it isn't possible for two calls to spi_engine_transfer_one_message() to happen at the same time.

Alright,

I'll do this for the 2022_R2 branch and assume for main we well get it in sync with upstream + offload stuff