[PATCH] spi: sirf: fix the issue while transferring more than 256 words

Barry Song 21cnbao at gmail.com
Wed May 15 08:59:47 EDT 2013


ping Mark, Ping Grant.

2013/3/18 Barry Song <Barry.Song at csr.com>:
> From: Qipan Li <Qipan.Li at csr.com>
>
> currently, spi irq handler only does rx processing and  fetching data from rx
> fifo when "FRM_END" irq happens. FRM_END indicates one transfer completes. if
> rx size is less than 256, it works well.
> but the problem is that spi rx fifo size is only 256 bytes, then if data size
> of one frame is more than 256, before FRM_END comes, rx fifo will be filled with
> RXFIFO_OFLOW overflow interrupt, it will make us lose some data due to fifo
> overflow.
> Explicitly we need do fetch work from device rx fifo in irq handler not only in
> "FRM_END" irq but also in "THD_REACH" irq. THD_REACH means rx fifo has come to
> its threshold and will come to overflow if we don't take data from it in time.
>
> In this patch, we fix this issue. we take data from rx fifo when either FRM_END
> or RX_THD_REACH irq comes, we put data into tx fifo when either TX_FIFO_EMPTY
> or TX_THD_REACH irq comes.
>
> Signed-off-by: Qipan Li <Qipan.Li at csr.com>
> Signed-off-by: Zhiwu Song <Zhiwu.Song at csr.com>
> Signed-off-by: Barry Song <Baohua.Song at csr.com>
> ---
>  drivers/spi/spi-sirf.c |   43 +++++++++++++------------------------------
>  1 files changed, 13 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
> index f59d417..d2bd1e5 100644
> --- a/drivers/spi/spi-sirf.c
> +++ b/drivers/spi/spi-sirf.c
> @@ -142,9 +142,6 @@ struct sirfsoc_spi {
>         unsigned int left_tx_cnt;
>         unsigned int left_rx_cnt;
>
> -       /* tasklet to push tx msg into FIFO */
> -       struct tasklet_struct tasklet_tx;
> -
>         int chipselect[0];
>  };
>
> @@ -236,17 +233,6 @@ static void spi_sirfsoc_tx_word_u32(struct sirfsoc_spi *sspi)
>         sspi->left_tx_cnt--;
>  }
>
> -static void spi_sirfsoc_tasklet_tx(unsigned long arg)
> -{
> -       struct sirfsoc_spi *sspi = (struct sirfsoc_spi *)arg;
> -
> -       /* Fill Tx FIFO while there are left words to be transmitted */
> -       while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS) &
> -                       SIRFSOC_SPI_FIFO_FULL)) &&
> -                       sspi->left_tx_cnt)
> -               sspi->tx_word(sspi);
> -}
> -
>  static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
>  {
>         struct sirfsoc_spi *sspi = dev_id;
> @@ -261,25 +247,25 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
>                 writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
>         }
>
> -       if (spi_stat & SIRFSOC_SPI_FRM_END) {
> +       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_cnt)
>                         sspi->rx_word(sspi);
>
> -               /* Received all words */
> -               if ((sspi->left_rx_cnt == 0) && (sspi->left_tx_cnt == 0)) {
> -                       complete(&sspi->done);
> -                       writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
> -               }
> -       }
> -
> -       if (spi_stat & SIRFSOC_SPI_RXFIFO_THD_REACH ||
> -               spi_stat & SIRFSOC_SPI_TXFIFO_THD_REACH ||
> -               spi_stat & SIRFSOC_SPI_RX_FIFO_FULL ||
> -               spi_stat & SIRFSOC_SPI_TXFIFO_EMPTY)
> -               tasklet_schedule(&sspi->tasklet_tx);
> +       if (spi_stat & (SIRFSOC_SPI_FIFO_EMPTY
> +                       | SIRFSOC_SPI_TXFIFO_THD_REACH))
> +               while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS)
> +                               & SIRFSOC_SPI_FIFO_FULL)) &&
> +                               sspi->left_tx_cnt)
> +                       sspi->tx_word(sspi);
>
> +       /* Received all words */
> +       if ((sspi->left_rx_cnt == 0) && (sspi->left_tx_cnt == 0)) {
> +               complete(&sspi->done);
> +               writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
> +       }
>         return IRQ_HANDLED;
>  }
>
> @@ -573,9 +559,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
>
>         init_completion(&sspi->done);
>
> -       tasklet_init(&sspi->tasklet_tx, spi_sirfsoc_tasklet_tx,
> -                    (unsigned long)sspi);
> -
>         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);
> --
> 1.7.5.4



More information about the linux-arm-kernel mailing list