aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Zhang <zhangwm@marvell.com>2011-12-20 00:20:20 -0500
committerFelipe Balbi <balbi@ti.com>2011-12-20 05:53:21 -0500
commitc2bbd16b03d036bfeaa3efaae6491132500aa7ec (patch)
treefe9a269db5a327191c88211ae04144d8c321cd6d
parenta7250db36308424ae040f1b2eeb5bfd0cbee0b0d (diff)
usb: gadget: mv_udc: fix bug in ep_dequeue
According to ChipIdea's SPEC, we cannot touch curr_dtd_ptr in dqh directly, use prime endpoint instead. Signed-off-by: Neil Zhang <zhangwm@marvell.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/gadget/mv_udc_core.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index 0ad321d94f23..a3a7664add19 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -778,6 +778,27 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
778 return 0; 778 return 0;
779} 779}
780 780
781static void mv_prime_ep(struct mv_ep *ep, struct mv_req *req)
782{
783 struct mv_dqh *dqh = ep->dqh;
784 u32 bit_pos;
785
786 /* Write dQH next pointer and terminate bit to 0 */
787 dqh->next_dtd_ptr = req->head->td_dma
788 & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
789
790 /* clear active and halt bit, in case set from a previous error */
791 dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
792
793 /* Ensure that updates to the QH will occure before priming. */
794 wmb();
795
796 bit_pos = 1 << (((ep_dir(ep) == EP_DIR_OUT) ? 0 : 16) + ep->ep_num);
797
798 /* Prime the Endpoint */
799 writel(bit_pos, &ep->udc->op_regs->epprime);
800}
801
781/* dequeues (cancels, unlinks) an I/O request from an endpoint */ 802/* dequeues (cancels, unlinks) an I/O request from an endpoint */
782static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) 803static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
783{ 804{
@@ -820,15 +841,13 @@ static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
820 841
821 /* The request isn't the last request in this ep queue */ 842 /* The request isn't the last request in this ep queue */
822 if (req->queue.next != &ep->queue) { 843 if (req->queue.next != &ep->queue) {
823 struct mv_dqh *qh;
824 struct mv_req *next_req; 844 struct mv_req *next_req;
825 845
826 qh = ep->dqh; 846 next_req = list_entry(req->queue.next,
827 next_req = list_entry(req->queue.next, struct mv_req, 847 struct mv_req, queue);
828 queue);
829 848
830 /* Point the QH to the first TD of next request */ 849 /* Point the QH to the first TD of next request */
831 writel((u32) next_req->head, &qh->curr_dtd_ptr); 850 mv_prime_ep(ep, next_req);
832 } else { 851 } else {
833 struct mv_dqh *qh; 852 struct mv_dqh *qh;
834 853