On 9/27/2026 11:02 AM, Lukas Wunner wrote:
> Downstream Port Containment does not mandate presence of an Advanced Error
> Reporting capability, so a Downstream Port may support DPC, but not AER
> (PCIe r7.1 sec 6.2.11.2).
> 
> In February 2019, commit 9f08a5d896ce ("PCI/DPC: Fix print AER status in
> DPC event handling") amended the DPC driver to access the AER capability
> without checking for its presence.
> 
> In May 2020, commit 708b20003624 ("PCI/AER: Remove HEST/FIRMWARE_FIRST
> parsing for AER ownership") fixed it by inserting a call to
> pcie_aer_is_native() in dpc_probe(), which implicitly checks for presence
> of an AER capability.
> 
> However already in October 2019, commit 35a0b2378c19 ("PCI/DPC: Add
> "pcie_ports=dpc-native" to allow DPC without AER control") made it
> possible to override the check:  The DPC driver may access a non-existent
> AER capability if "pcie_ports=dpc-native" is passed on the command line.
> 
> Fix it by making the DPC driver cope with AER-unsupporting Downstream
> Ports.
> 
> There are two places where the AER capability is accessed:
> 
> - dpc_get_aer_uncorrect_severity() uses it to discern whether a Fatal or
>   Non-Fatal Error triggered DPC.  Access the Device Status Register
>   instead, in accordance with PCIe r7.1 sec 6.2.5.

This changes behavior not only for AER-incapable ports, but also for
the AER-capable ones.  PCIe r7.1 sec 7.5.3.5 says for the Fatal/
Non-Fatal Error Detected bits:

  "For Functions supporting Advanced Error Handling, errors are logged
   in this register regardless of the settings of the Uncorrectable
   Error Mask register."

The old code only considered unmasked errors, the new code also picks
up masked ones.  So a masked Fatal error (e.g. Surprise Down) alongside
the unmasked Non-Fatal error which triggered DPC is now reported as
Fatal.  Stale bits from earlier masked errors can have the same effect.

Since this is tagged for stable, how about keeping the AER-based logic
when dev->aer_cap is present and using DEVSTA only as a fallback?

> 
> - dpc_is_surprise_removal() uses it to detect whether a Surprise Down
>   Error triggered DPC.  Return false on AER-unsupporting devices.  The
>   function works around an AMD-specific quirk and it seems reasonable to
>   assume that all affected products are AER-supporting.  In any case the
>   detection is not possible without AER capability.
> 
> Insert a temporary check for an AER capability after the call to
> aer_get_device_error_info() because the function currently returns false
> for AER-unsupporting devices.  The check will become obsolete and will be
> removed with the imminent baseline capability error reporting.
> 
> Fixes: 35a0b2378c19 ("PCI/DPC: Add "pcie_ports=dpc-native" to allow DPC 
> without AER control")
> Signed-off-by: Lukas Wunner <[email protected]>
> Cc: [email protected] # v5.5+
> ---
>  drivers/pci/pcie/dpc.c | 23 ++++++++++-------------
>  1 file changed, 10 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c
> index 2b779bd1d861..793a799053f1 100644
> --- a/drivers/pci/pcie/dpc.c
> +++ b/drivers/pci/pcie/dpc.c
> @@ -236,21 +236,15 @@ static void dpc_process_rp_pio_error(struct pci_dev 
> *pdev)
>  static int dpc_get_aer_uncorrect_severity(struct pci_dev *dev,
>                                         struct aer_err_info *info)
>  {
> -     int pos = dev->aer_cap;
> -     u32 status, mask, sev;
> +     u16 devsta;
>  
> -     pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
> -     pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &mask);
> -     status &= ~mask;
> -     if (!status)
> -             return 0;
> -
> -     pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &sev);
> -     status &= sev;
> -     if (status)
> +     pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &devsta);
> +     if (devsta & PCI_EXP_DEVSTA_FED)
>               info->severity = AER_FATAL;
> -     else
> +     else if (devsta & PCI_EXP_DEVSTA_NFED)
>               info->severity = AER_NONFATAL;
> +     else
> +             return 0;
>  
>       info->level = KERN_ERR;
>  
> @@ -275,7 +269,7 @@ void dpc_process_error(struct pci_dev *pdev)
>               pci_warn(pdev, "containment event, status:%#06x: unmasked 
> uncorrectable error detected\n",
>                        status);
>               if (dpc_get_aer_uncorrect_severity(pdev, &info) &&
> -                 aer_get_device_error_info(&info, 0)) {
> +                 (aer_get_device_error_info(&info, 0) || !pdev->aer_cap)) {
>                       aer_print_error(&info, 0);
>                       pci_aer_clear_nonfatal_status(pdev);
>                       pci_aer_clear_fatal_status(pdev);
> @@ -353,6 +347,9 @@ static bool dpc_is_surprise_removal(struct pci_dev *pdev)
>       if (!pdev->is_hotplug_bridge)
>               return false;
>  
> +     if (!pdev->aer_cap)
> +             return false;
> +
>       if (pci_read_config_word(pdev, pdev->aer_cap + PCI_ERR_UNCOR_STATUS,
>                                &status))
>               return false;

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


Reply via email to