]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
usb: cdnsp: fix L1 resume issue for RTL_REVISION_NEW_LPM version
authorPawel Laszczak <pawell@cadence.com>
Fri, 25 Apr 2025 05:55:40 +0000 (05:55 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 18 May 2025 06:20:37 +0000 (08:20 +0200)
commit 8614ecdb1570e4fffe87ebdc62b613ed66f1f6a6 upstream.

The controllers with rtl version larger than
RTL_REVISION_NEW_LPM (0x00002700) has bug which causes that controller
doesn't resume from L1 state. It happens if after receiving LPM packet
controller starts transitioning to L1 and in this moment the driver force
resuming by write operation to PORTSC.PLS.
It's corner case and happens when write operation to PORTSC occurs during
device delay before transitioning to L1 after transmitting ACK
time (TL1TokenRetry).

Forcing transition from L1->L0 by driver for revision larger than
RTL_REVISION_NEW_LPM is not needed, so driver can simply fix this issue
through block call of cdnsp_force_l0_go function.

Fixes: 3d82904559f4 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver")
Cc: stable <stable@kernel.org>
Signed-off-by: Pawel Laszczak <pawell@cadence.com>
Acked-by: Peter Chen <peter.chen@kernel.org>
Link: https://lore.kernel.org/r/PH7PR07MB9538B55C3A6E71F9ED29E980DD842@PH7PR07MB9538.namprd07.prod.outlook.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/cdns3/cdnsp-gadget.c
drivers/usb/cdns3/cdnsp-gadget.h
drivers/usb/cdns3/cdnsp-ring.c

index 6f7aa495f929219f248472c779f38e9f7eefdd10..1c29491ee56d5a676589b20a5db87de806c33202 100644 (file)
@@ -1799,6 +1799,8 @@ static void cdnsp_get_rev_cap(struct cdnsp_device *pdev)
        reg += cdnsp_find_next_ext_cap(reg, 0, RTL_REV_CAP);
        pdev->rev_cap  = reg;
 
+       pdev->rtl_revision = readl(&pdev->rev_cap->rtl_revision);
+
        dev_info(pdev->dev, "Rev: %08x/%08x, eps: %08x, buff: %08x/%08x\n",
                 readl(&pdev->rev_cap->ctrl_revision),
                 readl(&pdev->rev_cap->rtl_revision),
index 79376b1e3419ef449874cca27a35c6c8720f929d..5cffc1444d3a0cedf9c6a3c9291c786cd6a9465f 100644 (file)
@@ -1362,6 +1362,7 @@ struct cdnsp_port {
  * @rev_cap: Controller Capabilities Registers.
  * @hcs_params1: Cached register copies of read-only HCSPARAMS1
  * @hcc_params: Cached register copies of read-only HCCPARAMS1
+ * @rtl_revision: Cached controller rtl revision.
  * @setup: Temporary buffer for setup packet.
  * @ep0_preq: Internal allocated request used during enumeration.
  * @ep0_stage: ep0 stage during enumeration process.
@@ -1416,6 +1417,8 @@ struct cdnsp_device {
        __u32 hcs_params1;
        __u32 hcs_params3;
        __u32 hcc_params;
+       #define RTL_REVISION_NEW_LPM 0x2700
+       __u32 rtl_revision;
        /* Lock used in interrupt thread context. */
        spinlock_t lock;
        struct usb_ctrlrequest setup;
index 47096b8e317939e747279c08408505f54241a2ca..6247584cb93913a459d51021bf074964853d5be9 100644 (file)
@@ -308,7 +308,8 @@ static bool cdnsp_ring_ep_doorbell(struct cdnsp_device *pdev,
 
        writel(db_value, reg_addr);
 
-       cdnsp_force_l0_go(pdev);
+       if (pdev->rtl_revision < RTL_REVISION_NEW_LPM)
+               cdnsp_force_l0_go(pdev);
 
        /* Doorbell was set. */
        return true;