| From 2633692689f0e9774be17b7feaaab42a83a92afd Mon Sep 17 00:00:00 2001 |
| From: Bin Liu <b-liu@ti.com> |
| Date: Tue, 3 Jan 2017 18:13:46 -0600 |
| Subject: [PATCH] usb: musb: core: add clear_ep_rxintr() to musb_platform_ops |
| |
| commit 6def85a396ce7796bd9f4561c6ae8138833f7a52 upstream. |
| |
| During dma teardown for dequque urb, if musb load is high, musb might |
| generate bogus rx ep interrupt even when the rx fifo is flushed. In such |
| case any of the follow log messages could happen. |
| |
| musb_host_rx 1853: BOGUS RX2 ready, csr 0000, count 0 |
| |
| musb_host_rx 1936: RX3 dma busy, csr 2020 |
| |
| As mentioned in the current inline comment, clearing ep interrupt in the |
| teardown path avoids the bogus interrupt. |
| |
| Clearing ep interrupt is platform dependent, so this patch adds a |
| platform callback to allow glue driver to clear the ep interrupt. |
| |
| This bug seems to be existing since the initial driver for musb support, |
| but I only validated the fix back to v4.1, so only cc stable for v4.1+. |
| |
| cc: stable@vger.kernel.org # 4.1+ |
| Signed-off-by: Bin Liu <b-liu@ti.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h |
| index b55a776b03eb..9fac6a99471f 100644 |
| --- a/drivers/usb/musb/musb_core.h |
| +++ b/drivers/usb/musb/musb_core.h |
| @@ -216,6 +216,7 @@ struct musb_platform_ops { |
| void (*pre_root_reset_end)(struct musb *musb); |
| void (*post_root_reset_end)(struct musb *musb); |
| int (*phy_callback)(enum musb_vbus_id_status status); |
| + void (*clear_ep_rxintr)(struct musb *musb, int epnum); |
| }; |
| |
| /* |
| @@ -615,4 +616,10 @@ static inline void musb_platform_post_root_reset_end(struct musb *musb) |
| musb->ops->post_root_reset_end(musb); |
| } |
| |
| +static inline void musb_platform_clear_ep_rxintr(struct musb *musb, int epnum) |
| +{ |
| + if (musb->ops->clear_ep_rxintr) |
| + musb->ops->clear_ep_rxintr(musb, epnum); |
| +} |
| + |
| #endif /* __MUSB_CORE_H__ */ |
| diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c |
| index 53bc4ceefe89..806451418cfe 100644 |
| --- a/drivers/usb/musb/musb_host.c |
| +++ b/drivers/usb/musb/musb_host.c |
| @@ -2374,12 +2374,11 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) |
| int is_in = usb_pipein(urb->pipe); |
| int status = 0; |
| u16 csr; |
| + struct dma_channel *dma = NULL; |
| |
| musb_ep_select(regs, hw_end); |
| |
| if (is_dma_capable()) { |
| - struct dma_channel *dma; |
| - |
| dma = is_in ? ep->rx_channel : ep->tx_channel; |
| if (dma) { |
| status = ep->musb->dma_controller->channel_abort(dma); |
| @@ -2395,10 +2394,9 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) |
| /* giveback saves bulk toggle */ |
| csr = musb_h_flush_rxfifo(ep, 0); |
| |
| - /* REVISIT we still get an irq; should likely clear the |
| - * endpoint's irq status here to avoid bogus irqs. |
| - * clearing that status is platform-specific... |
| - */ |
| + /* clear the endpoint's irq status here to avoid bogus irqs */ |
| + if (is_dma_capable() && dma) |
| + musb_platform_clear_ep_rxintr(musb, ep->epnum); |
| } else if (ep->epnum) { |
| musb_h_tx_flush_fifo(ep); |
| csr = musb_readw(epio, MUSB_TXCSR); |
| -- |
| 2.10.1 |
| |