diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch | 417 |
1 files changed, 0 insertions, 417 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch deleted file mode 100644 index 7d546e10b..000000000 --- a/meta/recipes-kernel/linux/linux-omap-2.6.29/musb/0011-musb-fix-isochronous-TXDMA-take-2.patch +++ /dev/null @@ -1,417 +0,0 @@ -From 035cd4a26e9b1638b4b0419b98409026176563ca Mon Sep 17 00:00:00 2001 -From: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org> -Date: Thu, 26 Mar 2009 18:29:19 -0700 -Subject: [PATCH] musb: fix isochronous TXDMA (take 2) - -Multi-frame isochronous TX URBs transfers in DMA mode never -complete with CPPI DMA because musb_host_tx() doesn't restart -DMA on the second frame, only emitting a debug message. -With Inventra DMA they complete, but in PIO mode. To fix: - - - Factor out programming of the DMA transfer from - musb_ep_program() into musb_tx_dma_program(); - - - Reorder the code at the end of musb_host_tx() to - facilitate the fallback to PIO iff DMA fails; - - - Handle the buffer offset consistently for both - PIO and DMA modes; - - - Add an argument to musb_ep_program() for the same - reason (it only worked correctly with non-zero - offset of the first frame in PIO mode); - - - Set the completed isochronous frame descriptor's - 'actual_length' and 'status' fields correctly in - DMA mode. - -Also, since CPPI reportedly doesn't like sending isochronous -packets in the RNDIS mode, change the criterion for this -mode to be used only for multi-packet transfers. (There's -no need for that mode in the single-packet case anyway.) - -[ dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org: split comment paragraph -into bullet list, shrink patch delta, style tweaks ] - -Signed-off-by: Pavel Kiryukhin <pkiryukhin-hkdhdckH98+B+jHODAdFcQ@public.gmane.org> -Signed-off-by: Sergei Shtylyov <sshtylyov-hkdhdckH98+B+jHODAdFcQ@public.gmane.org> -Signed-off-by: David Brownell <dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org> ---- - drivers/usb/musb/cppi_dma.c | 1 + - drivers/usb/musb/musb_host.c | 227 +++++++++++++++++++----------------------- - 2 files changed, 105 insertions(+), 123 deletions(-) - -diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c -index 569ef0f..ac7227c 100644 ---- a/drivers/usb/musb/cppi_dma.c -+++ b/drivers/usb/musb/cppi_dma.c -@@ -579,6 +579,7 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx) - * trigger the "send a ZLP?" confusion. - */ - rndis = (maxpacket & 0x3f) == 0 -+ && length > maxpacket - && length < 0xffff - && (length % maxpacket) != 0; - -diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c -index 6591282..f6e84a0 100644 ---- a/drivers/usb/musb/musb_host.c -+++ b/drivers/usb/musb/musb_host.c -@@ -96,8 +96,8 @@ - - - static void musb_ep_program(struct musb *musb, u8 epnum, -- struct urb *urb, unsigned int nOut, -- u8 *buf, u32 len); -+ struct urb *urb, int is_out, -+ u8 *buf, u32 offset, u32 len); - - /* - * Clear TX fifo. Needed to avoid BABBLE errors. -@@ -189,9 +189,10 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) - { - u16 frame; - u32 len; -- void *buf; - void __iomem *mbase = musb->mregs; - struct urb *urb = next_urb(qh); -+ void *buf = urb->transfer_buffer; -+ u32 offset = 0; - struct musb_hw_ep *hw_ep = qh->hw_ep; - unsigned pipe = urb->pipe; - u8 address = usb_pipedevice(pipe); -@@ -214,7 +215,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) - case USB_ENDPOINT_XFER_ISOC: - qh->iso_idx = 0; - qh->frame = 0; -- buf = urb->transfer_buffer + urb->iso_frame_desc[0].offset; -+ offset = urb->iso_frame_desc[0].offset; - len = urb->iso_frame_desc[0].length; - break; - default: /* bulk, interrupt */ -@@ -232,14 +233,14 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) - case USB_ENDPOINT_XFER_ISOC: s = "-iso"; break; - default: s = "-intr"; break; - }; s; }), -- epnum, buf, len); -+ epnum, buf + offset, len); - - /* Configure endpoint */ - if (is_in || hw_ep->is_shared_fifo) - hw_ep->in_qh = qh; - else - hw_ep->out_qh = qh; -- musb_ep_program(musb, epnum, urb, !is_in, buf, len); -+ musb_ep_program(musb, epnum, urb, !is_in, buf, offset, len); - - /* transmit may have more work: start it when it is time */ - if (is_in) -@@ -250,7 +251,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) - case USB_ENDPOINT_XFER_ISOC: - case USB_ENDPOINT_XFER_INT: - DBG(3, "check whether there's still time for periodic Tx\n"); -- qh->iso_idx = 0; - frame = musb_readw(mbase, MUSB_FRAME); - /* FIXME this doesn't implement that scheduling policy ... - * or handle framecounter wrapping -@@ -631,14 +631,68 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) - ep->rx_reinit = 0; - } - -+static bool musb_tx_dma_program(struct dma_controller *dma, -+ struct musb_hw_ep *hw_ep, struct musb_qh *qh, -+ struct urb *urb, u32 offset, u32 length) -+{ -+ struct dma_channel *channel = hw_ep->tx_channel; -+ void __iomem *epio = hw_ep->regs; -+ u16 pkt_size = qh->maxpacket; -+ u16 csr; -+ u8 mode; -+ -+#ifdef CONFIG_USB_INVENTRA_DMA -+ if (length > channel->max_len) -+ length = channel->max_len; -+ -+ csr = musb_readw(epio, MUSB_TXCSR); -+ if (length > pkt_size) { -+ mode = 1; -+ csr |= MUSB_TXCSR_AUTOSET -+ | MUSB_TXCSR_DMAMODE -+ | MUSB_TXCSR_DMAENAB; -+ } else { -+ mode = 0; -+ csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE); -+ csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */ -+ } -+ channel->desired_mode = mode; -+ musb_writew(epio, MUSB_TXCSR, csr); -+#else -+ if (!is_cppi_enabled() && !tusb_dma_omap()) -+ return false; -+ -+ channel->actual_len = 0; -+ -+ /* -+ * TX uses "RNDIS" mode automatically but needs help -+ * to identify the zero-length-final-packet case. -+ */ -+ mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0; -+#endif -+ -+ qh->segsize = length; -+ -+ if (!dma->channel_program(channel, pkt_size, mode, -+ urb->transfer_dma + offset, length)) { -+ dma->channel_release(channel); -+ hw_ep->tx_channel = NULL; -+ -+ csr = musb_readw(epio, MUSB_TXCSR); -+ csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); -+ musb_writew(epio, MUSB_TXCSR, csr | MUSB_TXCSR_H_WZC_BITS); -+ return false; -+ } -+ return true; -+} - - /* - * Program an HDRC endpoint as per the given URB - * Context: irqs blocked, controller lock held - */ - static void musb_ep_program(struct musb *musb, u8 epnum, -- struct urb *urb, unsigned int is_out, -- u8 *buf, u32 len) -+ struct urb *urb, int is_out, -+ u8 *buf, u32 offset, u32 len) - { - struct dma_controller *dma_controller; - struct dma_channel *dma_channel; -@@ -764,82 +818,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum, - else - load_count = min((u32) packet_sz, len); - --#ifdef CONFIG_USB_INVENTRA_DMA -- if (dma_channel) { -- qh->segsize = min(len, dma_channel->max_len); -- if (qh->segsize <= packet_sz) -- dma_channel->desired_mode = 0; -- else -- dma_channel->desired_mode = 1; -- -- if (dma_channel->desired_mode == 0) { -- /* Against the programming guide */ -- csr |= (MUSB_TXCSR_DMAENAB); -- } else -- csr |= (MUSB_TXCSR_AUTOSET -- | MUSB_TXCSR_DMAENAB -- | MUSB_TXCSR_DMAMODE); -- musb_writew(epio, MUSB_TXCSR, csr); -- -- dma_ok = dma_controller->channel_program( -- dma_channel, packet_sz, -- dma_channel->desired_mode, -- urb->transfer_dma, -- qh->segsize); -- if (dma_ok) { -- load_count = 0; -- } else { -- dma_controller->channel_release(dma_channel); -- if (is_out) -- hw_ep->tx_channel = NULL; -- else -- hw_ep->rx_channel = NULL; -- dma_channel = NULL; -- -- /* -- * The programming guide says that we must -- * clear the DMAENAB bit before DMAMODE... -- */ -- csr = musb_readw(epio, MUSB_TXCSR); -- csr &= ~(MUSB_TXCSR_DMAENAB -- | MUSB_TXCSR_AUTOSET); -- musb_writew(epio, MUSB_TXCSR, csr); -- csr &= ~MUSB_TXCSR_DMAMODE; -- musb_writew(epio, MUSB_TXCSR, csr); -- } -- } --#endif -- -- /* candidate for DMA */ -- if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) { -- -- /* Defer enabling DMA */ -- dma_channel->actual_len = 0L; -- qh->segsize = len; -- -- /* TX uses "rndis" mode automatically, but needs help -- * to identify the zero-length-final-packet case. -- */ -- dma_ok = dma_controller->channel_program( -- dma_channel, packet_sz, -- (urb->transfer_flags -- & URB_ZERO_PACKET) -- == URB_ZERO_PACKET, -- urb->transfer_dma, -- qh->segsize); -- if (dma_ok) { -- load_count = 0; -- } else { -- dma_controller->channel_release(dma_channel); -- hw_ep->tx_channel = NULL; -- dma_channel = NULL; -- -- /* REVISIT there's an error path here that -- * needs handling: can't do dma, but -- * there's no pio buffer address... -- */ -- } -- } -+ if (dma_channel && musb_tx_dma_program(dma_controller, -+ hw_ep, qh, urb, offset, len)) -+ load_count = 0; - - if (load_count) { - /* PIO to load FIFO */ -@@ -899,7 +880,7 @@ static void musb_ep_program(struct musb *musb, u8 epnum, - dma_channel, packet_sz, - !(urb->transfer_flags - & URB_SHORT_NOT_OK), -- urb->transfer_dma, -+ urb->transfer_dma + offset, - qh->segsize); - if (!dma_ok) { - dma_controller->channel_release( -@@ -1142,8 +1123,8 @@ void musb_host_tx(struct musb *musb, u8 epnum) - int pipe; - bool done = false; - u16 tx_csr; -- size_t wLength = 0; -- u8 *buf = NULL; -+ size_t length = 0; -+ size_t offset = 0; - struct urb *urb; - struct musb_hw_ep *hw_ep = musb->endpoints + epnum; - void __iomem *epio = hw_ep->regs; -@@ -1161,7 +1142,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) - /* with CPPI, DMA sometimes triggers "extra" irqs */ - if (!urb) { - DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr); -- goto finish; -+ return; - } - - pipe = urb->pipe; -@@ -1198,7 +1179,7 @@ void musb_host_tx(struct musb *musb, u8 epnum) - musb_writew(epio, MUSB_TXCSR, - MUSB_TXCSR_H_WZC_BITS - | MUSB_TXCSR_TXPKTRDY); -- goto finish; -+ return; - } - - if (status) { -@@ -1230,29 +1211,28 @@ void musb_host_tx(struct musb *musb, u8 epnum) - /* second cppi case */ - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - DBG(4, "extra TX%d ready, csr %04x\n", epnum, tx_csr); -- goto finish; -- -+ return; - } - -- /* REVISIT this looks wrong... */ - if (!status || dma || usb_pipeisoc(pipe)) { - if (dma) -- wLength = dma->actual_len; -+ length = dma->actual_len; - else -- wLength = qh->segsize; -- qh->offset += wLength; -+ length = qh->segsize; -+ qh->offset += length; - - if (usb_pipeisoc(pipe)) { - struct usb_iso_packet_descriptor *d; - - d = urb->iso_frame_desc + qh->iso_idx; -- d->actual_length = qh->segsize; -+ d->actual_length = length; -+ d->status = status; - if (++qh->iso_idx >= urb->number_of_packets) { - done = true; - } else { - d++; -- buf = urb->transfer_buffer + d->offset; -- wLength = d->length; -+ offset = d->offset; -+ length = d->length; - } - } else if (dma) { - done = true; -@@ -1265,10 +1245,8 @@ void musb_host_tx(struct musb *musb, u8 epnum) - & URB_ZERO_PACKET)) - done = true; - if (!done) { -- buf = urb->transfer_buffer -- + qh->offset; -- wLength = urb->transfer_buffer_length -- - qh->offset; -+ offset = qh->offset; -+ length = urb->transfer_buffer_length - offset; - } - } - } -@@ -1287,28 +1265,31 @@ void musb_host_tx(struct musb *musb, u8 epnum) - urb->status = status; - urb->actual_length = qh->offset; - musb_advance_schedule(musb, urb, hw_ep, USB_DIR_OUT); -+ return; -+ } else if (usb_pipeisoc(pipe) && dma) { -+ if (musb_tx_dma_program(musb->dma_controller, hw_ep, qh, urb, -+ offset, length)) -+ return; -+ } else if (tx_csr & MUSB_TXCSR_DMAENAB) { -+ DBG(1, "not complete, but DMA enabled?\n"); -+ return; -+ } - -- } else if (!(tx_csr & MUSB_TXCSR_DMAENAB)) { -- /* WARN_ON(!buf); */ -- -- /* REVISIT: some docs say that when hw_ep->tx_double_buffered, -- * (and presumably, fifo is not half-full) we should write TWO -- * packets before updating TXCSR ... other docs disagree ... -- */ -- /* PIO: start next packet in this URB */ -- if (wLength > qh->maxpacket) -- wLength = qh->maxpacket; -- musb_write_fifo(hw_ep, wLength, buf); -- qh->segsize = wLength; -- -- musb_ep_select(mbase, epnum); -- musb_writew(epio, MUSB_TXCSR, -- MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); -- } else -- DBG(1, "not complete, but dma enabled?\n"); -+ /* -+ * PIO: start next packet in this URB. -+ * -+ * REVISIT: some docs say that when hw_ep->tx_double_buffered, -+ * (and presumably, FIFO is not half-full) we should write *two* -+ * packets before updating TXCSR; other docs disagree... -+ */ -+ if (length > qh->maxpacket) -+ length = qh->maxpacket; -+ musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); -+ qh->segsize = length; - --finish: -- return; -+ musb_ep_select(mbase, epnum); -+ musb_writew(epio, MUSB_TXCSR, -+ MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); - } - - --- -1.6.0.4 - |