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
