mirror of https://gitee.com/openkylin/linux.git
usb: dwc3: gadget: rework the dequeue on RESET & DISCONNECT
- since a while we are disabling an endpoint and purging every requests on RESET and DISCONNECT which leads to a warning since the endpoint was disabled twice (once by the UDC, and second time by the gadget). I think UDC should nuke all requests because all those requests become invalid. It's gadget driver's responsability, though, to disable its used endpoints. This is done by merging dwc3_stop_active_transfer() and dwc3_gadget_nuke_reqs() into dwc3_remove_requests(). - dwc3_stop_active_transfer() is now no longer called unconditionaly. This has the advantage that it is always called to disable an active transfer which means if res_trans_idx 0 than something went wrong and it is an error condition because we can't clean up the requests. - Remove the DWC3_EP_WILL_SHUTDOWN which was introduced while introducing the command complete part for dequeue. All requests on req_queued list should be removed during the dwc3_cleanup_done_reqs() callback so there is no reason to go through the list again. We consider it an error condition if requests are still on this list since we never queue TRB without LST=1 (the last requests has always LST=1, there are no requests with LST=0 behind it). [ balbi@ti.com : reworked commit log a bit, made patch apply ] Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
7650bd74d3
commit
624407f96f
|
@ -348,7 +348,6 @@ struct dwc3_ep {
|
||||||
#define DWC3_EP_WEDGE (1 << 2)
|
#define DWC3_EP_WEDGE (1 << 2)
|
||||||
#define DWC3_EP_BUSY (1 << 4)
|
#define DWC3_EP_BUSY (1 << 4)
|
||||||
#define DWC3_EP_PENDING_REQUEST (1 << 5)
|
#define DWC3_EP_PENDING_REQUEST (1 << 5)
|
||||||
#define DWC3_EP_WILL_SHUTDOWN (1 << 6)
|
|
||||||
|
|
||||||
/* This last one is specific to EP0 */
|
/* This last one is specific to EP0 */
|
||||||
#define DWC3_EP0_DIR_IN (1 << 31)
|
#define DWC3_EP0_DIR_IN (1 << 31)
|
||||||
|
|
|
@ -359,34 +359,36 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dwc3_gadget_nuke_reqs(struct dwc3_ep *dep, const int status)
|
static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
|
||||||
|
static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||||
{
|
{
|
||||||
struct dwc3_request *req;
|
struct dwc3_request *req;
|
||||||
|
|
||||||
|
if (!list_empty(&dep->req_queued))
|
||||||
|
dwc3_stop_active_transfer(dwc, dep->number);
|
||||||
|
|
||||||
while (!list_empty(&dep->request_list)) {
|
while (!list_empty(&dep->request_list)) {
|
||||||
req = next_request(&dep->request_list);
|
req = next_request(&dep->request_list);
|
||||||
|
|
||||||
dwc3_gadget_giveback(dep, req, status);
|
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
|
||||||
}
|
}
|
||||||
/* nuke queued TRBs as well on command complete */
|
|
||||||
dep->flags |= DWC3_EP_WILL_SHUTDOWN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __dwc3_gadget_ep_disable - Disables a HW endpoint
|
* __dwc3_gadget_ep_disable - Disables a HW endpoint
|
||||||
* @dep: the endpoint to disable
|
* @dep: the endpoint to disable
|
||||||
*
|
*
|
||||||
* Caller should take care of locking
|
* This function also removes requests which are currently processed ny the
|
||||||
|
* hardware and those which are not yet scheduled.
|
||||||
|
* Caller should take care of locking.
|
||||||
*/
|
*/
|
||||||
static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
|
|
||||||
static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
|
static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
|
||||||
{
|
{
|
||||||
struct dwc3 *dwc = dep->dwc;
|
struct dwc3 *dwc = dep->dwc;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
|
||||||
dep->flags &= ~DWC3_EP_ENABLED;
|
dep->flags &= ~DWC3_EP_ENABLED;
|
||||||
dwc3_stop_active_transfer(dwc, dep->number);
|
dwc3_remove_requests(dwc, dep);
|
||||||
dwc3_gadget_nuke_reqs(dep, -ESHUTDOWN);
|
|
||||||
|
|
||||||
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
|
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
|
||||||
reg &= ~DWC3_DALEPENA_EP(dep->number);
|
reg &= ~DWC3_DALEPENA_EP(dep->number);
|
||||||
|
@ -1416,16 +1418,6 @@ static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
|
||||||
dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
|
dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
|
||||||
dep->flags &= ~DWC3_EP_BUSY;
|
dep->flags &= ~DWC3_EP_BUSY;
|
||||||
/* pending requets are ignored and are queued on XferNotReady */
|
/* pending requets are ignored and are queued on XferNotReady */
|
||||||
|
|
||||||
if (dep->flags & DWC3_EP_WILL_SHUTDOWN) {
|
|
||||||
while (!list_empty(&dep->req_queued)) {
|
|
||||||
struct dwc3_request *req;
|
|
||||||
|
|
||||||
req = next_request(&dep->req_queued);
|
|
||||||
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
|
|
||||||
}
|
|
||||||
dep->flags &= ~DWC3_EP_WILL_SHUTDOWN;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
|
static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
|
||||||
|
@ -1533,6 +1525,7 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
|
||||||
|
|
||||||
dep = dwc->eps[epnum];
|
dep = dwc->eps[epnum];
|
||||||
|
|
||||||
|
WARN_ON(!dep->res_trans_idx);
|
||||||
if (dep->res_trans_idx) {
|
if (dep->res_trans_idx) {
|
||||||
cmd = DWC3_DEPCMD_ENDTRANSFER;
|
cmd = DWC3_DEPCMD_ENDTRANSFER;
|
||||||
cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
|
cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
|
||||||
|
@ -1555,7 +1548,7 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
|
||||||
if (!(dep->flags & DWC3_EP_ENABLED))
|
if (!(dep->flags & DWC3_EP_ENABLED))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
__dwc3_gadget_ep_disable(dep);
|
dwc3_remove_requests(dwc, dep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue