2023-03-10 09:26:19

by Leonard Göhrs

[permalink] [raw]
Subject: [PATCH v1 1/2] spi: core: add spi_split_transfers_maxwords

Add spi_split_transfers_maxwords() function that splits
spi_transfers transparently into multiple transfers
that are below a given number of SPI words.

This function reuses most of its code from
spi_split_transfers_maxsize() and for transfers with
eight or less bits per word actually behaves the same.

Signed-off-by: Leonard Göhrs <[email protected]>
---
drivers/spi/spi.c | 49 +++++++++++++++++++++++++++++++++++++++++
include/linux/spi/spi.h | 4 ++++
2 files changed, 53 insertions(+)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 44b85a8d47f1..165e4a286080 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -3621,6 +3621,55 @@ int spi_split_transfers_maxsize(struct spi_controller *ctlr,
}
EXPORT_SYMBOL_GPL(spi_split_transfers_maxsize);

+
+/**
+ * spi_split_transfers_maxwords - split spi transfers into multiple transfers
+ * when an individual transfer exceeds a
+ * certain number of SPI words
+ * @ctlr: the @spi_controller for this transfer
+ * @msg: the @spi_message to transform
+ * @maxwords: the number of words to limit each transfer to
+ * @gfp: GFP allocation flags
+ *
+ * Return: status of transformation
+ */
+int spi_split_transfers_maxwords(struct spi_controller *ctlr,
+ struct spi_message *msg,
+ size_t maxwords,
+ gfp_t gfp)
+{
+ struct spi_transfer *xfer;
+
+ /*
+ * Iterate over the transfer_list,
+ * but note that xfer is advanced to the last transfer inserted
+ * to avoid checking sizes again unnecessarily (also xfer does
+ * potentially belong to a different list by the time the
+ * replacement has happened).
+ */
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ size_t maxsize;
+ int ret;
+
+ if (xfer->bits_per_word <= 8)
+ maxsize = maxwords;
+ else if (xfer->bits_per_word <= 16)
+ maxsize = 2 * maxwords;
+ else
+ maxsize = 4 * maxwords;
+
+ if (xfer->len > maxsize) {
+ ret = __spi_split_transfer_maxsize(ctlr, msg, &xfer,
+ maxsize, gfp);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_split_transfers_maxwords);
+
/*-------------------------------------------------------------------------*/

/* Core methods for SPI controller protocol drivers. Some of the
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 4fa26b9a3572..f8dff44d77e5 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -1295,6 +1295,10 @@ extern int spi_split_transfers_maxsize(struct spi_controller *ctlr,
struct spi_message *msg,
size_t maxsize,
gfp_t gfp);
+extern int spi_split_transfers_maxwords(struct spi_controller *ctlr,
+ struct spi_message *msg,
+ size_t maxwords,
+ gfp_t gfp);

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


base-commit: fe15c26ee26efa11741a7b632e9f23b01aca4cc6
--
2.30.2



2023-03-10 09:26:42

by Leonard Göhrs

[permalink] [raw]
Subject: [PATCH v1 2/2] spi: stm32: split large transfers based on word size instead of bytes

The TSIZE register in CR2, to which the number of words to transfer
is written, is only 16 Bit. This limits transfers to 65535 SPI
_words_ at a time. The existing code uses spi_split_transfers_maxsize
to limit transfers to 65535 _bytes_ at a time.

This breaks large transfers with bits_per_word > 8, as they are
split inside of a word boundary by the odd size limit.

Split transfers based on the number of words instead.
This has the added benefit of not artificially limiting the maximum
length of bpw > 8 transfers to half or a quarter of the actual limit.

The combination of very large transfers and bits_per_word = 16 is triggered
e.g. by MIPI DBI displays when updating large parts of the screen.

Signed-off-by: Leonard Göhrs <[email protected]>
---
drivers/spi/spi-stm32.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index def09cf0dc14..d2e16f16fae6 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -984,9 +984,9 @@ static int stm32_spi_prepare_msg(struct spi_master *master,
if (spi->cfg->set_number_of_data) {
int ret;

- ret = spi_split_transfers_maxsize(master, msg,
- STM32H7_SPI_TSIZE_MAX,
- GFP_KERNEL | GFP_DMA);
+ ret = spi_split_transfers_maxwords(master, msg,
+ STM32H7_SPI_TSIZE_MAX,
+ GFP_KERNEL | GFP_DMA);
if (ret)
return ret;
}
--
2.30.2


2023-03-16 12:59:17

by Alain Volmat

[permalink] [raw]
Subject: Re: [PATCH v1 2/2] spi: stm32: split large transfers based on word size instead of bytes

Hi Leonard,

thanks for your patch. I agree with this patch and tested it ok
as well on my side.

On Fri, Mar 10, 2023 at 10:20:53AM +0100, Leonard G?hrs wrote:
> The TSIZE register in CR2, to which the number of words to transfer
> is written, is only 16 Bit. This limits transfers to 65535 SPI
> _words_ at a time. The existing code uses spi_split_transfers_maxsize
> to limit transfers to 65535 _bytes_ at a time.
>
> This breaks large transfers with bits_per_word > 8, as they are
> split inside of a word boundary by the odd size limit.
>
> Split transfers based on the number of words instead.
> This has the added benefit of not artificially limiting the maximum
> length of bpw > 8 transfers to half or a quarter of the actual limit.
>
> The combination of very large transfers and bits_per_word = 16 is triggered
> e.g. by MIPI DBI displays when updating large parts of the screen.
>
> Signed-off-by: Leonard G?hrs <[email protected]>
> ---
> drivers/spi/spi-stm32.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
> index def09cf0dc14..d2e16f16fae6 100644
> --- a/drivers/spi/spi-stm32.c
> +++ b/drivers/spi/spi-stm32.c
> @@ -984,9 +984,9 @@ static int stm32_spi_prepare_msg(struct spi_master *master,
> if (spi->cfg->set_number_of_data) {
> int ret;
>
> - ret = spi_split_transfers_maxsize(master, msg,
> - STM32H7_SPI_TSIZE_MAX,
> - GFP_KERNEL | GFP_DMA);
> + ret = spi_split_transfers_maxwords(master, msg,
> + STM32H7_SPI_TSIZE_MAX,
> + GFP_KERNEL | GFP_DMA);
> if (ret)
> return ret;
> }

Acked-by: Alain Volmat <[email protected]>
> --
> 2.30.2
>

2023-03-16 14:26:14

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v1 1/2] spi: core: add spi_split_transfers_maxwords

On Fri, 10 Mar 2023 10:20:52 +0100, Leonard Göhrs wrote:
> Add spi_split_transfers_maxwords() function that splits
> spi_transfers transparently into multiple transfers
> that are below a given number of SPI words.
>
> This function reuses most of its code from
> spi_split_transfers_maxsize() and for transfers with
> eight or less bits per word actually behaves the same.
>
> [...]

Applied to

https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/2] spi: core: add spi_split_transfers_maxwords
commit: 027781f3920ad16f40133890fc87247b8baa2d8d
[2/2] spi: stm32: split large transfers based on word size instead of bytes
commit: 1e4929112507f145951f4c356161ab80ad9c1f0e

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark