usb: mtu3: fix the failure of qmu stop
authorChunfeng Yun <chunfeng.yun@mediatek.com>
Thu, 19 Jan 2023 03:33:22 +0000 (11:33 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 19 Jan 2023 13:12:08 +0000 (14:12 +0100)
This happens when do stress test of uvc stream on/off which will
enable/disable endpoints. uvc has four tx requests, and may disable
endpoint between queue tx requests as following:
    enable ep --> start qmu
    queue tx request0
    queue tx request1
    queue tx request2 --> resume qmu
    disable ep --> stop qmu may fail [1]
    queue tx request3 --> will resume qmu, may cause qmu can't work
                          when enable ep next time [2]

[1]: when the tx fifo has some data to transmit, and
    try to stop qmu (stop ep) meanwhile resume qmu (queue tx request),
    it may cause stop qmu timeout, then can be fixed by flushing fifo
    when stop qmu.
[2]: it resumes qmu again, shall stop qmu again.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
Reported-by: Min Guo <min.guo@mediatek.com>
Link: https://lore.kernel.org/r/20230119033322.21426-1-chunfeng.yun@mediatek.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/mtu3/mtu3_gadget.c
drivers/usb/mtu3/mtu3_hw_regs.h
drivers/usb/mtu3/mtu3_qmu.c

index 80236e7b08957f406d4ba388a48150547c99c238..c0264d5426bfe6c289869dfc5292b1cb2ad8dfd2 100644 (file)
@@ -133,10 +133,9 @@ static int mtu3_ep_disable(struct mtu3_ep *mep)
 {
        struct mtu3 *mtu = mep->mtu;
 
-       mtu3_qmu_stop(mep);
-
        /* abort all pending requests */
        nuke(mep, -ESHUTDOWN);
+       mtu3_qmu_stop(mep);
        mtu3_deconfig_ep(mtu, mep);
        mtu3_gpd_ring_free(mep);
 
index 519a58301f450c4b056aaa4733a0a7a89db99003..ee30ae0a4b54579afba67d7bdf74b67203221dc9 100644 (file)
 #define TX_FIFOEMPTY           BIT(24)
 #define TX_SENTSTALL           BIT(22)
 #define TX_SENDSTALL           BIT(21)
+#define TX_FLUSHFIFO           BIT(20)
 #define TX_TXPKTRDY            BIT(16)
 #define TX_TXMAXPKTSZ_MSK      GENMASK(10, 0)
 #define TX_TXMAXPKTSZ(x)       ((x) & TX_TXMAXPKTSZ_MSK)
index 2ea3157ddb6e25b0301bf57a5af4a9128b7ccf8d..a2fdab8b63b2824aaf0cc8264c2e1139fba79dec 100644 (file)
@@ -388,6 +388,9 @@ void mtu3_qmu_stop(struct mtu3_ep *mep)
        }
        mtu3_writel(mbase, qcsr, QMU_Q_STOP);
 
+       if (mep->is_in)
+               mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_FLUSHFIFO);
+
        ret = readl_poll_timeout_atomic(mbase + qcsr, value,
                        !(value & QMU_Q_ACTIVE), 1, 1000);
        if (ret) {
@@ -395,6 +398,10 @@ void mtu3_qmu_stop(struct mtu3_ep *mep)
                return;
        }
 
+       /* flush fifo again to make sure the fifo is empty */
+       if (mep->is_in)
+               mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_FLUSHFIFO);
+
        dev_dbg(mtu->dev, "%s's qmu stop now!\n", mep->name);
 }