Commit c61e2775 authored by Alex Deucher's avatar Alex Deucher

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: default avatarAlex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
parent 7c3906d0
...@@ -142,21 +142,6 @@ struct radeon_device; ...@@ -142,21 +142,6 @@ struct radeon_device;
/* /*
* BIOS. * 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); bool radeon_get_bios(struct radeon_device *rdev);
/* /*
......
...@@ -30,57 +30,8 @@ static struct radeon_atpx_priv { ...@@ -30,57 +30,8 @@ static struct radeon_atpx_priv {
/* handle for device - and atpx */ /* handle for device - and atpx */
acpi_handle dhandle; acpi_handle dhandle;
acpi_handle atpx_handle; acpi_handle atpx_handle;
acpi_handle atrm_handle;
} radeon_atpx_priv; } 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) static int radeon_atpx_get_version(acpi_handle handle)
{ {
acpi_status status; acpi_status status;
...@@ -198,7 +149,7 @@ static int radeon_atpx_power_state(enum vga_switcheroo_client_id id, ...@@ -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) 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; acpi_status status;
dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
...@@ -209,13 +160,8 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) ...@@ -209,13 +160,8 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return false; return false;
status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
if (ACPI_FAILURE(status))
return false;
radeon_atpx_priv.dhandle = dhandle; radeon_atpx_priv.dhandle = dhandle;
radeon_atpx_priv.atpx_handle = atpx_handle; radeon_atpx_priv.atpx_handle = atpx_handle;
radeon_atpx_priv.atrm_handle = atrm_handle;
return true; return true;
} }
......
...@@ -99,16 +99,81 @@ static bool radeon_read_bios(struct radeon_device *rdev) ...@@ -99,16 +99,81 @@ static bool radeon_read_bios(struct radeon_device *rdev)
return true; return true;
} }
#ifdef CONFIG_ACPI
/* ATRM is used to get the BIOS on the discrete cards in /* ATRM is used to get the BIOS on the discrete cards in
* dual-gpu systems. * 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) static bool radeon_atrm_get_bios(struct radeon_device *rdev)
{ {
int ret; int ret;
int size = 256 * 1024; int size = 256 * 1024;
int i; 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; return false;
rdev->bios = kmalloc(size, GFP_KERNEL); rdev->bios = kmalloc(size, GFP_KERNEL);
...@@ -118,9 +183,10 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) ...@@ -118,9 +183,10 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
} }
for (i = 0; i < size / ATRM_BIOS_PAGE; i++) { for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
ret = radeon_atrm_get_bios_chunk(rdev->bios, ret = radeon_atrm_call(atrm_handle,
(i * ATRM_BIOS_PAGE), rdev->bios,
ATRM_BIOS_PAGE); (i * ATRM_BIOS_PAGE),
ATRM_BIOS_PAGE);
if (ret < ATRM_BIOS_PAGE) if (ret < ATRM_BIOS_PAGE)
break; break;
} }
...@@ -131,6 +197,12 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) ...@@ -131,6 +197,12 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
} }
return true; 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) static bool ni_read_disabled_bios(struct radeon_device *rdev)
{ {
......
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