aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/card/sdio_uart.c
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2007-08-20 17:17:37 -0400
committerPierre Ossman <drzeus@drzeus.cx>2007-09-23 15:24:52 -0400
commit15b82b46de358a574c2a6a6dea4c8076bef7ac43 (patch)
tree8ba3384b5dc10f7fca38de998e36366d5b2c8c4f /drivers/mmc/card/sdio_uart.c
parent2ba30eedec37e2f65babf4ea54233f98afbe0871 (diff)
sdio: fix recursion issues between sdio-uart driver and tty layer
In a few places, sdio_uart_irq() is called directly instead of waiting for the actual interrupt to be raised and the SDIO IRQ thread scheduled in order to reduce latency. However, some interaction with the tty core may end up calling us back (serial echo, flow control, etc.) creating two issues: - the host lock gets claimed twice from the same thread causing a deadlock; - the same direct calls to sdio_uart_irq() may be performed causing unexpected reentrancy into the IRQ handler. This patch handles both of those issues. Signed-off-by: Nicolas Pitre <npitre@mvista.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/card/sdio_uart.c')
-rw-r--r--drivers/mmc/card/sdio_uart.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 606100212afa..d552de683110 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -79,6 +79,7 @@ struct sdio_uart_port {
79 struct mutex open_lock; 79 struct mutex open_lock;
80 struct sdio_func *func; 80 struct sdio_func *func;
81 struct mutex func_lock; 81 struct mutex func_lock;
82 struct task_struct *in_sdio_uart_irq;
82 unsigned int regs_offset; 83 unsigned int regs_offset;
83 struct circ_buf xmit; 84 struct circ_buf xmit;
84 spinlock_t write_lock; 85 spinlock_t write_lock;
@@ -186,14 +187,16 @@ static int sdio_uart_claim_func(struct sdio_uart_port *port)
186 mutex_unlock(&port->func_lock); 187 mutex_unlock(&port->func_lock);
187 return -ENODEV; 188 return -ENODEV;
188 } 189 }
189 sdio_claim_host(port->func); 190 if (likely(port->in_sdio_uart_irq != current))
191 sdio_claim_host(port->func);
190 mutex_unlock(&port->func_lock); 192 mutex_unlock(&port->func_lock);
191 return 0; 193 return 0;
192} 194}
193 195
194static inline void sdio_uart_release_func(struct sdio_uart_port *port) 196static inline void sdio_uart_release_func(struct sdio_uart_port *port)
195{ 197{
196 sdio_release_host(port->func); 198 if (likely(port->in_sdio_uart_irq != current))
199 sdio_release_host(port->func);
197} 200}
198 201
199static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset) 202static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset)
@@ -511,15 +514,29 @@ static void sdio_uart_irq(struct sdio_func *func)
511 struct sdio_uart_port *port = sdio_get_drvdata(func); 514 struct sdio_uart_port *port = sdio_get_drvdata(func);
512 unsigned int iir, lsr; 515 unsigned int iir, lsr;
513 516
517 /*
518 * In a few places sdio_uart_irq() is called directly instead of
519 * waiting for the actual interrupt to be raised and the SDIO IRQ
520 * thread scheduled in order to reduce latency. However, some
521 * interaction with the tty core may end up calling us back
522 * (serial echo, flow control, etc.) through those same places
523 * causing undesirable effects. Let's stop the recursion here.
524 */
525 if (unlikely(port->in_sdio_uart_irq == current))
526 return;
527
514 iir = sdio_in(port, UART_IIR); 528 iir = sdio_in(port, UART_IIR);
515 if (iir & UART_IIR_NO_INT) 529 if (iir & UART_IIR_NO_INT)
516 return; 530 return;
531
532 port->in_sdio_uart_irq = current;
517 lsr = sdio_in(port, UART_LSR); 533 lsr = sdio_in(port, UART_LSR);
518 if (lsr & UART_LSR_DR) 534 if (lsr & UART_LSR_DR)
519 sdio_uart_receive_chars(port, &lsr); 535 sdio_uart_receive_chars(port, &lsr);
520 sdio_uart_check_modem_status(port); 536 sdio_uart_check_modem_status(port);
521 if (lsr & UART_LSR_THRE) 537 if (lsr & UART_LSR_THRE)
522 sdio_uart_transmit_chars(port); 538 sdio_uart_transmit_chars(port);
539 port->in_sdio_uart_irq = NULL;
523} 540}
524 541
525static int sdio_uart_startup(struct sdio_uart_port *port) 542static int sdio_uart_startup(struct sdio_uart_port *port)