usb: pch_udc: Fixed issue which does not work with g_ether
PATCH 1/1 usb: pch_udc: Fixed issue which does not work with g_ether
This PCH_UDC driver does not work normally when "Ethernet gadget" is used.
This patch fixed this issue.
The following was modified.
- The FIFO flush process.
- The descriptor creation process.
- The adjustment of DMA buffer align.
Currently the PCH_UDC driver can work normally with "Ethernet gadget", "Serial gadget" or "File-backed Storage Gadget".
Signed-off-by Toshiharu Okada <[email protected]>
--- drivers/usb/gadget/pch_udc.c | 178 ++++++++++++++++++++++++----------------- 1 files changed, 104 insertions(+), 74 deletions(-)
drivers/usb/gadget/pch_udc.c +104 -74
@@ -367,7 +367,6 @@ struct pch_udc_dev {static const char ep0_string[] ="ep0in" ;static DEFINE_SPINLOCK (udc_stall_spinlock);/* stall spin lock */ struct pch_udc_dev *pch_udc;/* pointer to device object */ -static int speed_fs;module_param_named (speed_fs, speed_fs, bool,S_IRUGO );MODULE_PARM_DESC (speed_fs,"true for Full speed operation" );
@@ -383,6 +382,8 @@ MODULE_PARM_DESC(speed_fs, "true for Full speed operation");* @dma_mapped: DMA memory mapped for request * @dma_done: DMA completed for request * @chain_len: chain length +* @buf: Buffer memory for align adjustment +* @dma: DMA memory for align adjustment */ struct pch_udc_request {struct usb_request req;
@@ -394,6 +395,8 @@ struct pch_udc_request { dma_mapped:1 , dma_done:1;unsigned chain_len; +void *buf; +dma_addr_t dma; };static inline u32 pch_udc_readl (struct pch_udc_dev *dev,unsigned long reg)
@@ -615,7 +618,7 @@ static inline void pch_udc_ep_set_trfr_type(struct pch_udc_ep *ep,/** * pch_udc_ep_set_bufsz() - Set the maximum packet size for the endpoint * @ep: Reference to structure of type pch_udc_ep_regs -* @buf_size: The buffer size +* @buf_size: The buffer word size */ static void pch_udc_ep_set_bufsz (struct pch_udc_ep *ep,u32 buf_size,u32 ep_in)
@@ -635,7 +638,7 @@ static void pch_udc_ep_set_bufsz(struct pch_udc_ep *ep,/** * pch_udc_ep_set_maxpkt() - Set the Max packet size for the endpoint * @ep: Reference to structure of type pch_udc_ep_regs -* @pkt_size: The packet size +* @pkt_size: The packet byte size */ static void pch_udc_ep_set_maxpkt (struct pch_udc_ep *ep,u32 pkt_size) {
@@ -920,25 +923,10 @@ static void pch_udc_ep_clear_nak(struct pch_udc_ep *ep)*/ static void pch_udc_ep_fifo_flush (struct pch_udc_ep *ep,int dir) { -unsigned int loopcnt =0 ; -struct pch_udc_dev *dev = ep->dev; -if (dir) {/* IN ep */ pch_udc_ep_bit_set (ep,UDC_EPCTL_ADDR ,UDC_EPCTL_F );return ; } - -if (pch_udc_read_ep_status (ep) &UDC_EPSTS_MRXFIFO_EMP ) -return ; -pch_udc_ep_bit_set (ep,UDC_EPCTL_ADDR ,UDC_EPCTL_MRXFLUSH ); -/* Wait for RxFIFO Empty */ - loopcnt =10000 ; -while (!(pch_udc_read_ep_status (ep) &UDC_EPSTS_MRXFIFO_EMP ) && - --loopcnt) -udelay (5 ); -if (!loopcnt) -dev_err (&dev->pdev->dev,"RxFIFO not Empty\n" ); -pch_udc_ep_bit_clr (ep,UDC_EPCTL_ADDR ,UDC_EPCTL_MRXFLUSH ); }/**
@@ -1220,14 +1208,31 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req, dev = ep->dev;if (req->dma_mapped) { -if (ep->in) -dma_unmap_single (&dev->pdev->dev, req->req.dma, - req->req.length,DMA_TO_DEVICE ); -else -dma_unmap_single (&dev->pdev->dev, req->req.dma, - req->req.length,DMA_FROM_DEVICE ); +if (req->dma ==DMA_ADDR_INVALID ) { +if (ep->in) +dma_unmap_single (&dev->pdev->dev, req->req.dma, + req->req.length, +DMA_TO_DEVICE ); +else +dma_unmap_single (&dev->pdev->dev, req->req.dma, + req->req.length, +DMA_FROM_DEVICE ); + req->req.dma =DMA_ADDR_INVALID ; + }else { +if (ep->in) +dma_unmap_single (&dev->pdev->dev, req->dma, + req->req.length, +DMA_TO_DEVICE ); +else { +dma_unmap_single (&dev->pdev->dev, req->dma, + req->req.length, +DMA_FROM_DEVICE ); +memcpy (req->req.buf, req->buf, req->req.length); + } +kfree (req->buf); + req->dma =DMA_ADDR_INVALID ; + } req->dma_mapped =0 ; - req->req.dma =DMA_ADDR_INVALID ; } ep->halted =1 ;spin_unlock (&dev->lock);
@@ -1268,12 +1273,18 @@ static void pch_udc_free_dma_chain(struct pch_udc_dev *dev,struct pch_udc_data_dma_desc *td = req->td_data;unsigned i = req->chain_len; +dma_addr_t addr2; +dma_addr_t addr = (dma_addr_t )td->next; + td->next =0x00 ;for (; i >1 ; --i) { -dma_addr_t addr = (dma_addr_t )td->next;/* do not free first desc., will be done by free for request */ td =phys_to_virt (addr); + addr2 = (dma_addr_t )td->next;pci_pool_free (dev->data_requests, td, addr); + td->next =0x00 ; + addr = addr2; } + req->chain_len =1 ; }/**
@@ -1301,23 +1312,23 @@ static int pch_udc_create_dma_chain(struct pch_udc_ep *ep,if (req->chain_len >1 )pch_udc_free_dma_chain (ep->dev, req); -for (; ; bytes -= buf_len, ++len) { -if (ep->in) - td->status =PCH_UDC_BS_HST_BSY |min (buf_len, bytes); -else - td->status =PCH_UDC_BS_HST_BSY ; +if (req->dma ==DMA_ADDR_INVALID ) + td->dataptr = req->req.dma; +else + td->dataptr = req->dma; + td->status =PCH_UDC_BS_HST_BSY ; +for (; ; bytes -= buf_len, ++len) { + td->status =PCH_UDC_BS_HST_BSY |min (buf_len, bytes);if (bytes <= buf_len)break ; - last = td; td =pci_pool_alloc (ep->dev->data_requests, gfp_flags, &dma_addr);if (!td) goto nomem; - i += buf_len; - td->dataptr = req->req.dma + i; + td->dataptr = req->td_data->dataptr + i; last->next = dma_addr; }
@@ -1352,28 +1363,15 @@ static int prepare_dma(struct pch_udc_ep *ep, struct pch_udc_request *req, {int retval; - req->td_data->dataptr = req->req.dma; - req->td_data->status |=PCH_UDC_DMA_LAST ;/* Allocate and create a DMA chain */ retval =pch_udc_create_dma_chain (ep, req, ep->ep.maxpacket, gfp);if (retval) { -pr_err ("%s: could not create DMA chain: %d\n" , - __func__, retval); +pr_err ("%s: could not create DMA chain:%d\n" , __func__, retval);return retval; } -if (!ep->in) -return 0 ; -if (req->req.length <= ep->ep.maxpacket) - req->td_data->status =PCH_UDC_DMA_LAST |PCH_UDC_BS_HST_BSY | - req->req.length; -/* if bytes < max packet then tx bytes must -* be written in packet per buffer mode -*/ -if ((req->req.length < ep->ep.maxpacket) || !ep->num) +if (ep->in) req->td_data->status = (req->td_data->status & - ~PCH_UDC_RXTX_BYTES ) | req->req.length; - req->td_data->status = (req->td_data->status & - ~PCH_UDC_BUFF_STS ) |PCH_UDC_BS_HST_BSY ; + ~PCH_UDC_BUFF_STS ) |PCH_UDC_BS_HST_RDY ;return 0 ; }
@@ -1529,6 +1527,7 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,if (!req)return NULL ; req->req.dma =DMA_ADDR_INVALID ; + req->dma =DMA_ADDR_INVALID ;INIT_LIST_HEAD (&req->queue);if (!ep->dev->dma_addr)return &req->req;
@@ -1613,16 +1612,33 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,/* map the buffer for dma */ if (usbreq->length && ((usbreq->dma ==DMA_ADDR_INVALID ) || !usbreq->dma)) { -if (ep->in) - usbreq->dma =dma_map_single (&dev->pdev->dev, - usbreq->buf, - usbreq->length, -DMA_TO_DEVICE ); -else - usbreq->dma =dma_map_single (&dev->pdev->dev, - usbreq->buf, - usbreq->length, -DMA_FROM_DEVICE ); +if (!((unsigned long )(usbreq->buf) &0x03 )) { +if (ep->in) + usbreq->dma =dma_map_single (&dev->pdev->dev, + usbreq->buf, + usbreq->length, +DMA_TO_DEVICE ); +else + usbreq->dma =dma_map_single (&dev->pdev->dev, + usbreq->buf, + usbreq->length, +DMA_FROM_DEVICE ); + }else { + req->buf =kzalloc (usbreq->length,GFP_ATOMIC ); +if (!req->buf) +return -ENOMEM ; +if (ep->in) { +memcpy (req->buf, usbreq->buf, usbreq->length); + req->dma =dma_map_single (&dev->pdev->dev, + req->buf, + usbreq->length, +DMA_TO_DEVICE ); + }else + req->dma =dma_map_single (&dev->pdev->dev, + req->buf, + usbreq->length, +DMA_FROM_DEVICE ); + } req->dma_mapped =1 ; }if (usbreq->length >0 ) {
@@ -1920,32 +1936,46 @@ static void pch_udc_complete_receiver(struct pch_udc_ep *ep)struct pch_udc_request *req;struct pch_udc_dev *dev = ep->dev;unsigned int count; +struct pch_udc_data_dma_desc *td; +dma_addr_t addr;if (list_empty (&ep->queue))return ; -/* next request */ req = list_entry(ep->queue.next, struct pch_udc_request, queue); -if ((req->td_data_last->status &PCH_UDC_BUFF_STS ) != -PCH_UDC_BS_DMA_DONE ) -return ;pch_udc_clear_dma (ep->dev,DMA_DIR_RX );pch_udc_ep_set_ddptr (ep,0 ); -if ((req->td_data_last->status &PCH_UDC_RXTX_STS ) != -PCH_UDC_RTS_SUCC ) { -dev_err (&dev->pdev->dev,"Invalid RXTX status (0x%08x) " -"epstatus=0x%08x\n" , - (req->td_data_last->status &PCH_UDC_RXTX_STS ), - (int )(ep->epsts)); -return ; - } - count = req->td_data_last->status &PCH_UDC_RXTX_BYTES ; +if ((req->td_data_last->status &PCH_UDC_BUFF_STS ) == +PCH_UDC_BS_DMA_DONE ) + td = req->td_data_last; +else + td = req->td_data; +while (1 ) { +if ((td->status &PCH_UDC_RXTX_STS ) !=PCH_UDC_RTS_SUCC ) { +dev_err (&dev->pdev->dev,"Invalid RXTX status=0x%08x " +"epstatus=0x%08x\n" , + (req->td_data->status &PCH_UDC_RXTX_STS ), + (int )(ep->epsts)); +return ; + } +if ((td->status &PCH_UDC_BUFF_STS ) ==PCH_UDC_BS_DMA_DONE ) +if (td->status |PCH_UDC_DMA_LAST ) { + count = td->status &PCH_UDC_RXTX_BYTES ; +break ; + } +if (td == req->td_data_last) { +dev_err (&dev->pdev->dev,"Not complete RX descriptor" ); +return ; + } + addr = (dma_addr_t )td->next; + td =phys_to_virt (addr); + }/* on 64k packets the RXBYTES field is zero */ if (!count && (req->req.length ==UDC_DMA_MAXPACKET )) count =UDC_DMA_MAXPACKET ; req->td_data->status |=PCH_UDC_DMA_LAST ; - req->td_data_last->status |=PCH_UDC_BS_HST_BSY ; + td->status |=PCH_UDC_BS_HST_BSY ; req->dma_going =0 ; req->req.actual = count;
Signature · 1 line
1.6.2.5