PCIe r7.1 sec 6.2.1 defines two error reporting paradigms:  Baseline
capability and Advanced Error Reporting Extended Capability (AER).

So far the kernel only supports the AER paradigm.  Enable the baseline
capability paradigm to complete the kernel's support for error reporting.

Baseline capability (solely) relies on the error enable/status bits in the
Device Control and Device Status registers, which exist on every PCIe
device.  One difference between baseline capability and AER is that the
severity of Uncorrectable Errors cannot be controlled.  Another difference
is that Advisory Non-Fatal Errors are not reported at all (PCIe r7.1 sec
6.2.5).

But the main difference to AER is that no detailed error information is
available:  It is only known that an error occurred and which severity it
had, but not its type or the Prefix / Header of the TLP that caused it.
An exception are Unsupported Request Errors which are signaled with a
dedicated bit in the Device Status register.  Report these as if the
Unsupported Request Error Status bit in the Uncorrectable Error Status
register was set, for consistency with the AER paradigm.

Error recovery works the same for baseline capability as it already does
for AER:  Drivers are informed about errors through the pci_error_handlers
callbacks.  Recovery from Fatal Errors (and from Non-Fatal Errors, if
chosen by drivers) is attempted through a Secondary Bus Reset.

Similarly to commit f26e58bf6f54 ("PCI/AER: Enable error reporting when
AER is native"), which universally enabled error reporting on AER-capable
devices, the present commit is invasive because it universally enables
error reporting on non-AER-capable devices.  Previously those errors were
neither reported nor recovered.  It may be necessary to amend more drivers
with pci_error_handlers callbacks to recover from newly reported errors.

Baseline capability is only enabled if firmware grants AER control to the
operating system.  Otherwise firmware owns the error enable/status bits in
the Device Control and Device Status registers (PCI Firmware r3.3 table
4-6 bit 3).

Baseline capability support is initially only implemented for native error
handling, not Firmware First error handling:  ghes_handle_aer() would have
to be amended to pass the Device Control and Device Status registers to
aer_recover_queue(), and to only pass an AER capability structure if it is
present in the CPER record.  It's not clear whether any firmware actually
generates such CPER records and whether implementing support for it is
worthwhile, so postpone that for now.

Suggested-by: Bjorn Helgaas <[email protected]>
Link: https://lore.kernel.org/r/20260826212619.GA1566339@bhelgaas/
Signed-off-by: Lukas Wunner <[email protected]>
---
 .../ABI/testing/sysfs-bus-pci-devices-aer     | 26 ++++++++----
 Documentation/PCI/pcieaer-howto.rst           |  9 ++--
 drivers/pci/pcie/aer.c                        | 42 ++++++++++++-------
 drivers/pci/pcie/dpc.c                        |  2 +-
 4 files changed, 50 insertions(+), 29 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-aer 
b/Documentation/ABI/testing/sysfs-bus-pci-devices-aer
index 5ed284523956..9e772e1ed9b3 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci-devices-aer
+++ b/Documentation/ABI/testing/sysfs-bus-pci-devices-aer
@@ -1,9 +1,9 @@
 PCIe Device AER statistics
 --------------------------
 
-These attributes show up under all the devices that are AER capable. These
+These attributes show up under all PCIe devices (AER capable or not). These
 statistical counters indicate the errors "as seen/reported by the device".
-Note that this may mean that if an endpoint is causing problems, the AER
+Note that this may mean that if an endpoint is causing problems, the error
 counters may increment at its link partner (e.g. root port) because the
 errors may be "seen" / reported by the link partner and not the
 problematic endpoint itself (which may report all counters as 0 as it never
@@ -17,7 +17,10 @@ Description: List of correctable errors seen and reported by 
this
                PCI device using ERR_COR. Note that since multiple errors may
                be reported using a single ERR_COR message, thus
                TOTAL_ERR_COR at the end of the file may not match the actual
-               total of all the errors in the file. Sample output::
+               total of all the errors in the file.
+               For PCIe devices without AER Extended Capability, only the
+               total counter is meaningful while all other counters remain 0.
+               Sample output::
 
                    localhost /sys/devices/pci0000:00/0000:00:1c.0 # cat 
aer_dev_correctable
                    Receiver Error 2
@@ -38,7 +41,10 @@ Description: List of uncorrectable fatal errors seen and 
reported by this
                PCI device using ERR_FATAL. Note that since multiple errors may
                be reported using a single ERR_FATAL message, thus
                TOTAL_ERR_FATAL at the end of the file may not match the actual
-               total of all the errors in the file. Sample output::
+               total of all the errors in the file.
+               For PCIe devices without AER Extended Capability, only the
+               total counter is meaningful while all other counters remain 0.
+               Sample output::
 
                    localhost /sys/devices/pci0000:00/0000:00:1c.0 # cat 
aer_dev_fatal
                    Undefined 0
@@ -68,7 +74,11 @@ Description: List of uncorrectable nonfatal errors seen and 
reported by this
                PCI device using ERR_NONFATAL. Note that since multiple errors
                may be reported using a single ERR_FATAL message, thus
                TOTAL_ERR_NONFATAL at the end of the file may not match the
-               actual total of all the errors in the file. Sample output::
+               actual total of all the errors in the file.
+               For PCIe devices without AER Extended Capability, only the
+               total counter and the Unsupported Request counter is meaningful
+               while all other counters remain 0.
+               Sample output::
 
                    localhost /sys/devices/pci0000:00/0000:00:1c.0 # cat 
aer_dev_nonfatal
                    Undefined 0
@@ -121,7 +131,7 @@ Description:        Total number of ERR_NONFATAL messages 
reported to rootport.
 PCIe AER ratelimits
 -------------------
 
-These attributes show up under all the devices that are AER capable.
+These attributes show up under all PCIe devices (AER capable or not).
 They represent configurable ratelimits of logs per error type.
 
 See Documentation/PCI/pcieaer-howto.rst for more info on ratelimits.
@@ -130,7 +140,7 @@ What:               
/sys/bus/pci/devices/<dev>/aer/correctable_ratelimit_interval_ms
 Date:          May 2025
 KernelVersion: 6.16.0
 Contact:       [email protected]
-Description:   Writing 0 disables AER correctable error log ratelimiting.
+Description:   Writing 0 disables Correctable Error log ratelimiting.
                Writing a positive value sets the ratelimit interval in ms.
                Default is DEFAULT_RATELIMIT_INTERVAL (5000 ms).
 
@@ -147,7 +157,7 @@ What:               
/sys/bus/pci/devices/<dev>/aer/nonfatal_ratelimit_interval_ms
 Date:          May 2025
 KernelVersion: 6.16.0
 Contact:       [email protected]
-Description:   Writing 0 disables AER non-fatal uncorrectable error log
+Description:   Writing 0 disables Non-Fatal Uncorrectable Error log
                ratelimiting. Writing a positive value sets the ratelimit
                interval in ms. Default is DEFAULT_RATELIMIT_INTERVAL
                (5000 ms).
diff --git a/Documentation/PCI/pcieaer-howto.rst 
b/Documentation/PCI/pcieaer-howto.rst
index 90fdfddd3ae5..e969e563b61d 100644
--- a/Documentation/PCI/pcieaer-howto.rst
+++ b/Documentation/PCI/pcieaer-howto.rst
@@ -34,9 +34,8 @@ set of error reporting requirements. Advanced Error Reporting
 capability is implemented with a PCIe Advanced Error Reporting
 extended capability structure providing more robust error reporting.
 
-The PCIe AER driver provides the infrastructure to support PCIe Advanced
-Error Reporting capability. The PCIe AER driver provides three basic
-functions:
+The PCIe AER driver provides the infrastructure to support both paradigms.
+It provides three basic functions:
 
   - Gathers the comprehensive error information if errors occurred.
   - Reports error to the users.
@@ -69,7 +68,7 @@ Specification for details regarding _OSC usage.
 AER error output
 ----------------
 
-When a PCIe AER error is captured, an error message will be output to
+When a PCIe error is captured, an error message will be output to
 console. If it's a correctable error, it is output as a warning message.
 Otherwise, it is printed as an error. So users could choose different
 log level to filter out correctable error messages.
@@ -113,7 +112,7 @@ See Documentation/ABI/testing/sysfs-bus-pci-devices-aer.
 AER Statistics / Counters
 -------------------------
 
-When PCIe AER errors are captured, the counters / statistics are also exposed
+When PCIe errors are captured, the counters / statistics are also exposed
 in the form of sysfs attributes which are documented at
 Documentation/ABI/testing/sysfs-bus-pci-devices-aer.
 
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 6bc843ab9b37..62376aab4b6f 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -397,21 +397,22 @@ void pci_aer_init(struct pci_dev *dev)
 {
        int n;
 
-       dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
-       if (!dev->aer_cap)
+       if (!pci_is_pcie(dev))
                return;
 
        dev->aer_info = kzalloc_obj(*dev->aer_info);
-       if (!dev->aer_info) {
-               dev->aer_cap = 0;
+       if (!dev->aer_info)
                return;
-       }
 
        ratelimit_state_init(&dev->aer_info->correctable_ratelimit,
                             DEFAULT_RATELIMIT_INTERVAL, 
DEFAULT_RATELIMIT_BURST);
        ratelimit_state_init(&dev->aer_info->nonfatal_ratelimit,
                             DEFAULT_RATELIMIT_INTERVAL, 
DEFAULT_RATELIMIT_BURST);
 
+       dev->aer_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+       if (!dev->aer_cap)
+               goto enable;
+
        /*
         * We save/restore PCI_ERR_UNCOR_MASK, PCI_ERR_UNCOR_SEVER,
         * PCI_ERR_COR_MASK, and PCI_ERR_CAP.  Root and Root Complex Event
@@ -431,6 +432,9 @@ void pci_aer_init(struct pci_dev *dev)
                                               PCI_ERR_COR_ADV_NFAT, 0);
 
        pci_aer_clear_status(dev);
+enable:
+       if (pcie_aer_is_native(dev))
+               pcie_clear_device_status(dev);
 
        if (pci_aer_available())
                pci_enable_pcie_error_reporting(dev);
@@ -980,15 +984,12 @@ void aer_print_error(struct aer_err_info *info, int i)
        if (!info->ratelimit_print[i])
                goto anfe;
 
-       if (!info->status) {
-               pci_err(dev, "%s Bus Error: severity=%s (Inaccessible)\n",
-                       bus_type, aer_error_severity_string[info->severity]);
-               return;
-       }
-
        aer_printk(level, dev, "%s Bus Error: severity=%s\n",
                   bus_type, aer_error_severity_string[info->severity]);
 
+       if (!info->status)
+               return;
+
        aer_printk(level, dev, "  device [%04x:%04x] error 
status/mask=%08x/%08x\n",
                   dev->vendor, dev->device, info->status, info->mask);
 
@@ -1182,8 +1183,11 @@ static bool is_error_source(struct pci_dev *dev, struct 
aer_err_info *e_info)
        if (!(reg16 & PCI_EXP_AER_FLAGS))
                return false;
 
-       if (!aer)
-               return false;
+       if (!aer) {
+               pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &reg16);
+               return reg16 & BIT(e_info->severity) &&
+                      !PCI_POSSIBLE_ERROR(reg16);
+       }
 
        /* Check if error is recorded */
        if (e_info->severity == AER_CORRECTABLE) {
@@ -1455,6 +1459,7 @@ int aer_get_device_error_info(struct aer_err_info *info, 
int i)
 {
        struct pci_dev *dev;
        int type, aer;
+       u16 devsta;
 
        if (i >= AER_MAX_MULTI_ERR_DEVICES)
                return 0;
@@ -1470,8 +1475,15 @@ int aer_get_device_error_info(struct aer_err_info *info, 
int i)
        info->is_cxl = pcie_is_cxl(dev);
 
        /* The device might not support AER */
-       if (!aer)
-               return 0;
+       if (!aer) {
+               if (info->severity != AER_CORRECTABLE) {
+                       pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &devsta);
+                       if (devsta & PCI_EXP_DEVSTA_URD &&
+                           !PCI_POSSIBLE_ERROR(devsta))
+                               info->status = PCI_ERR_UNC_UNSUP;
+               }
+               return 1;
+       }
 
        if (info->severity == AER_CORRECTABLE) {
                pci_read_config_dword(dev, aer + PCI_ERR_COR_STATUS,
diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c
index 104ff2b91f1f..fdea3db61a4a 100644
--- a/drivers/pci/pcie/dpc.c
+++ b/drivers/pci/pcie/dpc.c
@@ -269,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) || !pdev->aer_cap)) {
+                   aer_get_device_error_info(&info, 0)) {
                        aer_print_error(&info, 0);
                        pci_aer_clear_nonfatal_status(pdev);
                        pci_aer_clear_fatal_status(pdev);
-- 
2.53.0


Reply via email to