|
@@ -593,11 +593,14 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
|
dep->comp_desc = comp_desc;
|
|
dep->comp_desc = comp_desc;
|
|
dep->type = usb_endpoint_type(desc);
|
|
dep->type = usb_endpoint_type(desc);
|
|
dep->flags |= DWC3_EP_ENABLED;
|
|
dep->flags |= DWC3_EP_ENABLED;
|
|
|
|
+ dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
|
|
|
|
|
|
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);
|
|
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
|
|
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
|
|
|
|
|
|
|
|
+ init_waitqueue_head(&dep->wait_end_transfer);
|
|
|
|
+
|
|
if (usb_endpoint_xfer_control(desc))
|
|
if (usb_endpoint_xfer_control(desc))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
@@ -699,7 +702,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
|
|
dep->endpoint.desc = NULL;
|
|
dep->endpoint.desc = NULL;
|
|
dep->comp_desc = NULL;
|
|
dep->comp_desc = NULL;
|
|
dep->type = 0;
|
|
dep->type = 0;
|
|
- dep->flags = 0;
|
|
|
|
|
|
+ dep->flags &= DWC3_EP_END_TRANSFER_PENDING;
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -1783,9 +1786,6 @@ err0:
|
|
|
|
|
|
static void __dwc3_gadget_stop(struct dwc3 *dwc)
|
|
static void __dwc3_gadget_stop(struct dwc3 *dwc)
|
|
{
|
|
{
|
|
- if (pm_runtime_suspended(dwc->dev))
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
dwc3_gadget_disable_irq(dwc);
|
|
dwc3_gadget_disable_irq(dwc);
|
|
__dwc3_gadget_ep_disable(dwc->eps[0]);
|
|
__dwc3_gadget_ep_disable(dwc->eps[0]);
|
|
__dwc3_gadget_ep_disable(dwc->eps[1]);
|
|
__dwc3_gadget_ep_disable(dwc->eps[1]);
|
|
@@ -1795,9 +1795,30 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
|
|
{
|
|
{
|
|
struct dwc3 *dwc = gadget_to_dwc(g);
|
|
struct dwc3 *dwc = gadget_to_dwc(g);
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
+ int epnum;
|
|
|
|
|
|
spin_lock_irqsave(&dwc->lock, flags);
|
|
spin_lock_irqsave(&dwc->lock, flags);
|
|
|
|
+
|
|
|
|
+ if (pm_runtime_suspended(dwc->dev))
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
__dwc3_gadget_stop(dwc);
|
|
__dwc3_gadget_stop(dwc);
|
|
|
|
+
|
|
|
|
+ for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
|
|
|
|
+ struct dwc3_ep *dep = dwc->eps[epnum];
|
|
|
|
+
|
|
|
|
+ if (!dep)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ wait_event_lock_irq(dep->wait_end_transfer,
|
|
|
|
+ !(dep->flags & DWC3_EP_END_TRANSFER_PENDING),
|
|
|
|
+ dwc->lock);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+out:
|
|
dwc->gadget_driver = NULL;
|
|
dwc->gadget_driver = NULL;
|
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
|
|
|
|
|
@@ -2171,10 +2192,12 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
|
{
|
|
{
|
|
struct dwc3_ep *dep;
|
|
struct dwc3_ep *dep;
|
|
u8 epnum = event->endpoint_number;
|
|
u8 epnum = event->endpoint_number;
|
|
|
|
+ u8 cmd;
|
|
|
|
|
|
dep = dwc->eps[epnum];
|
|
dep = dwc->eps[epnum];
|
|
|
|
|
|
- if (!(dep->flags & DWC3_EP_ENABLED))
|
|
|
|
|
|
+ if (!(dep->flags & DWC3_EP_ENABLED) &&
|
|
|
|
+ !(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
|
|
return;
|
|
return;
|
|
|
|
|
|
if (epnum == 0 || epnum == 1) {
|
|
if (epnum == 0 || epnum == 1) {
|
|
@@ -2215,8 +2238,15 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
- case DWC3_DEPEVT_RXTXFIFOEVT:
|
|
|
|
case DWC3_DEPEVT_EPCMDCMPLT:
|
|
case DWC3_DEPEVT_EPCMDCMPLT:
|
|
|
|
+ cmd = DEPEVT_PARAMETER_CMD(event->parameters);
|
|
|
|
+
|
|
|
|
+ if (cmd == DWC3_DEPCMD_ENDTRANSFER) {
|
|
|
|
+ dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
|
|
|
|
+ wake_up(&dep->wait_end_transfer);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case DWC3_DEPEVT_RXTXFIFOEVT:
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -2269,7 +2299,8 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
|
|
|
|
|
|
dep = dwc->eps[epnum];
|
|
dep = dwc->eps[epnum];
|
|
|
|
|
|
- if (!dep->resource_index)
|
|
|
|
|
|
+ if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) ||
|
|
|
|
+ !dep->resource_index)
|
|
return;
|
|
return;
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -2313,8 +2344,10 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
|
|
dep->resource_index = 0;
|
|
dep->resource_index = 0;
|
|
dep->flags &= ~DWC3_EP_BUSY;
|
|
dep->flags &= ~DWC3_EP_BUSY;
|
|
|
|
|
|
- if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A)
|
|
|
|
|
|
+ if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) {
|
|
|
|
+ dep->flags |= DWC3_EP_END_TRANSFER_PENDING;
|
|
udelay(100);
|
|
udelay(100);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
|
|
static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
|