Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: fsl-cpm: Use 16 bit mode for large transfers with even size

On CPM, the RISC core is a lot more efficiant when doing transfers
in 16-bits chunks than in 8-bits chunks, but unfortunately the
words need to be byte swapped as seen in a previous commit.

So, for large tranfers with an even size, allocate a temporary tx
buffer and byte-swap data before and after transfer.

This change allows setting higher speed for transfer. For instance
on an MPC 8xx (CPM1 comms RISC processor), the documentation tells
that transfer in byte mode at 1 kbit/s uses 0.200% of CPM load
at 25 MHz while a word transfer at the same speed uses 0.032%
of CPM load. This means the speed can be 6 times higher in
word mode for the same CPM load.

For the time being, only do it on CPM1 as there must be a
trade-off between the CPM load reduction and the CPU load required
to byte swap the data.

Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Link: https://lore.kernel.org/r/f2e981f20f92dd28983c3949702a09248c23845c.1680371809.git.christophe.leroy@csgroup.eu
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Christophe Leroy and committed by
Mark Brown
fc96ec82 8a5299a1

+26
+23
drivers/spi/spi-fsl-cpm.c
··· 21 21 #include <linux/spi/spi.h> 22 22 #include <linux/types.h> 23 23 #include <linux/platform_device.h> 24 + #include <linux/byteorder/generic.h> 24 25 25 26 #include "spi-fsl-cpm.h" 26 27 #include "spi-fsl-lib.h" ··· 121 120 mspi->rx_dma = mspi->dma_dummy_rx; 122 121 mspi->map_rx_dma = 0; 123 122 } 123 + if (t->bits_per_word == 16 && t->tx_buf) { 124 + const u16 *src = t->tx_buf; 125 + u16 *dst; 126 + int i; 127 + 128 + dst = kmalloc(t->len, GFP_KERNEL); 129 + if (!dst) 130 + return -ENOMEM; 131 + 132 + for (i = 0; i < t->len >> 1; i++) 133 + dst[i] = cpu_to_le16p(src + i); 134 + 135 + mspi->tx = dst; 136 + mspi->map_tx_dma = 1; 137 + } 124 138 125 139 if (mspi->map_tx_dma) { 126 140 void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */ ··· 189 173 if (mspi->map_rx_dma) 190 174 dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE); 191 175 mspi->xfer_in_progress = NULL; 176 + 177 + if (t->bits_per_word == 16 && t->rx_buf) { 178 + int i; 179 + 180 + for (i = 0; i < t->len; i += 2) 181 + le16_to_cpus(t->rx_buf + i); 182 + } 192 183 } 193 184 EXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs_complete); 194 185
+3
drivers/spi/spi-fsl-spi.c
··· 351 351 return -EINVAL; 352 352 if (t->bits_per_word == 16 || t->bits_per_word == 32) 353 353 t->bits_per_word = 8; /* pretend its 8 bits */ 354 + if (t->bits_per_word == 8 && t->len >= 256 && 355 + (mpc8xxx_spi->flags & SPI_CPM1)) 356 + t->bits_per_word = 16; 354 357 } 355 358 } 356 359 return fsl_spi_setup_transfer(m->spi, first);