[PATCH V2 0/5] spi: spi-message transformation framework

Martin Sperl kernel at martin.sperl.org
Wed Dec 9 01:38:32 PST 2015

On 07.12.2015 16:21, kernel at martin.sperl.org wrote:
> From: Martin Sperl <kernel at martin.sperl.org>
> This patchset implements a spi-message transformation framework in
> SPI-core, that allows drivers to transfor individual spi messages
> into something that can more easily get handled by the HW.
> This would typically be used for HW which has some limitations on
> DMA alignment or max transfer sizes.
> This patchset implements at this very moment only splitting
> transfers longer than 60k in size into multiple transfers.
> Future patches based on this basic patchset:
> * split misalligned transfers (there are probably multiple
>    variations necessary for different HW)
> * merge multiple small transfers into a single transfer
> The patch-set essentially is based arround spi resource
> management on a spi_message basis, which was inspired by
> devres.
> This framework could also get used to handle spi_unmap_buf
> calls with the framework.
> Right now the drivers themselves have to implement
> spi_master.translate_message, but as soon as the "typical"
> HW-variations become apparent this may be reduced to assign
> one of a set of "standard" translation methods to
> spi_master.translate_message instead, but this may require
> some additional parametrization of the HW characteristics.
> The whole patch set has been tested successfully on a RPI with:
> * spi_loopback_test
> * enc28j60
> * fb_st7735r - framebuffer playing BigBuckBunny
> * mmc-spi with an out of tree patch to work arround the mmc_spi
>    internal dma mapping issues, that inhibits the driver from working
>    correctly - this got introduced with commit 0589342c27944e50
>     ("of: set dma_mask to point to coherent_dma_mask")
> Martin Sperl (5):
>    spi: core: added spi_resource management
>    spi: core: add spi_replace_transfers method
>    spi: core: add spi_split_transfers_maxsize
>    spi: core add spi_master.translate_message
>    spi: bcm2835: make use of the spi_translate_message methods
>   drivers/spi/spi-bcm2835.c |   31 +++--
>   drivers/spi/spi.c         |  339 +++++++++++++++++++++++++++++++++++++++++++++
>   include/linux/spi/spi.h   |   92 ++++++++++++
>   3 files changed, 448 insertions(+), 14 deletions(-)

Please note that Patch 1/5 (spi: core: added spi_resource management)
requires that method spi_message_init_no_memset exists(see patch-set
for spi-loopback-test) - this note did not make it into the description
of the second version of this patchset.

In the meantime I have implemented 2 more transformations:
* alignment of buffers (first spi_transfer.tx/rx_buf buffer
   remains unaligned, but has spi_transfer.len < alignment,
   second spi_transfer is fully alligned for rx/tx_buf with
   copying of tx_buf to make it alligned in the case where
   rx_buf and tx_buf are misaligned to different offsets)
* merging multiple tiny transfers

One code issue showed up (but that impacted only the new use-cases)
and there was a missing kerneldoc for one of the spi_statistics
members - these are 2 separate patches.

Should I send these separately or do you want a big patchset that
contains all of them?

Here the some of the statistics when running my spi-loopback-test:
==> /sys/class/spi_master/spi32766/statistics/transfers
==> /sys/class/spi_master/spi32766/statistics/transfers_merged
==> /sys/class/spi_master/spi32766/statistics/transfers_split_maxsize
==> /sys/class/spi_master/spi32766/statistics/transfers_split_unaligned

Based on the above I am starting to think of readying a default
implementation for translation that drivers may use:

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,
         if (ret)
                 return ret;

         /* limit transfer length */
         if (master->max_dma_len) {
                 ret = spi_split_transfers_maxsize(master, message,
                 if (ret)
                         return ret;

         /* merge spi_transfers up to a full page */
         ret = spi_merge_transfers(master, message, 2, PAGE_SIZE);

         return ret;

The spi_master driver would need to set these:
	master->translate_message =
	master->min_dma_len = BCM2835_SPI_DMA_MIN_LENGTH;
	master->max_dma_len = 15 * PAGE_SIZE;
	master->dma_alignment = 4;

As seen above we would need to define a min_dma_len that can get used
as a parameter to align transfers (if a driver is doing PIO for short
transfers, then it makes no sense aligning them in the first place).

This value could also get used in a default implementation of can_dma.

Note that we could also expose min_dma_size via sysfs.

More information about the linux-rpi-kernel mailing list