Skip to content

Commit

Permalink
drm/radeon: properly validate the atpx interface
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Alex Deucher committed Feb 20, 2013
1 parent d041889 commit 43a23aa
Showing 1 changed file with 71 additions and 2 deletions.
73 changes: 71 additions & 2 deletions drivers/gpu/drm/radeon/radeon_atpx_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ struct atpx_verify_interface {
u32 function_bits; /* supported functions bit vector */
} __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 {
u16 size;
u8 dgpu_state;
Expand Down Expand Up @@ -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;
}

/**
* 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
*
* @handle: acpi handle
* @atpx: radeon atpx struct
*
* Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function
Expand Down Expand Up @@ -406,8 +464,19 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
*/
static int radeon_atpx_init(void)
{
int r;

/* 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;
}

/**
Expand Down

0 comments on commit 43a23aa

Please sign in to comment.