Skip to content

Commit c139ec1

Browse files
Meng Dongyangrkhuangtao
authored andcommitted
UPSTREAM: usb: dwc3: gadget: cope with XferNotReady before usb_ep_queue()
If XferNotReady comes before usb_ep_queue() we will set our PENDING request flag and wait for a request. However, originally, we were assuming usb_ep_queue() would always happen before our first XferNotReady and that causes a corner case where we could try to issue ENDTRANSFER command before STARTTRANSFER. Let's fix that by tracking endpoints which have been started. Change-Id: I8432a70fff0da1b4bc1ea7d86e13d491e89a05bb Reported-by: Janusz Dziedzic <januszx.dziedzic@intel.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com> Signed-off-by: Meng Dongyang <daniel.meng@rock-chips.com> (cherry picked from commit 6cb2e4e3de10893f38dbf3923a9cc50c76548a89)
1 parent 4b36c00 commit c139ec1

2 files changed

Lines changed: 30 additions & 4 deletions

File tree

drivers/usb/dwc3/core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ struct dwc3_ep {
534534
#define DWC3_EP_BUSY (1 << 4)
535535
#define DWC3_EP_PENDING_REQUEST (1 << 5)
536536
#define DWC3_EP_MISSED_ISOC (1 << 6)
537+
#define DWC3_EP_TRANSFER_STARTED (1 << 8)
537538

538539
/* This last one is specific to EP0 */
539540
#define DWC3_EP0_DIR_IN (1 << 31)

drivers/usb/dwc3/gadget.c

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,20 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
338338

339339
trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status);
340340

341+
if (ret == 0) {
342+
switch (DWC3_DEPCMD_CMD(cmd)) {
343+
case DWC3_DEPCMD_STARTTRANSFER:
344+
dep->flags |= DWC3_EP_TRANSFER_STARTED;
345+
break;
346+
case DWC3_DEPCMD_ENDTRANSFER:
347+
dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
348+
break;
349+
default:
350+
/* nothing */
351+
break;
352+
}
353+
}
354+
341355
if (unlikely(susphy)) {
342356
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
343357
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
@@ -1058,6 +1072,14 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
10581072
return 0;
10591073
}
10601074

1075+
static int __dwc3_gadget_get_frame(struct dwc3 *dwc)
1076+
{
1077+
u32 reg;
1078+
1079+
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
1080+
return DWC3_DSTS_SOFFN(reg);
1081+
}
1082+
10611083
static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
10621084
struct dwc3_ep *dep, u32 cur_uf)
10631085
{
@@ -1178,9 +1200,14 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
11781200
* notion of current microframe.
11791201
*/
11801202
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
1181-
if (list_empty(&dep->started_list)) {
1203+
if (dep->flags & DWC3_EP_TRANSFER_STARTED) {
11821204
dwc3_stop_active_transfer(dwc, dep->number, true);
11831205
dep->flags = DWC3_EP_ENABLED;
1206+
} else {
1207+
u32 cur_uf;
1208+
1209+
cur_uf = __dwc3_gadget_get_frame(dwc);
1210+
__dwc3_gadget_start_isoc(dwc, dep, cur_uf);
11841211
}
11851212
return 0;
11861213
}
@@ -1451,10 +1478,8 @@ static const struct usb_ep_ops dwc3_gadget_ep_ops = {
14511478
static int dwc3_gadget_get_frame(struct usb_gadget *g)
14521479
{
14531480
struct dwc3 *dwc = gadget_to_dwc(g);
1454-
u32 reg;
14551481

1456-
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
1457-
return DWC3_DSTS_SOFFN(reg);
1482+
return __dwc3_gadget_get_frame(dwc);
14581483
}
14591484

14601485
static int __dwc3_gadget_wakeup(struct dwc3 *dwc)

0 commit comments

Comments
 (0)