]> exis.tech > repos - linux.git/blobdiff - drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
Merge tag 'hwmon-for-v7.2-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/groec...
[linux.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_bios.c
index aa039e148a5ee795fa5635b6c684691c64a5e80c..8525c45ab209b75fb33ee4edf7daf20cadfc4f90 100644 (file)
@@ -372,19 +372,59 @@ static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)
 }
 
 #ifdef CONFIG_ACPI
+/**
+ * amdgpu_acpi_vfct_match() - Check if a VFCT entry matches the device
+ * @adev: AMDGPU device
+ * @vhdr: VFCT image header to check
+ *
+ * VFCT entries contain the PCI bus number as recorded during BIOS POST.
+ * On systems where the kernel renumbers PCI buses (e.g. pci=realloc or
+ * resource conflicts), the runtime bus number may differ from the POST
+ * value.  Match by device identity (vendor + device + function) and use
+ * the bus number as a preference: exact bus match is preferred, but when
+ * the bus numbers disagree we accept the entry if the device identity
+ * matches.
+ *
+ * Returns: 0 on match, -ENODEV on no match
+ */
+static int amdgpu_acpi_vfct_match(struct amdgpu_device *adev,
+                                 VFCT_IMAGE_HEADER *vhdr)
+{
+       /* Vendor and device IDs must always match */
+       if (vhdr->VendorID != adev->pdev->vendor ||
+           vhdr->DeviceID != adev->pdev->device)
+               return -ENODEV;
+
+       if (vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) ||
+           vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn))
+               return -ENODEV;
+
+       /* Exact bus number match - preferred */
+       if (vhdr->PCIBus == adev->pdev->bus->number)
+               return 0;
+
+       /* 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",
+                  vhdr->PCIBus, adev->pdev->bus->number,
+                  adev->pdev->vendor, adev->pdev->device);
+       return 0;
+}
+
 static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
 {
        struct acpi_table_header *hdr;
        acpi_size tbl_size;
        UEFI_ACPI_VFCT *vfct;
        unsigned int offset;
+       bool r = false;
 
        if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
                return false;
        tbl_size = hdr->length;
        if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
                dev_info(adev->dev, "ACPI VFCT table present but broken (too short #1),skipping\n");
-               return false;
+               goto out;
        }
 
        vfct = (UEFI_ACPI_VFCT *)hdr;
@@ -397,36 +437,36 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
                offset += sizeof(VFCT_IMAGE_HEADER);
                if (offset > tbl_size) {
                        dev_info(adev->dev, "ACPI VFCT image header truncated,skipping\n");
-                       return false;
+                       goto out;
                }
 
                offset += vhdr->ImageLength;
                if (offset > tbl_size) {
                        dev_info(adev->dev, "ACPI VFCT image truncated,skipping\n");
-                       return false;
+                       goto out;
                }
 
                if (vhdr->ImageLength &&
-                   vhdr->PCIBus == adev->pdev->bus->number &&
-                   vhdr->PCIDevice == PCI_SLOT(adev->pdev->devfn) &&
-                   vhdr->PCIFunction == PCI_FUNC(adev->pdev->devfn) &&
-                   vhdr->VendorID == adev->pdev->vendor &&
-                   vhdr->DeviceID == adev->pdev->device) {
+                   !amdgpu_acpi_vfct_match(adev, vhdr)) {
                        adev->bios = kmemdup(&vbios->VbiosContent,
                                             vhdr->ImageLength,
                                             GFP_KERNEL);
 
                        if (!check_atom_bios(adev, vhdr->ImageLength)) {
                                amdgpu_bios_release(adev);
-                               return false;
+                               goto out;
                        }
                        adev->bios_size = vhdr->ImageLength;
-                       return true;
+                       r = true;
+                       goto out;
                }
        }
 
        dev_info(adev->dev, "ACPI VFCT table present but broken (too short #2),skipping\n");
-       return false;
+
+out:
+       acpi_put_table(hdr);
+       return r;
 }
 #else
 static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)