From: Qipan Li <[email protected]>

The old codes use the below flow to do TX: send one word at first, after
this word is finished and TX empty interrupt is generated, send more
words. This causes redundant interrupt overhead at least for the 1st
word.

This patch moves to send as many as possible words at the beginning and
handle TX empty interrupt to send another bundle of words. so interrupt
overhead is decreased.

Signed-off-by: Qipan Li <[email protected]>
Signed-off-by: Barry Song <[email protected]>
---
 drivers/spi/spi-sirf.c | 101 ++++++++++++++++++++++++++-----------------------
 1 file changed, 54 insertions(+), 47 deletions(-)

diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index 2d23899..95ac276 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -86,6 +86,7 @@
 #define SIRFSOC_SPI_TX_DONE            BIT(1)
 #define SIRFSOC_SPI_RX_OFLOW           BIT(2)
 #define SIRFSOC_SPI_TX_UFLOW           BIT(3)
+#define SIRFSOC_SPI_RX_IO_DMA          BIT(4)
 #define SIRFSOC_SPI_RX_FIFO_FULL       BIT(6)
 #define SIRFSOC_SPI_TXFIFO_EMPTY       BIT(7)
 #define SIRFSOC_SPI_RXFIFO_THD_REACH   BIT(8)
@@ -265,41 +266,34 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
 {
        struct sirfsoc_spi *sspi = dev_id;
        u32 spi_stat = readl(sspi->base + SIRFSOC_SPI_INT_STATUS);
-
-       writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS);
-
        if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) {
                complete(&sspi->tx_done);
                writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
+               writel(SIRFSOC_SPI_INT_MASK_ALL,
+                               sspi->base + SIRFSOC_SPI_INT_STATUS);
                return IRQ_HANDLED;
        }
 
        /* Error Conditions */
        if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
                        spi_stat & SIRFSOC_SPI_TX_UFLOW) {
+               complete(&sspi->tx_done);
                complete(&sspi->rx_done);
                writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
+               writel(SIRFSOC_SPI_INT_MASK_ALL,
+                               sspi->base + SIRFSOC_SPI_INT_STATUS);
+               return IRQ_HANDLED;
        }
+       if (spi_stat & SIRFSOC_SPI_TXFIFO_EMPTY)
+               complete(&sspi->tx_done);
+       while (!(readl(sspi->base + SIRFSOC_SPI_INT_STATUS) &
+               SIRFSOC_SPI_RX_IO_DMA))
+               cpu_relax();
+       complete(&sspi->rx_done);
+       writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
+       writel(SIRFSOC_SPI_INT_MASK_ALL,
+                       sspi->base + SIRFSOC_SPI_INT_STATUS);
 
-       if (spi_stat & (SIRFSOC_SPI_FRM_END
-                       | SIRFSOC_SPI_RXFIFO_THD_REACH))
-               while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS)
-                               & SIRFSOC_SPI_FIFO_EMPTY)) &&
-                               sspi->left_rx_word)
-                       sspi->rx_word(sspi);
-
-       if (spi_stat & (SIRFSOC_SPI_TXFIFO_EMPTY |
-                       SIRFSOC_SPI_TXFIFO_THD_REACH))
-               while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS)
-                               & SIRFSOC_SPI_FIFO_FULL)) &&
-                               sspi->left_tx_word)
-                       sspi->tx_word(sspi);
-
-       /* Received all words */
-       if ((sspi->left_rx_word == 0) && (sspi->left_tx_word == 0)) {
-               complete(&sspi->rx_done);
-               writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
-       }
        return IRQ_HANDLED;
 }
 
@@ -420,32 +414,45 @@ static void spi_sirfsoc_pio_transfer(struct spi_device 
*spi,
        int timeout = t->len * 10;
 
        sspi = spi_master_get_devdata(spi->master);
-       writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
-       writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
-       writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
-       writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
-       writel(0, sspi->base + SIRFSOC_SPI_INT_EN);
-       writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS);
-       writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | SIRFSOC_SPI_MUL_DAT_MODE |
-               SIRFSOC_SPI_ENA_AUTO_CLR, sspi->base + SIRFSOC_SPI_CTRL);
-       writel(sspi->left_tx_word - 1,
-                       sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);
-       writel(sspi->left_rx_word - 1,
-                       sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);
-       sspi->tx_word(sspi);
-       writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN | SIRFSOC_SPI_TX_UFLOW_INT_EN |
-               SIRFSOC_SPI_RX_OFLOW_INT_EN | SIRFSOC_SPI_RXFIFO_THD_INT_EN |
-               SIRFSOC_SPI_TXFIFO_THD_INT_EN | SIRFSOC_SPI_FRM_END_INT_EN|
-               SIRFSOC_SPI_RXFIFO_FULL_INT_EN,
-               sspi->base + SIRFSOC_SPI_INT_EN);
-       writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN,
+       do {
+               writel(SIRFSOC_SPI_FIFO_RESET,
+                       sspi->base + SIRFSOC_SPI_RXFIFO_OP);
+               writel(SIRFSOC_SPI_FIFO_RESET,
+                       sspi->base + SIRFSOC_SPI_TXFIFO_OP);
+               writel(SIRFSOC_SPI_FIFO_START,
+                       sspi->base + SIRFSOC_SPI_RXFIFO_OP);
+               writel(SIRFSOC_SPI_FIFO_START,
+                       sspi->base + SIRFSOC_SPI_TXFIFO_OP);
+               writel(0, sspi->base + SIRFSOC_SPI_INT_EN);
+               writel(SIRFSOC_SPI_INT_MASK_ALL,
+                       sspi->base + SIRFSOC_SPI_INT_STATUS);
+               writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
+                       SIRFSOC_SPI_MUL_DAT_MODE | SIRFSOC_SPI_ENA_AUTO_CLR,
+                       sspi->base + SIRFSOC_SPI_CTRL);
+               writel(min(sspi->left_tx_word, (u32)(256 / sspi->word_width))
+                               - 1, sspi->base + SIRFSOC_SPI_TX_DMA_IO_LEN);
+               writel(min(sspi->left_rx_word, (u32)(256 / sspi->word_width))
+                               - 1, sspi->base + SIRFSOC_SPI_RX_DMA_IO_LEN);
+               while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS)
+                       & SIRFSOC_SPI_FIFO_FULL)) && sspi->left_tx_word)
+                       sspi->tx_word(sspi);
+               writel(SIRFSOC_SPI_TXFIFO_EMPTY_INT_EN |
+                       SIRFSOC_SPI_TX_UFLOW_INT_EN |
+                       SIRFSOC_SPI_RX_OFLOW_INT_EN,
+                       sspi->base + SIRFSOC_SPI_INT_EN);
+               writel(SIRFSOC_SPI_RX_EN | SIRFSOC_SPI_TX_EN,
                        sspi->base + SIRFSOC_SPI_TX_RX_EN);
-       if (wait_for_completion_timeout(&sspi->rx_done, timeout) == 0)
-               dev_err(&spi->dev, "transfer timeout\n");
-       writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
-       writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
-       writel(0, sspi->base + SIRFSOC_SPI_TX_RX_EN);
-       writel(0, sspi->base + SIRFSOC_SPI_INT_EN);
+               if (!wait_for_completion_timeout(&sspi->tx_done, timeout) ||
+                       !wait_for_completion_timeout(&sspi->rx_done, timeout)) {
+                       dev_err(&spi->dev, "transfer timeout\n");
+                       break;
+               }
+               while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS)
+                       & SIRFSOC_SPI_FIFO_EMPTY)) && sspi->left_rx_word)
+                       sspi->rx_word(sspi);
+               writel(0, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
+               writel(0, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
+       } while (sspi->left_tx_word != 0 || sspi->left_rx_word != 0);
 }
 
 static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to