summaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb
diff options
context:
space:
mode:
authorDaniel Mack2014-05-26 14:52:39 +0200
committerFelipe Balbi2014-06-30 21:26:25 +0200
commitf50e67853b363b96336718597823ed7a7e8652de (patch)
tree994c988398d3206c48d789b83c20e3c611404b92 /drivers/usb/musb
parentusb: musb: introduce dma_channel.rx_packet_done (diff)
downloadkernel-qcow2-linux-f50e67853b363b96336718597823ed7a7e8652de.tar.gz
kernel-qcow2-linux-f50e67853b363b96336718597823ed7a7e8652de.tar.xz
kernel-qcow2-linux-f50e67853b363b96336718597823ed7a7e8652de.zip
usb: musb/cppi41: call musb_ep_select() before accessing an endpoint's CSR
Before accessing any of an endpoint's CSR registers, make sure the correct endpoint is selected. Otherwise, data read from or written to the registers is likely to affect the wrong endpoint as long as the connected device has more than one endpoint. This, of course, leads to all sorts of strange effects such as stream starvation and driver internal state machine confusion due to spurious interrupts. Signed-off-by: Daniel Mack <zonque@gmail.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r--drivers/usb/musb/musb_cppi41.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
index 4187ef1fab29..932464ffb10c 100644
--- a/drivers/usb/musb/musb_cppi41.c
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -74,15 +74,18 @@ static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
{
+ struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
+ struct musb *musb = hw_ep->musb;
u16 csr;
u8 toggle;
if (cppi41_channel->is_tx)
return;
- if (!is_host_active(cppi41_channel->controller->musb))
+ if (!is_host_active(musb))
return;
- csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+ musb_ep_select(musb->mregs, hw_ep->epnum);
+ csr = musb_readw(hw_ep->regs, MUSB_RXCSR);
toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
/*
@@ -107,6 +110,7 @@ static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep)
void __iomem *epio = musb->endpoints[epnum].regs;
u16 csr;
+ musb_ep_select(musb->mregs, hw_ep->epnum);
csr = musb_readw(epio, MUSB_TXCSR);
if (csr & MUSB_TXCSR_TXPKTRDY)
return false;
@@ -173,6 +177,7 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
dma_async_issue_pending(dc);
if (!cppi41_channel->is_tx) {
+ musb_ep_select(musb->mregs, hw_ep->epnum);
csr = musb_readw(epio, MUSB_RXCSR);
csr |= MUSB_RXCSR_H_REQPKT;
musb_writew(epio, MUSB_RXCSR, csr);