Just a hack. Someone probably has an idea about how this should be done.

Signed-off-by: Noralf Trønnes <noralf at tronnes.org>
---
 drivers/spi/spi.c       | 24 +++++++++++++++++-------
 include/linux/spi/spi.h |  4 ++++
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 838783c..b2958be 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -808,23 +808,28 @@ static int __spi_map_msg(struct spi_master *master, 
struct spi_message *msg)
                if (!master->can_dma(master, msg->spi, xfer))
                        continue;

-               if (xfer->tx_buf != NULL) {
+               if (xfer->tx_buf != NULL && !xfer->tx_sg.nents) {
                        ret = spi_map_buf(master, tx_dev, &xfer->tx_sg,
                                          (void *)xfer->tx_buf, xfer->len,
                                          DMA_TO_DEVICE);
                        if (ret != 0)
                                return ret;
+
+                       xfer->tx_sg_core_mapped = true;
                }

-               if (xfer->rx_buf != NULL) {
+               if (xfer->rx_buf != NULL && !xfer->rx_sg.nents) {
                        ret = spi_map_buf(master, rx_dev, &xfer->rx_sg,
                                          xfer->rx_buf, xfer->len,
                                          DMA_FROM_DEVICE);
                        if (ret != 0) {
                                spi_unmap_buf(master, tx_dev, &xfer->tx_sg,
                                              DMA_TO_DEVICE);
+                               xfer->tx_sg_core_mapped = false;
                                return ret;
                        }
+
+                       xfer->rx_sg_core_mapped = true;
                }
        }

@@ -852,11 +857,16 @@ static int __spi_unmap_msg(struct spi_master *master, 
struct spi_message *msg)
                rx_dev = &master->dev;

        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
-               if (!master->can_dma(master, msg->spi, xfer))
-                       continue;
-
-               spi_unmap_buf(master, rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
-               spi_unmap_buf(master, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
+               if (xfer->rx_sg_core_mapped) {
+                       spi_unmap_buf(master, rx_dev, &xfer->rx_sg,
+                                     DMA_FROM_DEVICE);
+                       xfer->rx_sg.nents = 0;
+               }
+               if (xfer->tx_sg_core_mapped) {
+                       spi_unmap_buf(master, tx_dev, &xfer->tx_sg,
+                                     DMA_TO_DEVICE);
+                       xfer->tx_sg.nents = 0;
+               }
        }

        return 0;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 4b743ac..f27fda6 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -682,6 +682,8 @@ extern void spi_res_release(struct spi_master *master,
  * @transfer_list: transfers are sequenced through @spi_message.transfers
  * @tx_sg: Scatterlist for transmit, currently not for client use
  * @rx_sg: Scatterlist for receive, currently not for client use
+ * @tx_sg_core_mapped: Scatterlist has been mapped by spi core
+ * @rx_sg_core_mapped: Scatterlist has been mapped by spi core
  *
  * SPI transfers always write the same number of bytes as they read.
  * Protocol drivers should always provide @rx_buf and/or @tx_buf.
@@ -751,6 +753,8 @@ struct spi_transfer {
        dma_addr_t      rx_dma;
        struct sg_table tx_sg;
        struct sg_table rx_sg;
+       bool            tx_sg_core_mapped;
+       bool            rx_sg_core_mapped;

        unsigned        cs_change:1;
        unsigned        tx_nbits:3;
-- 
2.10.2

Reply via email to