aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2012-05-04 06:03:54 -0400
committerFelipe Balbi <balbi@ti.com>2012-06-03 16:08:18 -0400
commita0807881af93646b5d94b5594119df609e756945 (patch)
treef8fb042eefbfafefbedbc97101ebbda4223c8439 /drivers/usb
parent4552a0ca61cb2133bc77dc432ea20538ea28638a (diff)
usb: dwc3: handle pending unaligned Control OUT data phase correctly
When DWC3_EP_PENDING_REQUEST flag is set for a Control OUT Data phase transfer, we would be missing the proper handling for unaligned OUT requests, thus hanging a transfer. Since proper handling is already done on dwc3_ep0_do_control_data(), we simply re-factor that function so it can be re-used from __dwc3_gadget_ep0_queue(). Reported-by: Pratyush Anand <pratyush.anand@st.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/dwc3/ep0.c72
1 files changed, 43 insertions, 29 deletions
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index e6ca218ef130..15ec36eb461b 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -55,6 +55,8 @@
55#include "io.h" 55#include "io.h"
56 56
57static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum); 57static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum);
58static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
59 struct dwc3_ep *dep, struct dwc3_request *req);
58 60
59static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) 61static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
60{ 62{
@@ -150,9 +152,8 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
150 return 0; 152 return 0;
151 } 153 }
152 154
153 ret = dwc3_ep0_start_trans(dwc, direction, 155 __dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req);
154 req->request.dma, req->request.length, 156
155 DWC3_TRBCTL_CONTROL_DATA);
156 dep->flags &= ~(DWC3_EP_PENDING_REQUEST | 157 dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
157 DWC3_EP0_DIR_IN); 158 DWC3_EP0_DIR_IN);
158 } else if (dwc->delayed_status) { 159 } else if (dwc->delayed_status) {
@@ -787,35 +788,23 @@ static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
787 dwc3_ep0_out_start(dwc); 788 dwc3_ep0_out_start(dwc);
788} 789}
789 790
790static void dwc3_ep0_do_control_data(struct dwc3 *dwc, 791static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
791 const struct dwc3_event_depevt *event) 792 struct dwc3_ep *dep, struct dwc3_request *req)
792{ 793{
793 struct dwc3_ep *dep;
794 struct dwc3_request *req;
795 int ret; 794 int ret;
796 795
797 dep = dwc->eps[0]; 796 req->direction = !!dep->number;
798
799 if (list_empty(&dep->request_list)) {
800 dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
801 dep->flags |= DWC3_EP_PENDING_REQUEST;
802
803 if (event->endpoint_number)
804 dep->flags |= DWC3_EP0_DIR_IN;
805 return;
806 }
807
808 req = next_request(&dep->request_list);
809 req->direction = !!event->endpoint_number;
810 797
811 if (req->request.length == 0) { 798 if (req->request.length == 0) {
812 ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, 799 ret = dwc3_ep0_start_trans(dwc, dep->number,
813 dwc->ctrl_req_addr, 0, 800 dwc->ctrl_req_addr, 0,
814 DWC3_TRBCTL_CONTROL_DATA); 801 DWC3_TRBCTL_CONTROL_DATA);
815 } else if ((req->request.length % dep->endpoint.maxpacket) 802 } else if ((req->request.length % dep->endpoint.maxpacket)
816 && (event->endpoint_number == 0)) { 803 && (dep->number == 0)) {
804 u32 transfer_size;
805
817 ret = usb_gadget_map_request(&dwc->gadget, &req->request, 806 ret = usb_gadget_map_request(&dwc->gadget, &req->request,
818 event->endpoint_number); 807 dep->number);
819 if (ret) { 808 if (ret) {
820 dev_dbg(dwc->dev, "failed to map request\n"); 809 dev_dbg(dwc->dev, "failed to map request\n");
821 return; 810 return;
@@ -823,6 +812,9 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
823 812
824 WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE); 813 WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE);
825 814
815 transfer_size = roundup(req->request.length,
816 (u32) dep->endpoint.maxpacket);
817
826 dwc->ep0_bounced = true; 818 dwc->ep0_bounced = true;
827 819
828 /* 820 /*
@@ -830,25 +822,47 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
830 * DWC3_EP0_BOUNCE_SIZE we will need two chained 822 * DWC3_EP0_BOUNCE_SIZE we will need two chained
831 * TRBs to handle the transfer. 823 * TRBs to handle the transfer.
832 */ 824 */
833 ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, 825 ret = dwc3_ep0_start_trans(dwc, dep->number,
834 dwc->ep0_bounce_addr, dep->endpoint.maxpacket, 826 dwc->ep0_bounce_addr, transfer_size,
835 DWC3_TRBCTL_CONTROL_DATA); 827 DWC3_TRBCTL_CONTROL_DATA);
836 } else { 828 } else {
837 ret = usb_gadget_map_request(&dwc->gadget, &req->request, 829 ret = usb_gadget_map_request(&dwc->gadget, &req->request,
838 event->endpoint_number); 830 dep->number);
839 if (ret) { 831 if (ret) {
840 dev_dbg(dwc->dev, "failed to map request\n"); 832 dev_dbg(dwc->dev, "failed to map request\n");
841 return; 833 return;
842 } 834 }
843 835
844 ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, 836 ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
845 req->request.dma, req->request.length, 837 req->request.length, DWC3_TRBCTL_CONTROL_DATA);
846 DWC3_TRBCTL_CONTROL_DATA);
847 } 838 }
848 839
849 WARN_ON(ret < 0); 840 WARN_ON(ret < 0);
850} 841}
851 842
843static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
844 const struct dwc3_event_depevt *event)
845{
846 struct dwc3_ep *dep;
847 struct dwc3_request *req;
848
849 dep = dwc->eps[0];
850
851 if (list_empty(&dep->request_list)) {
852 dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
853 dep->flags |= DWC3_EP_PENDING_REQUEST;
854
855 if (event->endpoint_number)
856 dep->flags |= DWC3_EP0_DIR_IN;
857 return;
858 }
859
860 req = next_request(&dep->request_list);
861 dep = dwc->eps[event->endpoint_number];
862
863 __dwc3_ep0_do_control_data(dwc, dep, req);
864}
865
852static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) 866static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
853{ 867{
854 struct dwc3 *dwc = dep->dwc; 868 struct dwc3 *dwc = dep->dwc;