Commit 55016b9e6084a85d212dfdc17ee708c67c18507d

Authored by Felipe Balbi
Committed by Greg Kroah-Hartman
1 parent d8325cceb3

usb: dwc3: gadget: fix set_halt() bug with pending transfers

[ Upstream commit 7a60855972f0d3c014093046cb6f013a1ee5bb19 ]

According to our Gadget Framework API documentation,
->set_halt() *must* return -EAGAIN if we have pending
transfers (on either direction) or FIFO isn't empty (on
TX endpoints).

Fix this bug so that the mass storage gadget can be used
without stall=0 parameter.

This patch should be backported to all kernels since v3.2.

Suggested-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 3 changed files with 15 additions and 7 deletions Side-by-side Diff

drivers/usb/dwc3/ep0.c
... ... @@ -251,7 +251,7 @@
251 251  
252 252 /* stall is always issued on EP0 */
253 253 dep = dwc->eps[0];
254   - __dwc3_gadget_ep_set_halt(dep, 1);
  254 + __dwc3_gadget_ep_set_halt(dep, 1, false);
255 255 dep->flags = DWC3_EP_ENABLED;
256 256 dwc->delayed_status = false;
257 257  
... ... @@ -461,7 +461,7 @@
461 461 return -EINVAL;
462 462 if (set == 0 && (dep->flags & DWC3_EP_WEDGE))
463 463 break;
464   - ret = __dwc3_gadget_ep_set_halt(dep, set);
  464 + ret = __dwc3_gadget_ep_set_halt(dep, set, true);
465 465 if (ret)
466 466 return -EINVAL;
467 467 break;
drivers/usb/dwc3/gadget.c
... ... @@ -587,7 +587,7 @@
587 587  
588 588 /* make sure HW endpoint isn't stalled */
589 589 if (dep->flags & DWC3_EP_STALL)
590   - __dwc3_gadget_ep_set_halt(dep, 0);
  590 + __dwc3_gadget_ep_set_halt(dep, 0, false);
591 591  
592 592 reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
593 593 reg &= ~DWC3_DALEPENA_EP(dep->number);
... ... @@ -1185,7 +1185,7 @@
1185 1185 return ret;
1186 1186 }
1187 1187  
1188   -int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
  1188 +int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
1189 1189 {
1190 1190 struct dwc3_gadget_ep_cmd_params params;
1191 1191 struct dwc3 *dwc = dep->dwc;
... ... @@ -1194,6 +1194,14 @@
1194 1194 memset(&params, 0x00, sizeof(params));
1195 1195  
1196 1196 if (value) {
  1197 + if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) ||
  1198 + (!list_empty(&dep->req_queued) ||
  1199 + !list_empty(&dep->request_list)))) {
  1200 + dev_dbg(dwc->dev, "%s: pending request, cannot halt\n",
  1201 + dep->name);
  1202 + return -EAGAIN;
  1203 + }
  1204 +
1197 1205 ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
1198 1206 DWC3_DEPCMD_SETSTALL, &params);
1199 1207 if (ret)
... ... @@ -1233,7 +1241,7 @@
1233 1241 goto out;
1234 1242 }
1235 1243  
1236   - ret = __dwc3_gadget_ep_set_halt(dep, value);
  1244 + ret = __dwc3_gadget_ep_set_halt(dep, value, false);
1237 1245 out:
1238 1246 spin_unlock_irqrestore(&dwc->lock, flags);
1239 1247  
... ... @@ -1253,7 +1261,7 @@
1253 1261 if (dep->number == 0 || dep->number == 1)
1254 1262 return dwc3_gadget_ep0_set_halt(ep, 1);
1255 1263 else
1256   - return dwc3_gadget_ep_set_halt(ep, 1);
  1264 + return __dwc3_gadget_ep_set_halt(dep, 1, false);
1257 1265 }
1258 1266  
1259 1267 /* -------------------------------------------------------------------------- */
drivers/usb/dwc3/gadget.h
... ... @@ -85,7 +85,7 @@
85 85 int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
86 86 int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
87 87 gfp_t gfp_flags);
88   -int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
  88 +int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
89 89  
90 90 /**
91 91 * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW