| From fecb3a171db425e5068b27231f8efe154bf72637 Mon Sep 17 00:00:00 2001 |
| From: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com> |
| Date: Tue, 13 Jul 2021 09:32:55 +0400 |
| Subject: usb: dwc2: gadget: Fix GOUTNAK flow for Slave mode. |
| |
| From: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com> |
| |
| commit fecb3a171db425e5068b27231f8efe154bf72637 upstream. |
| |
| Because of dwc2_hsotg_ep_stop_xfr() function uses poll |
| mode, first need to mask GINTSTS_GOUTNAKEFF interrupt. |
| In Slave mode GINTSTS_GOUTNAKEFF interrupt will be |
| aserted only after pop OUT NAK status packet from RxFIFO. |
| |
| In dwc2_hsotg_ep_sethalt() function before setting |
| DCTL_SGOUTNAK need to unmask GOUTNAKEFF interrupt. |
| |
| Tested by USBCV CH9 and MSC tests set in Slave, BDMA and DDMA. |
| All tests are passed. |
| |
| Fixes: a4f827714539a ("usb: dwc2: gadget: Disable enabled HW endpoint in dwc2_hsotg_ep_disable") |
| Fixes: 6070636c4918c ("usb: dwc2: Fix Stalling a Non-Isochronous OUT EP") |
| Cc: stable <stable@vger.kernel.org> |
| Signed-off-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com> |
| Link: https://lore.kernel.org/r/e17fad802bbcaf879e1ed6745030993abb93baf8.1626152924.git.Minas.Harutyunyan@synopsys.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/usb/dwc2/gadget.c | 21 +++++++++++++++++++++ |
| 1 file changed, 21 insertions(+) |
| |
| --- a/drivers/usb/dwc2/gadget.c |
| +++ b/drivers/usb/dwc2/gadget.c |
| @@ -3900,9 +3900,27 @@ static void dwc2_hsotg_ep_stop_xfr(struc |
| __func__); |
| } |
| } else { |
| + /* Mask GINTSTS_GOUTNAKEFF interrupt */ |
| + dwc2_hsotg_disable_gsint(hsotg, GINTSTS_GOUTNAKEFF); |
| + |
| if (!(dwc2_readl(hsotg, GINTSTS) & GINTSTS_GOUTNAKEFF)) |
| dwc2_set_bit(hsotg, DCTL, DCTL_SGOUTNAK); |
| |
| + if (!using_dma(hsotg)) { |
| + /* Wait for GINTSTS_RXFLVL interrupt */ |
| + if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, |
| + GINTSTS_RXFLVL, 100)) { |
| + dev_warn(hsotg->dev, "%s: timeout GINTSTS.RXFLVL\n", |
| + __func__); |
| + } else { |
| + /* |
| + * Pop GLOBAL OUT NAK status packet from RxFIFO |
| + * to assert GOUTNAKEFF interrupt |
| + */ |
| + dwc2_readl(hsotg, GRXSTSP); |
| + } |
| + } |
| + |
| /* Wait for global nak to take effect */ |
| if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS, |
| GINTSTS_GOUTNAKEFF, 100)) |
| @@ -4348,6 +4366,9 @@ static int dwc2_hsotg_ep_sethalt(struct |
| epctl = dwc2_readl(hs, epreg); |
| |
| if (value) { |
| + /* Unmask GOUTNAKEFF interrupt */ |
| + dwc2_hsotg_en_gsint(hs, GINTSTS_GOUTNAKEFF); |
| + |
| if (!(dwc2_readl(hs, GINTSTS) & GINTSTS_GOUTNAKEFF)) |
| dwc2_set_bit(hs, DCTL, DCTL_SGOUTNAK); |
| // STALL bit will be set in GOUTNAKEFF interrupt handler |