From 4b345c9a3c7452340fb477868d8db475f05978b1 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 16 Jul 2012 14:08:16 +0300 Subject: usb: dwc3: gadget: set Ignore Sequence Number bit from ConnectDone Event Databook says we should set Ignore Sequence Number bit from ConnectDone Event, so let's do so. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 58fdfad..283c0cb 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -431,7 +431,8 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep) static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, const struct usb_endpoint_descriptor *desc, - const struct usb_ss_ep_comp_descriptor *comp_desc) + const struct usb_ss_ep_comp_descriptor *comp_desc, + bool ignore) { struct dwc3_gadget_ep_cmd_params params; @@ -441,6 +442,9 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc)) | DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst - 1); + if (ignore) + params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM; + params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN | DWC3_DEPCFG_XFER_NOT_READY_EN; @@ -498,7 +502,8 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep) */ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, const struct usb_endpoint_descriptor *desc, - const struct usb_ss_ep_comp_descriptor *comp_desc) + const struct usb_ss_ep_comp_descriptor *comp_desc, + bool ignore) { struct dwc3 *dwc = dep->dwc; u32 reg; @@ -510,7 +515,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, return ret; } - ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc); + ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore); if (ret) return ret; @@ -683,7 +688,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); spin_lock_irqsave(&dwc->lock, flags); - ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc); + ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false); spin_unlock_irqrestore(&dwc->lock, flags); return ret; @@ -1518,14 +1523,14 @@ static int dwc3_gadget_start(struct usb_gadget *g, dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); dep = dwc->eps[0]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); goto err0; } dep = dwc->eps[1]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); goto err1; @@ -2141,14 +2146,14 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) } dep = dwc->eps[0]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); return; } dep = dwc->eps[1]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); return; -- cgit v0.10.2 From 35f75696649d43aee8031d81783322b0708805b5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 19 Jul 2012 08:49:01 +0300 Subject: usb: dwc3: ep0: drop unnecessary variable When returning from ep0_queue, we have an unnecessary ret variable which is always zero. Remove it. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 9b94886..962fb9b 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -125,7 +125,6 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, struct dwc3_request *req) { struct dwc3 *dwc = dep->dwc; - int ret = 0; req->request.actual = 0; req->request.status = -EINPROGRESS; @@ -165,7 +164,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, dev_dbg(dwc->dev, "too early for delayed status\n"); } - return ret; + return 0; } int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, -- cgit v0.10.2 From d9b33c605c398df1d42c694bda28fe8708754c64 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 19 Jul 2012 08:51:13 +0300 Subject: usb: dwc3: ep0: split the special cases on ep0_queue We can return early from each if () branch and split the special cases for clarity. While at that also add a comment to the delayed_status case. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 962fb9b..28bce9b 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -155,13 +155,23 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, dep->flags &= ~(DWC3_EP_PENDING_REQUEST | DWC3_EP0_DIR_IN); - } else if (dwc->delayed_status) { + + return 0; + } + + /* + * In case gadget driver asked us to delay the STATUS phase, + * handle it here. + */ + if (dwc->delayed_status) { dwc->delayed_status = false; if (dwc->ep0state == EP0_STATUS_PHASE) __dwc3_ep0_do_control_status(dwc, dwc->eps[1]); else dev_dbg(dwc->dev, "too early for delayed status\n"); + + return 0; } return 0; -- cgit v0.10.2 From 4635d3f29864d723a74983339ffc85db212e304b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 19 Jul 2012 08:53:41 +0300 Subject: usb: dwc3: ep0: drop dead code There's no such thing as XferNotReady(SETUP), we can safely drop all that code with no problems whatsoever. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 151eca8..c611d80 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -457,7 +457,6 @@ enum dwc3_phy { enum dwc3_ep0_next { DWC3_EP0_UNKNOWN = 0, DWC3_EP0_COMPLETE, - DWC3_EP0_NRDY_SETUP, DWC3_EP0_NRDY_DATA, DWC3_EP0_NRDY_STATUS, }; @@ -779,7 +778,6 @@ struct dwc3_event_depevt { #define DEPEVT_STREAMEVT_NOTFOUND 2 /* Control-only Status */ -#define DEPEVT_STATUS_CONTROL_SETUP 0 #define DEPEVT_STATUS_CONTROL_DATA 1 #define DEPEVT_STATUS_CONTROL_STATUS 2 diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 28bce9b..d4b38c7 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -809,12 +809,6 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, } } -static void dwc3_ep0_do_control_setup(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - dwc3_ep0_out_start(dwc); -} - static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req) { @@ -926,50 +920,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, { dwc->setup_packet_pending = true; - /* - * This part is very tricky: If we have just handled - * XferNotReady(Setup) and we're now expecting a - * XferComplete but, instead, we receive another - * XferNotReady(Setup), we should STALL and restart - * the state machine. - * - * In all other cases, we just continue waiting - * for the XferComplete event. - * - * We are a little bit unsafe here because we're - * not trying to ensure that last event was, indeed, - * XferNotReady(Setup). - * - * Still, we don't expect any condition where that - * should happen and, even if it does, it would be - * another error condition. - */ - if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) { - switch (event->status) { - case DEPEVT_STATUS_CONTROL_SETUP: - dev_vdbg(dwc->dev, "Unexpected XferNotReady(Setup)\n"); - dwc3_ep0_stall_and_restart(dwc); - break; - case DEPEVT_STATUS_CONTROL_DATA: - /* FALLTHROUGH */ - case DEPEVT_STATUS_CONTROL_STATUS: - /* FALLTHROUGH */ - default: - dev_vdbg(dwc->dev, "waiting for XferComplete\n"); - } - - return; - } - switch (event->status) { - case DEPEVT_STATUS_CONTROL_SETUP: - dev_vdbg(dwc->dev, "Control Setup\n"); - - dwc->ep0state = EP0_SETUP_PHASE; - - dwc3_ep0_do_control_setup(dwc, event); - break; - case DEPEVT_STATUS_CONTROL_DATA: dev_vdbg(dwc->dev, "Control Data\n"); -- cgit v0.10.2 From 77fa6df82f154535293beb9bc68851f75c2c22cb Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 23 Jul 2012 09:09:32 +0300 Subject: usb: dwc3: ep0: ignore XferNotReady(STATUS) when we're not expecting it Databook doesn't say we should stall if we get XferNotReady(STATUS) while we're expecting something else. Instead of stalling and restarting, tests have proven that ignoring the event is far more effective. This problem has been caught while rewriting ep0 handling in order we pass Link Layer TD7.6. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index d4b38c7..39abc58 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -953,19 +953,13 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, break; case DEPEVT_STATUS_CONTROL_STATUS: + if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) + return; + dev_vdbg(dwc->dev, "Control Status\n"); dwc->ep0state = EP0_STATUS_PHASE; - if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) { - dev_vdbg(dwc->dev, "Expected %d got %d\n", - dwc->ep0_next_event, - DWC3_EP0_NRDY_STATUS); - - dwc3_ep0_stall_and_restart(dwc); - return; - } - if (dwc->delayed_status) { WARN_ON_ONCE(event->endpoint_number != 1); dev_vdbg(dwc->dev, "Mass Storage delayed status\n"); -- cgit v0.10.2 From fca8892ae552668e726ec9dad6ba7a26743e9a09 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 19 Jul 2012 09:05:35 +0300 Subject: usb: dwc3: ep0: move DATA phase away from on-demand We uncovered a limitation of this core WRT to the Link Layer Compliance Suite's TD7.06. On that test, host will start a GetDescriptor(DEVICE) standard request, but it will do so only on the SETUP phase, meaning there will *NOT* be any DATA or STATUS phases. The idea of the test is to verify robustness of the IP WRT framing errors, so the test will send a sequence of different SETUP_DPs each with a different framing error and the Suite expects us to be able to receive all SETUP_DPs with no timeouts. This core, has the ability to tell us which phase the host is expecting before we start it. Whenever we receive a TP or DP when no transfers are cached on the internal IP's caches, the IP will generate a XferNotReady event with status informing us (in case of physical ep0/ep1) if it's related to DATA or STATUS phases - SETUP phase is expected to be prestarted. Because we're always waiting for XferNotReady events for DATA and STATUS phases, we will never be able to know that the Host wants to start another SETUP phase instead, which will render us "not compliant" with TD7.06. In order to "fix" the problem we must not rely on XferNotReady events for the DATA phase and try to always pre-start DATA transfers on physical endpoints 0 and 1. If host goes back to SETUP phase from DATA phase we will receive a XferComplete for that phase with TRB's status set to SETUP_PENDING, which is only useful for printing a debugging log as the core expects us to still go through to the STATUS phase, initiate a CONTROL_STATUS TRB just so it completes right away and, only then, we go back to the pending SETUP phase. SNPS has decided to modify the programming model of the core so that on-demand DATA phases will not be supported anymore. Note that this limitation does not affect 2-stage transfers, meaning that if TD7.06 would start a 2-stage transfer instead of a 3-stage transfer, we would receive a "fake" XferNotReady(STATUS) which would complete right after being initiated with SETUP_PENDING status. Other endpoints are also not affected, so we can still use on-demand transfers on Bulk/Isoc/Interrupt endpoints. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 39abc58..69d5741 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -174,6 +174,49 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, return 0; } + /* + * Unfortunately we have uncovered a limitation wrt the Data Phase. + * + * Section 9.4 says we can wait for the XferNotReady(DATA) event to + * come before issueing Start Transfer command, but if we do, we will + * miss situations where the host starts another SETUP phase instead of + * the DATA phase. Such cases happen at least on TD.7.6 of the Link + * Layer Compliance Suite. + * + * The problem surfaces due to the fact that in case of back-to-back + * SETUP packets there will be no XferNotReady(DATA) generated and we + * will be stuck waiting for XferNotReady(DATA) forever. + * + * By looking at tables 9-13 and 9-14 of the Databook, we can see that + * it tells us to start Data Phase right away. It also mentions that if + * we receive a SETUP phase instead of the DATA phase, core will issue + * XferComplete for the DATA phase, before actually initiating it in + * the wire, with the TRB's status set to "SETUP_PENDING". Such status + * can only be used to print some debugging logs, as the core expects + * us to go through to the STATUS phase and start a CONTROL_STATUS TRB, + * just so it completes right away, without transferring anything and, + * only then, we can go back to the SETUP phase. + * + * Because of this scenario, SNPS decided to change the programming + * model of control transfers and support on-demand transfers only for + * the STATUS phase. To fix the issue we have now, we will always wait + * for gadget driver to queue the DATA phase's struct usb_request, then + * start it right away. + * + * If we're actually in a 2-stage transfer, we will wait for + * XferNotReady(STATUS). + */ + if (dwc->three_stage_setup) { + unsigned direction; + + direction = dwc->ep0_expect_in; + dwc->ep0state = EP0_DATA_PHASE; + + __dwc3_ep0_do_control_data(dwc, dwc->eps[direction], req); + + dep->flags &= ~DWC3_EP0_DIR_IN; + } + return 0; } @@ -707,6 +750,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, struct dwc3_trb *trb; struct dwc3_ep *ep0; u32 transferred; + u32 status; u32 length; u8 epnum; @@ -719,6 +763,17 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ur = &r->request; trb = dwc->ep0_trb; + + status = DWC3_TRB_SIZE_TRBSTS(trb->size); + if (status == DWC3_TRBSTS_SETUP_PENDING) { + dev_dbg(dwc->dev, "Setup Pending received\n"); + + if (r) + dwc3_gadget_giveback(ep0, r, -ECONNRESET); + + return; + } + length = trb->size & DWC3_TRB_SIZE_MASK; if (dwc->ep0_bounced) { @@ -755,8 +810,11 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, { struct dwc3_request *r; struct dwc3_ep *dep; + struct dwc3_trb *trb; + u32 status; dep = dwc->eps[0]; + trb = dwc->ep0_trb; if (!list_empty(&dep->request_list)) { r = next_request(&dep->request_list); @@ -776,6 +834,10 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, } } + status = DWC3_TRB_SIZE_TRBSTS(trb->size); + if (status == DWC3_TRBSTS_SETUP_PENDING) + dev_dbg(dwc->dev, "Setup Pending received\n"); + dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); } -- cgit v0.10.2 From 2e3db064855a637c45f7e011214f15bc536e61ad Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 19 Jul 2012 09:26:59 +0300 Subject: usb: dwc3: ep0: drop XferNotReady(DATA) support Due to the late Silicon limitation found, we are now pre-starting DATA phase's TRBs. If, still, we get XferNotReady(DATA) we will ignore it unless we're getting it for the wrong direction. In that case we must keep the error case handling plus add a ENDTRANSFER command to forcefully end the Data TRB we started previously, then continue to SetStall and so on. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 69d5741..3936c64 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -923,29 +923,6 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, WARN_ON(ret < 0); } -static void dwc3_ep0_do_control_data(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - struct dwc3_ep *dep; - struct dwc3_request *req; - - dep = dwc->eps[0]; - - if (list_empty(&dep->request_list)) { - dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n"); - dep->flags |= DWC3_EP_PENDING_REQUEST; - - if (event->endpoint_number) - dep->flags |= DWC3_EP0_DIR_IN; - return; - } - - req = next_request(&dep->request_list); - dep = dwc->eps[event->endpoint_number]; - - __dwc3_ep0_do_control_data(dwc, dep, req); -} - static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; @@ -977,6 +954,24 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, __dwc3_ep0_do_control_status(dwc, dep); } +static void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep) +{ + struct dwc3_gadget_ep_cmd_params params; + u32 cmd; + int ret; + + if (!dep->resource_index) + return; + + cmd = DWC3_DEPCMD_ENDTRANSFER; + cmd |= DWC3_DEPCMD_CMDIOC; + cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); + memset(¶ms, 0, sizeof(params)); + ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); + WARN_ON_ONCE(ret); + dep->resource_index = 0; +} + static void dwc3_ep0_xfernotready(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { @@ -986,32 +981,24 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, case DEPEVT_STATUS_CONTROL_DATA: dev_vdbg(dwc->dev, "Control Data\n"); - dwc->ep0state = EP0_DATA_PHASE; - - if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) { - dev_vdbg(dwc->dev, "Expected %d got %d\n", - dwc->ep0_next_event, - DWC3_EP0_NRDY_DATA); - - dwc3_ep0_stall_and_restart(dwc); - return; - } - /* - * One of the possible error cases is when Host _does_ - * request for Data Phase, but it does so on the wrong - * direction. + * We already have a DATA transfer in the controller's cache, + * if we receive a XferNotReady(DATA) we will ignore it, unless + * it's for the wrong direction. * - * Here, we already know ep0_next_event is DATA (see above), - * so we only need to check for direction. + * In that case, we must issue END_TRANSFER command to the Data + * Phase we already have started and issue SetStall on the + * control endpoint. */ if (dwc->ep0_expect_in != event->endpoint_number) { + struct dwc3_ep *dep = dwc->eps[dwc->ep0_expect_in]; + dev_vdbg(dwc->dev, "Wrong direction for Data phase\n"); + dwc3_ep0_end_control_data(dwc, dep); dwc3_ep0_stall_and_restart(dwc); return; } - dwc3_ep0_do_control_data(dwc, event); break; case DEPEVT_STATUS_CONTROL_STATUS: -- cgit v0.10.2 From 7125d584d20ba7624488ddefa84b17ea6ce558f1 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 19 Jul 2012 21:05:08 +0300 Subject: usb: dwc3: ep0: fix status phase delayed status direction commit 68d3e66 (usb: dwc3: ep0: fix for possible early delayed_status) added handling for early delayed status, but the current code only works because so far delayed status will always be on the IN direction. This patch makes the code more robust by making sure that we can handle all directions properly. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3936c64..3f2c698 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -164,10 +164,13 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, * handle it here. */ if (dwc->delayed_status) { + unsigned direction; + + direction = !dwc->ep0_expect_in; dwc->delayed_status = false; if (dwc->ep0state == EP0_STATUS_PHASE) - __dwc3_ep0_do_control_status(dwc, dwc->eps[1]); + __dwc3_ep0_do_control_status(dwc, dwc->eps[direction]); else dev_dbg(dwc->dev, "too early for delayed status\n"); -- cgit v0.10.2 From 2dfe37d4a5f9a7586a7ff79249492fb8280afb6f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 23 Jul 2012 09:07:41 +0300 Subject: usb: dwc3: ep0: make sure to reinitilize ep1 on STALL When issuing SetStall on ep0, we must make sure to reinitialize all flags on physical ep1 too. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3f2c698..1bba97b 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -262,9 +262,14 @@ out: static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) { - struct dwc3_ep *dep = dwc->eps[0]; + struct dwc3_ep *dep; + + /* reinitialize physical ep1 */ + dep = dwc->eps[1]; + dep->flags = DWC3_EP_ENABLED; /* stall is always issued on EP0 */ + dep = dwc->eps[0]; __dwc3_gadget_ep_set_halt(dep, 1); dep->flags = DWC3_EP_ENABLED; dwc->delayed_status = false; -- cgit v0.10.2 From 348e026fafe2501281db5fb7fed599b337cad358 Mon Sep 17 00:00:00 2001 From: Moiz Sonasath Date: Wed, 1 Aug 2012 14:08:30 -0500 Subject: usb: dwc3: gadget: Fix sparse warnings This patch fixes the following sparse warnings: drivers/usb/dwc3/gadget.c:1096:7: warning: symbol 'ret' shadows an earlier one drivers/usb/dwc3/gadget.c:1058:8: originally declared here drivers/usb/dwc3/gadget.c:1100:16: warning: symbol 'dwc' shadows an earlier one drivers/usb/dwc3/gadget.c:1057:15: originally declared here drivers/usb/dwc3/gadget.c:1118:16: warning: symbol 'dwc' shadows an earlier one drivers/usb/dwc3/gadget.c:1057:15: originally declared here drivers/usb/dwc3/gadget.c:1800:19: warning: symbol 'dep' shadows an earlier one drivers/usb/dwc3/gadget.c:1778:18: originally declared here Also, fix the potential checkpatch errors around the if() loops that this fix patch can create. Signed-off-by: Moiz Sonasath Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 283c0cb..920d997 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1092,15 +1092,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * */ if (dep->flags & DWC3_EP_PENDING_REQUEST) { - int ret; - ret = __dwc3_gadget_kick_transfer(dep, 0, true); - if (ret && ret != -EBUSY) { - struct dwc3 *dwc = dep->dwc; - + if (ret && ret != -EBUSY) dev_dbg(dwc->dev, "%s: failed to kick transfers\n", dep->name); - } } /* @@ -1113,12 +1108,9 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) WARN_ON_ONCE(!dep->resource_index); ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index, false); - if (ret && ret != -EBUSY) { - struct dwc3 *dwc = dep->dwc; - + if (ret && ret != -EBUSY) dev_dbg(dwc->dev, "%s: failed to kick transfers\n", dep->name); - } } /* @@ -1755,7 +1747,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, int i; for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { - struct dwc3_ep *dep = dwc->eps[i]; + dep = dwc->eps[i]; if (!(dep->flags & DWC3_EP_ENABLED)) continue; -- cgit v0.10.2 From 79c9046ec52b5aaa9f055e3d928d676dd37a6f9d Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Tue, 7 Aug 2012 16:54:18 +0530 Subject: usb: dwc3: gadget: correct missed isoc when endpoint is busy When MISSED_ISOC is set, BUSY is also set. Since, we are handling MISSED_ISOC as a separate case in third scenario, therefore handle only BUSY but not MISSED_ISOC in second scenario. Signed-off-by: Pratyush Anand Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 920d997..fc05910 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1104,7 +1104,8 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * core may not see the modified TRB(s). */ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && - (dep->flags & DWC3_EP_BUSY)) { + (dep->flags & DWC3_EP_BUSY) && + !(dep->flags & DWC3_EP_MISSED_ISOC)) { WARN_ON_ONCE(!dep->resource_index); ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index, false); -- cgit v0.10.2 From 57911504a93909034ba5b90c20f3e6df8409ebd8 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Fri, 6 Jul 2012 15:19:10 +0530 Subject: usb: dwc3: gadget: Fix dwc3_stop_active_transfer for synchronization delay dwc3_stop_active_transfer has been called from two places. After each calling of this function , we should allow 100 us delay to synchronize with interconnect. It would be better if we put this delay in that function only, rather than into calling routine of this function. Signed-off-by: Pratyush Anand Reported-by: Michel Sanches Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index fc05910..dd5945c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -563,27 +563,7 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) if (!list_empty(&dep->req_queued)) { dwc3_stop_active_transfer(dwc, dep->number); - /* - * NOTICE: We are violating what the Databook says about the - * EndTransfer command. Ideally we would _always_ wait for the - * EndTransfer Command Completion IRQ, but that's causing too - * much trouble synchronizing between us and gadget driver. - * - * We have discussed this with the IP Provider and it was - * suggested to giveback all requests here, but give HW some - * extra time to synchronize with the interconnect. We're using - * an arbitraty 100us delay for that. - * - * Note also that a similar handling was tested by Synopsys - * (thanks a lot Paul) and nothing bad has come out of it. - * In short, what we're doing is: - * - * - Issue EndTransfer WITH CMDIOC bit set - * - Wait 100us - * - giveback all requests to gadget driver - */ - udelay(100); - + /* - giveback all requests to gadget driver */ while (!list_empty(&dep->req_queued)) { req = next_request(&dep->req_queued); @@ -1875,6 +1855,25 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) if (!dep->resource_index) return; + /* + * NOTICE: We are violating what the Databook says about the + * EndTransfer command. Ideally we would _always_ wait for the + * EndTransfer Command Completion IRQ, but that's causing too + * much trouble synchronizing between us and gadget driver. + * + * We have discussed this with the IP Provider and it was + * suggested to giveback all requests here, but give HW some + * extra time to synchronize with the interconnect. We're using + * an arbitraty 100us delay for that. + * + * Note also that a similar handling was tested by Synopsys + * (thanks a lot Paul) and nothing bad has come out of it. + * In short, what we're doing is: + * + * - Issue EndTransfer WITH CMDIOC bit set + * - Wait 100us + */ + cmd = DWC3_DEPCMD_ENDTRANSFER; cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC; cmd |= DWC3_DEPCMD_PARAM(dep->resource_index); @@ -1882,6 +1881,8 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); WARN_ON_ONCE(ret); dep->resource_index = 0; + + udelay(100); } static void dwc3_stop_active_transfers(struct dwc3 *dwc) -- cgit v0.10.2 From b7e38aa67d73cbb9d5d2e1e5de379f473fa7d7bf Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 10 Aug 2012 09:16:43 +0300 Subject: usb: dwc3: core: use devm_iremap_nocache() version This just guarantees that this piece of memory will be marked uncachable. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index c34452a..4f2ef53 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -459,7 +459,7 @@ static int __devinit dwc3_probe(struct platform_device *pdev) return -ENOMEM; } - regs = devm_ioremap(dev, res->start, resource_size(res)); + regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!regs) { dev_err(dev, "ioremap failed\n"); return -ENOMEM; -- cgit v0.10.2 From c6f83f386c2f7987a344368e33e55840c12bd38f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 15 Aug 2012 12:28:29 +0300 Subject: usb: dwc3: gadget: warn about endpoint already enabled before changing ep name In case some gadget driver tries to enable an endpoint which is already enabled, we print a nice WARN so we can track broken gadget drivers. The only problem is that we're printing the WARN when we already changed endpoint's name, which would result in endpoints named as: ep1in-bulk-bulk-bulk-bulk-bulk-bulk-bulk To prevent that, we will continue to print the WARN, but do so before changing endpoint's name and return early. Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index dd5945c..029cf06 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -642,6 +642,12 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, dep = to_dwc3_ep(ep); dwc = dep->dwc; + if (dep->flags & DWC3_EP_ENABLED) { + dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n", + dep->name); + return 0; + } + switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_CONTROL: strlcat(dep->name, "-control", sizeof(dep->name)); @@ -659,12 +665,6 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, dev_err(dwc->dev, "invalid endpoint transfer type\n"); } - if (dep->flags & DWC3_EP_ENABLED) { - dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n", - dep->name); - return 0; - } - dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); spin_lock_irqsave(&dwc->lock, flags); -- cgit v0.10.2 From 2a540edf7bb02f3e968d1ce7cb355e740ba7de13 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Sun, 26 Aug 2012 21:34:19 +0200 Subject: usb: dwc3: core: memory ordering fix in close As a bitmap is used for free/used. As a device freed all memory operations must be scheduled before the bitmap is manipulated. Signed-off-by: Oliver Neukum Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 4f2ef53..08a5738 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -99,6 +99,7 @@ void dwc3_put_device_id(int id) ret = test_bit(id, dwc3_devs); WARN(!ret, "dwc3: ID %d not in use\n", id); + smp_mb__before_clear_bit(); clear_bit(id, dwc3_devs); } EXPORT_SYMBOL_GPL(dwc3_put_device_id); -- cgit v0.10.2 From d2e9a13a388304bc2a7b25a6c34c6e2ab1540a5d Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Fri, 31 Aug 2012 16:54:07 +0900 Subject: usb: dwc3: set up burst size only superspeed mode When connection is established non-ss mode, endpoint.maxburst is correctly set to 0, this means that current code will set maxburst bitfield on DEPCFG's parameter 0 to the highest possible value (0x0f) which is wrong. Even though this hasn't caused any issues so far (HW seems to ignore that when not running in SS mode) we want to make sure maxburst bitfield is only set to anything other than zero if we're running on SuperSpeed mode. In order to achieve that, let's check for gadget's operating speed before setting maxburst bitfield when issuing DEPCFG command. [ balbi@ti.com : improved commit log a bit in order to clarify the situation ] Signed-off-by: Chanho Park Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 029cf06..ba444e7 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -439,8 +439,14 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, memset(¶ms, 0x00, sizeof(params)); params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc)) - | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc)) - | DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst - 1); + | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc)); + + /* Burst size is only needed in SuperSpeed mode */ + if (dwc->gadget.speed == USB_SPEED_SUPER) { + u32 burst = dep->endpoint.maxburst - 1; + + params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst); + } if (ignore) params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM; -- cgit v0.10.2