aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Mack <zonque@gmail.com>2014-05-26 08:52:36 -0400
committerFelipe Balbi <balbi@ti.com>2014-06-30 15:26:22 -0400
commitc03da38d5d4b28f6ab559c4df8646dbda536b674 (patch)
tree2d957ae28494a31fbb84c96455b31a403e93d67b
parent9c547699cce1f9da38af525b692fefb50d96158d (diff)
usb: musb: use is_host_active() to distinguish between host and gadget mode
On AM33xx platforms, unplugging a device in the middle of an active transfer leads to a drop of MUSB_DEVCTL_HM in MUSB_DEVCTL before the system is informed about a disconnect. This consequently makes the musb core call the gadget code to handle the interrupt request, which then crashes the kernel because the relevant pointers haven't been set up for gadget mode. To fix this, use is_host_active() rather than (devctl & MUSB_DEVCTL_HM) in musb_interrupt() and musb_dma_completion() to detect whether the controller is in host or peripheral mode. This information is provided by the driver logic and does not rely on register contents. Signed-off-by: Daniel Mack <zonque@gmail.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/musb/musb_core.c16
1 files changed, 7 insertions, 9 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 61da471b7aed..3c6043c1b8ac 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1517,7 +1517,7 @@ irqreturn_t musb_interrupt(struct musb *musb)
1517 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); 1517 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
1518 1518
1519 dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n", 1519 dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n",
1520 (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral", 1520 is_host_active(musb) ? "host" : "peripheral",
1521 musb->int_usb, musb->int_tx, musb->int_rx); 1521 musb->int_usb, musb->int_tx, musb->int_rx);
1522 1522
1523 /* the core can interrupt us for multiple reasons; docs have 1523 /* the core can interrupt us for multiple reasons; docs have
@@ -1531,7 +1531,7 @@ irqreturn_t musb_interrupt(struct musb *musb)
1531 1531
1532 /* handle endpoint 0 first */ 1532 /* handle endpoint 0 first */
1533 if (musb->int_tx & 1) { 1533 if (musb->int_tx & 1) {
1534 if (devctl & MUSB_DEVCTL_HM) 1534 if (is_host_active(musb))
1535 retval |= musb_h_ep0_irq(musb); 1535 retval |= musb_h_ep0_irq(musb);
1536 else 1536 else
1537 retval |= musb_g_ep0_irq(musb); 1537 retval |= musb_g_ep0_irq(musb);
@@ -1545,7 +1545,7 @@ irqreturn_t musb_interrupt(struct musb *musb)
1545 /* musb_ep_select(musb->mregs, ep_num); */ 1545 /* musb_ep_select(musb->mregs, ep_num); */
1546 /* REVISIT just retval = ep->rx_irq(...) */ 1546 /* REVISIT just retval = ep->rx_irq(...) */
1547 retval = IRQ_HANDLED; 1547 retval = IRQ_HANDLED;
1548 if (devctl & MUSB_DEVCTL_HM) 1548 if (is_host_active(musb))
1549 musb_host_rx(musb, ep_num); 1549 musb_host_rx(musb, ep_num);
1550 else 1550 else
1551 musb_g_rx(musb, ep_num); 1551 musb_g_rx(musb, ep_num);
@@ -1563,7 +1563,7 @@ irqreturn_t musb_interrupt(struct musb *musb)
1563 /* musb_ep_select(musb->mregs, ep_num); */ 1563 /* musb_ep_select(musb->mregs, ep_num); */
1564 /* REVISIT just retval |= ep->tx_irq(...) */ 1564 /* REVISIT just retval |= ep->tx_irq(...) */
1565 retval = IRQ_HANDLED; 1565 retval = IRQ_HANDLED;
1566 if (devctl & MUSB_DEVCTL_HM) 1566 if (is_host_active(musb))
1567 musb_host_tx(musb, ep_num); 1567 musb_host_tx(musb, ep_num);
1568 else 1568 else
1569 musb_g_tx(musb, ep_num); 1569 musb_g_tx(musb, ep_num);
@@ -1585,15 +1585,13 @@ MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
1585 1585
1586void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) 1586void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
1587{ 1587{
1588 u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
1589
1590 /* called with controller lock already held */ 1588 /* called with controller lock already held */
1591 1589
1592 if (!epnum) { 1590 if (!epnum) {
1593#ifndef CONFIG_USB_TUSB_OMAP_DMA 1591#ifndef CONFIG_USB_TUSB_OMAP_DMA
1594 if (!is_cppi_enabled()) { 1592 if (!is_cppi_enabled()) {
1595 /* endpoint 0 */ 1593 /* endpoint 0 */
1596 if (devctl & MUSB_DEVCTL_HM) 1594 if (is_host_active(musb))
1597 musb_h_ep0_irq(musb); 1595 musb_h_ep0_irq(musb);
1598 else 1596 else
1599 musb_g_ep0_irq(musb); 1597 musb_g_ep0_irq(musb);
@@ -1602,13 +1600,13 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
1602 } else { 1600 } else {
1603 /* endpoints 1..15 */ 1601 /* endpoints 1..15 */
1604 if (transmit) { 1602 if (transmit) {
1605 if (devctl & MUSB_DEVCTL_HM) 1603 if (is_host_active(musb))
1606 musb_host_tx(musb, epnum); 1604 musb_host_tx(musb, epnum);
1607 else 1605 else
1608 musb_g_tx(musb, epnum); 1606 musb_g_tx(musb, epnum);
1609 } else { 1607 } else {
1610 /* receive */ 1608 /* receive */
1611 if (devctl & MUSB_DEVCTL_HM) 1609 if (is_host_active(musb))
1612 musb_host_rx(musb, epnum); 1610 musb_host_rx(musb, epnum);
1613 else 1611 else
1614 musb_g_rx(musb, epnum); 1612 musb_g_rx(musb, epnum);