From: Martin Sperl <ker...@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 <ker...@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

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to