Commit 43a23aa4 authored by Alex Deucher's avatar Alex Deucher

drm/radeon: properly validate the atpx interface

Some bioses don't set the function mask correctly
which caused required functions to be disabled.

Fixes:
https://bugzilla.kernel.org/show_bug.cgi?id=53111Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
parent d0418894
...@@ -43,6 +43,12 @@ struct atpx_verify_interface { ...@@ -43,6 +43,12 @@ struct atpx_verify_interface {
u32 function_bits; /* supported functions bit vector */ u32 function_bits; /* supported functions bit vector */
} __packed; } __packed;
struct atpx_px_params {
u16 size; /* structure size in bytes (includes size field) */
u32 valid_flags; /* which flags are valid */
u32 flags; /* flags */
} __packed;
struct atpx_power_control { struct atpx_power_control {
u16 size; u16 size;
u8 dgpu_state; u8 dgpu_state;
...@@ -122,10 +128,62 @@ static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mas ...@@ -122,10 +128,62 @@ static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mas
f->disp_detetion_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED; f->disp_detetion_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED;
} }
/**
* radeon_atpx_validate_functions - validate ATPX functions
*
* @atpx: radeon atpx struct
*
* Validate that required functions are enabled (all asics).
* returns 0 on success, error on failure.
*/
static int radeon_atpx_validate(struct radeon_atpx *atpx)
{
/* make sure required functions are enabled */
/* dGPU power control is required */
atpx->functions.power_cntl = true;
if (atpx->functions.px_params) {
union acpi_object *info;
struct atpx_px_params output;
size_t size;
u32 valid_bits;
info = radeon_atpx_call(atpx->handle, ATPX_FUNCTION_GET_PX_PARAMETERS, NULL);
if (!info)
return -EIO;
memset(&output, 0, sizeof(output));
size = *(u16 *) info->buffer.pointer;
if (size < 10) {
printk("ATPX buffer is too small: %zu\n", size);
kfree(info);
return -EINVAL;
}
size = min(sizeof(output), size);
memcpy(&output, info->buffer.pointer, size);
valid_bits = output.flags & output.valid_flags;
/* if separate mux flag is set, mux controls are required */
if (valid_bits & ATPX_SEPARATE_MUX_FOR_I2C) {
atpx->functions.i2c_mux_cntl = true;
atpx->functions.disp_mux_cntl = true;
}
/* if any outputs are muxed, mux controls are required */
if (valid_bits & (ATPX_CRT1_RGB_SIGNAL_MUXED |
ATPX_TV_SIGNAL_MUXED |
ATPX_DFP_SIGNAL_MUXED))
atpx->functions.disp_mux_cntl = true;
kfree(info);
}
return 0;
}
/** /**
* radeon_atpx_verify_interface - verify ATPX * radeon_atpx_verify_interface - verify ATPX
* *
* @handle: acpi handle
* @atpx: radeon atpx struct * @atpx: radeon atpx struct
* *
* Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function
...@@ -406,8 +464,19 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) ...@@ -406,8 +464,19 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
*/ */
static int radeon_atpx_init(void) static int radeon_atpx_init(void)
{ {
int r;
/* set up the ATPX handle */ /* set up the ATPX handle */
return radeon_atpx_verify_interface(&radeon_atpx_priv.atpx); r = radeon_atpx_verify_interface(&radeon_atpx_priv.atpx);
if (r)
return r;
/* validate the atpx setup */
r = radeon_atpx_validate(&radeon_atpx_priv.atpx);
if (r)
return r;
return 0;
} }
/** /**
......
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