spi/fsl-espi: avoid infinite loops on fsl_espi_cpu_irq()
authorNobuteru Hayashi <hayashi.nbb@ncos.nec.co.jp>
Fri, 18 Mar 2016 11:35:21 +0000 (11:35 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 28 Mar 2016 18:41:18 +0000 (19:41 +0100)
It brought nearly infinite loops, and was possible to be
occurred only if the SPI transaction total size are not
alighed with 4. Loops are here at while (tmp--),
tmp is unsigned, and set it with minus value.

The loops are executed as a result of unexpected RX interrupt
occurrence after that. This interrupt may be hardware eratta
and is not fixed.

Fix mspi->len from minus value to 0 and print warning message.

Signed-off-by: Nobuteru Hayashi <hayashi.nbb@ncos.nec.co.jp>
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-fsl-espi.c

index 64d794b99803b3936369cc00edff651c1fecdbbc..8d85a3c343dab635811cf4b6a871a841977fa09f 100644 (file)
@@ -544,6 +544,7 @@ void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
        if (events & SPIE_NE) {
                u32 rx_data, tmp;
                u8 rx_data_8;
+               int rx_nr_bytes = 4;
                int ret;
 
                /* Spin until RX is done */
@@ -560,7 +561,14 @@ void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
 
                if (mspi->len >= 4) {
                        rx_data = mpc8xxx_spi_read_reg(&reg_base->receive);
+               } else if (mspi->len <= 0) {
+                       dev_err(mspi->dev,
+                               "unexpected RX(SPIE_NE) interrupt occurred,\n"
+                               "(local rxlen %d bytes, reg rxlen %d bytes)\n",
+                               min(4, mspi->len), SPIE_RXCNT(events));
+                       rx_nr_bytes = 0;
                } else {
+                       rx_nr_bytes = mspi->len;
                        tmp = mspi->len;
                        rx_data = 0;
                        while (tmp--) {
@@ -571,7 +579,7 @@ void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
                        rx_data <<= (4 - mspi->len) * 8;
                }
 
-               mspi->len -= 4;
+               mspi->len -= rx_nr_bytes;
 
                if (mspi->rx)
                        mspi->get_rx(rx_data, mspi);