AMD General

pci-stub can provide the same functionality and is a common solution for all 
PCI devices. We probably do not need to add an amdgpu specific parameter for 
this.

Regards,
Hawking

-----Original Message-----
From: Wang, Yang(Kevin) <[email protected]>
Sent: Friday, June 12, 2026 6:03 PM
To: [email protected]
Cc: Deucher, Alexander <[email protected]>; Zhang, Hawking 
<[email protected]>; Koenig, Christian <[email protected]>
Subject: [PATCH] drm/amdgpu: add parameter to allow skip specified PCI devices

Add the disable_pci_ids module parameter to let amdgpu skip selected PCI 
devices before normal device initialization starts.

This is useful on multi-GPU systems where only a subset of devices should be 
claimed by amdgpu, and for bring-up or debug cases where early probe of 
specific devices needs to be avoided.

The parameter accepts a comma-separated list of hex PCI IDs. The device ID is 
required, while the vendor ID and revision ID are optional:

  device ID
  vendor ID:device ID
  vendor ID:device ID:revision ID

For example:
  # cat /proc/cmdline
  amdgpu.disable_pci_ids=73bf,1002:7550:c0

Kernel log:
[ 3327.298156] amdgpu 0000:63:00.0: skipping PCI device [1002:7550] (rev c0) by 
module parameter

Signed-off-by: Yang Wang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 175 ++++++++++++++++++++++++
 1 file changed, 175 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 503bb64c1e55..48aded458987 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -35,9 +35,11 @@
 #include <linux/cc_platform.h>
 #include <linux/console.h>
 #include <linux/dynamic_debug.h>
+#include <linux/kstrtox.h>
 #include <linux/module.h>
 #include <linux/mmu_notifier.h>
 #include <linux/pm_runtime.h>
+#include <linux/string.h>
 #include <linux/suspend.h>
 #include <linux/vga_switcheroo.h>

@@ -183,6 +185,7 @@ uint amdgpu_pg_mask = 0xffffffff;  uint 
amdgpu_sdma_phase_quantum = 32;  char *amdgpu_disable_cu;  char 
*amdgpu_virtual_display;
+char amdgpu_disable_pci_ids[256];
 int amdgpu_enforce_isolation = -1;
 int amdgpu_modeset = -1;

@@ -564,6 +567,28 @@ MODULE_PARM_DESC(virtual_display,
                 "Enable virtual display feature (the virtual_display will be 
set like xxxx:xx:xx.x,x;xxxx:xx:xx.x,x)");  module_param_named(virtual_display, 
amdgpu_virtual_display, charp, 0444);

+/**
+ * DOC: disable_pci_ids (string)
+ * Comma separated list of PCI IDs to skip during probe.
+ *
+ * This can be useful on multi-GPU systems where only a subset of
+devices
+ * should be claimed by amdgpu, or for bring-up and debug cases where
+early
+ * probe of specific devices needs to be avoided.
+ *
+ * The device ID is required. Vendor ID and revision ID are optional.
+Hex IDs
+ * with or without a 0x prefix are accepted. Valid formats are:
+ *
+ * - device ID
+ * - vendor ID:device ID
+ * - vendor ID:device ID:revision ID
+ *
+ * For example: disable_pci_ids=73bf,1002:73df:01.
+ */
+MODULE_PARM_DESC(disable_pci_ids,
+                "Skip probing devices matching PCI ID patterns: device ID, 
vendor
+ID:device ID, or vendor ID:device ID:revision ID"); 
module_param_string(disable_pci_ids, amdgpu_disable_pci_ids,
+                   sizeof(amdgpu_disable_pci_ids), 0444);
+
 /**
  * DOC: lbpw (int)
  * Override Load Balancing Per Watt (LBPW) support (1 = enable, 0 = disable). 
The default is -1 (auto, enabled).
@@ -2216,6 +2241,149 @@ static const struct amdgpu_asic_type_quirk 
asic_type_quirks[] = {

 static const struct drm_driver amdgpu_kms_driver;

+struct amdgpu_disabled_pci_id {
+       u16 vendor;
+       u16 device;
+       u8 revision;
+       bool has_vendor;
+       bool has_revision;
+};
+
+static int amdgpu_parse_disabled_pci_id_field(const char *str, u16 *id)
+{
+       if (!strncasecmp(str, "0x", 2))
+               str += 2;
+
+       return kstrtou16(str, 16, id);
+}
+
+static int amdgpu_parse_disabled_pci_revision(const char *str, u8
+*revision) {
+       if (!strncasecmp(str, "0x", 2))
+               str += 2;
+
+       return kstrtou8(str, 16, revision);
+}
+
+static int amdgpu_parse_disabled_pci_id(const char *str,
+                                       struct amdgpu_disabled_pci_id *id) {
+       char pci_id[32], *fields[3], *tmp;
+       int count = 0;
+
+       strscpy(pci_id, str, sizeof(pci_id));
+       tmp = pci_id;
+
+       while (tmp && count < ARRAY_SIZE(fields))
+               fields[count++] = strsep(&tmp, ":");
+
+       if (tmp || !count)
+               return -EINVAL;
+
+       id->has_vendor = false;
+       id->has_revision = false;
+
+       switch (count) {
+       case 1:
+               if (!fields[0][0])
+                       return -EINVAL;
+
+               return amdgpu_parse_disabled_pci_id_field(fields[0],
+                                                         &id->device);
+       case 2:
+               if (!fields[0][0] || !fields[1][0])
+                       return -EINVAL;
+
+               if (amdgpu_parse_disabled_pci_id_field(fields[0],
+                                                      &id->vendor))
+                       return -EINVAL;
+
+               if (amdgpu_parse_disabled_pci_id_field(fields[1],
+                                                      &id->device))
+                       return -EINVAL;
+
+               id->has_vendor = true;
+               return 0;
+       case 3:
+               if (!fields[0][0] || !fields[1][0] || !fields[2][0])
+                       return -EINVAL;
+
+               if (amdgpu_parse_disabled_pci_id_field(fields[0],
+                                                      &id->vendor))
+                       return -EINVAL;
+
+               if (amdgpu_parse_disabled_pci_id_field(fields[1],
+                                                      &id->device))
+                       return -EINVAL;
+
+               if (amdgpu_parse_disabled_pci_revision(fields[2],
+                                                      &id->revision))
+                       return -EINVAL;
+
+               id->has_vendor = true;
+               id->has_revision = true;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static bool amdgpu_disabled_pci_id_match(struct pci_dev *pdev,
+                                        const struct amdgpu_disabled_pci_id 
*id) {
+       if (id->device != pdev->device)
+               return false;
+
+       if (id->has_vendor && id->vendor != pdev->vendor)
+               return false;
+
+       if (id->has_revision && id->revision != pdev->revision)
+               return false;
+
+       return true;
+}
+
+static bool amdgpu_device_id_disabled(struct pci_dev *pdev) {
+       const char *ids = amdgpu_disable_pci_ids;
+       char id[32];
+       struct amdgpu_disabled_pci_id pci_id;
+       size_t len;
+
+       while (*ids) {
+               ids += strspn(ids, ",; \t\n");
+               if (!*ids)
+                       break;
+
+               len = strcspn(ids, ",; \t\n");
+
+               if (len >= sizeof(id)) {
+                       dev_warn(&pdev->dev,
+                                "invalid disabled PCI id '%.*s'\n",
+                                (int)len, ids);
+                       ids += len;
+                       continue;
+               }
+
+               memcpy(id, ids, len);
+               id[len] = '\0';
+
+               if (amdgpu_parse_disabled_pci_id(id, &pci_id)) {
+                       dev_warn(&pdev->dev,
+                                "invalid disabled PCI id '%s'\n", id);
+                       ids += len;
+                       continue;
+               }
+
+               if (amdgpu_disabled_pci_id_match(pdev, &pci_id))
+                       return true;
+
+               ids += len;
+       }
+
+       return false;
+}
+
 static void amdgpu_get_secondary_funcs(struct amdgpu_device *adev)  {
        struct pci_dev *p = NULL;
@@ -2389,6 +2557,13 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
                        return -EINVAL;
        }

+       if (amdgpu_device_id_disabled(pdev)) {
+               dev_info(&pdev->dev,
+                        "skipping PCI device [%04x:%04x] (rev %02x) by module 
parameter\n",
+                         pdev->vendor, pdev->device, pdev->revision);
+               return -ENODEV;
+       }
+
        /* skip devices which are owned by radeon */
        for (i = 0; i < ARRAY_SIZE(amdgpu_unsupported_pciidlist); i++) {
                if (amdgpu_unsupported_pciidlist[i] == pdev->device)
--
2.47.3

Reply via email to