irda: ali-ircc: Fix deadlock in ali_ircc_sir_change_speed()
ali_ircc_sir_change_speed() is always called with self->lock held, so acquiring the lock inside it leads to unavoidable deadlock. Call graph: ali_ircc_sir_change_speed() is called from ali_ircc_change_speed() ali_ircc_fir_hard_xmit() under spin_lock_irqsave(&self->lock, flags); ali_ircc_sir_hard_xmit() under spin_lock_irqsave(&self->lock, flags); ali_ircc_net_ioctl() under spin_lock_irqsave(&self->lock, flags); ali_ircc_dma_xmit_complete() ali_ircc_fir_interrupt() ali_ircc_interrupt() under spin_lock(&self->lock); ali_ircc_sir_write_wakeup() ali_ircc_sir_interrupt() ali_ircc_interrupt() under spin_lock(&self->lock); The patch removes spin_lock/unlock from ali_ircc_sir_change_speed(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
38c089d1d8
commit
e8684c8877
|
@ -1031,7 +1031,6 @@ static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud)
|
||||||
static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed)
|
static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed)
|
||||||
{
|
{
|
||||||
struct ali_ircc_cb *self = priv;
|
struct ali_ircc_cb *self = priv;
|
||||||
unsigned long flags;
|
|
||||||
int iobase;
|
int iobase;
|
||||||
int fcr; /* FIFO control reg */
|
int fcr; /* FIFO control reg */
|
||||||
int lcr; /* Line control reg */
|
int lcr; /* Line control reg */
|
||||||
|
@ -1061,8 +1060,6 @@ static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed)
|
||||||
/* Update accounting for new speed */
|
/* Update accounting for new speed */
|
||||||
self->io.speed = speed;
|
self->io.speed = speed;
|
||||||
|
|
||||||
spin_lock_irqsave(&self->lock, flags);
|
|
||||||
|
|
||||||
divisor = 115200/speed;
|
divisor = 115200/speed;
|
||||||
|
|
||||||
fcr = UART_FCR_ENABLE_FIFO;
|
fcr = UART_FCR_ENABLE_FIFO;
|
||||||
|
@ -1089,9 +1086,6 @@ static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed)
|
||||||
/* without this, the connection will be broken after come back from FIR speed,
|
/* without this, the connection will be broken after come back from FIR speed,
|
||||||
but with this, the SIR connection is harder to established */
|
but with this, the SIR connection is harder to established */
|
||||||
outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
|
outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&self->lock, flags);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed)
|
static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed)
|
||||||
|
|
Loading…
Reference in New Issue