[PATCH v3 7/8] spi: core: add spi_master.min_dma_len and supporting methods

kernel at martin.sperl.org kernel at martin.sperl.org
Mon Dec 14 07:20:24 PST 2015


From: Martin Sperl <kernel at martin.sperl.org>

Added spi_master.min_dma_len plus methods requireing this information:
* spi_translate_message_size_align_merge
* spi_can_dma_min_dma_len

Signed-off-by: Martin Sperl <kernel at martin.sperl.org>
---
 drivers/spi/spi.c       |   66 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/spi/spi.h |   14 +++++++++-
 2 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 020e34d..883bfa8 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -277,6 +277,27 @@ void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
 }
 EXPORT_SYMBOL_GPL(spi_statistics_add_transfer_stats);

+/**
+ * spi_can_dma_min_dma_len - default implementation for spi_can_dma
+ *                           that only checks spi_transfer.len is bigger
+ *                           spi_master.min_dma_len
+ * @master: the spi_master device
+ * @spi:    the spi_device
+ * @tfr:    the spi_transfer
+ */
+bool spi_can_dma_min_dma_len(struct spi_master *master,
+			     struct spi_device *spi,
+			     struct spi_transfer *tfr)
+{
+	/* we start DMA efforts only on bigger transfers */
+	if (tfr->len < master->min_dma_len)
+		return false;
+
+	/* return OK */
+	return true;
+}
+EXPORT_SYMBOL_GPL(spi_can_dma_min_dma_len);
+
 /* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
  * and the sysfs version makes coldplug work too.
  */
@@ -2793,6 +2814,51 @@ int spi_merge_transfers(struct spi_master *master,
 	return 0;
 }
 EXPORT_SYMBOL_GPL(spi_merge_transfers);
+/*-------------------------------------------------------------------------*/
+
+/**
+ * spi_translate_message_size_align_merge - default spi_message translation
+ *                                          code that takes its parameters
+ *                                          from @spi_master
+ *
+ * @master:  the spi_master for which we run this translation
+ * @message: the spi_message which we need to translate
+ *
+ * Returns: status of tranformation
+ */
+int spi_translate_message_size_align_merge(
+	struct spi_master *master, struct spi_message *message)
+{
+	int ret;
+
+	/* translate the message */
+
+	/* fix alignment of transfers by splitting rx_buf/tx_buf
+	 * (and worsted case copying tx_buf)
+	 */
+	ret = spi_split_transfers_unaligned(master, message,
+					    master->min_dma_len,
+					    master->dma_alignment,
+					    GFP_KERNEL);
+	if (ret)
+		return ret;
+
+	/* limit transfer length */
+	if (master->max_dma_len) {
+		ret = spi_split_transfers_maxsize(master, message,
+						  master->max_dma_len,
+						  GFP_KERNEL);
+		if (ret)
+			return ret;
+	}
+
+	/* merge spi_transfers up to a full page */
+	ret = spi_merge_transfers(master, message, 2, PAGE_SIZE,
+				  GFP_KERNEL);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(spi_translate_message_size_align_merge);

 /*-------------------------------------------------------------------------*/

diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 4b4c1e9..f055a47 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -351,6 +351,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  *                   while the hardware is prepared, using the parent
  *                   device for the spidev
  * @max_dma_len: Maximum length of a DMA transfer for the device.
+ * @min_dma_len: Minimum length of a DMA transfer for the device.
+ *               (mostly to avoid dma_mapping a buffer when dma is not used,
+ *                should be multiple of dma_alignment)
  * @prepare_transfer_hardware: a message will soon arrive from the queue
  *	so the subsystem requests the driver to prepare the transfer hardware
  *	by issuing this call
@@ -423,7 +426,6 @@ struct spi_master {
 	 * buffers; let protocol drivers know about these requirements.
 	 */
 	u16			dma_alignment;
-
 	/* spi_device.mode flags understood by this controller driver */
 	u16			mode_bits;

@@ -517,6 +519,7 @@ struct spi_master {
 	bool                            cur_msg_prepared;
 	bool				cur_msg_mapped;
 	struct completion               xfer_completion;
+	size_t				min_dma_len;
 	size_t				max_dma_len;

 	int (*prepare_transfer_hardware)(struct spi_master *master);
@@ -940,6 +943,15 @@ extern struct spi_replaced_transfers *spi_replace_transfers(
 	size_t extradatasize,
 	gfp_t gfp);

+/* some default implementations that drivers may use */
+extern int spi_translate_message_size_align_merge(
+	struct spi_master *master, struct spi_message *message);
+
+/* a default implementation of can_dma */
+extern bool spi_can_dma_min_dma_len(struct spi_master *master,
+				    struct spi_device *spi,
+				    struct spi_transfer *tfr);
+
 /*---------------------------------------------------------------------------*/

 /* SPI transfer transformation methods */
--
1.7.10.4




More information about the linux-rpi-kernel mailing list