The eSPI driver does not work on our P2010 board with an 8-bit SPI slave.

- The transmission length is always twice the expected. The length is set to 
(n_tx + n_rx), which is incorrect for a full duplex SPI interface.
- Bytes and characters are mixed up. The len field in struct spi_transfer is 
counted in bytes, while the TRANLEN field in the eSPI controller is counted in 
characters, and bits_per_word si the relation between the two.
- The bytes received from the controller are written at the wrong offset in the 
driver's receive buffer.
- The interrupt handler calculation of remaining bytes is incorrect.

This fix is based on a previous patch that was not included to lack of 
response, see http://sourceforge.net/mailarchive/message.php?msg_id=27820036

Signed-off-by: Kenth Eriksson <kenth.eriks...@transmode.com>
---
 drivers/spi/spi-fsl-espi.c |   36 ++++++++++++++++++++++++++----------
 drivers/spi/spi-fsl-lib.h  |    1 +
 2 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 249d244..2c4224b 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -232,21 +232,32 @@ static int fsl_espi_bufs(struct spi_device *spi, struct 
spi_transfer *t)
                bits_per_word = t->bits_per_word;
 
        mpc8xxx_spi->len = t->len;
-       len = roundup(len, 4) / 4;
 
        mpc8xxx_spi->tx = t->tx_buf;
        mpc8xxx_spi->rx = t->rx_buf;
+       mpc8xxx_spi->bits_per_word = bits_per_word;
 
        INIT_COMPLETION(mpc8xxx_spi->done);
 
+       /* Convert between t->len (in bytes) and count (in
+        * characters). For character lengths of 9 to 16 bits, each
+        * character occupies 2 bytes in Rx/Tx FIFO.
+        */
+       if (bits_per_word <= 8)
+               len = t->len;
+       else if (bits_per_word <= 16)
+               len = t->len >> 1;
+       else
+               return -EINVAL;
+
        /* Set SPCOM[CS] and SPCOM[TRANLEN] field */
-       if ((t->len - 1) > SPCOM_TRANLEN_MAX) {
+       if ((len - 1) > SPCOM_TRANLEN_MAX) {
                dev_err(mpc8xxx_spi->dev, "Transaction length (%d)"
-                               " beyond the SPCOM[TRANLEN] field\n", t->len);
+                       " beyond the SPCOM[TRANLEN] field\n", len);
                return -EINVAL;
        }
        mpc8xxx_spi_write_reg(&reg_base->command,
-               (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
+               (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(len - 1)));
 
        ret = fsl_espi_cpu_bufs(mpc8xxx_spi, t, len);
        if (ret)
@@ -405,12 +416,12 @@ static void fsl_espi_rw_trans(struct spi_message *m,
 
                espi_trans->n_tx = n_tx;
                espi_trans->n_rx = trans_len;
-               espi_trans->len = trans_len + n_tx;
+               espi_trans->len = n_tx;
                espi_trans->tx_buf = local_buf;
                espi_trans->rx_buf = local_buf + n_tx;
                fsl_espi_do_trans(m, espi_trans);
 
-               memcpy(rx_buf + pos, espi_trans->rx_buf + n_tx, trans_len);
+               memcpy(rx_buf + pos, espi_trans->rx_buf, trans_len);
 
                if (loop > 0)
                        espi_trans->actual_length += espi_trans->len - n_tx;
@@ -440,7 +451,7 @@ static void fsl_espi_do_one_msg(struct spi_message *m)
 
        espi_trans.n_tx = n_tx;
        espi_trans.n_rx = n_rx;
-       espi_trans.len = n_tx + n_rx;
+       espi_trans.len = n_tx;
        espi_trans.actual_length = 0;
        espi_trans.status = 0;
 
@@ -522,6 +533,7 @@ void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
 
                if (mspi->len >= 4) {
                        rx_data = mpc8xxx_spi_read_reg(&reg_base->receive);
+                       mspi->len -= 4;
                } else {
                        tmp = mspi->len;
                        rx_data = 0;
@@ -531,10 +543,9 @@ void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
                        }
 
                        rx_data <<= (4 - mspi->len) * 8;
+                       mspi->len = 0;
                }
 
-               mspi->len -= 4;
-
                if (mspi->rx)
                        mspi->get_rx(rx_data, mspi);
        }
@@ -554,7 +565,12 @@ void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
        /* Clear the events */
        mpc8xxx_spi_write_reg(&reg_base->event, events);
 
-       mspi->count -= 1;
+       if (mspi->bits_per_word <= 8) {
+               mspi->count = mspi->len;
+       } else if (mspi->bits_per_word <= 16) {
+               mspi->count = mspi->len >> 1;
+       }
+
        if (mspi->count) {
                u32 word = mspi->get_tx(mspi);
 
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index cbe881b..53c7cb6 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -57,6 +57,7 @@ struct mpc8xxx_spi {
        void (*spi_remove) (struct mpc8xxx_spi *mspi);
 
        unsigned int count;
+       u8 bits_per_word;
        unsigned int irq;
 
        unsigned nsecs;         /* (clock cycle time)/2 */
-- 
1.7.3.4


------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
spi-devel-general mailing list
spi-devel-general@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

Reply via email to