Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=15b82b46de358a574c2a6a6dea4c8076bef7ac43
Commit:     15b82b46de358a574c2a6a6dea4c8076bef7ac43
Parent:     2ba30eedec37e2f65babf4ea54233f98afbe0871
Author:     Nicolas Pitre <[EMAIL PROTECTED]>
AuthorDate: Mon Aug 20 17:17:37 2007 -0400
Committer:  Pierre Ossman <[EMAIL PROTECTED]>
CommitDate: Sun Sep 23 21:24:52 2007 +0200

    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 <[EMAIL PROTECTED]>
    Signed-off-by: Pierre Ossman <[EMAIL PROTECTED]>
---
 drivers/mmc/card/sdio_uart.c |   21 +++++++++++++++++++--
 1 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index 6061002..d552de6 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -79,6 +79,7 @@ struct sdio_uart_port {
        struct mutex            open_lock;
        struct sdio_func        *func;
        struct mutex            func_lock;
+       struct task_struct      *in_sdio_uart_irq;
        unsigned int            regs_offset;
        struct circ_buf         xmit;
        spinlock_t              write_lock;
@@ -186,14 +187,16 @@ static int sdio_uart_claim_func(struct sdio_uart_port 
*port)
                mutex_unlock(&port->func_lock);
                return -ENODEV;
        }
-       sdio_claim_host(port->func);
+       if (likely(port->in_sdio_uart_irq != current))
+               sdio_claim_host(port->func);
        mutex_unlock(&port->func_lock);
        return 0;
 }
 
 static inline void sdio_uart_release_func(struct sdio_uart_port *port)
 {
-       sdio_release_host(port->func);
+       if (likely(port->in_sdio_uart_irq != current))
+               sdio_release_host(port->func);
 }
 
 static 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)
        struct sdio_uart_port *port = sdio_get_drvdata(func);
        unsigned int iir, lsr;
 
+       /*
+        * 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.) through those same places
+        * causing undesirable effects.  Let's stop the recursion here.
+        */
+       if (unlikely(port->in_sdio_uart_irq == current))
+               return;
+
        iir = sdio_in(port, UART_IIR);
        if (iir & UART_IIR_NO_INT)
                return;
+
+       port->in_sdio_uart_irq = current;
        lsr = sdio_in(port, UART_LSR);
        if (lsr & UART_LSR_DR)
                sdio_uart_receive_chars(port, &lsr);
        sdio_uart_check_modem_status(port);
        if (lsr & UART_LSR_THRE)
                sdio_uart_transmit_chars(port);
+       port->in_sdio_uart_irq = NULL;
 }
 
 static int sdio_uart_startup(struct sdio_uart_port *port)
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to