aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRuslan Bilovol <ruslan.bilovol@ti.com>2012-06-14 17:12:15 +0300
committerRuslan Bilovol <ruslan.bilovol@ti.com>2012-08-30 14:37:33 +0300
commita4336ccb54a0f228f0b5676096d8c0da324072b0 (patch)
tree85e0e9aec655701df0173ed24396e5bbfdd3a39d
parent547b66d0802bb9dfac8f933bd9c00dda8dafb2eb (diff)
downloadkernel_samsung_espresso10-a4336ccb54a0f228f0b5676096d8c0da324072b0.zip
kernel_samsung_espresso10-a4336ccb54a0f228f0b5676096d8c0da324072b0.tar.gz
kernel_samsung_espresso10-a4336ccb54a0f228f0b5676096d8c0da324072b0.tar.bz2
USB: musb: do not proceed with interrupt completions if qh is not ready
It's not safe to modify hw_ep if qh is not ready. This may corrupt data in musb_qh. In RX/TX completions this may happen on SMP system with current musb host implementation The main issue is with musb_giveback function. It unlocks and and after that locks musb->lock so during this time musb_qh data may be corrupted. This results in null-pointers dereferences / programming of busy DMA channel / etc in different places. This often happens during unlinking URB for ISO and looks like: CPU0 CPU1 ... musb_urb_dequeue ... spin_lock_irqsave(&musb->lock) ... (work with musb_qh) ... musb_giveback ... spin_unlock(&musb->lock) generic_interrupt() ... spin_lock_irqsave(&musb->lock) ... (work with musb_qh) ... spin_unlock_irqrestore(&musb->lock) ... ... spin_lock(&musb->lock) ... (continues work with musb_qh) ... spin_lock_irqrestore(&musb->lock) Go out from completion if qh is not ready. Change-Id: I9c9280a7ab7f8e89b2e8bf745800217f903108fc Signed-off-by: Ruslan Bilovol <ruslan.bilovol@ti.com>
-rw-r--r--drivers/usb/musb/musb_host.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 8a08dd3..329182e 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -1113,6 +1113,11 @@ void musb_host_tx(struct musb *musb, u8 epnum)
return;
}
+ if (!qh->is_ready) {
+ dev_dbg(musb->controller, "received TX%d completion when qh is not ready\n", epnum);
+ return;
+ }
+
pipe = urb->pipe;
dma = is_dma_capable() ? hw_ep->tx_channel : NULL;
dev_dbg(musb->controller, "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr,
@@ -1451,6 +1456,12 @@ void musb_host_rx(struct musb *musb, u8 epnum)
return;
}
+ if (!qh->is_ready) {
+ dev_dbg(musb->controller, "received RX%d completion when qh is not ready\n", epnum);
+ musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG);
+ return;
+ }
+
pipe = urb->pipe;
dev_dbg(musb->controller, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)\n",