-----Original Message----- From: Ming Lei [mailto:tom.leiming@xxxxxxxxx] Sent: Wednesday, October 20, 2010 12:00 AM To: Liu, Bob Cc: Bob Liu; balbi@xxxxxx; Cai, Cliff; Zhang, Sonic; greg@xxxxxxxxx; linux-usb@xxxxxxxxxxxxxxx; David Brownell; Gadiyar, Anand; Mike Frysinger; Sergei Shtylyov Subject: Re: [PATCH 2/2] USB: musb: gadget: fix MUSB_TXMAXP and MUSB_RXMAXP configuration Hi Bob, 2010/10/19 Liu, Bob <Bob.Liu@xxxxxxxxxx>: > Hi, Ming > > Sorry for my mistake, in my test the failed case was case5 not case4. > Case5 is BULK OUT transfer, so this patch changed txstate() only won't have effect, > sorry for the noise. > > Now the problem is if "fixed MUSB_TXMAXP and MUSB_RXMAXP configuration", > double buffer mode will be auto enabled on our platform which makes case5 fail sometimes. > > And the root cause is in function rxstate() > === > if (csr & MUSB_RXCSR_RXPKTRDY) { > len = musb_readw(epio, MUSB_RXCOUNT); > == > len will be read out with very strange value like 1022,514 which are not expected and > make things mess, so case5 failed. I guess it is caused by double buffer, since double buffer support depends on rx_double_buffered flag now but the flag isn't set in blackfin musb. Please try the patch below. If the patch still doesn't work, please enable musb debug switch and post the debug info on list. diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 2a82362..f86dce9 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -536,6 +536,25 @@ static inline void musb_configure_ep0(struct musb *musb) musb->endpoints[0].is_shared_fifo = true; } +static inline void musb_update_double_fifo(struct musb_ep *musb_ep, + int rx) +{ + struct musb_hw_ep *hw_ep = musb_ep->hw_ep; + + if (rx) { + if (hw_ep->max_packet_sz_rx >= (musb_ep->packet_sz * 2)) { + hw_ep->rx_double_buffered = 1; + hw_ep->max_packet_sz_rx >>= 1; + } else + hw_ep->rx_double_buffered = 0; + } else { + if (hw_ep->max_packet_sz_tx >= (musb_ep->packet_sz * 2)) { + hw_ep->tx_double_buffered = 1; + hw_ep->max_packet_sz_tx >>= 1; + } else + hw_ep->tx_double_buffered = 0; + } +} #else static inline int musb_read_fifosize(struct musb *musb, @@ -574,6 +593,11 @@ static inline void musb_configure_ep0(struct musb *musb) musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE; musb->endpoints[0].is_shared_fifo = true; } +static inline void musb_update_double_fifo(struct musb_ep *musb_ep, + int rx) +{ + +} #endif /* CONFIG_BLACKFIN */ diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 9cfd18b..bcecd13 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -920,6 +927,8 @@ static int musb_gadget_enable(struct usb_ep *ep, goto fail; } + musb_update_double_fifo(musb_ep, 0); + int_txe |= (1 << epnum); musb_writew(mbase, MUSB_INTRTXE, int_txe); @@ -956,6 +965,8 @@ static int musb_gadget_enable(struct usb_ep *ep, goto fail; } + musb_update_double_fifo(musb_ep, 1); + int_rxe |= (1 << epnum); musb_writew(mbase, MUSB_INTRRXE, int_rxe); ====================================================================== Hi, I made a new clean environment to test it yesterday. The test results is different. Now testusb#5 and #7 will always Broken pipe Like this: root@adam-desktop:~/usb# ./testusb -D /proc/bus/usb/002/020 -c 1024 -t 5 -s 32768 -g 8 unknown speed /proc/bus/usb/002/020 /proc/bus/usb/002/020 test 1 --> 32 (Broken pipe) And on the board: root:/> PHY: 0:01 - Link is Up - 100/Full zero gadget: high speed config #3: source/sink zero gadget: bad OUT byte, buf[3072] = 85, pattern 0 And the all the change in my environment is(diff from the version worked fine): === --- musb_gadget.c (revision 9256) +++ musb_gadget.c (working copy) @@ -313,7 +313,7 @@ * currently, don't use mode1 on Blackfin. */ #if !defined(CONFIG_BLACKFIN) || defined(USE_MODE1) - request_size = min_t(size_t, request->length, + request_size = min_t(size_t, request->length - request->actual, musb_ep->dma->max_len); #else request_size = fifo_count; @@ -512,29 +512,16 @@ | MUSB_TXCSR_TXPKTRDY); request->zero = 0; } - if (request->actual < request->length) - return; + if (request->actual == request->length) { + /* ... or if not, then complete it. */ + musb_g_giveback(musb_ep, request, 0); - /* ... or if not, then complete it. */ - musb_g_giveback(musb_ep, request, 0); - - /* - * Kickstart next transfer if appropriate; - * the packet that just completed might not - * be transmitted for hours or days. - * REVISIT for double buffering... - * FIXME revisit for stalls too... - */ - musb_ep_select(mbase, epnum); - csr = musb_readw(epio, MUSB_TXCSR); - if (csr & MUSB_TXCSR_FIFONOTEMPTY) - return; - - request = musb_ep->desc ? next_request(musb_ep) : NULL; - if (!request) { - DBG(4, "%s idle now\n", - musb_ep->end_point.name); - return; + request = musb_ep->desc ? next_request(musb_ep) : NULL; + if (!request) { + DBG(4, "%s idle now\n", + musb_ep->end_point.name); + return; + } } } @@ -672,15 +659,18 @@ musb_writew(epio, MUSB_RXCSR, csr | MUSB_RXCSR_DMAMODE); #endif + if(musb_ep->hw_ep->rx_double_buffered) /* bf enabled double buffer mode but not set rx_double_buffered */ + csr |= MUSB_RXCSR_AUTOCLEAR; musb_writew(epio, MUSB_RXCSR, csr); if (request->actual < request->length) { int transfer_size = 0; #ifdef USE_MODE1 - transfer_size = min(request->length, + transfer_size = min(request->length - request->actual, channel->max_len); #else - transfer_size = len; + transfer_size = min(request->length - request->actual, + len); #endif if (transfer_size <= musb_ep->packet_sz) musb_ep->dma->desired_mode = 0; @@ -819,7 +809,7 @@ #if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) /* Autoclear doesn't clear RxPktRdy for short packets */ - if ((dma->desired_mode == 0) + if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered) || (dma->actual_len & (musb_ep->packet_sz - 1))) { /* ack the read! */ @@ -830,8 +820,14 @@ /* incomplete, and not short? wait for next IN packet */ if ((request->actual < request->length) && (musb_ep->dma->actual_len - == musb_ep->packet_sz)) + == musb_ep->packet_sz)) { + if(hw_ep->rx_double_buffered) { + csr = musb_readw(epio, MUSB_RXCSR); + if(csr & MUSB_RXCSR_RXPKTRDY) + goto received; + } return; + } #endif musb_g_giveback(musb_ep, request, 0); @@ -839,7 +835,7 @@ if (!request) return; } - +received: /* analyze request if the ep is hot */ if (request) rxstate(musb, to_musb_request(request)); @@ -918,9 +914,9 @@ * to disable double buffering mode. Currently, It seems that double * buffering has problem if musb RTL revision number < 2.0. */ - if (musb->hwvers < MUSB_HWVERS_2000) - musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx); - else + //if (musb->hwvers < MUSB_HWVERS_2000) + // musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx); + //else musb_writew(regs, MUSB_TXMAXP, tmp); csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG; @@ -944,7 +940,10 @@ goto fail; if (tmp > hw_ep->max_packet_sz_rx) goto fail; - + if (hw_ep->max_packet_sz_rx >= (musb_ep->packet_sz *2)) { + hw_ep->rx_double_buffered = 1; + hw_ep->max_packet_sz_rx >>= 1; + } int_rxe |= (1 << epnum); musb_writew(mbase, MUSB_INTRRXE, int_rxe); @@ -954,9 +953,9 @@ /* Set RXMAXP with the FIFO size of the endpoint * to disable double buffering mode. */ - if (musb->hwvers < MUSB_HWVERS_2000) - musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_rx); - else + //if (musb->hwvers < MUSB_HWVERS_2000) + // musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_rx); + //else musb_writew(regs, MUSB_RXMAXP, tmp); /* force shared fifo to OUT-only mode */ === Is there any patch I forgot to patch in order to make double buffer mode works well? Thanks -- -Bob -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html