* [PATCH v2 1/2] PCI: Add pci=noaer_recovery kernel boot option
2026-07-09 18:54 [PATCH v2 0/2] PCI: Add boot options to disable DPC and AER recovery Yury Murashka
@ 2026-07-09 18:54 ` Yury Murashka
2026-07-09 18:54 ` [PATCH v2 2/2] PCI: Add pci=nodpc " Yury Murashka
2026-07-09 22:42 ` [PATCH v2 0/2] PCI: Add boot options to disable DPC and AER recovery Bjorn Helgaas
2 siblings, 0 replies; 4+ messages in thread
From: Yury Murashka @ 2026-07-09 18:54 UTC (permalink / raw)
To: bhelgaas
Cc: corbet, skhan, mahesh, oohall, linux-pci, linux-doc, linux-kernel,
linuxppc-dev, Yury Murashka
AER error recovery is part of the AER error handling subsystem in the
Linux kernel. On large modular systems with a complex PCIe tree, AER
recovery could cause unexpected behavior and side effects. Sometimes it
would be nice to have the option to keep the system in an unmodified
state and be able to handle PCIe errors from userspace.
Add pci=noaer_recovery kernel boot option to disable AER error recovery
when an uncorrectable error is reported. When this option is set, the
error is still logged but no recovery actions are taken. AER error
status bits are preserved so userspace can inspect the error state.
Signed-off-by: Yury Murashka <yurypm@arista.com>
---
.../admin-guide/kernel-parameters.txt | 6 ++++
drivers/pci/pci.c | 2 ++
drivers/pci/pci.h | 2 ++
drivers/pci/pcie/aer.c | 30 ++++++++++++-------
4 files changed, 30 insertions(+), 10 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index b5493a7f8f22..13c6b53bb9ee 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -5053,6 +5053,12 @@ 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] If the PCIEAER kernel config parameter is
+ enabled, this kernel boot option can be used to
+ disable AER error recovery when an uncorrectable
+ error is reported. AER error status bits are
+ preserved so userspace can inspect the error
+ state.
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 77b17b13ee61..a215dd567d5d 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -6756,6 +6756,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 4469e1a77f3c..c4a42bbc277b 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1283,6 +1283,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;
@@ -1294,6 +1295,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 c4fd9c0b2a54..fb79990ce8ff 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -128,6 +128,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)
@@ -135,6 +136,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();
@@ -1187,10 +1193,12 @@ static void pci_aer_handle_error(struct pci_dev *dev, struct aer_err_info *info)
pdrv->err_handler->cor_error_detected(dev);
pcie_clear_device_status(dev);
}
- } else if (info->severity == AER_NONFATAL)
- pcie_do_recovery(dev, pci_channel_io_normal, aer_root_reset);
- else if (info->severity == AER_FATAL)
- pcie_do_recovery(dev, pci_channel_io_frozen, aer_root_reset);
+ } else if (!pcie_aer_recovery_disable) {
+ if (info->severity == AER_NONFATAL)
+ pcie_do_recovery(dev, pci_channel_io_normal, aer_root_reset);
+ else if (info->severity == AER_FATAL)
+ pcie_do_recovery(dev, pci_channel_io_frozen, aer_root_reset);
+ }
}
static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info)
@@ -1242,12 +1250,14 @@ 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 (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);
+ if (!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);
}
}
--
2.51.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH v2 2/2] PCI: Add pci=nodpc kernel boot option
2026-07-09 18:54 [PATCH v2 0/2] PCI: Add boot options to disable DPC and AER recovery Yury Murashka
2026-07-09 18:54 ` [PATCH v2 1/2] PCI: Add pci=noaer_recovery kernel boot option Yury Murashka
@ 2026-07-09 18:54 ` Yury Murashka
2026-07-09 22:42 ` [PATCH v2 0/2] PCI: Add boot options to disable DPC and AER recovery Bjorn Helgaas
2 siblings, 0 replies; 4+ messages in thread
From: Yury Murashka @ 2026-07-09 18:54 UTC (permalink / raw)
To: bhelgaas
Cc: corbet, skhan, mahesh, oohall, linux-pci, linux-doc, linux-kernel,
linuxppc-dev, Yury Murashka
PCI DPC (Downstream Port Containment) support can be advertised by PCIe
devices, but it might not be fully supported in the firmware. On large
modular systems with a complex PCIe tree, enabling DPC could cause
unexpected behavior and side effects. Sometimes it would be nice to have
the option to keep the system in an unmodified state and be able to
handle PCIe errors from userspace.
Add pci=nodpc kernel boot option to disable PCI DPC. When this option
is set, DPC initialization, state save/restore, recovery, and driver
registration are all skipped.
Signed-off-by: Yury Murashka <yurypm@arista.com>
---
.../admin-guide/kernel-parameters.txt | 3 +++
drivers/pci/pci.c | 2 ++
drivers/pci/pci.h | 2 ++
drivers/pci/pcie/dpc.c | 19 ++++++++++++++++---
4 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 13c6b53bb9ee..ccc26849a1ae 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -5050,6 +5050,9 @@ Kernel parameters
through ports 0xC000-0xCFFF).
See http://wiki.osdev.org/PCI for more info
on the configuration access mechanisms.
+ nodpc [PCIE] If the PCIE_DPC kernel config parameter is
+ enabled, this kernel boot option can be used to
+ disable the use of PCIE DPC.
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.
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a215dd567d5d..6cd06a872ba0 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -6754,6 +6754,8 @@ static int __init pci_setup(char *str)
} else if (!strncmp(str, "noats", 5)) {
pr_info("PCIe: ATS is disabled\n");
pcie_ats_disabled = true;
+ } else if (!strcmp(str, "nodpc")) {
+ pci_no_dpc();
} else if (!strcmp(str, "noaer")) {
pci_no_aer();
} else if (!strcmp(str, "noaer_recovery")) {
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index c4a42bbc277b..146cd5df985a 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -880,6 +880,7 @@ struct rcec_ea {
#endif
#ifdef CONFIG_PCIE_DPC
+void pci_no_dpc(void);
void pci_save_dpc_state(struct pci_dev *dev);
void pci_restore_dpc_state(struct pci_dev *dev);
void pci_dpc_init(struct pci_dev *pdev);
@@ -888,6 +889,7 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev);
bool pci_dpc_recovered(struct pci_dev *pdev);
unsigned int dpc_tlp_log_len(struct pci_dev *dev);
#else
+static inline void pci_no_dpc(void) { }
static inline void pci_save_dpc_state(struct pci_dev *dev) { }
static inline void pci_restore_dpc_state(struct pci_dev *dev) { }
static inline void pci_dpc_init(struct pci_dev *pdev) { }
diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c
index 2b779bd1d861..759d9f18812e 100644
--- a/drivers/pci/pcie/dpc.c
+++ b/drivers/pci/pcie/dpc.c
@@ -43,12 +43,19 @@ static const char * const rp_pio_error_string[] = {
"Memory Request Completion Timeout", /* Bit Position 18 */
};
+static bool pcie_dpc_disable;
+
+void pci_no_dpc(void)
+{
+ pcie_dpc_disable = true;
+}
+
void pci_save_dpc_state(struct pci_dev *dev)
{
struct pci_cap_saved_state *save_state;
u16 *cap;
- if (!pci_is_pcie(dev))
+ if (pcie_dpc_disable || !pci_is_pcie(dev))
return;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DPC);
@@ -64,7 +71,7 @@ void pci_restore_dpc_state(struct pci_dev *dev)
struct pci_cap_saved_state *save_state;
u16 *cap;
- if (!pci_is_pcie(dev))
+ if (pcie_dpc_disable || !pci_is_pcie(dev))
return;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DPC);
@@ -104,7 +111,7 @@ bool pci_dpc_recovered(struct pci_dev *pdev)
{
struct pci_host_bridge *host;
- if (!pdev->dpc_cap)
+ if (pcie_dpc_disable || !pdev->dpc_cap)
return false;
/*
@@ -404,6 +411,9 @@ void pci_dpc_init(struct pci_dev *pdev)
{
u16 cap;
+ if (pcie_dpc_disable)
+ return;
+
pdev->dpc_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DPC);
if (!pdev->dpc_cap)
return;
@@ -532,5 +542,8 @@ static struct pcie_port_service_driver dpcdriver = {
int __init pcie_dpc_init(void)
{
+ if (pcie_dpc_disable)
+ return 0;
+
return pcie_port_service_register(&dpcdriver);
}
--
2.51.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH v2 0/2] PCI: Add boot options to disable DPC and AER recovery
2026-07-09 18:54 [PATCH v2 0/2] PCI: Add boot options to disable DPC and AER recovery Yury Murashka
2026-07-09 18:54 ` [PATCH v2 1/2] PCI: Add pci=noaer_recovery kernel boot option Yury Murashka
2026-07-09 18:54 ` [PATCH v2 2/2] PCI: Add pci=nodpc " Yury Murashka
@ 2026-07-09 22:42 ` Bjorn Helgaas
2 siblings, 0 replies; 4+ messages in thread
From: Bjorn Helgaas @ 2026-07-09 22:42 UTC (permalink / raw)
To: Yury Murashka
Cc: bhelgaas, corbet, skhan, mahesh, oohall, linux-pci, linux-doc,
linux-kernel, linuxppc-dev
On Thu, Jul 09, 2026 at 06:54:27PM +0000, Yury Murashka wrote:
> On large modular systems with a complex PCIe tree, the default kernel
> AER recovery and DPC behavior could cause unexpected side effects.
I can't tell what the actual issues are, but if there are kernel
defects in this area, we should fix them. If this is to work around
platform defects, maybe we need quirks to work around them
automatically?
^ permalink raw reply [flat|nested] 4+ messages in thread