diff options
| author | Neil Zhang <zhangwm@marvell.com> | 2011-12-20 00:20:20 -0500 |
|---|---|---|
| committer | Felipe Balbi <balbi@ti.com> | 2011-12-20 05:53:21 -0500 |
| commit | c2bbd16b03d036bfeaa3efaae6491132500aa7ec (patch) | |
| tree | fe9a269db5a327191c88211ae04144d8c321cd6d | |
| parent | a7250db36308424ae040f1b2eeb5bfd0cbee0b0d (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.c | 29 |
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 | ||
| 781 | static 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 */ |
| 782 | static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) | 803 | static 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 | ||
