[PATCH v3 1/2] PCI: Add pci=noaer_recovery kernel boot option
From: Yury Murashka
Date: Thu Oct 22 2026 - 13:00:20 EST
On large modular systems with a complex PCIe topology, allow userspace to
inspect uncorrectable AER errors before Linux attempts recovery.
Add pci=noaer_recovery to retain AER logging while skipping recovery for
uncorrectable errors. Check the option before dispatching either CXL RCH
internal errors or ordinary PCIe errors so CXL driver error callbacks
cannot bypass it. Also skip recovery for errors reported through GHES,
while retaining error logging and releasing error buffers and device
references.
Correctable errors continue to be handled normally. Skipping recovery
avoids its clearing of uncorrectable error status, but does not suppress
Root Port interrupt acknowledgment or change firmware error handling.
The option is AER-specific and does not disable DPC recovery.
Signed-off-by: Yury Murashka <yurypm@xxxxxxxxxx>
---
Changes in v3:
- Check the option before both CXL RCH and ordinary PCIe error dispatch.
- Preserve logging, correctable handling, and current GHES cleanup.
- Clarify the AER-only scope and rebase onto PCI next.
v2: https://lore.kernel.org/linux-pci/20260709185429.627968-2-yurypm@xxxxxxxxxx/
Review: https://lore.kernel.org/linux-pci/20260709190616.DF0CF1F000E9@xxxxxxxxxxxxxxx/
Documentation/admin-guide/kernel-parameters.txt | 5 +++++
drivers/pci/pci.c | 2 ++
drivers/pci/pci.h | 2 ++
drivers/pci/pcie/aer.c | 13 +++++++++++--
4 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 68647ff4b..6047efd3c 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -5118,6 +5118,11 @@ Kernel parameters
noaer [PCIE] If the PCIEAER kernel config parameter is
enabled, this kernel boot option can be used to
disable the use of PCIE advanced error reporting.
+ noaer_recovery [PCIE] Disable Linux AER recovery for
+ uncorrectable errors, including CXL RCH errors,
+ while retaining AER logging. Correctable errors
+ are handled normally. Requires CONFIG_PCIEAER.
+ Does not disable DPC or firmware error recovery.
nodomains [PCI] Disable support for multiple PCI
root domains (aka PCI segments, in ACPI-speak).
nommconf [X86] Disable use of MMCONFIG for PCI
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a62af7320..9ca8d3fbb 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -6840,6 +6840,8 @@ static int __init pci_setup(char *str)
pcie_ats_disabled = true;
} else if (!strcmp(str, "noaer")) {
pci_no_aer();
+ } else if (!strcmp(str, "noaer_recovery")) {
+ pci_no_aer_recovery();
} else if (!strcmp(str, "earlydump")) {
pci_early_dump = true;
} else if (!strncmp(str, "realloc=", 8)) {
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 77efa4c5c..ccc6a678c 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1337,6 +1337,7 @@ static inline void of_pci_remove_host_bridge_node(struct pci_host_bridge *bridge
#ifdef CONFIG_PCIEAER
void pci_no_aer(void);
+void pci_no_aer_recovery(void);
void pci_aer_init(struct pci_dev *dev);
void pci_aer_exit(struct pci_dev *dev);
extern const struct attribute_group aer_stats_attr_group;
@@ -1348,6 +1349,7 @@ void pci_save_aer_state(struct pci_dev *dev);
void pci_restore_aer_state(struct pci_dev *dev);
#else
static inline void pci_no_aer(void) { }
+static inline void pci_no_aer_recovery(void) { }
static inline void pci_aer_init(struct pci_dev *d) { }
static inline void pci_aer_exit(struct pci_dev *d) { }
static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index c376c3adb..c41e5e13f 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -142,6 +142,7 @@ struct aer_info {
PCI_ERR_ROOT_MULTI_UNCOR_RCV)
static bool pcie_aer_disable;
+static bool pcie_aer_recovery_disable;
static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
void pci_no_aer(void)
@@ -149,6 +150,11 @@ void pci_no_aer(void)
pcie_aer_disable = true;
}
+void pci_no_aer_recovery(void)
+{
+ pcie_aer_recovery_disable = true;
+}
+
bool pci_aer_available(void)
{
return !pcie_aer_disable && pci_msi_enabled();
@@ -1338,6 +1344,9 @@ static void pci_aer_handle_error(struct pci_dev *dev, struct aer_err_info *info)
static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info)
{
+ if (pcie_aer_recovery_disable && info->severity != AER_CORRECTABLE)
+ return;
+
cxl_rch_handle_error(dev, info);
pci_aer_handle_error(dev, info);
}
@@ -1383,15 +1392,15 @@ static void aer_recover_work_func(struct work_struct *work)
ghes_estatus_pool_region_free((unsigned long)entry.regs,
sizeof(struct aer_capability_regs));
- if (pdev) {
+ if (pdev && !pcie_aer_recovery_disable) {
if (entry.severity == AER_NONFATAL)
pcie_do_recovery(pdev, pci_channel_io_normal,
aer_root_reset);
else if (entry.severity == AER_FATAL)
pcie_do_recovery(pdev, pci_channel_io_frozen,
aer_root_reset);
- pci_dev_put(pdev);
}
+ pci_dev_put(pdev);
}
}
--
2.51.0