Skip to content

Commit 91cf42c

Browse files
ConchuODbroonie
authored andcommitted
spi: microchip-core: prevent RX overflows when transmit size > FIFO size
When the size of a transfer exceeds the size of the FIFO (32 bytes), RX overflows will be generated and receive data will be corrupted and warnings will be produced. For example, here's an error generated by a transfer of 36 bytes: spi_master spi0: mchp_corespi_interrupt: RX OVERFLOW: rxlen: 4, txlen: 0 The driver is currently split between handling receiving in the interrupt handler, and sending outside of it. Move all handling out of the interrupt handling, and explicitly link the number of bytes read of of the RX FIFO to the number written into the TX one. This both resolves the overflow problems as well as simplifying the flow of the driver. CC: stable@vger.kernel.org Fixes: 9ac8d17 ("spi: add support for microchip fpga spi controllers") Signed-off-by: Conor Dooley <conor.dooley@microchip.com> Link: https://patch.msgid.link/20250303-veal-snooper-712c1dfad336@wendy Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 3d7a20f commit 91cf42c

File tree

1 file changed

+18
-23
lines changed

1 file changed

+18
-23
lines changed

drivers/spi/spi-microchip-core.c

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@
7070
#define INT_RX_CHANNEL_OVERFLOW BIT(2)
7171
#define INT_TX_CHANNEL_UNDERRUN BIT(3)
7272

73-
#define INT_ENABLE_MASK (CONTROL_RX_DATA_INT | CONTROL_TX_DATA_INT | \
74-
CONTROL_RX_OVER_INT | CONTROL_TX_UNDER_INT)
73+
#define INT_ENABLE_MASK (CONTROL_RX_OVER_INT | CONTROL_TX_UNDER_INT)
7574

7675
#define REG_CONTROL (0x00)
7776
#define REG_FRAME_SIZE (0x04)
@@ -133,10 +132,15 @@ static inline void mchp_corespi_disable(struct mchp_corespi *spi)
133132
mchp_corespi_write(spi, REG_CONTROL, control);
134133
}
135134

136-
static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi)
135+
static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi, int fifo_max)
137136
{
138-
while (spi->rx_len >= spi->n_bytes && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY)) {
139-
u32 data = mchp_corespi_read(spi, REG_RX_DATA);
137+
for (int i = 0; i < fifo_max; i++) {
138+
u32 data;
139+
140+
while (mchp_corespi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY)
141+
;
142+
143+
data = mchp_corespi_read(spi, REG_RX_DATA);
140144

141145
spi->rx_len -= spi->n_bytes;
142146

@@ -211,11 +215,10 @@ static inline void mchp_corespi_set_xfer_size(struct mchp_corespi *spi, int len)
211215
mchp_corespi_write(spi, REG_FRAMESUP, len);
212216
}
213217

214-
static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi)
218+
static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi, int fifo_max)
215219
{
216-
int fifo_max, i = 0;
220+
int i = 0;
217221

218-
fifo_max = DIV_ROUND_UP(min(spi->tx_len, FIFO_DEPTH), spi->n_bytes);
219222
mchp_corespi_set_xfer_size(spi, fifo_max);
220223

221224
while ((i < fifo_max) && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_TXFIFO_FULL)) {
@@ -413,19 +416,6 @@ static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id)
413416
if (intfield == 0)
414417
return IRQ_NONE;
415418

416-
if (intfield & INT_TXDONE)
417-
mchp_corespi_write(spi, REG_INT_CLEAR, INT_TXDONE);
418-
419-
if (intfield & INT_RXRDY) {
420-
mchp_corespi_write(spi, REG_INT_CLEAR, INT_RXRDY);
421-
422-
if (spi->rx_len)
423-
mchp_corespi_read_fifo(spi);
424-
}
425-
426-
if (!spi->rx_len && !spi->tx_len)
427-
finalise = true;
428-
429419
if (intfield & INT_RX_CHANNEL_OVERFLOW) {
430420
mchp_corespi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW);
431421
finalise = true;
@@ -512,9 +502,14 @@ static int mchp_corespi_transfer_one(struct spi_controller *host,
512502

513503
mchp_corespi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select);
514504

515-
while (spi->tx_len)
516-
mchp_corespi_write_fifo(spi);
505+
while (spi->tx_len) {
506+
int fifo_max = DIV_ROUND_UP(min(spi->tx_len, FIFO_DEPTH), spi->n_bytes);
507+
508+
mchp_corespi_write_fifo(spi, fifo_max);
509+
mchp_corespi_read_fifo(spi, fifo_max);
510+
}
517511

512+
spi_finalize_current_transfer(host);
518513
return 1;
519514
}
520515

0 commit comments

Comments
 (0)