Linux Documentation
 help / color / mirror / Atom feed
From: Yury Murashka <yurypm@arista.com>
To: bhelgaas@google.com
Cc: rafael@kernel.org, lenb@kernel.org, corbet@lwn.net,
	skhan@linuxfoundation.org, rdunlap@infradead.org,
	mahesh@linux.ibm.com, oohall@gmail.com,
	linux-pci@vger.kernel.org, linux-acpi@vger.kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linuxppc-dev@lists.ozlabs.org
Subject: [PATCH v3 2/2] PCI: Add pci=nodpc kernel boot option
Date: Thu, 22 Oct 2026 16:58:42 +0000	[thread overview]
Message-ID: <20261022165842.1463451-3-yurypm@arista.com> (raw)
In-Reply-To: <20261022165842.1463451-1-yurypm@arista.com>

Add pci=nodpc to let Linux opt out of Downstream Port Containment (DPC)
and Error Disconnect Recover (EDR) support on systems where userspace
manages PCIe errors.

Skip DPC initialization, state operations, hotplug recovery checks, and
port service registration when disabled. Expose pci_dpc_available() so
ACPI negotiation and PCIe port service discovery honor the same policy.
Do not advertise EDR support or request DPC control through _OSC, and
prevent native-port overrides from reintroducing DPC ownership.

Skip EDR notifier installation before the DPC-enabling _DSM call. Merely
skipping the native DPC driver would allow EDR to enable hardware DPC
while the handler lacks the capability information needed to recover.

The option disables Linux participation in DPC and EDR; it does not turn
off firmware-owned DPC hardware. AER reporting and recovery remain
independent and can be controlled with their own boot options.

Signed-off-by: Yury Murashka <yurypm@arista.com>
---
Changes in v3:
- Add pci_dpc_available() and use it for ACPI DPC/EDR negotiation.
- Skip EDR notifier registration and its DPC-enabling _DSM call.
- Gate DPC service discovery and prevent forced native DPC ownership.
- Clarify the firmware boundary and rebase onto PCI next.

v2: https://lore.kernel.org/linux-pci/20260709185429.627968-3-yurypm@arista.com/
Review: https://lore.kernel.org/linux-pci/20260709190730.E19A11F000E9@smtp.kernel.org/

 .../admin-guide/kernel-parameters.txt         |  4 ++++
 drivers/acpi/pci_root.c                       |  9 +++++--
 drivers/pci/pci.c                             |  2 ++
 drivers/pci/pci.h                             |  2 ++
 drivers/pci/pcie/dpc.c                        | 24 ++++++++++++++++---
 drivers/pci/pcie/edr.c                        |  5 +++-
 drivers/pci/pcie/portdrv.c                    |  3 ++-
 include/linux/pci.h                           |  6 +++++
 8 files changed, 48 insertions(+), 7 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 6047efd3c..f98486d4d 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -5115,6 +5115,10 @@ Kernel parameters
 				through ports 0xC000-0xCFFF).
 				See http://wiki.osdev.org/PCI for more info
 				on the configuration access mechanisms.
+		nodpc		[PCIE] Disable Linux DPC and EDR support. Linux
+				neither requests DPC control from firmware nor
+				enables DPC through EDR. Firmware-owned DPC
+				settings are not changed. Requires CONFIG_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/acpi/pci_root.c b/drivers/acpi/pci_root.c
index a1a9c0601..6bca8206c 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -438,7 +438,7 @@ static u32 calculate_support(void)
 		support |= OSC_PCI_ASPM_SUPPORT | OSC_PCI_CLOCK_PM_SUPPORT;
 	if (pci_msi_enabled())
 		support |= OSC_PCI_MSI_SUPPORT;
-	if (IS_ENABLED(CONFIG_PCIE_EDR))
+	if (IS_ENABLED(CONFIG_PCIE_EDR) && pci_dpc_available())
 		support |= OSC_PCI_EDR_SUPPORT;
 
 	return support;
@@ -517,7 +517,7 @@ static u32 calculate_control(void)
 	 * OSC_PCI_EXPRESS_DPC_CONTROL indicates the OS supports both DPC
 	 * and EDR.
 	 */
-	if (IS_ENABLED(CONFIG_PCIE_DPC) && IS_ENABLED(CONFIG_PCIE_EDR))
+	if (pci_dpc_available() && IS_ENABLED(CONFIG_PCIE_EDR))
 		control |= OSC_PCI_EXPRESS_DPC_CONTROL;
 
 	return control;
@@ -1064,6 +1064,11 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
 	else if (pcie_ports_dpc_native)
 		override = OSC_PCI_EXPRESS_DPC_CONTROL & ~ctrl;
 
+	if (!pci_dpc_available()) {
+		ctrl &= ~OSC_PCI_EXPRESS_DPC_CONTROL;
+		override &= ~OSC_PCI_EXPRESS_DPC_CONTROL;
+	}
+
 	if (override) {
 		decode_osc_control(root, pcie_ports_native ?
 				   "OS forcing control (\"pcie_ports=native\") of" :
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 9ca8d3fbb..c2a6aacc5 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -6838,6 +6838,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 ccc6a678c..ae8fc06e5 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -934,6 +934,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);
@@ -942,6 +943,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 2b779bd1d..fbafc3ca0 100644
--- a/drivers/pci/pcie/dpc.c
+++ b/drivers/pci/pcie/dpc.c
@@ -43,12 +43,24 @@ 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;
+}
+
+bool pci_dpc_available(void)
+{
+	return !pcie_dpc_disable;
+}
+
 void pci_save_dpc_state(struct pci_dev *dev)
 {
 	struct pci_cap_saved_state *save_state;
 	u16 *cap;
 
-	if (!pci_is_pcie(dev))
+	if (!pci_dpc_available() || !pci_is_pcie(dev))
 		return;
 
 	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DPC);
@@ -64,7 +76,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 (!pci_dpc_available() || !pci_is_pcie(dev))
 		return;
 
 	save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DPC);
@@ -104,7 +116,7 @@ bool pci_dpc_recovered(struct pci_dev *pdev)
 {
 	struct pci_host_bridge *host;
 
-	if (!pdev->dpc_cap)
+	if (!pci_dpc_available() || !pdev->dpc_cap)
 		return false;
 
 	/*
@@ -404,6 +416,9 @@ void pci_dpc_init(struct pci_dev *pdev)
 {
 	u16 cap;
 
+	if (!pci_dpc_available())
+		return;
+
 	pdev->dpc_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DPC);
 	if (!pdev->dpc_cap)
 		return;
@@ -532,5 +547,8 @@ static struct pcie_port_service_driver dpcdriver = {
 
 int __init pcie_dpc_init(void)
 {
+	if (!pci_dpc_available())
+		return 0;
+
 	return pcie_port_service_register(&dpcdriver);
 }
diff --git a/drivers/pci/pcie/edr.c b/drivers/pci/pcie/edr.c
index e86298dbb..8567dd1d5 100644
--- a/drivers/pci/pcie/edr.c
+++ b/drivers/pci/pcie/edr.c
@@ -223,6 +223,9 @@ void pci_acpi_add_edr_notifier(struct pci_dev *pdev)
 	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
 	acpi_status status;
 
+	if (!pci_dpc_available())
+		return;
+
 	if (!adev) {
 		pci_dbg(pdev, "No valid ACPI node, skipping EDR init\n");
 		return;
@@ -246,7 +249,7 @@ void pci_acpi_remove_edr_notifier(struct pci_dev *pdev)
 {
 	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
 
-	if (!adev)
+	if (!pci_dpc_available() || !adev)
 		return;
 
 	acpi_remove_notify_handler(adev->handle, ACPI_SYSTEM_NOTIFY,
diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c
index 32fc623dd..aa1c57e33 100644
--- a/drivers/pci/pcie/portdrv.c
+++ b/drivers/pci/pcie/portdrv.c
@@ -262,7 +262,8 @@ static int get_port_device_capability(struct pci_dev *dev)
 	 * With dpc-native, allow Linux to use DPC even if it doesn't have
 	 * permission to use AER.
 	 */
-	if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DPC) &&
+	if (pci_dpc_available() &&
+	    pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DPC) &&
 	    pci_aer_available() &&
 	    (pcie_ports_dpc_native || host->native_aer))
 		services |= PCIE_PORT_SERVICE_DPC;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index f3e9c6c9c..dd667223b 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1984,6 +1984,12 @@ bool pci_aer_available(void);
 static inline bool pci_aer_available(void) { return false; }
 #endif
 
+#ifdef CONFIG_PCIE_DPC
+bool pci_dpc_available(void);
+#else
+static inline bool pci_dpc_available(void) { return false; }
+#endif
+
 bool pci_ats_disabled(void);
 
 #define PCIE_PTM_CONTEXT_UPDATE_AUTO 0
-- 
2.51.0


      parent reply	other threads:[~2026-10-22 16:59 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-22 16:58 [PATCH v3 0/2] PCI: Add boot options to disable DPC and AER recovery Yury Murashka
2026-10-22 16:58 ` [PATCH v3 1/2] PCI: Add pci=noaer_recovery kernel boot option Yury Murashka
2026-10-22 16:58 ` Yury Murashka [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261022165842.1463451-3-yurypm@arista.com \
    --to=yurypm@arista.com \
    --cc=bhelgaas@google.com \
    --cc=corbet@lwn.net \
    --cc=lenb@kernel.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=mahesh@linux.ibm.com \
    --cc=oohall@gmail.com \
    --cc=rafael@kernel.org \
    --cc=rdunlap@infradead.org \
    --cc=skhan@linuxfoundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox