Commit bd9971f0 authored by Vardan Mikayelyan's avatar Vardan Mikayelyan Committed by Felipe Balbi

usb: dwc2: gadget: Add EP disabled interrupt handler

Reimplemented EP disabled interrupt handler and moved to
corresponding function.

This interrupt indicates that the endpoint has been disabled per
the application's request.

For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK,
in case of ISOC completes current request.

For ISOC-OUT endpoints completes expired requests. If there is
remaining request starts it. This is the part of ISOC-OUT transfer
drop flow. When ISOC-OUT transfer expired we must disable ep to drop
ongoing transfer.
Tested-by: default avatarJohn Keeping <john@metanate.com>
Reviewed-by: default avatarVahram Aharonyan <vahrama@synopsys.com>
Signed-off-by: default avatarVardan Mikayelyan <mvardan@synopsys.com>
Signed-off-by: default avatarJohn Youn <johnyoun@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 381fc8f8
......@@ -2023,6 +2023,74 @@ static u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg,
return ints;
}
/**
* dwc2_gadget_handle_ep_disabled - handle DXEPINT_EPDISBLD
* @hs_ep: The endpoint on which interrupt is asserted.
*
* This interrupt indicates that the endpoint has been disabled per the
* application's request.
*
* For IN endpoints flushes txfifo, in case of BULK clears DCTL_CGNPINNAK,
* in case of ISOC completes current request.
*
* For ISOC-OUT endpoints completes expired requests. If there is remaining
* request starts it.
*/
static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep)
{
struct dwc2_hsotg *hsotg = hs_ep->parent;
struct dwc2_hsotg_req *hs_req;
unsigned char idx = hs_ep->index;
int dir_in = hs_ep->dir_in;
u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);
int dctl = dwc2_readl(hsotg->regs + DCTL);
dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
if (dir_in) {
int epctl = dwc2_readl(hsotg->regs + epctl_reg);
dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index);
if (hs_ep->isochronous) {
dwc2_hsotg_complete_in(hsotg, hs_ep);
return;
}
if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) {
int dctl = dwc2_readl(hsotg->regs + DCTL);
dctl |= DCTL_CGNPINNAK;
dwc2_writel(dctl, hsotg->regs + DCTL);
}
return;
}
if (dctl & DCTL_GOUTNAKSTS) {
dctl |= DCTL_CGOUTNAK;
dwc2_writel(dctl, hsotg->regs + DCTL);
}
if (!hs_ep->isochronous)
return;
if (list_empty(&hs_ep->queue)) {
dev_dbg(hsotg->dev, "%s: complete_ep 0x%p, ep->queue empty!\n",
__func__, hs_ep);
return;
}
do {
hs_req = get_ep_head(hs_ep);
if (hs_req)
dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req,
-ENODATA);
dwc2_gadget_incr_frame_num(hs_ep);
} while (dwc2_gadget_target_frame_elapsed(hs_ep));
dwc2_gadget_start_next_request(hs_ep);
}
/**
* dwc2_gadget_handle_out_token_ep_disabled - handle DXEPINT_OUTTKNEPDIS
* @hs_ep: The endpoint on which interrupt is asserted.
......@@ -2177,23 +2245,8 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
}
}
if (ints & DXEPINT_EPDISBLD) {
dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
if (dir_in) {
int epctl = dwc2_readl(hsotg->regs + epctl_reg);
dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index);
if ((epctl & DXEPCTL_STALL) &&
(epctl & DXEPCTL_EPTYPE_BULK)) {
int dctl = dwc2_readl(hsotg->regs + DCTL);
dctl |= DCTL_CGNPINNAK;
dwc2_writel(dctl, hsotg->regs + DCTL);
}
}
}
if (ints & DXEPINT_EPDISBLD)
dwc2_gadget_handle_ep_disabled(hs_ep);
if (ints & DXEPINT_OUTTKNEPDIS)
dwc2_gadget_handle_out_token_ep_disabled(hs_ep);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment