aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2014-09-24 15:19:52 -0400
committerFelipe Balbi <balbi@ti.com>2014-10-20 16:58:48 -0400
commit7a60855972f0d3c014093046cb6f013a1ee5bb19 (patch)
tree8c25e151ddaab4d8840bcd82ba31c0c5eff99a94 /drivers/usb
parent95aa4e8d658778f787e2ce205d3018443d027477 (diff)
usb: dwc3: gadget: fix set_halt() bug with pending transfers
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. Cc: <stable@vger.kernel.org> # v3.2+ Suggested-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/dwc3/ep0.c4
-rw-r--r--drivers/usb/dwc3/gadget.c16
-rw-r--r--drivers/usb/dwc3/gadget.h2
3 files changed, 15 insertions, 7 deletions
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 36f61582b5b5..ae6b5753fe67 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -256,7 +256,7 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
256 256
257 /* stall is always issued on EP0 */ 257 /* stall is always issued on EP0 */
258 dep = dwc->eps[0]; 258 dep = dwc->eps[0];
259 __dwc3_gadget_ep_set_halt(dep, 1); 259 __dwc3_gadget_ep_set_halt(dep, 1, false);
260 dep->flags = DWC3_EP_ENABLED; 260 dep->flags = DWC3_EP_ENABLED;
261 dwc->delayed_status = false; 261 dwc->delayed_status = false;
262 262
@@ -480,7 +480,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
480 return -EINVAL; 480 return -EINVAL;
481 if (set == 0 && (dep->flags & DWC3_EP_WEDGE)) 481 if (set == 0 && (dep->flags & DWC3_EP_WEDGE))
482 break; 482 break;
483 ret = __dwc3_gadget_ep_set_halt(dep, set); 483 ret = __dwc3_gadget_ep_set_halt(dep, set, true);
484 if (ret) 484 if (ret)
485 return -EINVAL; 485 return -EINVAL;
486 break; 486 break;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index b98295efd912..f6d1dbafa298 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -581,7 +581,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
581 581
582 /* make sure HW endpoint isn't stalled */ 582 /* make sure HW endpoint isn't stalled */
583 if (dep->flags & DWC3_EP_STALL) 583 if (dep->flags & DWC3_EP_STALL)
584 __dwc3_gadget_ep_set_halt(dep, 0); 584 __dwc3_gadget_ep_set_halt(dep, 0, false);
585 585
586 reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); 586 reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
587 reg &= ~DWC3_DALEPENA_EP(dep->number); 587 reg &= ~DWC3_DALEPENA_EP(dep->number);
@@ -1202,7 +1202,7 @@ out0:
1202 return ret; 1202 return ret;
1203} 1203}
1204 1204
1205int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) 1205int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
1206{ 1206{
1207 struct dwc3_gadget_ep_cmd_params params; 1207 struct dwc3_gadget_ep_cmd_params params;
1208 struct dwc3 *dwc = dep->dwc; 1208 struct dwc3 *dwc = dep->dwc;
@@ -1216,6 +1216,14 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
1216 memset(&params, 0x00, sizeof(params)); 1216 memset(&params, 0x00, sizeof(params));
1217 1217
1218 if (value) { 1218 if (value) {
1219 if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) ||
1220 (!list_empty(&dep->req_queued) ||
1221 !list_empty(&dep->request_list)))) {
1222 dev_dbg(dwc->dev, "%s: pending request, cannot halt\n",
1223 dep->name);
1224 return -EAGAIN;
1225 }
1226
1219 ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, 1227 ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
1220 DWC3_DEPCMD_SETSTALL, &params); 1228 DWC3_DEPCMD_SETSTALL, &params);
1221 if (ret) 1229 if (ret)
@@ -1246,7 +1254,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
1246 int ret; 1254 int ret;
1247 1255
1248 spin_lock_irqsave(&dwc->lock, flags); 1256 spin_lock_irqsave(&dwc->lock, flags);
1249 ret = __dwc3_gadget_ep_set_halt(dep, value); 1257 ret = __dwc3_gadget_ep_set_halt(dep, value, false);
1250 spin_unlock_irqrestore(&dwc->lock, flags); 1258 spin_unlock_irqrestore(&dwc->lock, flags);
1251 1259
1252 return ret; 1260 return ret;
@@ -1265,7 +1273,7 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
1265 if (dep->number == 0 || dep->number == 1) 1273 if (dep->number == 0 || dep->number == 1)
1266 ret = __dwc3_gadget_ep0_set_halt(ep, 1); 1274 ret = __dwc3_gadget_ep0_set_halt(ep, 1);
1267 else 1275 else
1268 ret = __dwc3_gadget_ep_set_halt(dep, 1); 1276 ret = __dwc3_gadget_ep_set_halt(dep, 1, false);
1269 spin_unlock_irqrestore(&dwc->lock, flags); 1277 spin_unlock_irqrestore(&dwc->lock, flags);
1270 1278
1271 return ret; 1279 return ret;
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index f889008faa63..18ae3eaa8b6f 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -86,7 +86,7 @@ int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
86int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); 86int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
87int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, 87int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
88 gfp_t gfp_flags); 88 gfp_t gfp_flags);
89int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value); 89int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
90 90
91/** 91/**
92 * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW 92 * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW