]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
spi: rockchip: Read ISR, not IMR, to detect cs-inactive IRQ
authorJohn Madieu <john.madieu@gmail.com>
Sat, 25 Apr 2026 09:29:34 +0000 (09:29 +0000)
committerMark Brown <broonie@kernel.org>
Sun, 26 Apr 2026 21:57:20 +0000 (06:57 +0900)
rockchip_spi_isr() decides whether the current interrupt was the
cs-inactive event by reading IMR:

if (rs->cs_inactive &&
    readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE)
ctlr->target_abort(ctlr);

IMR is the interrupt mask register: it tells which sources are enabled,
not which one fired. In the PIO path, rockchip_spi_prepare_irq() enables
both INT_RF_FULL and INT_CS_INACTIVE in IMR when rs->cs_inactive is true:

if (rs->cs_inactive)
writel_relaxed(INT_RF_FULL | INT_CS_INACTIVE,
       rs->regs + ROCKCHIP_SPI_IMR);

so the IMR check is always true once cs_inactive is enabled, and every
PIO interrupt - including normal RF_FULL completions - is dispatched to
ctlr->target_abort(), aborting the transfer. The bug is reachable on
ROCKCHIP_SPI_VER2_TYPE2 in target mode with a DMA-capable controller
when the transfer is short enough to fall back to PIO
(rockchip_spi_can_dma() returns false below fifo_len).

Read ISR (which is RISR masked by IMR) so the check actually reflects
which interrupt fired, and parenthesise the expression for clarity while
at it.

Fixes: 869f2c94db92 ("spi: rockchip: Stop spi slave dma receiver when cs inactive")
Signed-off-by: John Madieu <john.madieu@gmail.com>
Link: https://patch.msgid.link/20260425092936.2590132-2-john.madieu@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-rockchip.c

index 14cd1b9d9793e2d15772fdefaace0b3c7898a095..de39f5da62cb58701ce1b0b1a82d8a90ca81f3a6 100644 (file)
@@ -357,7 +357,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id)
        struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
 
        /* When int_cs_inactive comes, spi target abort */
-       if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) {
+       if (rs->cs_inactive &&
+           (readl_relaxed(rs->regs + ROCKCHIP_SPI_ISR) & INT_CS_INACTIVE)) {
                ctlr->target_abort(ctlr);
                writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR);
                writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR);