2020-08-31 06:54:58

by Shah, Nehal-bakulchandra

[permalink] [raw]
Subject: [PATCH] xhci: workaround for S3 issue on AMD SNPS 3.0 xHC

From: Nehal Bakulchandra Shah <[email protected]>

On some platform of AMD, S3 fails with HCE and SRE errors.To fix this,
sparse controller enable bit has to be disabled.

Signed-off-by: Nehal Bakulchandra Shah <[email protected]>
---
drivers/usb/host/xhci-pci.c | 12 ++++++++++++
drivers/usb/host/xhci.h | 1 +
2 files changed, 13 insertions(+)

diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 3feaafebfe58..865a16e6c1ed 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -160,6 +160,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
(pdev->device == 0x15e0 || pdev->device == 0x15e1))
xhci->quirks |= XHCI_SNPS_BROKEN_SUSPEND;

+ if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x15e5)
+ xhci->quirks |= XHCI_DISABLE_SPARSE;
+
if (pdev->vendor == PCI_VENDOR_ID_AMD)
xhci->quirks |= XHCI_TRUST_TX_LENGTH;

@@ -371,6 +374,15 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
/* USB 2.0 roothub is stored in the PCI device now. */
hcd = dev_get_drvdata(&dev->dev);
xhci = hcd_to_xhci(hcd);
+
+ if (xhci->quirks & XHCI_DISABLE_SPARSE) {
+ u32 reg;
+
+ reg = readl(hcd->regs + 0xC12C);
+ reg &= ~BIT(17);
+ writel(reg, hcd->regs + 0xC12C);
+ }
+
xhci->shared_hcd = usb_create_shared_hcd(&xhci_pci_hc_driver, &dev->dev,
pci_name(dev), hcd);
if (!xhci->shared_hcd) {
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index ea1754f185a2..ea966d70f1ee 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1874,6 +1874,7 @@ struct xhci_hcd {
#define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
#define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
#define XHCI_RENESAS_FW_QUIRK BIT_ULL(36)
+#define XHCI_DISABLE_SPARSE BIT_ULL(37)

unsigned int num_active_eps;
unsigned int limit_active_eps;
--
2.25.1


2020-09-16 08:06:39

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH] xhci: workaround for S3 issue on AMD SNPS 3.0 xHC

On Mon, Aug 31, 2020 at 06:52:46AM +0000, Nehal Bakulchandra Shah wrote:
> From: Nehal Bakulchandra Shah <[email protected]>
>
> On some platform of AMD, S3 fails with HCE and SRE errors.To fix this,
> sparse controller enable bit has to be disabled.
>
> Signed-off-by: Nehal Bakulchandra Shah <[email protected]>
> ---
> drivers/usb/host/xhci-pci.c | 12 ++++++++++++
> drivers/usb/host/xhci.h | 1 +
> 2 files changed, 13 insertions(+)
>
> diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
> index 3feaafebfe58..865a16e6c1ed 100644
> --- a/drivers/usb/host/xhci-pci.c
> +++ b/drivers/usb/host/xhci-pci.c
> @@ -160,6 +160,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
> (pdev->device == 0x15e0 || pdev->device == 0x15e1))
> xhci->quirks |= XHCI_SNPS_BROKEN_SUSPEND;
>
> + if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x15e5)
> + xhci->quirks |= XHCI_DISABLE_SPARSE;
> +
> if (pdev->vendor == PCI_VENDOR_ID_AMD)
> xhci->quirks |= XHCI_TRUST_TX_LENGTH;
>
> @@ -371,6 +374,15 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
> /* USB 2.0 roothub is stored in the PCI device now. */
> hcd = dev_get_drvdata(&dev->dev);
> xhci = hcd_to_xhci(hcd);
> +
> + if (xhci->quirks & XHCI_DISABLE_SPARSE) {
> + u32 reg;
> +
> + reg = readl(hcd->regs + 0xC12C);
> + reg &= ~BIT(17);

Odd spacing :(

Anyway, what is magic bit 17? Shouldn't that be documented somewhere?

And you forgot to handle endian issues here, right?

> + writel(reg, hcd->regs + 0xC12C);

Same for this magic address, shouldn't you document that here please?

And is this the proper place to be testing for quirks and applying them?
Why not do the above in the xhci_pci_quirks() call?

thanks,

greg k-h

2020-09-16 08:06:59

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH] xhci: workaround for S3 issue on AMD SNPS 3.0 xHC

On Wed, Sep 16, 2020 at 12:28:40AM +0530, Singh, Sandeep wrote:
> On 8/31/2020 12:22 PM, Nehal Bakulchandra Shah wrote:
> > From: Nehal Bakulchandra Shah <[email protected]>
> >
> > On some platform of AMD, S3 fails with HCE and SRE errors.To fix this,
> > sparse controller enable bit has to be disabled.
> >
> > Signed-off-by: Nehal Bakulchandra Shah <[email protected]>
> > ---
> > drivers/usb/host/xhci-pci.c | 12 ++++++++++++
> > drivers/usb/host/xhci.h | 1 +
> > 2 files changed, 13 insertions(+)
> >
> > diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
> > index 3feaafebfe58..865a16e6c1ed 100644
> > --- a/drivers/usb/host/xhci-pci.c
> > +++ b/drivers/usb/host/xhci-pci.c
> > @@ -160,6 +160,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
> > (pdev->device == 0x15e0 || pdev->device == 0x15e1))
> > xhci->quirks |= XHCI_SNPS_BROKEN_SUSPEND;
> > + if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x15e5)
> > + xhci->quirks |= XHCI_DISABLE_SPARSE;
> > +
> > if (pdev->vendor == PCI_VENDOR_ID_AMD)
> > xhci->quirks |= XHCI_TRUST_TX_LENGTH;
> > @@ -371,6 +374,15 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
> > /* USB 2.0 roothub is stored in the PCI device now. */
> > hcd = dev_get_drvdata(&dev->dev);
> > xhci = hcd_to_xhci(hcd);
> > +
> > + if (xhci->quirks & XHCI_DISABLE_SPARSE) {
> > + u32 reg;
> > +
> > + reg = readl(hcd->regs + 0xC12C);
> > + reg &= ~BIT(17);
> > + writel(reg, hcd->regs + 0xC12C);
> > + }
> > +
> > xhci->shared_hcd = usb_create_shared_hcd(&xhci_pci_hc_driver, &dev->dev,
> > pci_name(dev), hcd);
> > if (!xhci->shared_hcd) {
> > diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> > index ea1754f185a2..ea966d70f1ee 100644
> > --- a/drivers/usb/host/xhci.h
> > +++ b/drivers/usb/host/xhci.h
> > @@ -1874,6 +1874,7 @@ struct xhci_hcd {
> > #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
> > #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
> > #define XHCI_RENESAS_FW_QUIRK BIT_ULL(36)
> > +#define XHCI_DISABLE_SPARSE BIT_ULL(37)
> > unsigned int num_active_eps;
> > unsigned int limit_active_eps;
>
> Any feedback on this patch?

Do you agree with it? If so, can you review it and say so please?

thanks,

greg k-h

2020-09-16 14:17:30

by Mathias Nyman

[permalink] [raw]
Subject: Re: [PATCH] xhci: workaround for S3 issue on AMD SNPS 3.0 xHC

On 16.9.2020 11.06, Greg KH wrote:
> On Mon, Aug 31, 2020 at 06:52:46AM +0000, Nehal Bakulchandra Shah wrote:
>> From: Nehal Bakulchandra Shah <[email protected]>
>>
>> On some platform of AMD, S3 fails with HCE and SRE errors.To fix this,
>> sparse controller enable bit has to be disabled.
>>
>> Signed-off-by: Nehal Bakulchandra Shah <[email protected]>
>> ---
>> drivers/usb/host/xhci-pci.c | 12 ++++++++++++
>> drivers/usb/host/xhci.h | 1 +
>> 2 files changed, 13 insertions(+)
>>
>> diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
>> @@ -371,6 +374,15 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
>> /* USB 2.0 roothub is stored in the PCI device now. */
>> hcd = dev_get_drvdata(&dev->dev);
>> xhci = hcd_to_xhci(hcd);
>> +
>> + if (xhci->quirks & XHCI_DISABLE_SPARSE) {
>> + u32 reg;
>> +
>> + reg = readl(hcd->regs + 0xC12C);
>> + reg &= ~BIT(17);
>
> And is this the proper place to be testing for quirks and applying them?
> Why not do the above in the xhci_pci_quirks() call?

xhci_pci_quirks() is a confusing name, it actually only sets quirk flags based on PCI
vendor/device.

Anyway, point is still valid, this level of bitops in probe isn't very nice.
Turn it into a separate function, and call it from xhci_pci_setup(), or if flag
needs to be cleared more often, and is related to S3 problems then possibly from xhci_pci_suspend()

-Mathias

2020-09-16 20:39:57

by Mathias Nyman

[permalink] [raw]
Subject: Re: [PATCH] xhci: workaround for S3 issue on AMD SNPS 3.0 xHC

On 31.8.2020 9.52, Nehal Bakulchandra Shah wrote:
> From: Nehal Bakulchandra Shah <[email protected]>
>
> On some platform of AMD, S3 fails with HCE and SRE errors.To fix this,
> sparse controller enable bit has to be disabled.
>
> Signed-off-by: Nehal Bakulchandra Shah <[email protected]>
> ---
> drivers/usb/host/xhci-pci.c | 12 ++++++++++++
> drivers/usb/host/xhci.h | 1 +
> 2 files changed, 13 insertions(+)
>
> diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
> index 3feaafebfe58..865a16e6c1ed 100644
> --- a/drivers/usb/host/xhci-pci.c
> +++ b/drivers/usb/host/xhci-pci.c
> @@ -160,6 +160,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
> (pdev->device == 0x15e0 || pdev->device == 0x15e1))
> xhci->quirks |= XHCI_SNPS_BROKEN_SUSPEND;
>
> + if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x15e5)
> + xhci->quirks |= XHCI_DISABLE_SPARSE;
> +
> if (pdev->vendor == PCI_VENDOR_ID_AMD)
> xhci->quirks |= XHCI_TRUST_TX_LENGTH;
>
> @@ -371,6 +374,15 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
> /* USB 2.0 roothub is stored in the PCI device now. */
> hcd = dev_get_drvdata(&dev->dev);
> xhci = hcd_to_xhci(hcd);
> +
> + if (xhci->quirks & XHCI_DISABLE_SPARSE) {
> + u32 reg;
> +
> + reg = readl(hcd->regs + 0xC12C);
> + reg &= ~BIT(17);
> + writel(reg, hcd->regs + 0xC12C);
> + }
> +

Is disabling the bit once in probe enough?
xHC will be reset after hibernation as well, does this bit need to be cleared after that?

Also consider turning this into a separate function with a proper description,
see xhci_pme_quirk() for example. Avoids cluttering probe.
Actually if this bit only needs to be cleared once then that function could be called from xhci_pci_setup()

-Mathias