aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-xilinx.c
diff options
context:
space:
mode:
authorRicardo Ribalda Delgado <ricardo.ribalda@gmail.com>2015-10-28 11:16:02 -0400
committerMark Brown <broonie@kernel.org>2015-10-28 20:03:42 -0400
commiteca37c7c117460e2fbe4e32c991bff32a961f688 (patch)
treec4004827a2515d3db02bc1be219b12b8dba6221a /drivers/spi/spi-xilinx.c
parent6ff33f3902c3b1c5d0db6b1e2c70b6d76fba357f (diff)
spi/spi-xilinx: Fix race condition on last word read
Some users have reported that in polled mode the driver fails randomly to read the last word of the transfer. The end condition used for the transmissions (in polled and irq mode) has been the TX_EMPTY flag. But Lars-Peter Clausen has identified a delay from the TX_EMPTY to the actual end of the data rx. I believe that this race condition has not been detected until now because of the latency added by the IRQ handler or the PCIe bridge. This bugs affects setups with low latency access to the spi core. This patch replaces the readout logic: For all the words, except the last one, the TX_EMPTY flag is used (and cached). If !TX_EMPY or is the last word. The status register is read and the RX_EMPTY flag is used. The performance is not affected: there is an extra read of the Status Register, but the readout can start as soon as there is a word in the buffer. Reported-by: Edward Kigwana <ekigwana@scires.com> Initial-fix-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> Signed-off-by: Mark Brown <broonie@kernel.org> Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/spi/spi-xilinx.c')
-rw-r--r--drivers/spi/spi-xilinx.c38
1 files changed, 24 insertions, 14 deletions
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index a339c1e9997a..3009121173cd 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -270,6 +270,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
270 270
271 while (remaining_words) { 271 while (remaining_words) {
272 int n_words, tx_words, rx_words; 272 int n_words, tx_words, rx_words;
273 u32 sr;
273 274
274 n_words = min(remaining_words, xspi->buffer_size); 275 n_words = min(remaining_words, xspi->buffer_size);
275 276
@@ -284,24 +285,33 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
284 if (use_irq) { 285 if (use_irq) {
285 xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); 286 xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
286 wait_for_completion(&xspi->done); 287 wait_for_completion(&xspi->done);
287 } else 288 /* A transmit has just completed. Process received data
288 while (!(xspi->read_fn(xspi->regs + XSPI_SR_OFFSET) & 289 * and check for more data to transmit. Always inhibit
289 XSPI_SR_TX_EMPTY_MASK)) 290 * the transmitter while the Isr refills the transmit
290 ; 291 * register/FIFO, or make sure it is stopped if we're
291 292 * done.
292 /* A transmit has just completed. Process received data and 293 */
293 * check for more data to transmit. Always inhibit the
294 * transmitter while the Isr refills the transmit register/FIFO,
295 * or make sure it is stopped if we're done.
296 */
297 if (use_irq)
298 xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, 294 xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
299 xspi->regs + XSPI_CR_OFFSET); 295 xspi->regs + XSPI_CR_OFFSET);
296 sr = XSPI_SR_TX_EMPTY_MASK;
297 } else
298 sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
300 299
301 /* Read out all the data from the Rx FIFO */ 300 /* Read out all the data from the Rx FIFO */
302 rx_words = n_words; 301 rx_words = n_words;
303 while (rx_words--) 302 while (rx_words) {
304 xilinx_spi_rx(xspi); 303 if ((sr & XSPI_SR_TX_EMPTY_MASK) && (rx_words > 1)) {
304 xilinx_spi_rx(xspi);
305 rx_words--;
306 continue;
307 }
308
309 sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
310 if (!(sr & XSPI_SR_RX_EMPTY_MASK)) {
311 xilinx_spi_rx(xspi);
312 rx_words--;
313 }
314 }
305 315
306 remaining_words -= n_words; 316 remaining_words -= n_words;
307 } 317 }