Skip to content

Commit

Permalink
drm/radeon: implement ACPI VFCT vbios fetch (v3)
Browse files Browse the repository at this point in the history
This is required for pure UEFI systems.  The vbios is stored
in ACPI rather than at the legacy vga location.

Fixes:
https://bugs.freedesktop.org/show_bug.cgi?id=26891

V2: fix #ifdefs as per Greg's comments
V3: fix it harder

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Jerome Glisse <jglisse@redhat.com>
Cc: stable@vger.kernel.org
  • Loading branch information
David Lamparter authored and Alex Deucher committed Aug 20, 2012
1 parent 52e9b39 commit 268ba0a
Showing 1 changed file with 60 additions and 0 deletions.
60 changes: 60 additions & 0 deletions drivers/gpu/drm/radeon/radeon_bios.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#include <linux/vga_switcheroo.h>
#include <linux/slab.h>
#include <linux/acpi.h>
/*
* BIOS.
*/
Expand Down Expand Up @@ -476,13 +477,72 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev)
return legacy_read_disabled_bios(rdev);
}

#ifdef CONFIG_ACPI
static bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
{
bool ret = false;
struct acpi_table_header *hdr;
/* acpi_get_table_with_size is not exported :( */
acpi_size tbl_size = 0x7fffffff;
UEFI_ACPI_VFCT *vfct;
GOP_VBIOS_CONTENT *vbios;
VFCT_IMAGE_HEADER *vhdr;

if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr)))
return false;
if (tbl_size < sizeof(UEFI_ACPI_VFCT)) {
DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n");
goto out_unmap;
}

vfct = (UEFI_ACPI_VFCT *)hdr;
if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) > tbl_size) {
DRM_ERROR("ACPI VFCT table present but broken (too short #2)\n");
goto out_unmap;
}

vbios = (GOP_VBIOS_CONTENT *)((char *)hdr + vfct->VBIOSImageOffset);
vhdr = &vbios->VbiosHeader;
DRM_INFO("ACPI VFCT contains a BIOS for %02x:%02x.%d %04x:%04x, size %d\n",
vhdr->PCIBus, vhdr->PCIDevice, vhdr->PCIFunction,
vhdr->VendorID, vhdr->DeviceID, vhdr->ImageLength);

if (vhdr->PCIBus != rdev->pdev->bus->number ||
vhdr->PCIDevice != PCI_SLOT(rdev->pdev->devfn) ||
vhdr->PCIFunction != PCI_FUNC(rdev->pdev->devfn) ||
vhdr->VendorID != rdev->pdev->vendor ||
vhdr->DeviceID != rdev->pdev->device) {
DRM_INFO("ACPI VFCT table is not for this card\n");
goto out_unmap;
};

if (vfct->VBIOSImageOffset + sizeof(VFCT_IMAGE_HEADER) + vhdr->ImageLength > tbl_size) {
DRM_ERROR("ACPI VFCT image truncated\n");
goto out_unmap;
}

rdev->bios = kmemdup(&vbios->VbiosContent, vhdr->ImageLength, GFP_KERNEL);
ret = !!rdev->bios;

out_unmap:
/* uh, no idea what to do here... */
return ret;
}
#else
static inline bool radeon_acpi_vfct_bios(struct radeon_device *rdev)
{
return false;
}
#endif

bool radeon_get_bios(struct radeon_device *rdev)
{
bool r;
uint16_t tmp;

r = radeon_atrm_get_bios(rdev);
if (r == false)
r = radeon_acpi_vfct_bios(rdev);
if (r == false)
r = igp_read_bios_from_vram(rdev);
if (r == false)
Expand Down

0 comments on commit 268ba0a

Please sign in to comment.