diff options
author | Alex Deucher <alexander.deucher@amd.com> | 2013-02-19 12:55:52 -0500 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2013-02-20 08:51:21 -0500 |
commit | 43a23aa450cc19fe8996caf09e7e21ae5f6e56e8 (patch) | |
tree | 84492903b219c0be8637157d41a170272250be7e | |
parent | d0418894142f88041d2b7b5aa4f8bf3178d89514 (diff) |
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
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_atpx_handler.c | 73 |
1 files changed, 71 insertions, 2 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 15f5ded65e0c..d96070bf8388 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c | |||
@@ -43,6 +43,12 @@ struct atpx_verify_interface { | |||
43 | u32 function_bits; /* supported functions bit vector */ | 43 | u32 function_bits; /* supported functions bit vector */ |
44 | } __packed; | 44 | } __packed; |
45 | 45 | ||
46 | struct atpx_px_params { | ||
47 | u16 size; /* structure size in bytes (includes size field) */ | ||
48 | u32 valid_flags; /* which flags are valid */ | ||
49 | u32 flags; /* flags */ | ||
50 | } __packed; | ||
51 | |||
46 | struct atpx_power_control { | 52 | struct atpx_power_control { |
47 | u16 size; | 53 | u16 size; |
48 | u8 dgpu_state; | 54 | u8 dgpu_state; |
@@ -123,9 +129,61 @@ static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mas | |||
123 | } | 129 | } |
124 | 130 | ||
125 | /** | 131 | /** |
132 | * radeon_atpx_validate_functions - validate ATPX functions | ||
133 | * | ||
134 | * @atpx: radeon atpx struct | ||
135 | * | ||
136 | * Validate that required functions are enabled (all asics). | ||
137 | * returns 0 on success, error on failure. | ||
138 | */ | ||
139 | static int radeon_atpx_validate(struct radeon_atpx *atpx) | ||
140 | { | ||
141 | /* make sure required functions are enabled */ | ||
142 | /* dGPU power control is required */ | ||
143 | atpx->functions.power_cntl = true; | ||
144 | |||
145 | if (atpx->functions.px_params) { | ||
146 | union acpi_object *info; | ||
147 | struct atpx_px_params output; | ||
148 | size_t size; | ||
149 | u32 valid_bits; | ||
150 | |||
151 | info = radeon_atpx_call(atpx->handle, ATPX_FUNCTION_GET_PX_PARAMETERS, NULL); | ||
152 | if (!info) | ||
153 | return -EIO; | ||
154 | |||
155 | memset(&output, 0, sizeof(output)); | ||
156 | |||
157 | size = *(u16 *) info->buffer.pointer; | ||
158 | if (size < 10) { | ||
159 | printk("ATPX buffer is too small: %zu\n", size); | ||
160 | kfree(info); | ||
161 | return -EINVAL; | ||
162 | } | ||
163 | size = min(sizeof(output), size); | ||
164 | |||
165 | memcpy(&output, info->buffer.pointer, size); | ||
166 | |||
167 | valid_bits = output.flags & output.valid_flags; | ||
168 | /* if separate mux flag is set, mux controls are required */ | ||
169 | if (valid_bits & ATPX_SEPARATE_MUX_FOR_I2C) { | ||
170 | atpx->functions.i2c_mux_cntl = true; | ||
171 | atpx->functions.disp_mux_cntl = true; | ||
172 | } | ||
173 | /* if any outputs are muxed, mux controls are required */ | ||
174 | if (valid_bits & (ATPX_CRT1_RGB_SIGNAL_MUXED | | ||
175 | ATPX_TV_SIGNAL_MUXED | | ||
176 | ATPX_DFP_SIGNAL_MUXED)) | ||
177 | atpx->functions.disp_mux_cntl = true; | ||
178 | |||
179 | kfree(info); | ||
180 | } | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | /** | ||
126 | * radeon_atpx_verify_interface - verify ATPX | 185 | * radeon_atpx_verify_interface - verify ATPX |
127 | * | 186 | * |
128 | * @handle: acpi handle | ||
129 | * @atpx: radeon atpx struct | 187 | * @atpx: radeon atpx struct |
130 | * | 188 | * |
131 | * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function | 189 | * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function |
@@ -406,8 +464,19 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) | |||
406 | */ | 464 | */ |
407 | static int radeon_atpx_init(void) | 465 | static int radeon_atpx_init(void) |
408 | { | 466 | { |
467 | int r; | ||
468 | |||
409 | /* set up the ATPX handle */ | 469 | /* set up the ATPX handle */ |
410 | return radeon_atpx_verify_interface(&radeon_atpx_priv.atpx); | 470 | r = radeon_atpx_verify_interface(&radeon_atpx_priv.atpx); |
471 | if (r) | ||
472 | return r; | ||
473 | |||
474 | /* validate the atpx setup */ | ||
475 | r = radeon_atpx_validate(&radeon_atpx_priv.atpx); | ||
476 | if (r) | ||
477 | return r; | ||
478 | |||
479 | return 0; | ||
411 | } | 480 | } |
412 | 481 | ||
413 | /** | 482 | /** |