Commit 17ed9be8 authored by Alex Deucher's avatar Alex Deucher

drm/amdgpu: handle vfct with multiple vbios images

The vfct table can contain multiple vbios images if the
platform contains multiple GPUs. Noticed by netkas on
phoronix forums.  This patch fixes those platforms.
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
parent a882f5de
...@@ -358,8 +358,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) ...@@ -358,8 +358,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
struct acpi_table_header *hdr; struct acpi_table_header *hdr;
acpi_size tbl_size; acpi_size tbl_size;
UEFI_ACPI_VFCT *vfct; UEFI_ACPI_VFCT *vfct;
GOP_VBIOS_CONTENT *vbios; unsigned offset;
VFCT_IMAGE_HEADER *vhdr;
if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
return false; return false;
...@@ -370,31 +369,30 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) ...@@ -370,31 +369,30 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
} }
vfct = (UEFI_ACPI_VFCT *)hdr; vfct = (UEFI_ACPI_VFCT *)hdr;
if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) { offset = vfct->VBIOSImageOffset;
DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
return false;
}
vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset); while (offset < tbl_size) {
vhdr = &vbios->VbiosHeader; GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset);
DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n", VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader;
vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction,
vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength);
if (vhdr->PCIBus != adev->pdev->bus->number || offset += sizeof(VFCT_IMAGE_HEADER);
vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) || if (offset > tbl_size) {
vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn) || DRM_ERROR("ACPI VFCT image header truncated\n");
vhdr->VendorID != adev->pdev->vendor ||
vhdr->DeviceID != adev->pdev->device) {
DRM_INFO("ACPI VFCT table is not for this card\n");
return false; return false;
} }
if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) { offset += vhdr->ImageLength;
if (offset > tbl_size) {
DRM_ERROR("ACPI VFCT image truncated\n"); DRM_ERROR("ACPI VFCT image truncated\n");
return false; return false;
} }
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) {
adev->bios = kmemdup(&vbios->VbiosContent, adev->bios = kmemdup(&vbios->VbiosContent,
vhdr->ImageLength, vhdr->ImageLength,
GFP_KERNEL); GFP_KERNEL);
...@@ -404,8 +402,12 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) ...@@ -404,8 +402,12 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
return false; return false;
} }
adev->bios_size = vhdr->ImageLength; adev->bios_size = vhdr->ImageLength;
return true; return true;
}
}
DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
return false;
} }
#else #else
static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment