aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
diff options
context:
space:
mode:
authorAlex Deucher <alexander.deucher@amd.com>2017-01-25 15:35:38 -0500
committerAlex Deucher <alexander.deucher@amd.com>2017-01-27 12:20:42 -0500
commit17ed9be815821f18eb2a42282fa5416c06da03b0 (patch)
treef317a82647a08b4729ef95d7b716616d707a8d17 /drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
parenta882f5de402ded769af74fbf276132f9c175049c (diff)
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: Alex Deucher <alexander.deucher@amd.com> Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c66
1 files changed, 34 insertions, 32 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
index 2602ea12971e..d9def01f276e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -358,8 +358,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
358 struct acpi_table_header *hdr; 358 struct acpi_table_header *hdr;
359 acpi_size tbl_size; 359 acpi_size tbl_size;
360 UEFI_ACPI_VFCT *vfct; 360 UEFI_ACPI_VFCT *vfct;
361 GOP_VBIOS_CONTENT *vbios; 361 unsigned offset;
362 VFCT_IMAGE_HEADER *vhdr;
363 362
364 if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) 363 if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
365 return false; 364 return false;
@@ -370,42 +369,45 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
370 } 369 }
371 370
372 vfct = (UEFI_ACPI_VFCT *)hdr; 371 vfct = (UEFI_ACPI_VFCT *)hdr;
373 if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) { 372 offset = vfct->VBIOSImageOffset;
374 DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
375 return false;
376 }
377 373
378 vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset); 374 while (offset < tbl_size) {
379 vhdr = &vbios->VbiosHeader; 375 GOP_VBIOS_CONTENT *vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + offset);
380 DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n", 376 VFCT_IMAGE_HEADER *vhdr = &vbios->VbiosHeader;
381 vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction,
382 vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength);
383
384 if (vhdr->PCIBus != adev->pdev->bus->number ||
385 vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) ||
386 vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn) ||
387 vhdr->VendorID != adev->pdev->vendor ||
388 vhdr->DeviceID != adev->pdev->device) {
389 DRM_INFO("ACPI VFCT table is not for this card\n");
390 return false;
391 }
392 377
393 if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) { 378 offset += sizeof(VFCT_IMAGE_HEADER);
394 DRM_ERROR("ACPI VFCT image truncated\n"); 379 if (offset > tbl_size) {
395 return false; 380 DRM_ERROR("ACPI VFCT image header truncated\n");
396 } 381 return false;
382 }
397 383
398 adev->bios = kmemdup(&vbios->VbiosContent, 384 offset += vhdr->ImageLength;
399 vhdr->ImageLength, 385 if (offset > tbl_size) {
400 GFP_KERNEL); 386 DRM_ERROR("ACPI VFCT image truncated\n");
387 return false;
388 }
401 389
402 if (!check_atom_bios(adev->bios, vhdr->ImageLength)) { 390 if (vhdr->ImageLength &&
403 kfree(adev->bios); 391 vhdr->PCIBus == adev->pdev->bus->number &&
404 return false; 392 vhdr->PCIDevice == PCI_SLOT(adev->pdev->devfn) &&
393 vhdr->PCIFunction == PCI_FUNC(adev->pdev->devfn) &&
394 vhdr->VendorID == adev->pdev->vendor &&
395 vhdr->DeviceID == adev->pdev->device) {
396 adev->bios = kmemdup(&vbios->VbiosContent,
397 vhdr->ImageLength,
398 GFP_KERNEL);
399
400 if (!check_atom_bios(adev->bios, vhdr->ImageLength)) {
401 kfree(adev->bios);
402 return false;
403 }
404 adev->bios_size = vhdr->ImageLength;
405 return true;
406 }
405 } 407 }
406 adev->bios_size = vhdr->ImageLength;
407 408
408 return true; 409 DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
410 return false;
409} 411}
410#else 412#else
411static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) 413static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)