Skip to content

Commit e9803a6

Browse files
committed
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 RX one. This both resolves the overflow problems as well as simplifying the flow of the driver. CC: [email protected] Fixes: 9ac8d17 ("spi: add support for microchip fpga spi controllers") Signed-off-by: Conor Dooley <[email protected]>
1 parent 7c12f20 commit e9803a6

File tree

1 file changed

+17
-16
lines changed

1 file changed

+17
-16
lines changed

drivers/spi/spi-microchip-core.c

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,15 @@ static inline void mchp_corespi_disable(struct mchp_corespi *spi)
133133
mchp_corespi_write(spi, REG_CONTROL, control);
134134
}
135135

136-
static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi)
136+
static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi, int fifo_max)
137137
{
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);
138+
for (int i = 0; i < fifo_max; i++) {
139+
u32 data;
140+
141+
while (mchp_corespi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY)
142+
;
143+
144+
data = mchp_corespi_read(spi, REG_RX_DATA);
140145

141146
spi->rx_len -= spi->n_bytes;
142147

@@ -211,11 +216,10 @@ static inline void mchp_corespi_set_xfer_size(struct mchp_corespi *spi, int len)
211216
mchp_corespi_write(spi, REG_FRAMESUP, len);
212217
}
213218

214-
static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi)
219+
static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi, int fifo_max)
215220
{
216-
int fifo_max, i = 0;
221+
int i = 0;
217222

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

221225
while ((i < fifo_max) && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_TXFIFO_FULL)) {
@@ -417,16 +421,9 @@ static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id)
417421
if (intfield & INT_TXDONE)
418422
mchp_corespi_write(spi, REG_INT_CLEAR, INT_TXDONE);
419423

420-
if (intfield & INT_RXRDY) {
424+
if (intfield & INT_RXRDY)
421425
mchp_corespi_write(spi, REG_INT_CLEAR, INT_RXRDY);
422426

423-
if (spi->rx_len)
424-
mchp_corespi_read_fifo(spi);
425-
}
426-
427-
if (!spi->rx_len && !spi->tx_len)
428-
finalise = true;
429-
430427
if (intfield & INT_RX_CHANNEL_OVERFLOW) {
431428
mchp_corespi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW);
432429
finalise = true;
@@ -513,9 +510,13 @@ static int mchp_corespi_transfer_one(struct spi_master *master,
513510

514511
mchp_corespi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select);
515512

516-
while (spi->tx_len)
517-
mchp_corespi_write_fifo(spi);
513+
while (spi->tx_len) {
514+
int fifo_max = DIV_ROUND_UP(min(spi->tx_len, FIFO_DEPTH), spi->n_bytes);
515+
mchp_corespi_write_fifo(spi, fifo_max);
516+
mchp_corespi_read_fifo(spi, fifo_max);
517+
}
518518

519+
spi_finalize_current_transfer(host);
519520
return 1;
520521
}
521522

0 commit comments

Comments
 (0)