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)

Reply via email to