2022-04-10 18:22:33

by Kai-Heng Feng

[permalink] [raw]
Subject: [PATCH v4 1/2] PCI/AER: Disable AER service when link is in L2/L3 ready, L2 and L3 state

On Intel Alder Lake platforms, Thunderbolt entering D3cold can cause
some errors reported by AER:
[ 30.100211] pcieport 0000:00:1d.0: AER: Uncorrected (Non-Fatal) error received: 0000:00:1d.0
[ 30.100251] pcieport 0000:00:1d.0: PCIe Bus Error: severity=Uncorrected (Non-Fatal), type=Transaction Layer, (Requester ID)
[ 30.100256] pcieport 0000:00:1d.0: device [8086:7ab0] error status/mask=00100000/00004000
[ 30.100262] pcieport 0000:00:1d.0: [20] UnsupReq (First)
[ 30.100267] pcieport 0000:00:1d.0: AER: TLP Header: 34000000 08000052 00000000 00000000
[ 30.100372] thunderbolt 0000:0a:00.0: AER: can't recover (no error_detected callback)
[ 30.100401] xhci_hcd 0000:3e:00.0: AER: can't recover (no error_detected callback)
[ 30.100427] pcieport 0000:00:1d.0: AER: device recovery failed

So disable AER service to avoid the noises from turning power rails
on/off when the device is in low power states (D3hot and D3cold), as
PCIe Base Spec 5.0, section 5.2 "Link State Power Management" states
that TLP and DLLP transmission is disabled for a Link in L2/L3 Ready
(D3hot), L2 (D3cold with aux power) and L3 (D3cold).

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=215453
Reviewed-by: Mika Westerberg <[email protected]>
Signed-off-by: Kai-Heng Feng <[email protected]>
---
v4:
- Explicitly states the spec version.
- Wording change.

v3:
- Remove reference to ACS.
- Wording change.

v2:
- Wording change.

drivers/pci/pcie/aer.c | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 9fa1f97e5b270..e4e9d4a3098d7 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -1367,6 +1367,22 @@ static int aer_probe(struct pcie_device *dev)
return 0;
}

+static int aer_suspend(struct pcie_device *dev)
+{
+ struct aer_rpc *rpc = get_service_data(dev);
+
+ aer_disable_rootport(rpc);
+ return 0;
+}
+
+static int aer_resume(struct pcie_device *dev)
+{
+ struct aer_rpc *rpc = get_service_data(dev);
+
+ aer_enable_rootport(rpc);
+ return 0;
+}
+
/**
* aer_root_reset - reset Root Port hierarchy, RCEC, or RCiEP
* @dev: pointer to Root Port, RCEC, or RCiEP
@@ -1433,12 +1449,15 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
}

static struct pcie_port_service_driver aerdriver = {
- .name = "aer",
- .port_type = PCIE_ANY_PORT,
- .service = PCIE_PORT_SERVICE_AER,
-
- .probe = aer_probe,
- .remove = aer_remove,
+ .name = "aer",
+ .port_type = PCIE_ANY_PORT,
+ .service = PCIE_PORT_SERVICE_AER,
+ .probe = aer_probe,
+ .suspend = aer_suspend,
+ .resume = aer_resume,
+ .runtime_suspend = aer_suspend,
+ .runtime_resume = aer_resume,
+ .remove = aer_remove,
};

/**
--
2.34.1


2022-04-22 23:28:30

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v4 1/2] PCI/AER: Disable AER service when link is in L2/L3 ready, L2 and L3 state

[+cc Rajvi, David]

On Fri, Apr 08, 2022 at 11:31:58PM +0800, Kai-Heng Feng wrote:
> On Intel Alder Lake platforms, Thunderbolt entering D3cold can cause
> some errors reported by AER:
> [ 30.100211] pcieport 0000:00:1d.0: AER: Uncorrected (Non-Fatal) error received: 0000:00:1d.0
> [ 30.100251] pcieport 0000:00:1d.0: PCIe Bus Error: severity=Uncorrected (Non-Fatal), type=Transaction Layer, (Requester ID)
> [ 30.100256] pcieport 0000:00:1d.0: device [8086:7ab0] error status/mask=00100000/00004000
> [ 30.100262] pcieport 0000:00:1d.0: [20] UnsupReq (First)
> [ 30.100267] pcieport 0000:00:1d.0: AER: TLP Header: 34000000 08000052 00000000 00000000
> [ 30.100372] thunderbolt 0000:0a:00.0: AER: can't recover (no error_detected callback)
> [ 30.100401] xhci_hcd 0000:3e:00.0: AER: can't recover (no error_detected callback)
> [ 30.100427] pcieport 0000:00:1d.0: AER: device recovery failed
>
> So disable AER service to avoid the noises from turning power rails
> on/off when the device is in low power states (D3hot and D3cold), as
> PCIe Base Spec 5.0, section 5.2 "Link State Power Management" states
> that TLP and DLLP transmission is disabled for a Link in L2/L3 Ready
> (D3hot), L2 (D3cold with aux power) and L3 (D3cold).

Help me walk through what's happening here, because I'm never very
confident about how error reporting works. I *think* the Unsupported
Request error means some request was in progress and was not
completed. I don't think a link going down should by itself cause
an Unsupported Request error because there's no *request*.

I have a theory about what happened here. Decoding the TLP Header
(from PCIe r6.0, sec 2.2.1.1, 2.2.8.10) gives:

34000000 (0011 0100 ...):
Fmt 001 4 DW header, no data
Type 1 0100 Msg, Local - Terminate at Receiver

08000052 (0800 ... 0101 0010)
Requester ID 0800 00:08.0
Message Code 0101 0010 PTM Request

From your lspci in bugzilla, 08:00 has PTM enabled. So my theory is
that:

- 08:00.0 sent a PTM Request Message (a Posted Request)
- 00:1d.0 received the PTM Request Message
- The link transitioned to DL_Down
- Per sec 2.9.1, 00:1d.0 discarded the Request and reported an
Unsupported Request
- Or, per sec 6.21.3, if 00:1d.0 received a PTM Request when its
own PTM Enable was clear, it would also be treated as an
Unsupported Request

So I suspect we should disable PTM on 08:00.0 before putting it in a
low-power state. If you manually disable PTM on 08:00.0, do these
errors stop happening?

David did something like this [1], but just for Root Ports. That
looks wrong to me because sec 6.21.3 says we should not have PTM
enabled in an Upstream Port (i.e., in a downstream device like
08:00.0) unless it is already enabled in the Downstream Port (i.e., in
the Root Port 00:1d.0).

Nit: can you remove the timestamps from the log? They add clutter but
no useful information.

[1] https://git.kernel.org/linus/a697f072f5da

> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=215453
> Reviewed-by: Mika Westerberg <[email protected]>
> Signed-off-by: Kai-Heng Feng <[email protected]>
> ---
> v4:
> - Explicitly states the spec version.
> - Wording change.
>
> v3:
> - Remove reference to ACS.
> - Wording change.
>
> v2:
> - Wording change.
>
> drivers/pci/pcie/aer.c | 31 +++++++++++++++++++++++++------
> 1 file changed, 25 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index 9fa1f97e5b270..e4e9d4a3098d7 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -1367,6 +1367,22 @@ static int aer_probe(struct pcie_device *dev)
> return 0;
> }
>
> +static int aer_suspend(struct pcie_device *dev)
> +{
> + struct aer_rpc *rpc = get_service_data(dev);
> +
> + aer_disable_rootport(rpc);
> + return 0;
> +}
> +
> +static int aer_resume(struct pcie_device *dev)
> +{
> + struct aer_rpc *rpc = get_service_data(dev);
> +
> + aer_enable_rootport(rpc);
> + return 0;
> +}
> +
> /**
> * aer_root_reset - reset Root Port hierarchy, RCEC, or RCiEP
> * @dev: pointer to Root Port, RCEC, or RCiEP
> @@ -1433,12 +1449,15 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
> }
>
> static struct pcie_port_service_driver aerdriver = {
> - .name = "aer",
> - .port_type = PCIE_ANY_PORT,
> - .service = PCIE_PORT_SERVICE_AER,
> -
> - .probe = aer_probe,
> - .remove = aer_remove,
> + .name = "aer",
> + .port_type = PCIE_ANY_PORT,
> + .service = PCIE_PORT_SERVICE_AER,
> + .probe = aer_probe,
> + .suspend = aer_suspend,
> + .resume = aer_resume,
> + .runtime_suspend = aer_suspend,
> + .runtime_resume = aer_resume,
> + .remove = aer_remove,
> };
>
> /**
> --
> 2.34.1
>

2022-04-22 23:33:19

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v4 1/2] PCI/AER: Disable AER service when link is in L2/L3 ready, L2 and L3 state

[+cc Rafael, linux-pm; sorry forgot this last time]

On Fri, Apr 22, 2022 at 05:24:36PM -0500, Bjorn Helgaas wrote:
> On Fri, Apr 08, 2022 at 11:31:58PM +0800, Kai-Heng Feng wrote:
> > On Intel Alder Lake platforms, Thunderbolt entering D3cold can cause
> > some errors reported by AER:
> > [ 30.100211] pcieport 0000:00:1d.0: AER: Uncorrected (Non-Fatal) error received: 0000:00:1d.0
> > [ 30.100251] pcieport 0000:00:1d.0: PCIe Bus Error: severity=Uncorrected (Non-Fatal), type=Transaction Layer, (Requester ID)
> > [ 30.100256] pcieport 0000:00:1d.0: device [8086:7ab0] error status/mask=00100000/00004000
> > [ 30.100262] pcieport 0000:00:1d.0: [20] UnsupReq (First)
> > [ 30.100267] pcieport 0000:00:1d.0: AER: TLP Header: 34000000 08000052 00000000 00000000
> > [ 30.100372] thunderbolt 0000:0a:00.0: AER: can't recover (no error_detected callback)
> > [ 30.100401] xhci_hcd 0000:3e:00.0: AER: can't recover (no error_detected callback)
> > [ 30.100427] pcieport 0000:00:1d.0: AER: device recovery failed
> >
> > So disable AER service to avoid the noises from turning power rails
> > on/off when the device is in low power states (D3hot and D3cold), as
> > PCIe Base Spec 5.0, section 5.2 "Link State Power Management" states
> > that TLP and DLLP transmission is disabled for a Link in L2/L3 Ready
> > (D3hot), L2 (D3cold with aux power) and L3 (D3cold).
>
> Help me walk through what's happening here, because I'm never very
> confident about how error reporting works. I *think* the Unsupported
> Request error means some request was in progress and was not
> completed. I don't think a link going down should by itself cause
> an Unsupported Request error because there's no *request*.
>
> I have a theory about what happened here. Decoding the TLP Header
> (from PCIe r6.0, sec 2.2.1.1, 2.2.8.10) gives:
>
> 34000000 (0011 0100 ...):
> Fmt 001 4 DW header, no data
> Type 1 0100 Msg, Local - Terminate at Receiver
>
> 08000052 (0800 ... 0101 0010)
> Requester ID 0800 00:08.0
> Message Code 0101 0010 PTM Request
>
> From your lspci in bugzilla, 08:00 has PTM enabled. So my theory is
> that:
>
> - 08:00.0 sent a PTM Request Message (a Posted Request)
> - 00:1d.0 received the PTM Request Message
> - The link transitioned to DL_Down
> - Per sec 2.9.1, 00:1d.0 discarded the Request and reported an
> Unsupported Request
> - Or, per sec 6.21.3, if 00:1d.0 received a PTM Request when its
> own PTM Enable was clear, it would also be treated as an
> Unsupported Request
>
> So I suspect we should disable PTM on 08:00.0 before putting it in a
> low-power state. If you manually disable PTM on 08:00.0, do these
> errors stop happening?
>
> David did something like this [1], but just for Root Ports. That
> looks wrong to me because sec 6.21.3 says we should not have PTM
> enabled in an Upstream Port (i.e., in a downstream device like
> 08:00.0) unless it is already enabled in the Downstream Port (i.e., in
> the Root Port 00:1d.0).
>
> Nit: can you remove the timestamps from the log? They add clutter but
> no useful information.
>
> [1] https://git.kernel.org/linus/a697f072f5da
>
> > Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=215453
> > Reviewed-by: Mika Westerberg <[email protected]>
> > Signed-off-by: Kai-Heng Feng <[email protected]>
> > ---
> > v4:
> > - Explicitly states the spec version.
> > - Wording change.
> >
> > v3:
> > - Remove reference to ACS.
> > - Wording change.
> >
> > v2:
> > - Wording change.
> >
> > drivers/pci/pcie/aer.c | 31 +++++++++++++++++++++++++------
> > 1 file changed, 25 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> > index 9fa1f97e5b270..e4e9d4a3098d7 100644
> > --- a/drivers/pci/pcie/aer.c
> > +++ b/drivers/pci/pcie/aer.c
> > @@ -1367,6 +1367,22 @@ static int aer_probe(struct pcie_device *dev)
> > return 0;
> > }
> >
> > +static int aer_suspend(struct pcie_device *dev)
> > +{
> > + struct aer_rpc *rpc = get_service_data(dev);
> > +
> > + aer_disable_rootport(rpc);
> > + return 0;
> > +}
> > +
> > +static int aer_resume(struct pcie_device *dev)
> > +{
> > + struct aer_rpc *rpc = get_service_data(dev);
> > +
> > + aer_enable_rootport(rpc);
> > + return 0;
> > +}
> > +
> > /**
> > * aer_root_reset - reset Root Port hierarchy, RCEC, or RCiEP
> > * @dev: pointer to Root Port, RCEC, or RCiEP
> > @@ -1433,12 +1449,15 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
> > }
> >
> > static struct pcie_port_service_driver aerdriver = {
> > - .name = "aer",
> > - .port_type = PCIE_ANY_PORT,
> > - .service = PCIE_PORT_SERVICE_AER,
> > -
> > - .probe = aer_probe,
> > - .remove = aer_remove,
> > + .name = "aer",
> > + .port_type = PCIE_ANY_PORT,
> > + .service = PCIE_PORT_SERVICE_AER,
> > + .probe = aer_probe,
> > + .suspend = aer_suspend,
> > + .resume = aer_resume,
> > + .runtime_suspend = aer_suspend,
> > + .runtime_resume = aer_resume,
> > + .remove = aer_remove,
> > };
> >
> > /**
> > --
> > 2.34.1
> >

2022-07-01 04:30:39

by Kai-Heng Feng

[permalink] [raw]
Subject: Re: [PATCH v4 1/2] PCI/AER: Disable AER service when link is in L2/L3 ready, L2 and L3 state

On Sat, Apr 23, 2022 at 6:26 AM Bjorn Helgaas <[email protected]> wrote:
>
> [+cc Rafael, linux-pm; sorry forgot this last time]
>
> On Fri, Apr 22, 2022 at 05:24:36PM -0500, Bjorn Helgaas wrote:
> > On Fri, Apr 08, 2022 at 11:31:58PM +0800, Kai-Heng Feng wrote:
> > > On Intel Alder Lake platforms, Thunderbolt entering D3cold can cause
> > > some errors reported by AER:
> > > [ 30.100211] pcieport 0000:00:1d.0: AER: Uncorrected (Non-Fatal) error received: 0000:00:1d.0
> > > [ 30.100251] pcieport 0000:00:1d.0: PCIe Bus Error: severity=Uncorrected (Non-Fatal), type=Transaction Layer, (Requester ID)
> > > [ 30.100256] pcieport 0000:00:1d.0: device [8086:7ab0] error status/mask=00100000/00004000
> > > [ 30.100262] pcieport 0000:00:1d.0: [20] UnsupReq (First)
> > > [ 30.100267] pcieport 0000:00:1d.0: AER: TLP Header: 34000000 08000052 00000000 00000000
> > > [ 30.100372] thunderbolt 0000:0a:00.0: AER: can't recover (no error_detected callback)
> > > [ 30.100401] xhci_hcd 0000:3e:00.0: AER: can't recover (no error_detected callback)
> > > [ 30.100427] pcieport 0000:00:1d.0: AER: device recovery failed
> > >
> > > So disable AER service to avoid the noises from turning power rails
> > > on/off when the device is in low power states (D3hot and D3cold), as
> > > PCIe Base Spec 5.0, section 5.2 "Link State Power Management" states
> > > that TLP and DLLP transmission is disabled for a Link in L2/L3 Ready
> > > (D3hot), L2 (D3cold with aux power) and L3 (D3cold).
> >
> > Help me walk through what's happening here, because I'm never very
> > confident about how error reporting works. I *think* the Unsupported
> > Request error means some request was in progress and was not
> > completed. I don't think a link going down should by itself cause
> > an Unsupported Request error because there's no *request*.
> >
> > I have a theory about what happened here. Decoding the TLP Header
> > (from PCIe r6.0, sec 2.2.1.1, 2.2.8.10) gives:
> >
> > 34000000 (0011 0100 ...):
> > Fmt 001 4 DW header, no data
> > Type 1 0100 Msg, Local - Terminate at Receiver
> >
> > 08000052 (0800 ... 0101 0010)
> > Requester ID 0800 00:08.0
> > Message Code 0101 0010 PTM Request

Is there any TLP decoder software available? That will be really
helpful for debugging.

> >
> > From your lspci in bugzilla, 08:00 has PTM enabled. So my theory is
> > that:
> >
> > - 08:00.0 sent a PTM Request Message (a Posted Request)
> > - 00:1d.0 received the PTM Request Message
> > - The link transitioned to DL_Down
> > - Per sec 2.9.1, 00:1d.0 discarded the Request and reported an
> > Unsupported Request
> > - Or, per sec 6.21.3, if 00:1d.0 received a PTM Request when its
> > own PTM Enable was clear, it would also be treated as an
> > Unsupported Request
> >
> > So I suspect we should disable PTM on 08:00.0 before putting it in a
> > low-power state. If you manually disable PTM on 08:00.0, do these
> > errors stop happening?

Yes, disabling PTM on upstream port can solve the issue.
Thanks for find the root cause!

> >
> > David did something like this [1], but just for Root Ports. That
> > looks wrong to me because sec 6.21.3 says we should not have PTM
> > enabled in an Upstream Port (i.e., in a downstream device like
> > 08:00.0) unless it is already enabled in the Downstream Port (i.e., in
> > the Root Port 00:1d.0).

So I think it should be like this?
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index cfaf40a540a82..8ba8a0e12946e 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2717,7 +2717,8 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
* port to enter a lower-power PM state and the SoC to reach a
* lower-power idle state as a whole.
*/
- if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
+ if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
+ pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM)
pci_disable_ptm(dev);

pci_enable_wake(dev, target_state, wakeup);
@@ -2775,7 +2776,8 @@ int pci_finish_runtime_suspend(struct pci_dev *dev)
* port to enter a lower-power PM state and the SoC to reach a
* lower-power idle state as a whole.
*/
- if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
+ if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
+ pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM)
pci_disable_ptm(dev);

__pci_enable_wake(dev, target_state, pci_dev_run_wake(dev));


> >
> > Nit: can you remove the timestamps from the log? They add clutter but
> > no useful information.

Sure.

> >
> > [1] https://git.kernel.org/linus/a697f072f5da
> >
> > > Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=215453
> > > Reviewed-by: Mika Westerberg <[email protected]>
> > > Signed-off-by: Kai-Heng Feng <[email protected]>
> > > ---
> > > v4:
> > > - Explicitly states the spec version.
> > > - Wording change.
> > >
> > > v3:
> > > - Remove reference to ACS.
> > > - Wording change.
> > >
> > > v2:
> > > - Wording change.
> > >
> > > drivers/pci/pcie/aer.c | 31 +++++++++++++++++++++++++------
> > > 1 file changed, 25 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> > > index 9fa1f97e5b270..e4e9d4a3098d7 100644
> > > --- a/drivers/pci/pcie/aer.c
> > > +++ b/drivers/pci/pcie/aer.c
> > > @@ -1367,6 +1367,22 @@ static int aer_probe(struct pcie_device *dev)
> > > return 0;
> > > }
> > >
> > > +static int aer_suspend(struct pcie_device *dev)
> > > +{
> > > + struct aer_rpc *rpc = get_service_data(dev);
> > > +
> > > + aer_disable_rootport(rpc);
> > > + return 0;
> > > +}
> > > +
> > > +static int aer_resume(struct pcie_device *dev)
> > > +{
> > > + struct aer_rpc *rpc = get_service_data(dev);
> > > +
> > > + aer_enable_rootport(rpc);
> > > + return 0;
> > > +}
> > > +
> > > /**
> > > * aer_root_reset - reset Root Port hierarchy, RCEC, or RCiEP
> > > * @dev: pointer to Root Port, RCEC, or RCiEP
> > > @@ -1433,12 +1449,15 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
> > > }
> > >
> > > static struct pcie_port_service_driver aerdriver = {
> > > - .name = "aer",
> > > - .port_type = PCIE_ANY_PORT,
> > > - .service = PCIE_PORT_SERVICE_AER,
> > > -
> > > - .probe = aer_probe,
> > > - .remove = aer_remove,
> > > + .name = "aer",
> > > + .port_type = PCIE_ANY_PORT,
> > > + .service = PCIE_PORT_SERVICE_AER,
> > > + .probe = aer_probe,
> > > + .suspend = aer_suspend,
> > > + .resume = aer_resume,
> > > + .runtime_suspend = aer_suspend,
> > > + .runtime_resume = aer_resume,
> > > + .remove = aer_remove,
> > > };
> > >
> > > /**
> > > --
> > > 2.34.1
> > >