]> www.infradead.org Git - linux.git/commitdiff
spi: spi-mt65xx: Use threaded interrupt for non-SPIMEM transfer
authorAngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Fri, 26 Jul 2024 11:47:21 +0000 (13:47 +0200)
committerMark Brown <broonie@kernel.org>
Mon, 29 Jul 2024 00:23:25 +0000 (01:23 +0100)
In order to avoid blocking for an excessive amount of time, eventually
impacting on system responsiveness, interrupt handlers should finish
executing in as little time as possible.

Use threaded interrupt and move the SPI transfer handling (both
CPU and DMA) for the non-spimem case to an interrupt thread instead.

For SPI-MEM (IPM) controllers, handling is kept in the blocking
interrupt as it simply consists in signalling completion.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Link: https://patch.msgid.link/20240726114721.142196-1-angelogioacchino.delregno@collabora.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-mt65xx.c

index 36c2f52cd6b84653366afde4a360eb3e6056fd73..dfee244fc3173cb868f253247a9eb8b5bfcf0c25 100644 (file)
@@ -743,25 +743,13 @@ static int mtk_spi_setup(struct spi_device *spi)
        return 0;
 }
 
-static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
+static irqreturn_t mtk_spi_interrupt_thread(int irq, void *dev_id)
 {
        u32 cmd, reg_val, cnt, remainder, len;
        struct spi_controller *host = dev_id;
        struct mtk_spi *mdata = spi_controller_get_devdata(host);
        struct spi_transfer *xfer = mdata->cur_transfer;
 
-       reg_val = readl(mdata->base + SPI_STATUS0_REG);
-       if (reg_val & MTK_SPI_PAUSE_INT_STATUS)
-               mdata->state = MTK_SPI_PAUSED;
-       else
-               mdata->state = MTK_SPI_IDLE;
-
-       /* SPI-MEM ops */
-       if (mdata->use_spimem) {
-               complete(&mdata->spimem_done);
-               return IRQ_HANDLED;
-       }
-
        if (!host->can_dma(host, NULL, xfer)) {
                if (xfer->rx_buf) {
                        cnt = mdata->xfer_len / 4;
@@ -845,6 +833,27 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
+{
+       struct spi_controller *host = dev_id;
+       struct mtk_spi *mdata = spi_controller_get_devdata(host);
+       u32 reg_val;
+
+       reg_val = readl(mdata->base + SPI_STATUS0_REG);
+       if (reg_val & MTK_SPI_PAUSE_INT_STATUS)
+               mdata->state = MTK_SPI_PAUSED;
+       else
+               mdata->state = MTK_SPI_IDLE;
+
+       /* SPI-MEM ops */
+       if (mdata->use_spimem) {
+               complete(&mdata->spimem_done);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_WAKE_THREAD;
+}
+
 static int mtk_spi_mem_adjust_op_size(struct spi_mem *mem,
                                      struct spi_mem_op *op)
 {
@@ -1255,8 +1264,9 @@ static int mtk_spi_probe(struct platform_device *pdev)
                dev_notice(dev, "SPI dma_set_mask(%d) failed, ret:%d\n",
                           addr_bits, ret);
 
-       ret = devm_request_irq(dev, irq, mtk_spi_interrupt,
-                              IRQF_TRIGGER_NONE, dev_name(dev), host);
+       ret = devm_request_threaded_irq(dev, irq, mtk_spi_interrupt,
+                                       mtk_spi_interrupt_thread,
+                                       IRQF_TRIGGER_NONE, dev_name(dev), host);
        if (ret)
                return dev_err_probe(dev, ret, "failed to register irq\n");