drm/radeon: split ATRM support out from the ATPX handler (v3)

There are systems that use ATRM, but not ATPX.

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

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

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
This commit is contained in:
Alex Deucher 2012-08-16 15:39:09 -04:00
parent 7c3906d04a
commit c61e277587
3 changed files with 77 additions and 74 deletions

View File

@ -142,21 +142,6 @@ struct radeon_device;
/*
* BIOS.
*/
#define ATRM_BIOS_PAGE 4096
#if defined(CONFIG_VGA_SWITCHEROO)
bool radeon_atrm_supported(struct pci_dev *pdev);
int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len);
#else
static inline bool radeon_atrm_supported(struct pci_dev *pdev)
{
return false;
}
static inline int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len){
return -EINVAL;
}
#endif
bool radeon_get_bios(struct radeon_device *rdev);
/*

View File

@ -30,57 +30,8 @@ static struct radeon_atpx_priv {
/* handle for device - and atpx */
acpi_handle dhandle;
acpi_handle atpx_handle;
acpi_handle atrm_handle;
} radeon_atpx_priv;
/* retrieve the ROM in 4k blocks */
static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
int offset, int len)
{
acpi_status status;
union acpi_object atrm_arg_elements[2], *obj;
struct acpi_object_list atrm_arg;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
atrm_arg.count = 2;
atrm_arg.pointer = &atrm_arg_elements[0];
atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
atrm_arg_elements[0].integer.value = offset;
atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
atrm_arg_elements[1].integer.value = len;
status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
if (ACPI_FAILURE(status)) {
printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
return -ENODEV;
}
obj = (union acpi_object *)buffer.pointer;
memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length);
len = obj->buffer.length;
kfree(buffer.pointer);
return len;
}
bool radeon_atrm_supported(struct pci_dev *pdev)
{
/* get the discrete ROM only via ATRM */
if (!radeon_atpx_priv.atpx_detected)
return false;
if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
return false;
return true;
}
int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len)
{
return radeon_atrm_call(radeon_atpx_priv.atrm_handle, bios, offset, len);
}
static int radeon_atpx_get_version(acpi_handle handle)
{
acpi_status status;
@ -198,7 +149,7 @@ static int radeon_atpx_power_state(enum vga_switcheroo_client_id id,
static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
{
acpi_handle dhandle, atpx_handle, atrm_handle;
acpi_handle dhandle, atpx_handle;
acpi_status status;
dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
@ -209,13 +160,8 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
if (ACPI_FAILURE(status))
return false;
status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
if (ACPI_FAILURE(status))
return false;
radeon_atpx_priv.dhandle = dhandle;
radeon_atpx_priv.atpx_handle = atpx_handle;
radeon_atpx_priv.atrm_handle = atrm_handle;
return true;
}

View File

@ -99,16 +99,81 @@ static bool radeon_read_bios(struct radeon_device *rdev)
return true;
}
#ifdef CONFIG_ACPI
/* ATRM is used to get the BIOS on the discrete cards in
* dual-gpu systems.
*/
/* retrieve the ROM in 4k blocks */
#define ATRM_BIOS_PAGE 4096
/**
* radeon_atrm_call - fetch a chunk of the vbios
*
* @atrm_handle: acpi ATRM handle
* @bios: vbios image pointer
* @offset: offset of vbios image data to fetch
* @len: length of vbios image data to fetch
*
* Executes ATRM to fetch a chunk of the discrete
* vbios image on PX systems (all asics).
* Returns the length of the buffer fetched.
*/
static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
int offset, int len)
{
acpi_status status;
union acpi_object atrm_arg_elements[2], *obj;
struct acpi_object_list atrm_arg;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
atrm_arg.count = 2;
atrm_arg.pointer = &atrm_arg_elements[0];
atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
atrm_arg_elements[0].integer.value = offset;
atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
atrm_arg_elements[1].integer.value = len;
status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
if (ACPI_FAILURE(status)) {
printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
return -ENODEV;
}
obj = (union acpi_object *)buffer.pointer;
memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length);
len = obj->buffer.length;
kfree(buffer.pointer);
return len;
}
static bool radeon_atrm_get_bios(struct radeon_device *rdev)
{
int ret;
int size = 256 * 1024;
int i;
struct pci_dev *pdev = NULL;
acpi_handle dhandle, atrm_handle;
acpi_status status;
bool found = false;
if (!radeon_atrm_supported(rdev->pdev))
/* ATRM is for the discrete card only */
if (rdev->flags & RADEON_IS_IGP)
return false;
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
if (!dhandle)
continue;
status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
if (!ACPI_FAILURE(status)) {
found = true;
break;
}
}
if (!found)
return false;
rdev->bios = kmalloc(size, GFP_KERNEL);
@ -118,9 +183,10 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
}
for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
ret = radeon_atrm_get_bios_chunk(rdev->bios,
(i * ATRM_BIOS_PAGE),
ATRM_BIOS_PAGE);
ret = radeon_atrm_call(atrm_handle,
rdev->bios,
(i * ATRM_BIOS_PAGE),
ATRM_BIOS_PAGE);
if (ret < ATRM_BIOS_PAGE)
break;
}
@ -131,6 +197,12 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
}
return true;
}
#else
static inline bool radeon_atrm_get_bios(struct radeon_device *rdev)
{
return false;
}
#endif
static bool ni_read_disabled_bios(struct radeon_device *rdev)
{