aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Crosthwaite <peter.crosthwaite@petalogix.com>2013-06-04 10:02:34 -0400
committerMark Brown <broonie@linaro.org>2013-06-04 13:32:19 -0400
commit68c315bb951d94210c43c52166d326f9c26f7ce8 (patch)
tree1708d43440a40b87ce0531941a91f09c8d30f507
parentd683b96b072dc4680fc74964eca77e6a23d1fa6e (diff)
spi: spi-xilinx: Remove ISR race condition
The ISR currently consumes the rx buffer data and re-enables transmission from within interrupt context. This is bad because if the interrupt occurs again before the ISR exits, the new interrupt will be erroneously cleared by the still completing ISR. Simplified the ISR by just setting the completion variable and exiting with no action. Then just looped the transmit functionality in xilinx_spi_txrx_bufs(). Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com> Signed-off-by: Michal Simek <michal.simek@xilinx.com> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--drivers/spi/spi-xilinx.c74
1 files changed, 35 insertions, 39 deletions
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index e1d769607425..34d18dcfa0db 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -267,7 +267,6 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
267{ 267{
268 struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); 268 struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
269 u32 ipif_ier; 269 u32 ipif_ier;
270 u16 cr;
271 270
272 /* We get here with transmitter inhibited */ 271 /* We get here with transmitter inhibited */
273 272
@@ -276,7 +275,6 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
276 xspi->remaining_bytes = t->len; 275 xspi->remaining_bytes = t->len;
277 INIT_COMPLETION(xspi->done); 276 INIT_COMPLETION(xspi->done);
278 277
279 xilinx_spi_fill_tx_fifo(xspi);
280 278
281 /* Enable the transmit empty interrupt, which we use to determine 279 /* Enable the transmit empty interrupt, which we use to determine
282 * progress on the transmission. 280 * progress on the transmission.
@@ -285,12 +283,41 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
285 xspi->write_fn(ipif_ier | XSPI_INTR_TX_EMPTY, 283 xspi->write_fn(ipif_ier | XSPI_INTR_TX_EMPTY,
286 xspi->regs + XIPIF_V123B_IIER_OFFSET); 284 xspi->regs + XIPIF_V123B_IIER_OFFSET);
287 285
288 /* Start the transfer by not inhibiting the transmitter any longer */ 286 for (;;) {
289 cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & 287 u16 cr;
290 ~XSPI_CR_TRANS_INHIBIT; 288 u8 sr;
291 xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET); 289
290 xilinx_spi_fill_tx_fifo(xspi);
291
292 /* Start the transfer by not inhibiting the transmitter any
293 * longer
294 */
295 cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) &
296 ~XSPI_CR_TRANS_INHIBIT;
297 xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
298
299 wait_for_completion(&xspi->done);
300
301 /* A transmit has just completed. Process received data and
302 * check for more data to transmit. Always inhibit the
303 * transmitter while the Isr refills the transmit register/FIFO,
304 * or make sure it is stopped if we're done.
305 */
306 cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
307 xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
308 xspi->regs + XSPI_CR_OFFSET);
309
310 /* Read out all the data from the Rx FIFO */
311 sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
312 while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
313 xspi->rx_fn(xspi);
314 sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
315 }
292 316
293 wait_for_completion(&xspi->done); 317 /* See if there is more data to send */
318 if (!xspi->remaining_bytes > 0)
319 break;
320 }
294 321
295 /* Disable the transmit empty interrupt */ 322 /* Disable the transmit empty interrupt */
296 xspi->write_fn(ipif_ier, xspi->regs + XIPIF_V123B_IIER_OFFSET); 323 xspi->write_fn(ipif_ier, xspi->regs + XIPIF_V123B_IIER_OFFSET);
@@ -314,38 +341,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
314 xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET); 341 xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET);
315 342
316 if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */ 343 if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
317 u16 cr; 344 complete(&xspi->done);
318 u8 sr;
319
320 /* A transmit has just completed. Process received data and
321 * check for more data to transmit. Always inhibit the
322 * transmitter while the Isr refills the transmit register/FIFO,
323 * or make sure it is stopped if we're done.
324 */
325 cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
326 xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
327 xspi->regs + XSPI_CR_OFFSET);
328
329 /* Read out all the data from the Rx FIFO */
330 sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
331 while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
332 xspi->rx_fn(xspi);
333 sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
334 }
335
336 /* See if there is more data to send */
337 if (xspi->remaining_bytes > 0) {
338 xilinx_spi_fill_tx_fifo(xspi);
339 /* Start the transfer by not inhibiting the
340 * transmitter any longer
341 */
342 xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
343 } else {
344 /* No more data to send.
345 * Indicate the transfer is completed.
346 */
347 complete(&xspi->done);
348 }
349 } 345 }
350 346
351 return IRQ_HANDLED; 347 return IRQ_HANDLED;