On 25-04-25 05:55:40, Pawel Laszczak wrote: > 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@xxxxxxxxxxxxxxx > Signed-off-by: Pawel Laszczak <pawell@xxxxxxxxxxx> Acked-by: Peter Chen <peter.chen@xxxxxxxxxx> Peter > --- > Changelog: > v2: > - improved patch description > - changed RTL_REVISION_NEW_LPM value > > drivers/usb/cdns3/cdnsp-gadget.c | 2 ++ > drivers/usb/cdns3/cdnsp-gadget.h | 3 +++ > drivers/usb/cdns3/cdnsp-ring.c | 3 ++- > 3 files changed, 7 insertions(+), 1 deletion(-) > > diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c > index 87f310841735..e64c8f7eb0c5 100644 > --- a/drivers/usb/cdns3/cdnsp-gadget.c > +++ b/drivers/usb/cdns3/cdnsp-gadget.c > @@ -1773,6 +1773,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), > diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gadget.h > index 84887dfea763..357ddbe53917 100644 > --- a/drivers/usb/cdns3/cdnsp-gadget.h > +++ b/drivers/usb/cdns3/cdnsp-gadget.h > @@ -1357,6 +1357,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. > @@ -1411,6 +1412,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; > diff --git a/drivers/usb/cdns3/cdnsp-ring.c b/drivers/usb/cdns3/cdnsp-ring.c > index 46852529499d..fd06cb85c4ea 100644 > --- a/drivers/usb/cdns3/cdnsp-ring.c > +++ b/drivers/usb/cdns3/cdnsp-ring.c > @@ -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; > -- > 2.43.0 > -- Best regards, Peter