On 6/12/26 12:03, Yang Wang wrote: > 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
You are re-implementing the functionality of vfio-pci. Just use vfio-pci.ids=vendor_ID:device_ID for that. Not sure if vfio-pci supports filtering by revision ID, but that should be easy to add if it doesn't. Regards, Christian. > > 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)
