diff mbox

[RFC,4/6] spi: Let clients do scatter/gather transfers

Message ID 20170104133442.4534-5-noralf@tronnes.org (mailing list archive)
State New, archived
Headers show

Commit Message

Noralf Trønnes Jan. 4, 2017, 1:34 p.m. UTC
Just a hack. Someone probably has an idea about how this should be done.

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

Patch

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;