mbox series

[0/3] usb: dwc3: ulpi: Fix UPLI registers read/write ops

Message ID 20201010222351.7323-1-Sergey.Semin@baikalelectronics.ru
Headers show
Series usb: dwc3: ulpi: Fix UPLI registers read/write ops | expand

Message

Serge Semin Oct. 10, 2020, 10:23 p.m. UTC
Our Baikal-T1 SoC is equipped with DWC USB3 IP core as a USB2.0 bus
controller. In general the DWC USB3 driver is working well for it except
the ULPI-bus part. We've found out that the DWC USB3 ULPI-bus driver detected
PHY with VID:PID tuple as 0x0000:0x0000, which of course wasn't true since
it was supposed to be 0x0424:0x0006. After a short digging inside the
ulpi.c code and studying the DWC USB3 documentation, it has been
discovered that the ULPI bus IO ops didn't work quite correct. The
busy-loop had stopped waiting before the actual operation was finished. We
found out that the problem was caused by several bugs hidden in the DWC
USB3 ULPI-bus IO implementation.

First of all in accordance with the DWC USB3 databook [1] the ULPI IO
busy-loop is supposed to use the GUSB2PHYACCn.VStsDone flag as an
indication of the PHY vendor control access completion. Instead it polled
the GUSB2PHYACCn.VStsBsy flag, which as we discovered can be cleared a
bit before the VStsDone flag.

Secondly having the simple counter-based loop in the modern kernel is
really a weak design of the busy-looping pattern especially seeing the
ULPI operations delay can be easily estimated [2], since the bus clock is
fixed to 60MHz.

Finally the root cause of the denoted in the prologue problem was due to
the Suspend PHY DWC USB3 feature perception. The commit e0082698b689
("usb: dwc3: ulpi: conditionally resume ULPI PHY") introduced the Suspend
USB2.0 HS/FS/LS PHY regression as the Low-power consumption mode would be
disable after a first attempt to read/write from the ULPI PHY control
registers, and still didn't fix the problem it was originally intended for
since the very first attempt of the ULPI PHY control registers IO would
need much more time than the busy-loop provided. So instead of disabling
the Suspend USB2.0 HS/FS/LS PHY feature we suggest to just extend the
busy-loop delay in case if the GUSB2PHYCFGn.SusPHY flag set to 1. By doing
so we'll eliminate the regression and the fix the false busy-loop timeout
problem.

[1] Synopsys DesignWare Cores SuperSpeed USB 3.0 xHCI Host Controller
    Databook, 2.70a, December 2013, p.388

[1] UTMI+ Low Pin Interface (ULPI) Specification, Revision 1.1,
    October 20, 2004, pp. 30 - 36.

Fixes: e0082698b689 ("usb: dwc3: ulpi: conditionally resume ULPI PHY")
Fixes: 88bc9d194ff6 ("usb: dwc3: add ULPI interface support")
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
Cc: linux-usb@vger.kernel.org
Cc: linux-kernel@vger.kernel.org

Serge Semin (3):
  usb: dwc3: ulpi: Use VStsDone to detect PHY regs access completion
  usb: dwc3: ulpi: Replace CPU-based busyloop with Protocol-based one
  usb: dwc3: ulpi: Fix USB2.0 HS/FS/LS PHY suspend regression

 drivers/usb/dwc3/core.h |  1 +
 drivers/usb/dwc3/ulpi.c | 38 +++++++++++++++++++++-----------------
 2 files changed, 22 insertions(+), 17 deletions(-)

Comments

Heikki Krogerus Oct. 19, 2020, 1:58 p.m. UTC | #1
On Sun, Oct 11, 2020 at 01:23:48AM +0300, Serge Semin wrote:
> Our Baikal-T1 SoC is equipped with DWC USB3 IP core as a USB2.0 bus
> controller. In general the DWC USB3 driver is working well for it except
> the ULPI-bus part. We've found out that the DWC USB3 ULPI-bus driver detected
> PHY with VID:PID tuple as 0x0000:0x0000, which of course wasn't true since
> it was supposed to be 0x0424:0x0006. After a short digging inside the
> ulpi.c code and studying the DWC USB3 documentation, it has been
> discovered that the ULPI bus IO ops didn't work quite correct. The
> busy-loop had stopped waiting before the actual operation was finished. We
> found out that the problem was caused by several bugs hidden in the DWC
> USB3 ULPI-bus IO implementation.
> 
> First of all in accordance with the DWC USB3 databook [1] the ULPI IO
> busy-loop is supposed to use the GUSB2PHYACCn.VStsDone flag as an
> indication of the PHY vendor control access completion. Instead it polled
> the GUSB2PHYACCn.VStsBsy flag, which as we discovered can be cleared a
> bit before the VStsDone flag.
> 
> Secondly having the simple counter-based loop in the modern kernel is
> really a weak design of the busy-looping pattern especially seeing the
> ULPI operations delay can be easily estimated [2], since the bus clock is
> fixed to 60MHz.
> 
> Finally the root cause of the denoted in the prologue problem was due to
> the Suspend PHY DWC USB3 feature perception. The commit e0082698b689
> ("usb: dwc3: ulpi: conditionally resume ULPI PHY") introduced the Suspend
> USB2.0 HS/FS/LS PHY regression as the Low-power consumption mode would be
> disable after a first attempt to read/write from the ULPI PHY control
> registers, and still didn't fix the problem it was originally intended for
> since the very first attempt of the ULPI PHY control registers IO would
> need much more time than the busy-loop provided. So instead of disabling
> the Suspend USB2.0 HS/FS/LS PHY feature we suggest to just extend the
> busy-loop delay in case if the GUSB2PHYCFGn.SusPHY flag set to 1. By doing
> so we'll eliminate the regression and the fix the false busy-loop timeout
> problem.
> 
> [1] Synopsys DesignWare Cores SuperSpeed USB 3.0 xHCI Host Controller
>     Databook, 2.70a, December 2013, p.388
> 
> [1] UTMI+ Low Pin Interface (ULPI) Specification, Revision 1.1,
>     October 20, 2004, pp. 30 - 36.
> 
> Fixes: e0082698b689 ("usb: dwc3: ulpi: conditionally resume ULPI PHY")
> Fixes: 88bc9d194ff6 ("usb: dwc3: add ULPI interface support")
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
> Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
> Cc: linux-usb@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> 
> Serge Semin (3):
>   usb: dwc3: ulpi: Use VStsDone to detect PHY regs access completion
>   usb: dwc3: ulpi: Replace CPU-based busyloop with Protocol-based one
>   usb: dwc3: ulpi: Fix USB2.0 HS/FS/LS PHY suspend regression
> 
>  drivers/usb/dwc3/core.h |  1 +
>  drivers/usb/dwc3/ulpi.c | 38 +++++++++++++++++++++-----------------
>  2 files changed, 22 insertions(+), 17 deletions(-)

FWIW, for the whole series:

Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>

thanks,
Felipe Balbi Oct. 27, 2020, 9:13 a.m. UTC | #2
Serge Semin <Sergey.Semin@baikalelectronics.ru> writes:

> Our Baikal-T1 SoC is equipped with DWC USB3 IP core as a USB2.0 bus
> controller. In general the DWC USB3 driver is working well for it except
> the ULPI-bus part. We've found out that the DWC USB3 ULPI-bus driver detected
> PHY with VID:PID tuple as 0x0000:0x0000, which of course wasn't true since
> it was supposed to be 0x0424:0x0006. After a short digging inside the
> ulpi.c code and studying the DWC USB3 documentation, it has been
> discovered that the ULPI bus IO ops didn't work quite correct. The
> busy-loop had stopped waiting before the actual operation was finished. We
> found out that the problem was caused by several bugs hidden in the DWC
> USB3 ULPI-bus IO implementation.
>
> First of all in accordance with the DWC USB3 databook [1] the ULPI IO
> busy-loop is supposed to use the GUSB2PHYACCn.VStsDone flag as an
> indication of the PHY vendor control access completion. Instead it polled
> the GUSB2PHYACCn.VStsBsy flag, which as we discovered can be cleared a
> bit before the VStsDone flag.
>
> Secondly having the simple counter-based loop in the modern kernel is
> really a weak design of the busy-looping pattern especially seeing the
> ULPI operations delay can be easily estimated [2], since the bus clock is
> fixed to 60MHz.
>
> Finally the root cause of the denoted in the prologue problem was due to
> the Suspend PHY DWC USB3 feature perception. The commit e0082698b689
> ("usb: dwc3: ulpi: conditionally resume ULPI PHY") introduced the Suspend
> USB2.0 HS/FS/LS PHY regression as the Low-power consumption mode would be
> disable after a first attempt to read/write from the ULPI PHY control
> registers, and still didn't fix the problem it was originally intended for
> since the very first attempt of the ULPI PHY control registers IO would
> need much more time than the busy-loop provided. So instead of disabling
> the Suspend USB2.0 HS/FS/LS PHY feature we suggest to just extend the
> busy-loop delay in case if the GUSB2PHYCFGn.SusPHY flag set to 1. By doing
> so we'll eliminate the regression and the fix the false busy-loop timeout
> problem.
>
> [1] Synopsys DesignWare Cores SuperSpeed USB 3.0 xHCI Host Controller
>     Databook, 2.70a, December 2013, p.388
>
> [1] UTMI+ Low Pin Interface (ULPI) Specification, Revision 1.1,
>     October 20, 2004, pp. 30 - 36.
>
> Fixes: e0082698b689 ("usb: dwc3: ulpi: conditionally resume ULPI PHY")
> Fixes: 88bc9d194ff6 ("usb: dwc3: add ULPI interface support")
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
> Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
> Cc: linux-usb@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org

these should go in the relevant commits instead.

> Serge Semin (3):
>   usb: dwc3: ulpi: Use VStsDone to detect PHY regs access completion
>   usb: dwc3: ulpi: Replace CPU-based busyloop with Protocol-based one
>   usb: dwc3: ulpi: Fix USB2.0 HS/FS/LS PHY suspend regression

make sure fixes don't depend on other rework otherwise they can't be
taken during the -rc cycle.
Felipe Balbi Oct. 27, 2020, 9:15 a.m. UTC | #3
Hi,

Serge Semin <Sergey.Semin@baikalelectronics.ru> writes:

> In accordance with [1] the DWC_usb3 core sets the GUSB2PHYACCn.VStsDone
> bit when the PHY vendor control access is done and clears it when the
> application initiates a new transaction. The doc doesn't say anything
> about the GUSB2PHYACCn.VStsBsy flag serving for the same purpose. Moreover
> we've discovered that the VStsBsy flag can be cleared before the VStsDone
> bit. So using the former as a signal of the PHY control registers
> completion might be dangerous. Let's have the VStsDone flag utilized
> instead then.
>
> [1] Synopsys DesignWare Cores SuperSpeed USB 3.0 xHCI Host Controller
>     Databook, 2.70a, December 2013, p.388
>
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/usb/dwc3/core.h | 1 +
>  drivers/usb/dwc3/ulpi.c | 2 +-
>  2 files changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index 2f04b3e42bf1..8d5e5bba1bc2 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -284,6 +284,7 @@
>  
>  /* Global USB2 PHY Vendor Control Register */
>  #define DWC3_GUSB2PHYACC_NEWREGREQ	BIT(25)
> +#define DWC3_GUSB2PHYACC_DONE		BIT(24)
>  #define DWC3_GUSB2PHYACC_BUSY		BIT(23)
>  #define DWC3_GUSB2PHYACC_WRITE		BIT(22)
>  #define DWC3_GUSB2PHYACC_ADDR(n)	(n << 16)
> diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c
> index e6e6176386a4..20f5d9aba317 100644
> --- a/drivers/usb/dwc3/ulpi.c
> +++ b/drivers/usb/dwc3/ulpi.c
> @@ -24,7 +24,7 @@ static int dwc3_ulpi_busyloop(struct dwc3 *dwc)
>  
>  	while (count--) {
>  		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
> -		if (!(reg & DWC3_GUSB2PHYACC_BUSY))
> +		if (reg & DWC3_GUSB2PHYACC_DONE)

are you sure this works in all supported versions of the core?

John, could you confirm this for us?

thanks
Serge Semin Oct. 27, 2020, 8:07 p.m. UTC | #4
On Tue, Oct 27, 2020 at 11:13:14AM +0200, Felipe Balbi wrote:
> Serge Semin <Sergey.Semin@baikalelectronics.ru> writes:
> 
> > Our Baikal-T1 SoC is equipped with DWC USB3 IP core as a USB2.0 bus
> > controller. In general the DWC USB3 driver is working well for it except
> > the ULPI-bus part. We've found out that the DWC USB3 ULPI-bus driver detected
> > PHY with VID:PID tuple as 0x0000:0x0000, which of course wasn't true since
> > it was supposed to be 0x0424:0x0006. After a short digging inside the
> > ulpi.c code and studying the DWC USB3 documentation, it has been
> > discovered that the ULPI bus IO ops didn't work quite correct. The
> > busy-loop had stopped waiting before the actual operation was finished. We
> > found out that the problem was caused by several bugs hidden in the DWC
> > USB3 ULPI-bus IO implementation.
> >
> > First of all in accordance with the DWC USB3 databook [1] the ULPI IO
> > busy-loop is supposed to use the GUSB2PHYACCn.VStsDone flag as an
> > indication of the PHY vendor control access completion. Instead it polled
> > the GUSB2PHYACCn.VStsBsy flag, which as we discovered can be cleared a
> > bit before the VStsDone flag.
> >
> > Secondly having the simple counter-based loop in the modern kernel is
> > really a weak design of the busy-looping pattern especially seeing the
> > ULPI operations delay can be easily estimated [2], since the bus clock is
> > fixed to 60MHz.
> >
> > Finally the root cause of the denoted in the prologue problem was due to
> > the Suspend PHY DWC USB3 feature perception. The commit e0082698b689
> > ("usb: dwc3: ulpi: conditionally resume ULPI PHY") introduced the Suspend
> > USB2.0 HS/FS/LS PHY regression as the Low-power consumption mode would be
> > disable after a first attempt to read/write from the ULPI PHY control
> > registers, and still didn't fix the problem it was originally intended for
> > since the very first attempt of the ULPI PHY control registers IO would
> > need much more time than the busy-loop provided. So instead of disabling
> > the Suspend USB2.0 HS/FS/LS PHY feature we suggest to just extend the
> > busy-loop delay in case if the GUSB2PHYCFGn.SusPHY flag set to 1. By doing
> > so we'll eliminate the regression and the fix the false busy-loop timeout
> > problem.
> >
> > [1] Synopsys DesignWare Cores SuperSpeed USB 3.0 xHCI Host Controller
> >     Databook, 2.70a, December 2013, p.388
> >
> > [1] UTMI+ Low Pin Interface (ULPI) Specification, Revision 1.1,
> >     October 20, 2004, pp. 30 - 36.
> >
> > Fixes: e0082698b689 ("usb: dwc3: ulpi: conditionally resume ULPI PHY")
> > Fixes: 88bc9d194ff6 ("usb: dwc3: add ULPI interface support")
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
> > Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
> > Cc: linux-usb@vger.kernel.org
> > Cc: linux-kernel@vger.kernel.org
> 

> these should go in the relevant commits instead.

Could you elaborate what do you mean by "these"? If you meant the "Fixes" tag,
then it's already there except the very first patch. Which I think could be also
tagged with one.

> 
> > Serge Semin (3):
> >   usb: dwc3: ulpi: Use VStsDone to detect PHY regs access completion
> >   usb: dwc3: ulpi: Replace CPU-based busyloop with Protocol-based one
> >   usb: dwc3: ulpi: Fix USB2.0 HS/FS/LS PHY suspend regression
> 

> make sure fixes don't depend on other rework otherwise they can't be
> taken during the -rc cycle.

Logically they don't, but still the later patches won't apply cleanly without
the former ones. So I can add the "Fixes" tag to the very first patch (it would
be correct since basically it's also a fix) so all of them would be ported to
the -rc and stable kernels. Is that ok?

-Sergey

> 
> -- 
> balbi
Serge Semin Oct. 27, 2020, 8:13 p.m. UTC | #5
On Tue, Oct 27, 2020 at 11:15:24AM +0200, Felipe Balbi wrote:
> 
> Hi,
> 
> Serge Semin <Sergey.Semin@baikalelectronics.ru> writes:
> 
> > In accordance with [1] the DWC_usb3 core sets the GUSB2PHYACCn.VStsDone
> > bit when the PHY vendor control access is done and clears it when the
> > application initiates a new transaction. The doc doesn't say anything
> > about the GUSB2PHYACCn.VStsBsy flag serving for the same purpose. Moreover
> > we've discovered that the VStsBsy flag can be cleared before the VStsDone
> > bit. So using the former as a signal of the PHY control registers
> > completion might be dangerous. Let's have the VStsDone flag utilized
> > instead then.
> >
> > [1] Synopsys DesignWare Cores SuperSpeed USB 3.0 xHCI Host Controller
> >     Databook, 2.70a, December 2013, p.388
> >
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/usb/dwc3/core.h | 1 +
> >  drivers/usb/dwc3/ulpi.c | 2 +-
> >  2 files changed, 2 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> > index 2f04b3e42bf1..8d5e5bba1bc2 100644
> > --- a/drivers/usb/dwc3/core.h
> > +++ b/drivers/usb/dwc3/core.h
> > @@ -284,6 +284,7 @@
> >  
> >  /* Global USB2 PHY Vendor Control Register */
> >  #define DWC3_GUSB2PHYACC_NEWREGREQ	BIT(25)
> > +#define DWC3_GUSB2PHYACC_DONE		BIT(24)
> >  #define DWC3_GUSB2PHYACC_BUSY		BIT(23)
> >  #define DWC3_GUSB2PHYACC_WRITE		BIT(22)
> >  #define DWC3_GUSB2PHYACC_ADDR(n)	(n << 16)
> > diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c
> > index e6e6176386a4..20f5d9aba317 100644
> > --- a/drivers/usb/dwc3/ulpi.c
> > +++ b/drivers/usb/dwc3/ulpi.c
> > @@ -24,7 +24,7 @@ static int dwc3_ulpi_busyloop(struct dwc3 *dwc)
> >  
> >  	while (count--) {
> >  		reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
> > -		if (!(reg & DWC3_GUSB2PHYACC_BUSY))
> > +		if (reg & DWC3_GUSB2PHYACC_DONE)
> 

> are you sure this works in all supported versions of the core?

I can't be sure about that since I've got only the 2.70a version of the
core. But as I said in the patch log it was a bit incorrect to use the
BUSY flag here in the first place. So if there is no IP core peculiarity
here which had been workarounded by polling the BUSY-flag, then I'd stick
with the DONE-flag in the busy-loop. In the former case I'd suggest to add
a useful comment why the BUSY-flag is required to be polled though...

-Sergey

> 
> John, could you confirm this for us?
> 
> thanks
> 
> -- 
> balbi