[PATCH v2] spi: tegra20-slink: size words with spi_bpw_to_bytes()
From: Weibin Liu
Date: Mon Oct 26 2026 - 09:27:34 EST
tegra_slink_calculate_curr_xfer_param() derives bytes_per_word with
DIV_ROUND_UP(bits_per_word, 8), but the SPI core sizes words with
spi_bpw_to_bytes(), i.e. roundup_pow_of_two(BITS_TO_BYTES()), and
__spi_validate() only accepts lengths that are a multiple of that
power-of-two word size. For bits_per_word of 17..24 the two differ
(3 vs 4 bytes): a length like 8 passes core validation yet is measured
as three 3-byte words, so the copy helpers touch one byte past the
buffer, and cur_tx_pos/cur_rx_pos advance in multiples of 3 and never
land on the equality check cur_pos == t->len. The ISR then recomputes
remain_len = t->len - cur_pos, which wraps, and the driver keeps
copying 4096-word blocks past the client buffers until the transfer
times out.
Use spi_bpw_to_bytes() for bytes_per_word: 24 bit words can have
padding. The word count then divides the transfer length exactly, the
copies stay within t->len, the position counters land on t->len, and
the wire carries the words the caller asked for. For power-of-two
word sizes spi_bpw_to_bytes() returns the same value as
DIV_ROUND_UP(), so only bits_per_word of 17..24 change behaviour. The
non-packed setup already used the 4-byte configuration
(SLINK_PACK_SIZE_32) that bits_per_word = 32 has always used, TX
padding stays in the upper byte that the hardware does not shift out,
and the RX paths already mask the padding.
Verified with a userspace replica of the transfer arithmetic covering
all core-legal lengths for bits_per_word 8/16/24/32 in both
directions: the shipped driver and v1 overrun the buffers and never
complete for bits_per_word of 17..24 with lengths not divisible by 3,
while with this change no copy exceeds t->len and every transfer
completes. Compile-tested only; no Tegra SLINK hardware was
available.
Suggested-by: Mark Brown <broonie@xxxxxxxxxx>
Fixes: dc4dc3605639 ("spi: tegra: add spi driver for SLINK controller")
Cc: stable@xxxxxxxxxxxxxxx # 3.8+
Signed-off-by: Weibin Liu <liuwb@xxxxxxxxxxxx>
---
Changes in v2:
- v1 clamped the four copy loops to t->len. As Mark Brown pointed out,
the compact word size itself is the problem: 24 bit words can have
padding, so the core only guarantees lengths that are multiples of
spi_bpw_to_bytes(). Size words with spi_bpw_to_bytes() instead,
which also drops the clamps and lets the position counters land on
the equality completion test.
drivers/spi/spi-tegra20-slink.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index ed1fcf57dd30..3f507176b0c8 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -261,7 +261,7 @@ static unsigned tegra_slink_calculate_curr_xfer_param(
unsigned total_fifo_words;
bits_per_word = t->bits_per_word;
- tspi->bytes_per_word = DIV_ROUND_UP(bits_per_word, 8);
+ tspi->bytes_per_word = spi_bpw_to_bytes(bits_per_word);
if (bits_per_word == 8 || bits_per_word == 16) {
tspi->is_packed = true;
--
2.50.1