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=53111 Signed-off-by: Alex Deucher <alexander.deucher@amd.com> Cc: stable@vger.kernel.org
This commit is contained in:
parent
d041889414
commit
43a23aa450
|
@ -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
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue