aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorLi Yang <leoli@freescale.com>2011-11-23 07:12:56 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-11-29 09:19:04 -0500
commit6414e94c203d92b163ca61b5f51a25b80a621dbe (patch)
tree3fa3023953222644161601500170687399d75369 /drivers/usb
parent5ce1d0eb1cd1071347618d0a95515f300239d201 (diff)
usb: gadget: fsl_udc: fix dequeuing a request in progress
The original implementation of dequeuing a request in progress is not correct. Change to use a correct process and also clean up the related functions a little bit. Signed-off-by: Li Yang <leoli@freescale.com> Acked-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c68
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h10
2 files changed, 42 insertions, 36 deletions
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index bf1cd6e55ed9..dd28ef3def71 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -696,12 +696,31 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req)
696 kfree(req); 696 kfree(req);
697} 697}
698 698
699/*-------------------------------------------------------------------------*/ 699/* Actually add a dTD chain to an empty dQH and let go */
700static void fsl_prime_ep(struct fsl_ep *ep, struct ep_td_struct *td)
701{
702 struct ep_queue_head *qh = get_qh_by_ep(ep);
703
704 /* Write dQH next pointer and terminate bit to 0 */
705 qh->next_dtd_ptr = cpu_to_hc32(td->td_dma
706 & EP_QUEUE_HEAD_NEXT_POINTER_MASK);
707
708 /* Clear active and halt bit */
709 qh->size_ioc_int_sts &= cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
710 | EP_QUEUE_HEAD_STATUS_HALT));
711
712 /* Ensure that updates to the QH will occur before priming. */
713 wmb();
714
715 /* Prime endpoint by writing correct bit to ENDPTPRIME */
716 fsl_writel(ep_is_in(ep) ? (1 << (ep_index(ep) + 16))
717 : (1 << (ep_index(ep))), &dr_regs->endpointprime);
718}
719
720/* Add dTD chain to the dQH of an EP */
700static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) 721static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
701{ 722{
702 int i = ep_index(ep) * 2 + ep_is_in(ep);
703 u32 temp, bitmask, tmp_stat; 723 u32 temp, bitmask, tmp_stat;
704 struct ep_queue_head *dQH = &ep->udc->ep_qh[i];
705 724
706 /* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr); 725 /* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr);
707 VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */ 726 VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */
@@ -719,7 +738,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
719 cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK); 738 cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);
720 /* Read prime bit, if 1 goto done */ 739 /* Read prime bit, if 1 goto done */
721 if (fsl_readl(&dr_regs->endpointprime) & bitmask) 740 if (fsl_readl(&dr_regs->endpointprime) & bitmask)
722 goto out; 741 return;
723 742
724 do { 743 do {
725 /* Set ATDTW bit in USBCMD */ 744 /* Set ATDTW bit in USBCMD */
@@ -736,28 +755,10 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
736 fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd); 755 fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd);
737 756
738 if (tmp_stat) 757 if (tmp_stat)
739 goto out; 758 return;
740 } 759 }
741 760
742 /* Write dQH next pointer and terminate bit to 0 */ 761 fsl_prime_ep(ep, req->head);
743 temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
744 dQH->next_dtd_ptr = cpu_to_hc32(temp);
745
746 /* Clear active and halt bit */
747 temp = cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
748 | EP_QUEUE_HEAD_STATUS_HALT));
749 dQH->size_ioc_int_sts &= temp;
750
751 /* Ensure that updates to the QH will occur before priming. */
752 wmb();
753
754 /* Prime endpoint by writing 1 to ENDPTPRIME */
755 temp = ep_is_in(ep)
756 ? (1 << (ep_index(ep) + 16))
757 : (1 << (ep_index(ep)));
758 fsl_writel(temp, &dr_regs->endpointprime);
759out:
760 return;
761} 762}
762 763
763/* Fill in the dTD structure 764/* Fill in the dTD structure
@@ -973,25 +974,20 @@ static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
973 974
974 /* The request isn't the last request in this ep queue */ 975 /* The request isn't the last request in this ep queue */
975 if (req->queue.next != &ep->queue) { 976 if (req->queue.next != &ep->queue) {
976 struct ep_queue_head *qh;
977 struct fsl_req *next_req; 977 struct fsl_req *next_req;
978 978
979 qh = ep->qh;
980 next_req = list_entry(req->queue.next, struct fsl_req, 979 next_req = list_entry(req->queue.next, struct fsl_req,
981 queue); 980 queue);
982 981
983 /* Point the QH to the first TD of next request */ 982 /* prime with dTD of next request */
984 fsl_writel((u32) next_req->head, &qh->curr_dtd_ptr); 983 fsl_prime_ep(ep, next_req->head);
985 } 984 }
986 985 /* The request hasn't been processed, patch up the TD chain */
987 /* The request hasn't been processed, patch up the TD chain */
988 } else { 986 } else {
989 struct fsl_req *prev_req; 987 struct fsl_req *prev_req;
990 988
991 prev_req = list_entry(req->queue.prev, struct fsl_req, queue); 989 prev_req = list_entry(req->queue.prev, struct fsl_req, queue);
992 fsl_writel(fsl_readl(&req->tail->next_td_ptr), 990 prev_req->tail->next_td_ptr = req->tail->next_td_ptr;
993 &prev_req->tail->next_td_ptr);
994
995 } 991 }
996 992
997 done(ep, req, -ECONNRESET); 993 done(ep, req, -ECONNRESET);
@@ -1068,7 +1064,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)
1068 struct fsl_udc *udc; 1064 struct fsl_udc *udc;
1069 int size = 0; 1065 int size = 0;
1070 u32 bitmask; 1066 u32 bitmask;
1071 struct ep_queue_head *d_qh; 1067 struct ep_queue_head *qh;
1072 1068
1073 ep = container_of(_ep, struct fsl_ep, ep); 1069 ep = container_of(_ep, struct fsl_ep, ep);
1074 if (!_ep || (!ep->desc && ep_index(ep) != 0)) 1070 if (!_ep || (!ep->desc && ep_index(ep) != 0))
@@ -1079,13 +1075,13 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)
1079 if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) 1075 if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
1080 return -ESHUTDOWN; 1076 return -ESHUTDOWN;
1081 1077
1082 d_qh = &ep->udc->ep_qh[ep_index(ep) * 2 + ep_is_in(ep)]; 1078 qh = get_qh_by_ep(ep);
1083 1079
1084 bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) : 1080 bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
1085 (1 << (ep_index(ep))); 1081 (1 << (ep_index(ep)));
1086 1082
1087 if (fsl_readl(&dr_regs->endptstatus) & bitmask) 1083 if (fsl_readl(&dr_regs->endptstatus) & bitmask)
1088 size = (d_qh->size_ioc_int_sts & DTD_PACKET_SIZE) 1084 size = (qh->size_ioc_int_sts & DTD_PACKET_SIZE)
1089 >> DTD_LENGTH_BIT_POS; 1085 >> DTD_LENGTH_BIT_POS;
1090 1086
1091 pr_debug("%s %u\n", __func__, size); 1087 pr_debug("%s %u\n", __func__, size);
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index 1d51be83fda8..f781f5dec417 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -569,6 +569,16 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)
569 * 2 + ((windex & USB_DIR_IN) ? 1 : 0)) 569 * 2 + ((windex & USB_DIR_IN) ? 1 : 0))
570#define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP)) 570#define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP))
571 571
572static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep)
573{
574 /* we only have one ep0 structure but two queue heads */
575 if (ep_index(ep) != 0)
576 return ep->qh;
577 else
578 return &ep->udc->ep_qh[(ep->udc->ep0_dir ==
579 USB_DIR_IN) ? 1 : 0];
580}
581
572struct platform_device; 582struct platform_device;
573#ifdef CONFIG_ARCH_MXC 583#ifdef CONFIG_ARCH_MXC
574int fsl_udc_clk_init(struct platform_device *pdev); 584int fsl_udc_clk_init(struct platform_device *pdev);