Public

+ Mario

> -----Original Message-----
> From: Reza Nikzad Chaleshori <[email protected]>
> Sent: Wednesday, October 14, 2026 4:05 AM
> To: [email protected]
> Cc: Reza Nikzad Chaleshori <[email protected]>; Deucher, Alexander
> <[email protected]>; Koenig, Christian
> <[email protected]>; David Airlie <[email protected]>; Simona
> Vetter <[email protected]>; Zhang, Hawking <[email protected]>;
> Min, Frank <[email protected]>; Luo, Zhigang <[email protected]>;
> Wang, YuBiao (Ethan) <[email protected]>
> Subject: [PATCH] drm/amdgpu: prefer exact bus match when selecting VFCT
> VBIOS image
>
> amdgpu_acpi_vfct_match() accepts an entry whose bus number differs from
> the runtime bus number as long as vendor, device, slot and function match.
> The caller takes the first entry that matches and stops.
>
> On systems with several GPUs of the same model (e.g. mining boards) every
> card matches every entry on vendor/device/function, so an earlier entry is
> selected for a later card even when the table contains an entry with the exact
> bus number. The later card then runs with another board's VBIOS (different
> power/clock/memory tables) and can fail to initialize, for example with "UVD
> not responding" and a fatal error during GPU init.
>
> Search the table first for an exact bus match, and only if none exists fall 
> back to
> matching by device identity.
>
> Reproduced with two RX 580 (Polaris10, 1002:67df) from different vendors
> on an ASUS B250 mining board: VFCT holds entries for bus 1 and bus 12, the
> card at bus 12 was given the bus 1 image.
>
> Signed-off-by: Reza Nikzad Chaleshori <[email protected]>

I think I'd prefer to just revert the change the loosened the mapping.  The 
loosening was done to fix when someone sets pci=realloc on the kernel command 
line.  I'd consider that to be more of a corner case and presumably even that 
would potentially break on a system like yours anyway.

Alex

> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 71 +++++++++++++++-----
> ----
>  1 file changed, 46 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
> index f9315e047..d42485e6b 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
> @@ -441,10 +441,15 @@ static bool amdgpu_read_disabled_bios(struct
> amdgpu_device *adev)
>   * the bus numbers disagree we accept the entry if the device identity
>   * matches.
>   *
> + * @exact: if true, only an exact bus number match is accepted.  The
> + caller
> + * first searches the whole table with @exact set, and only retries
> + with it
> + * cleared when no entry matched exactly, so that an earlier entry for
> + an
> + * identical card on a different bus cannot shadow the correct one.
> + *
>   * Returns: 0 on match, -ENODEV on no match
>   */
>  static int amdgpu_acpi_vfct_match(struct amdgpu_device *adev,
> -                               VFCT_IMAGE_HEADER *vhdr)
> +                               VFCT_IMAGE_HEADER *vhdr, bool exact)
>  {
>       /* Vendor and device IDs must always match */
>       if (vhdr->VendorID != adev->pdev->vendor || @@ -459,6 +464,9 @@
> static int amdgpu_acpi_vfct_match(struct amdgpu_device *adev,
>       if (vhdr->PCIBus == adev->pdev->bus->number)
>               return 0;
>
> +     if (exact)
> +             return -ENODEV;
> +
>       /* Bus mismatch but device identity matches (PCI renumbering case)
> */
>       dev_notice(adev->dev,
>                  "VFCT bus number mismatch: table %u != runtime %u,
> matching by device identity (vendor 0x%04x device 0x%04x)\n", @@ -474,6
> +482,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
>       UEFI_ACPI_VFCT *vfct;
>       unsigned int offset;
>       bool r = false;
> +     bool exact;
>
>       if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
>               return false;
> @@ -484,38 +493,50 @@ static bool amdgpu_acpi_vfct_bios(struct
> amdgpu_device *adev)
>       }
>
>       vfct = (UEFI_ACPI_VFCT *)hdr;
> -     offset = vfct->VBIOSImageOffset;
>
> -     while (offset < tbl_size) {
> -             GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT
> *)((char *)hdr + offset);
> -             VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader;
> +     /*
> +      * Pass 1 looks for an entry whose bus number matches exactly.  Only
> if
> +      * there is none does pass 2 accept an entry that matches by device
> +      * identity alone.  Without this, on a system with several identical
> +      * GPUs an earlier entry would be picked for a later card.
> +      */
> +     for (exact = true; ; exact = false) {
> +             offset = vfct->VBIOSImageOffset;
>
> -             offset += sizeof(VFCT_IMAGE_HEADER);
> -             if (offset > tbl_size) {
> -                     dev_info(adev->dev, "ACPI VFCT image header
> truncated,skipping\n");
> -                     goto out;
> -             }
> +             while (offset < tbl_size) {
> +                     GOP_VBIOS_CONTENT *vbios =
> (GOP_VBIOS_CONTENT *)((char *)hdr + offset);
> +                     VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader;
>
> -             offset += vhdr->ImageLength;
> -             if (offset > tbl_size) {
> -                     dev_info(adev->dev, "ACPI VFCT image
> truncated,skipping\n");
> -                     goto out;
> -             }
> +                     offset += sizeof(VFCT_IMAGE_HEADER);
> +                     if (offset > tbl_size) {
> +                             dev_info(adev->dev, "ACPI VFCT image
> header truncated,skipping\n");
> +                             goto out;
> +                     }
>
> -             if (vhdr->ImageLength &&
> -                 !amdgpu_acpi_vfct_match(adev, vhdr)) {
> -                     adev->bios = kmemdup(&vbios->VbiosContent,
> -                                          vhdr->ImageLength,
> -                                          GFP_KERNEL);
> +                     offset += vhdr->ImageLength;
> +                     if (offset > tbl_size) {
> +                             dev_info(adev->dev, "ACPI VFCT image
> truncated,skipping\n");
> +                             goto out;
> +                     }
>
> -                     if (!check_atom_bios(adev, vhdr->ImageLength)) {
> -                             amdgpu_bios_release(adev);
> +                     if (vhdr->ImageLength &&
> +                         !amdgpu_acpi_vfct_match(adev, vhdr, exact)) {
> +                             adev->bios = kmemdup(&vbios-
> >VbiosContent,
> +                                                  vhdr->ImageLength,
> +                                                  GFP_KERNEL);
> +
> +                             if (!check_atom_bios(adev, vhdr-
> >ImageLength)) {
> +                                     amdgpu_bios_release(adev);
> +                                     goto out;
> +                             }
> +                             adev->bios_size = vhdr->ImageLength;
> +                             r = true;
>                               goto out;
>                       }
> -                     adev->bios_size = vhdr->ImageLength;
> -                     r = true;
> -                     goto out;
>               }
> +
> +             if (!exact)
> +                     break;
>       }
>
>       dev_info(adev->dev, "ACPI VFCT table present but broken (too short
> #2),skipping\n");
> --
> 2.53.0

Reply via email to