Skip to content

Commit

Permalink
spi: fsl-cpm: Use 16 bit mode for large transfers with even size
Browse files Browse the repository at this point in the history
commit fc96ec8 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
chleroy authored and gregkh committed May 17, 2023
1 parent 441fa64 commit 7f6738e
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 0 deletions.
23 changes: 23 additions & 0 deletions drivers/spi/spi-fsl-cpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/spi/spi.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/byteorder/generic.h>

#include "spi-fsl-cpm.h"
#include "spi-fsl-lib.h"
Expand Down Expand Up @@ -120,6 +121,21 @@ int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
mspi->rx_dma = mspi->dma_dummy_rx;
mspi->map_rx_dma = 0;
}
if (t->bits_per_word == 16 && t->tx_buf) {
const u16 *src = t->tx_buf;
u16 *dst;
int i;

dst = kmalloc(t->len, GFP_KERNEL);
if (!dst)
return -ENOMEM;

for (i = 0; i < t->len >> 1; i++)
dst[i] = cpu_to_le16p(src + i);

mspi->tx = dst;
mspi->map_tx_dma = 1;
}

if (mspi->map_tx_dma) {
void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */
Expand Down Expand Up @@ -173,6 +189,13 @@ void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
if (mspi->map_rx_dma)
dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
mspi->xfer_in_progress = NULL;

if (t->bits_per_word == 16 && t->rx_buf) {
int i;

for (i = 0; i < t->len; i += 2)
le16_to_cpus(t->rx_buf + i);
}
}
EXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs_complete);

Expand Down
3 changes: 3 additions & 0 deletions drivers/spi/spi-fsl-spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,9 @@ static int fsl_spi_prepare_message(struct spi_controller *ctlr,
return -EINVAL;
if (t->bits_per_word == 16 || t->bits_per_word == 32)
t->bits_per_word = 8; /* pretend its 8 bits */
if (t->bits_per_word == 8 && t->len >= 256 &&
(mpc8xxx_spi->flags & SPI_CPM1))
t->bits_per_word = 16;
}
}
return fsl_spi_setup_transfer(m->spi, first);
Expand Down

0 comments on commit 7f6738e

Please sign in to comment.