1 | // SPDX-License-Identifier: MIT |
2 | /* |
3 | * Copyright 2012 Advanced Micro Devices, Inc. |
4 | * |
5 | * Permission is hereby granted, free of charge, to any person obtaining a |
6 | * copy of this software and associated documentation files (the "Software"), |
7 | * to deal in the Software without restriction, including without limitation |
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
9 | * and/or sell copies of the Software, and to permit persons to whom the |
10 | * Software is furnished to do so, subject to the following conditions: |
11 | * |
12 | * The above copyright notice and this permission notice shall be included in |
13 | * all copies or substantial portions of the Software. |
14 | * |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
18 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
19 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
20 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
21 | * OTHER DEALINGS IN THE SOFTWARE. |
22 | * |
23 | */ |
24 | |
25 | #include <linux/pci.h> |
26 | #include <linux/acpi.h> |
27 | #include <linux/backlight.h> |
28 | #include <linux/slab.h> |
29 | #include <linux/xarray.h> |
30 | #include <linux/power_supply.h> |
31 | #include <linux/pm_runtime.h> |
32 | #include <linux/suspend.h> |
33 | #include <acpi/video.h> |
34 | #include <acpi/actbl.h> |
35 | |
36 | #include "amdgpu.h" |
37 | #include "amdgpu_pm.h" |
38 | #include "amdgpu_display.h" |
39 | #include "amd_acpi.h" |
40 | #include "atom.h" |
41 | |
42 | /* Declare GUID for AMD _DSM method for XCCs */ |
43 | static const guid_t amd_xcc_dsm_guid = GUID_INIT(0x8267f5d5, 0xa556, 0x44f2, |
44 | 0xb8, 0xb4, 0x45, 0x56, 0x2e, |
45 | 0x8c, 0x5b, 0xec); |
46 | |
47 | #define AMD_XCC_HID_START 3000 |
48 | #define AMD_XCC_DSM_GET_NUM_FUNCS 0 |
49 | #define AMD_XCC_DSM_GET_SUPP_MODE 1 |
50 | #define AMD_XCC_DSM_GET_XCP_MODE 2 |
51 | #define AMD_XCC_DSM_GET_VF_XCC_MAPPING 4 |
52 | #define AMD_XCC_DSM_GET_TMR_INFO 5 |
53 | #define AMD_XCC_DSM_NUM_FUNCS 5 |
54 | |
55 | #define AMD_XCC_MAX_HID 24 |
56 | |
57 | struct xarray numa_info_xa; |
58 | |
59 | /* Encapsulates the XCD acpi object information */ |
60 | struct amdgpu_acpi_xcc_info { |
61 | struct list_head list; |
62 | struct amdgpu_numa_info *numa_info; |
63 | uint8_t xcp_node; |
64 | uint8_t phy_id; |
65 | acpi_handle handle; |
66 | }; |
67 | |
68 | struct amdgpu_acpi_dev_info { |
69 | struct list_head list; |
70 | struct list_head xcc_list; |
71 | uint32_t sbdf; |
72 | uint16_t supp_xcp_mode; |
73 | uint16_t xcp_mode; |
74 | uint16_t mem_mode; |
75 | uint64_t tmr_base; |
76 | uint64_t tmr_size; |
77 | }; |
78 | |
79 | struct list_head amdgpu_acpi_dev_list; |
80 | |
81 | struct amdgpu_atif_notification_cfg { |
82 | bool enabled; |
83 | int command_code; |
84 | }; |
85 | |
86 | struct amdgpu_atif_notifications { |
87 | bool thermal_state; |
88 | bool forced_power_state; |
89 | bool system_power_state; |
90 | bool brightness_change; |
91 | bool dgpu_display_event; |
92 | bool gpu_package_power_limit; |
93 | }; |
94 | |
95 | struct amdgpu_atif_functions { |
96 | bool system_params; |
97 | bool sbios_requests; |
98 | bool temperature_change; |
99 | bool query_backlight_transfer_characteristics; |
100 | bool ready_to_undock; |
101 | bool external_gpu_information; |
102 | }; |
103 | |
104 | struct amdgpu_atif { |
105 | acpi_handle handle; |
106 | |
107 | struct amdgpu_atif_notifications notifications; |
108 | struct amdgpu_atif_functions functions; |
109 | struct amdgpu_atif_notification_cfg notification_cfg; |
110 | struct backlight_device *bd; |
111 | struct amdgpu_dm_backlight_caps backlight_caps; |
112 | }; |
113 | |
114 | struct amdgpu_atcs_functions { |
115 | bool get_ext_state; |
116 | bool pcie_perf_req; |
117 | bool pcie_dev_rdy; |
118 | bool pcie_bus_width; |
119 | bool power_shift_control; |
120 | }; |
121 | |
122 | struct amdgpu_atcs { |
123 | acpi_handle handle; |
124 | |
125 | struct amdgpu_atcs_functions functions; |
126 | }; |
127 | |
128 | static struct amdgpu_acpi_priv { |
129 | struct amdgpu_atif atif; |
130 | struct amdgpu_atcs atcs; |
131 | } amdgpu_acpi_priv; |
132 | |
133 | /* Call the ATIF method |
134 | */ |
135 | /** |
136 | * amdgpu_atif_call - call an ATIF method |
137 | * |
138 | * @atif: atif structure |
139 | * @function: the ATIF function to execute |
140 | * @params: ATIF function params |
141 | * |
142 | * Executes the requested ATIF function (all asics). |
143 | * Returns a pointer to the acpi output buffer. |
144 | */ |
145 | static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif, |
146 | int function, |
147 | struct acpi_buffer *params) |
148 | { |
149 | acpi_status status; |
150 | union acpi_object atif_arg_elements[2]; |
151 | struct acpi_object_list atif_arg; |
152 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
153 | |
154 | atif_arg.count = 2; |
155 | atif_arg.pointer = &atif_arg_elements[0]; |
156 | |
157 | atif_arg_elements[0].type = ACPI_TYPE_INTEGER; |
158 | atif_arg_elements[0].integer.value = function; |
159 | |
160 | if (params) { |
161 | atif_arg_elements[1].type = ACPI_TYPE_BUFFER; |
162 | atif_arg_elements[1].buffer.length = params->length; |
163 | atif_arg_elements[1].buffer.pointer = params->pointer; |
164 | } else { |
165 | /* We need a second fake parameter */ |
166 | atif_arg_elements[1].type = ACPI_TYPE_INTEGER; |
167 | atif_arg_elements[1].integer.value = 0; |
168 | } |
169 | |
170 | status = acpi_evaluate_object(object: atif->handle, NULL, parameter_objects: &atif_arg, |
171 | return_object_buffer: &buffer); |
172 | |
173 | /* Fail only if calling the method fails and ATIF is supported */ |
174 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
175 | DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n" , |
176 | acpi_format_exception(status)); |
177 | kfree(objp: buffer.pointer); |
178 | return NULL; |
179 | } |
180 | |
181 | return buffer.pointer; |
182 | } |
183 | |
184 | /** |
185 | * amdgpu_atif_parse_notification - parse supported notifications |
186 | * |
187 | * @n: supported notifications struct |
188 | * @mask: supported notifications mask from ATIF |
189 | * |
190 | * Use the supported notifications mask from ATIF function |
191 | * ATIF_FUNCTION_VERIFY_INTERFACE to determine what notifications |
192 | * are supported (all asics). |
193 | */ |
194 | static void amdgpu_atif_parse_notification(struct amdgpu_atif_notifications *n, u32 mask) |
195 | { |
196 | n->thermal_state = mask & ATIF_THERMAL_STATE_CHANGE_REQUEST_SUPPORTED; |
197 | n->forced_power_state = mask & ATIF_FORCED_POWER_STATE_CHANGE_REQUEST_SUPPORTED; |
198 | n->system_power_state = mask & ATIF_SYSTEM_POWER_SOURCE_CHANGE_REQUEST_SUPPORTED; |
199 | n->brightness_change = mask & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST_SUPPORTED; |
200 | n->dgpu_display_event = mask & ATIF_DGPU_DISPLAY_EVENT_SUPPORTED; |
201 | n->gpu_package_power_limit = mask & ATIF_GPU_PACKAGE_POWER_LIMIT_REQUEST_SUPPORTED; |
202 | } |
203 | |
204 | /** |
205 | * amdgpu_atif_parse_functions - parse supported functions |
206 | * |
207 | * @f: supported functions struct |
208 | * @mask: supported functions mask from ATIF |
209 | * |
210 | * Use the supported functions mask from ATIF function |
211 | * ATIF_FUNCTION_VERIFY_INTERFACE to determine what functions |
212 | * are supported (all asics). |
213 | */ |
214 | static void amdgpu_atif_parse_functions(struct amdgpu_atif_functions *f, u32 mask) |
215 | { |
216 | f->system_params = mask & ATIF_GET_SYSTEM_PARAMETERS_SUPPORTED; |
217 | f->sbios_requests = mask & ATIF_GET_SYSTEM_BIOS_REQUESTS_SUPPORTED; |
218 | f->temperature_change = mask & ATIF_TEMPERATURE_CHANGE_NOTIFICATION_SUPPORTED; |
219 | f->query_backlight_transfer_characteristics = |
220 | mask & ATIF_QUERY_BACKLIGHT_TRANSFER_CHARACTERISTICS_SUPPORTED; |
221 | f->ready_to_undock = mask & ATIF_READY_TO_UNDOCK_NOTIFICATION_SUPPORTED; |
222 | f->external_gpu_information = mask & ATIF_GET_EXTERNAL_GPU_INFORMATION_SUPPORTED; |
223 | } |
224 | |
225 | /** |
226 | * amdgpu_atif_verify_interface - verify ATIF |
227 | * |
228 | * @atif: amdgpu atif struct |
229 | * |
230 | * Execute the ATIF_FUNCTION_VERIFY_INTERFACE ATIF function |
231 | * to initialize ATIF and determine what features are supported |
232 | * (all asics). |
233 | * returns 0 on success, error on failure. |
234 | */ |
235 | static int amdgpu_atif_verify_interface(struct amdgpu_atif *atif) |
236 | { |
237 | union acpi_object *info; |
238 | struct atif_verify_interface output; |
239 | size_t size; |
240 | int err = 0; |
241 | |
242 | info = amdgpu_atif_call(atif, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); |
243 | if (!info) |
244 | return -EIO; |
245 | |
246 | memset(&output, 0, sizeof(output)); |
247 | |
248 | size = *(u16 *) info->buffer.pointer; |
249 | if (size < 12) { |
250 | DRM_INFO("ATIF buffer is too small: %zu\n" , size); |
251 | err = -EINVAL; |
252 | goto out; |
253 | } |
254 | size = min(sizeof(output), size); |
255 | |
256 | memcpy(&output, info->buffer.pointer, size); |
257 | |
258 | /* TODO: check version? */ |
259 | DRM_DEBUG_DRIVER("ATIF version %u\n" , output.version); |
260 | |
261 | amdgpu_atif_parse_notification(n: &atif->notifications, mask: output.notification_mask); |
262 | amdgpu_atif_parse_functions(f: &atif->functions, mask: output.function_bits); |
263 | |
264 | out: |
265 | kfree(objp: info); |
266 | return err; |
267 | } |
268 | |
269 | /** |
270 | * amdgpu_atif_get_notification_params - determine notify configuration |
271 | * |
272 | * @atif: acpi handle |
273 | * |
274 | * Execute the ATIF_FUNCTION_GET_SYSTEM_PARAMETERS ATIF function |
275 | * to determine if a notifier is used and if so which one |
276 | * (all asics). This is either Notify(VGA, 0x81) or Notify(VGA, n) |
277 | * where n is specified in the result if a notifier is used. |
278 | * Returns 0 on success, error on failure. |
279 | */ |
280 | static int amdgpu_atif_get_notification_params(struct amdgpu_atif *atif) |
281 | { |
282 | union acpi_object *info; |
283 | struct amdgpu_atif_notification_cfg *n = &atif->notification_cfg; |
284 | struct atif_system_params params; |
285 | size_t size; |
286 | int err = 0; |
287 | |
288 | info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, |
289 | NULL); |
290 | if (!info) { |
291 | err = -EIO; |
292 | goto out; |
293 | } |
294 | |
295 | size = *(u16 *) info->buffer.pointer; |
296 | if (size < 10) { |
297 | err = -EINVAL; |
298 | goto out; |
299 | } |
300 | |
301 | memset(¶ms, 0, sizeof(params)); |
302 | size = min(sizeof(params), size); |
303 | memcpy(¶ms, info->buffer.pointer, size); |
304 | |
305 | DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n" , |
306 | params.flags, params.valid_mask); |
307 | params.flags = params.flags & params.valid_mask; |
308 | |
309 | if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_NONE) { |
310 | n->enabled = false; |
311 | n->command_code = 0; |
312 | } else if ((params.flags & ATIF_NOTIFY_MASK) == ATIF_NOTIFY_81) { |
313 | n->enabled = true; |
314 | n->command_code = 0x81; |
315 | } else { |
316 | if (size < 11) { |
317 | err = -EINVAL; |
318 | goto out; |
319 | } |
320 | n->enabled = true; |
321 | n->command_code = params.command_code; |
322 | } |
323 | |
324 | out: |
325 | DRM_DEBUG_DRIVER("Notification %s, command code = %#x\n" , |
326 | (n->enabled ? "enabled" : "disabled" ), |
327 | n->command_code); |
328 | kfree(objp: info); |
329 | return err; |
330 | } |
331 | |
332 | /** |
333 | * amdgpu_atif_query_backlight_caps - get min and max backlight input signal |
334 | * |
335 | * @atif: acpi handle |
336 | * |
337 | * Execute the QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS ATIF function |
338 | * to determine the acceptable range of backlight values |
339 | * |
340 | * Backlight_caps.caps_valid will be set to true if the query is successful |
341 | * |
342 | * The input signals are in range 0-255 |
343 | * |
344 | * This function assumes the display with backlight is the first LCD |
345 | * |
346 | * Returns 0 on success, error on failure. |
347 | */ |
348 | static int amdgpu_atif_query_backlight_caps(struct amdgpu_atif *atif) |
349 | { |
350 | union acpi_object *info; |
351 | struct atif_qbtc_output characteristics; |
352 | struct atif_qbtc_arguments arguments; |
353 | struct acpi_buffer params; |
354 | size_t size; |
355 | int err = 0; |
356 | |
357 | arguments.size = sizeof(arguments); |
358 | arguments.requested_display = ATIF_QBTC_REQUEST_LCD1; |
359 | |
360 | params.length = sizeof(arguments); |
361 | params.pointer = (void *)&arguments; |
362 | |
363 | info = amdgpu_atif_call(atif, |
364 | ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS, |
365 | params: ¶ms); |
366 | if (!info) { |
367 | err = -EIO; |
368 | goto out; |
369 | } |
370 | |
371 | size = *(u16 *) info->buffer.pointer; |
372 | if (size < 10) { |
373 | err = -EINVAL; |
374 | goto out; |
375 | } |
376 | |
377 | memset(&characteristics, 0, sizeof(characteristics)); |
378 | size = min(sizeof(characteristics), size); |
379 | memcpy(&characteristics, info->buffer.pointer, size); |
380 | |
381 | atif->backlight_caps.caps_valid = true; |
382 | atif->backlight_caps.min_input_signal = |
383 | characteristics.min_input_signal; |
384 | atif->backlight_caps.max_input_signal = |
385 | characteristics.max_input_signal; |
386 | out: |
387 | kfree(objp: info); |
388 | return err; |
389 | } |
390 | |
391 | /** |
392 | * amdgpu_atif_get_sbios_requests - get requested sbios event |
393 | * |
394 | * @atif: acpi handle |
395 | * @req: atif sbios request struct |
396 | * |
397 | * Execute the ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS ATIF function |
398 | * to determine what requests the sbios is making to the driver |
399 | * (all asics). |
400 | * Returns 0 on success, error on failure. |
401 | */ |
402 | static int amdgpu_atif_get_sbios_requests(struct amdgpu_atif *atif, |
403 | struct atif_sbios_requests *req) |
404 | { |
405 | union acpi_object *info; |
406 | size_t size; |
407 | int count = 0; |
408 | |
409 | info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, |
410 | NULL); |
411 | if (!info) |
412 | return -EIO; |
413 | |
414 | size = *(u16 *)info->buffer.pointer; |
415 | if (size < 0xd) { |
416 | count = -EINVAL; |
417 | goto out; |
418 | } |
419 | memset(req, 0, sizeof(*req)); |
420 | |
421 | size = min(sizeof(*req), size); |
422 | memcpy(req, info->buffer.pointer, size); |
423 | DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n" , req->pending); |
424 | |
425 | count = hweight32(req->pending); |
426 | |
427 | out: |
428 | kfree(objp: info); |
429 | return count; |
430 | } |
431 | |
432 | /** |
433 | * amdgpu_atif_handler - handle ATIF notify requests |
434 | * |
435 | * @adev: amdgpu_device pointer |
436 | * @event: atif sbios request struct |
437 | * |
438 | * Checks the acpi event and if it matches an atif event, |
439 | * handles it. |
440 | * |
441 | * Returns: |
442 | * NOTIFY_BAD or NOTIFY_DONE, depending on the event. |
443 | */ |
444 | static int amdgpu_atif_handler(struct amdgpu_device *adev, |
445 | struct acpi_bus_event *event) |
446 | { |
447 | struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif; |
448 | int count; |
449 | |
450 | DRM_DEBUG_DRIVER("event, device_class = %s, type = %#x\n" , |
451 | event->device_class, event->type); |
452 | |
453 | if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0) |
454 | return NOTIFY_DONE; |
455 | |
456 | /* Is this actually our event? */ |
457 | if (!atif->notification_cfg.enabled || |
458 | event->type != atif->notification_cfg.command_code) { |
459 | /* These events will generate keypresses otherwise */ |
460 | if (event->type == ACPI_VIDEO_NOTIFY_PROBE) |
461 | return NOTIFY_BAD; |
462 | else |
463 | return NOTIFY_DONE; |
464 | } |
465 | |
466 | if (atif->functions.sbios_requests) { |
467 | struct atif_sbios_requests req; |
468 | |
469 | /* Check pending SBIOS requests */ |
470 | count = amdgpu_atif_get_sbios_requests(atif, req: &req); |
471 | |
472 | if (count <= 0) |
473 | return NOTIFY_BAD; |
474 | |
475 | DRM_DEBUG_DRIVER("ATIF: %d pending SBIOS requests\n" , count); |
476 | |
477 | if (req.pending & ATIF_PANEL_BRIGHTNESS_CHANGE_REQUEST) { |
478 | if (atif->bd) { |
479 | DRM_DEBUG_DRIVER("Changing brightness to %d\n" , |
480 | req.backlight_level); |
481 | /* |
482 | * XXX backlight_device_set_brightness() is |
483 | * hardwired to post BACKLIGHT_UPDATE_SYSFS. |
484 | * It probably should accept 'reason' parameter. |
485 | */ |
486 | backlight_device_set_brightness(bd: atif->bd, brightness: req.backlight_level); |
487 | } |
488 | } |
489 | |
490 | if (req.pending & ATIF_DGPU_DISPLAY_EVENT) { |
491 | if (adev->flags & AMD_IS_PX) { |
492 | pm_runtime_get_sync(dev: adev_to_drm(adev)->dev); |
493 | /* Just fire off a uevent and let userspace tell us what to do */ |
494 | drm_helper_hpd_irq_event(dev: adev_to_drm(adev)); |
495 | pm_runtime_mark_last_busy(dev: adev_to_drm(adev)->dev); |
496 | pm_runtime_put_autosuspend(dev: adev_to_drm(adev)->dev); |
497 | } |
498 | } |
499 | /* TODO: check other events */ |
500 | } |
501 | |
502 | /* We've handled the event, stop the notifier chain. The ACPI interface |
503 | * overloads ACPI_VIDEO_NOTIFY_PROBE, we don't want to send that to |
504 | * userspace if the event was generated only to signal a SBIOS |
505 | * request. |
506 | */ |
507 | return NOTIFY_BAD; |
508 | } |
509 | |
510 | /* Call the ATCS method |
511 | */ |
512 | /** |
513 | * amdgpu_atcs_call - call an ATCS method |
514 | * |
515 | * @atcs: atcs structure |
516 | * @function: the ATCS function to execute |
517 | * @params: ATCS function params |
518 | * |
519 | * Executes the requested ATCS function (all asics). |
520 | * Returns a pointer to the acpi output buffer. |
521 | */ |
522 | static union acpi_object *amdgpu_atcs_call(struct amdgpu_atcs *atcs, |
523 | int function, |
524 | struct acpi_buffer *params) |
525 | { |
526 | acpi_status status; |
527 | union acpi_object atcs_arg_elements[2]; |
528 | struct acpi_object_list atcs_arg; |
529 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
530 | |
531 | atcs_arg.count = 2; |
532 | atcs_arg.pointer = &atcs_arg_elements[0]; |
533 | |
534 | atcs_arg_elements[0].type = ACPI_TYPE_INTEGER; |
535 | atcs_arg_elements[0].integer.value = function; |
536 | |
537 | if (params) { |
538 | atcs_arg_elements[1].type = ACPI_TYPE_BUFFER; |
539 | atcs_arg_elements[1].buffer.length = params->length; |
540 | atcs_arg_elements[1].buffer.pointer = params->pointer; |
541 | } else { |
542 | /* We need a second fake parameter */ |
543 | atcs_arg_elements[1].type = ACPI_TYPE_INTEGER; |
544 | atcs_arg_elements[1].integer.value = 0; |
545 | } |
546 | |
547 | status = acpi_evaluate_object(object: atcs->handle, NULL, parameter_objects: &atcs_arg, return_object_buffer: &buffer); |
548 | |
549 | /* Fail only if calling the method fails and ATIF is supported */ |
550 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
551 | DRM_DEBUG_DRIVER("failed to evaluate ATCS got %s\n" , |
552 | acpi_format_exception(status)); |
553 | kfree(objp: buffer.pointer); |
554 | return NULL; |
555 | } |
556 | |
557 | return buffer.pointer; |
558 | } |
559 | |
560 | /** |
561 | * amdgpu_atcs_parse_functions - parse supported functions |
562 | * |
563 | * @f: supported functions struct |
564 | * @mask: supported functions mask from ATCS |
565 | * |
566 | * Use the supported functions mask from ATCS function |
567 | * ATCS_FUNCTION_VERIFY_INTERFACE to determine what functions |
568 | * are supported (all asics). |
569 | */ |
570 | static void amdgpu_atcs_parse_functions(struct amdgpu_atcs_functions *f, u32 mask) |
571 | { |
572 | f->get_ext_state = mask & ATCS_GET_EXTERNAL_STATE_SUPPORTED; |
573 | f->pcie_perf_req = mask & ATCS_PCIE_PERFORMANCE_REQUEST_SUPPORTED; |
574 | f->pcie_dev_rdy = mask & ATCS_PCIE_DEVICE_READY_NOTIFICATION_SUPPORTED; |
575 | f->pcie_bus_width = mask & ATCS_SET_PCIE_BUS_WIDTH_SUPPORTED; |
576 | f->power_shift_control = mask & ATCS_SET_POWER_SHIFT_CONTROL_SUPPORTED; |
577 | } |
578 | |
579 | /** |
580 | * amdgpu_atcs_verify_interface - verify ATCS |
581 | * |
582 | * @atcs: amdgpu atcs struct |
583 | * |
584 | * Execute the ATCS_FUNCTION_VERIFY_INTERFACE ATCS function |
585 | * to initialize ATCS and determine what features are supported |
586 | * (all asics). |
587 | * returns 0 on success, error on failure. |
588 | */ |
589 | static int amdgpu_atcs_verify_interface(struct amdgpu_atcs *atcs) |
590 | { |
591 | union acpi_object *info; |
592 | struct atcs_verify_interface output; |
593 | size_t size; |
594 | int err = 0; |
595 | |
596 | info = amdgpu_atcs_call(atcs, ATCS_FUNCTION_VERIFY_INTERFACE, NULL); |
597 | if (!info) |
598 | return -EIO; |
599 | |
600 | memset(&output, 0, sizeof(output)); |
601 | |
602 | size = *(u16 *) info->buffer.pointer; |
603 | if (size < 8) { |
604 | DRM_INFO("ATCS buffer is too small: %zu\n" , size); |
605 | err = -EINVAL; |
606 | goto out; |
607 | } |
608 | size = min(sizeof(output), size); |
609 | |
610 | memcpy(&output, info->buffer.pointer, size); |
611 | |
612 | /* TODO: check version? */ |
613 | DRM_DEBUG_DRIVER("ATCS version %u\n" , output.version); |
614 | |
615 | amdgpu_atcs_parse_functions(f: &atcs->functions, mask: output.function_bits); |
616 | |
617 | out: |
618 | kfree(objp: info); |
619 | return err; |
620 | } |
621 | |
622 | /** |
623 | * amdgpu_acpi_is_pcie_performance_request_supported |
624 | * |
625 | * @adev: amdgpu_device pointer |
626 | * |
627 | * Check if the ATCS pcie_perf_req and pcie_dev_rdy methods |
628 | * are supported (all asics). |
629 | * returns true if supported, false if not. |
630 | */ |
631 | bool amdgpu_acpi_is_pcie_performance_request_supported(struct amdgpu_device *adev) |
632 | { |
633 | struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs; |
634 | |
635 | if (atcs->functions.pcie_perf_req && atcs->functions.pcie_dev_rdy) |
636 | return true; |
637 | |
638 | return false; |
639 | } |
640 | |
641 | /** |
642 | * amdgpu_acpi_is_power_shift_control_supported |
643 | * |
644 | * Check if the ATCS power shift control method |
645 | * is supported. |
646 | * returns true if supported, false if not. |
647 | */ |
648 | bool amdgpu_acpi_is_power_shift_control_supported(void) |
649 | { |
650 | return amdgpu_acpi_priv.atcs.functions.power_shift_control; |
651 | } |
652 | |
653 | /** |
654 | * amdgpu_acpi_pcie_notify_device_ready |
655 | * |
656 | * @adev: amdgpu_device pointer |
657 | * |
658 | * Executes the PCIE_DEVICE_READY_NOTIFICATION method |
659 | * (all asics). |
660 | * returns 0 on success, error on failure. |
661 | */ |
662 | int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev) |
663 | { |
664 | union acpi_object *info; |
665 | struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs; |
666 | |
667 | if (!atcs->functions.pcie_dev_rdy) |
668 | return -EINVAL; |
669 | |
670 | info = amdgpu_atcs_call(atcs, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION, NULL); |
671 | if (!info) |
672 | return -EIO; |
673 | |
674 | kfree(objp: info); |
675 | |
676 | return 0; |
677 | } |
678 | |
679 | /** |
680 | * amdgpu_acpi_pcie_performance_request |
681 | * |
682 | * @adev: amdgpu_device pointer |
683 | * @perf_req: requested perf level (pcie gen speed) |
684 | * @advertise: set advertise caps flag if set |
685 | * |
686 | * Executes the PCIE_PERFORMANCE_REQUEST method to |
687 | * change the pcie gen speed (all asics). |
688 | * returns 0 on success, error on failure. |
689 | */ |
690 | int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, |
691 | u8 perf_req, bool advertise) |
692 | { |
693 | union acpi_object *info; |
694 | struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs; |
695 | struct atcs_pref_req_input atcs_input; |
696 | struct atcs_pref_req_output atcs_output; |
697 | struct acpi_buffer params; |
698 | size_t size; |
699 | u32 retry = 3; |
700 | |
701 | if (amdgpu_acpi_pcie_notify_device_ready(adev)) |
702 | return -EINVAL; |
703 | |
704 | if (!atcs->functions.pcie_perf_req) |
705 | return -EINVAL; |
706 | |
707 | atcs_input.size = sizeof(struct atcs_pref_req_input); |
708 | /* client id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */ |
709 | atcs_input.client_id = pci_dev_id(dev: adev->pdev); |
710 | atcs_input.valid_flags_mask = ATCS_VALID_FLAGS_MASK; |
711 | atcs_input.flags = ATCS_WAIT_FOR_COMPLETION; |
712 | if (advertise) |
713 | atcs_input.flags |= ATCS_ADVERTISE_CAPS; |
714 | atcs_input.req_type = ATCS_PCIE_LINK_SPEED; |
715 | atcs_input.perf_req = perf_req; |
716 | |
717 | params.length = sizeof(struct atcs_pref_req_input); |
718 | params.pointer = &atcs_input; |
719 | |
720 | while (retry--) { |
721 | info = amdgpu_atcs_call(atcs, ATCS_FUNCTION_PCIE_PERFORMANCE_REQUEST, params: ¶ms); |
722 | if (!info) |
723 | return -EIO; |
724 | |
725 | memset(&atcs_output, 0, sizeof(atcs_output)); |
726 | |
727 | size = *(u16 *) info->buffer.pointer; |
728 | if (size < 3) { |
729 | DRM_INFO("ATCS buffer is too small: %zu\n" , size); |
730 | kfree(objp: info); |
731 | return -EINVAL; |
732 | } |
733 | size = min(sizeof(atcs_output), size); |
734 | |
735 | memcpy(&atcs_output, info->buffer.pointer, size); |
736 | |
737 | kfree(objp: info); |
738 | |
739 | switch (atcs_output.ret_val) { |
740 | case ATCS_REQUEST_REFUSED: |
741 | default: |
742 | return -EINVAL; |
743 | case ATCS_REQUEST_COMPLETE: |
744 | return 0; |
745 | case ATCS_REQUEST_IN_PROGRESS: |
746 | udelay(10); |
747 | break; |
748 | } |
749 | } |
750 | |
751 | return 0; |
752 | } |
753 | |
754 | /** |
755 | * amdgpu_acpi_power_shift_control |
756 | * |
757 | * @adev: amdgpu_device pointer |
758 | * @dev_state: device acpi state |
759 | * @drv_state: driver state |
760 | * |
761 | * Executes the POWER_SHIFT_CONTROL method to |
762 | * communicate current dGPU device state and |
763 | * driver state to APU/SBIOS. |
764 | * returns 0 on success, error on failure. |
765 | */ |
766 | int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev, |
767 | u8 dev_state, bool drv_state) |
768 | { |
769 | union acpi_object *info; |
770 | struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs; |
771 | struct atcs_pwr_shift_input atcs_input; |
772 | struct acpi_buffer params; |
773 | |
774 | if (!amdgpu_acpi_is_power_shift_control_supported()) |
775 | return -EINVAL; |
776 | |
777 | atcs_input.size = sizeof(struct atcs_pwr_shift_input); |
778 | /* dGPU id (bit 2-0: func num, 7-3: dev num, 15-8: bus num) */ |
779 | atcs_input.dgpu_id = pci_dev_id(dev: adev->pdev); |
780 | atcs_input.dev_acpi_state = dev_state; |
781 | atcs_input.drv_state = drv_state; |
782 | |
783 | params.length = sizeof(struct atcs_pwr_shift_input); |
784 | params.pointer = &atcs_input; |
785 | |
786 | info = amdgpu_atcs_call(atcs, ATCS_FUNCTION_POWER_SHIFT_CONTROL, params: ¶ms); |
787 | if (!info) { |
788 | DRM_ERROR("ATCS PSC update failed\n" ); |
789 | return -EIO; |
790 | } |
791 | |
792 | return 0; |
793 | } |
794 | |
795 | /** |
796 | * amdgpu_acpi_smart_shift_update - update dGPU device state to SBIOS |
797 | * |
798 | * @dev: drm_device pointer |
799 | * @ss_state: current smart shift event |
800 | * |
801 | * returns 0 on success, |
802 | * otherwise return error number. |
803 | */ |
804 | int amdgpu_acpi_smart_shift_update(struct drm_device *dev, enum amdgpu_ss ss_state) |
805 | { |
806 | struct amdgpu_device *adev = drm_to_adev(ddev: dev); |
807 | int r; |
808 | |
809 | if (!amdgpu_device_supports_smart_shift(dev)) |
810 | return 0; |
811 | |
812 | switch (ss_state) { |
813 | /* SBIOS trigger “stop”, “enable” and “start” at D0, Driver Operational. |
814 | * SBIOS trigger “stop” at D3, Driver Not Operational. |
815 | * SBIOS trigger “stop” and “disable” at D0, Driver NOT operational. |
816 | */ |
817 | case AMDGPU_SS_DRV_LOAD: |
818 | r = amdgpu_acpi_power_shift_control(adev, |
819 | AMDGPU_ATCS_PSC_DEV_STATE_D0, |
820 | AMDGPU_ATCS_PSC_DRV_STATE_OPR); |
821 | break; |
822 | case AMDGPU_SS_DEV_D0: |
823 | r = amdgpu_acpi_power_shift_control(adev, |
824 | AMDGPU_ATCS_PSC_DEV_STATE_D0, |
825 | AMDGPU_ATCS_PSC_DRV_STATE_OPR); |
826 | break; |
827 | case AMDGPU_SS_DEV_D3: |
828 | r = amdgpu_acpi_power_shift_control(adev, |
829 | AMDGPU_ATCS_PSC_DEV_STATE_D3_HOT, |
830 | AMDGPU_ATCS_PSC_DRV_STATE_NOT_OPR); |
831 | break; |
832 | case AMDGPU_SS_DRV_UNLOAD: |
833 | r = amdgpu_acpi_power_shift_control(adev, |
834 | AMDGPU_ATCS_PSC_DEV_STATE_D0, |
835 | AMDGPU_ATCS_PSC_DRV_STATE_NOT_OPR); |
836 | break; |
837 | default: |
838 | return -EINVAL; |
839 | } |
840 | |
841 | return r; |
842 | } |
843 | |
844 | #ifdef CONFIG_ACPI_NUMA |
845 | static inline uint64_t amdgpu_acpi_get_numa_size(int nid) |
846 | { |
847 | /* This is directly using si_meminfo_node implementation as the |
848 | * function is not exported. |
849 | */ |
850 | int zone_type; |
851 | uint64_t managed_pages = 0; |
852 | |
853 | pg_data_t *pgdat = NODE_DATA(nid); |
854 | |
855 | for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++) |
856 | managed_pages += |
857 | zone_managed_pages(zone: &pgdat->node_zones[zone_type]); |
858 | return managed_pages * PAGE_SIZE; |
859 | } |
860 | |
861 | static struct amdgpu_numa_info *amdgpu_acpi_get_numa_info(uint32_t pxm) |
862 | { |
863 | struct amdgpu_numa_info *numa_info; |
864 | int nid; |
865 | |
866 | numa_info = xa_load(&numa_info_xa, index: pxm); |
867 | |
868 | if (!numa_info) { |
869 | struct sysinfo info; |
870 | |
871 | numa_info = kzalloc(size: sizeof(*numa_info), GFP_KERNEL); |
872 | if (!numa_info) |
873 | return NULL; |
874 | |
875 | nid = pxm_to_node(pxm); |
876 | numa_info->pxm = pxm; |
877 | numa_info->nid = nid; |
878 | |
879 | if (numa_info->nid == NUMA_NO_NODE) { |
880 | si_meminfo(val: &info); |
881 | numa_info->size = info.totalram * info.mem_unit; |
882 | } else { |
883 | numa_info->size = amdgpu_acpi_get_numa_size(nid); |
884 | } |
885 | xa_store(&numa_info_xa, index: numa_info->pxm, entry: numa_info, GFP_KERNEL); |
886 | } |
887 | |
888 | return numa_info; |
889 | } |
890 | #endif |
891 | |
892 | /** |
893 | * amdgpu_acpi_get_node_id - obtain the NUMA node id for corresponding amdgpu |
894 | * acpi device handle |
895 | * |
896 | * @handle: acpi handle |
897 | * @numa_info: amdgpu_numa_info structure holding numa information |
898 | * |
899 | * Queries the ACPI interface to fetch the corresponding NUMA Node ID for a |
900 | * given amdgpu acpi device. |
901 | * |
902 | * Returns ACPI STATUS OK with Node ID on success or the corresponding failure reason |
903 | */ |
904 | static acpi_status amdgpu_acpi_get_node_id(acpi_handle handle, |
905 | struct amdgpu_numa_info **numa_info) |
906 | { |
907 | #ifdef CONFIG_ACPI_NUMA |
908 | u64 pxm; |
909 | acpi_status status; |
910 | |
911 | if (!numa_info) |
912 | return_ACPI_STATUS(AE_ERROR); |
913 | |
914 | status = acpi_evaluate_integer(handle, pathname: "_PXM" , NULL, data: &pxm); |
915 | |
916 | if (ACPI_FAILURE(status)) |
917 | return status; |
918 | |
919 | *numa_info = amdgpu_acpi_get_numa_info(pxm); |
920 | |
921 | if (!*numa_info) |
922 | return_ACPI_STATUS(AE_ERROR); |
923 | |
924 | return_ACPI_STATUS(AE_OK); |
925 | #else |
926 | return_ACPI_STATUS(AE_NOT_EXIST); |
927 | #endif |
928 | } |
929 | |
930 | static struct amdgpu_acpi_dev_info *amdgpu_acpi_get_dev(u32 sbdf) |
931 | { |
932 | struct amdgpu_acpi_dev_info *acpi_dev; |
933 | |
934 | if (list_empty(head: &amdgpu_acpi_dev_list)) |
935 | return NULL; |
936 | |
937 | list_for_each_entry(acpi_dev, &amdgpu_acpi_dev_list, list) |
938 | if (acpi_dev->sbdf == sbdf) |
939 | return acpi_dev; |
940 | |
941 | return NULL; |
942 | } |
943 | |
944 | static int amdgpu_acpi_dev_init(struct amdgpu_acpi_dev_info **dev_info, |
945 | struct amdgpu_acpi_xcc_info *xcc_info, u32 sbdf) |
946 | { |
947 | struct amdgpu_acpi_dev_info *tmp; |
948 | union acpi_object *obj; |
949 | int ret = -ENOENT; |
950 | |
951 | *dev_info = NULL; |
952 | tmp = kzalloc(size: sizeof(struct amdgpu_acpi_dev_info), GFP_KERNEL); |
953 | if (!tmp) |
954 | return -ENOMEM; |
955 | |
956 | INIT_LIST_HEAD(list: &tmp->xcc_list); |
957 | INIT_LIST_HEAD(list: &tmp->list); |
958 | tmp->sbdf = sbdf; |
959 | |
960 | obj = acpi_evaluate_dsm_typed(handle: xcc_info->handle, guid: &amd_xcc_dsm_guid, rev: 0, |
961 | AMD_XCC_DSM_GET_SUPP_MODE, NULL, |
962 | ACPI_TYPE_INTEGER); |
963 | |
964 | if (!obj) { |
965 | acpi_handle_debug(xcc_info->handle, |
966 | "_DSM function %d evaluation failed" , |
967 | AMD_XCC_DSM_GET_SUPP_MODE); |
968 | ret = -ENOENT; |
969 | goto out; |
970 | } |
971 | |
972 | tmp->supp_xcp_mode = obj->integer.value & 0xFFFF; |
973 | ACPI_FREE(obj); |
974 | |
975 | obj = acpi_evaluate_dsm_typed(handle: xcc_info->handle, guid: &amd_xcc_dsm_guid, rev: 0, |
976 | AMD_XCC_DSM_GET_XCP_MODE, NULL, |
977 | ACPI_TYPE_INTEGER); |
978 | |
979 | if (!obj) { |
980 | acpi_handle_debug(xcc_info->handle, |
981 | "_DSM function %d evaluation failed" , |
982 | AMD_XCC_DSM_GET_XCP_MODE); |
983 | ret = -ENOENT; |
984 | goto out; |
985 | } |
986 | |
987 | tmp->xcp_mode = obj->integer.value & 0xFFFF; |
988 | tmp->mem_mode = (obj->integer.value >> 32) & 0xFFFF; |
989 | ACPI_FREE(obj); |
990 | |
991 | /* Evaluate DSMs and fill XCC information */ |
992 | obj = acpi_evaluate_dsm_typed(handle: xcc_info->handle, guid: &amd_xcc_dsm_guid, rev: 0, |
993 | AMD_XCC_DSM_GET_TMR_INFO, NULL, |
994 | ACPI_TYPE_PACKAGE); |
995 | |
996 | if (!obj || obj->package.count < 2) { |
997 | acpi_handle_debug(xcc_info->handle, |
998 | "_DSM function %d evaluation failed" , |
999 | AMD_XCC_DSM_GET_TMR_INFO); |
1000 | ret = -ENOENT; |
1001 | goto out; |
1002 | } |
1003 | |
1004 | tmp->tmr_base = obj->package.elements[0].integer.value; |
1005 | tmp->tmr_size = obj->package.elements[1].integer.value; |
1006 | ACPI_FREE(obj); |
1007 | |
1008 | DRM_DEBUG_DRIVER( |
1009 | "New dev(%x): Supported xcp mode: %x curr xcp_mode : %x mem mode : %x, tmr base: %llx tmr size: %llx " , |
1010 | tmp->sbdf, tmp->supp_xcp_mode, tmp->xcp_mode, tmp->mem_mode, |
1011 | tmp->tmr_base, tmp->tmr_size); |
1012 | list_add_tail(new: &tmp->list, head: &amdgpu_acpi_dev_list); |
1013 | *dev_info = tmp; |
1014 | |
1015 | return 0; |
1016 | |
1017 | out: |
1018 | if (obj) |
1019 | ACPI_FREE(obj); |
1020 | kfree(objp: tmp); |
1021 | |
1022 | return ret; |
1023 | } |
1024 | |
1025 | static int amdgpu_acpi_get_xcc_info(struct amdgpu_acpi_xcc_info *xcc_info, |
1026 | u32 *sbdf) |
1027 | { |
1028 | union acpi_object *obj; |
1029 | acpi_status status; |
1030 | int ret = -ENOENT; |
1031 | |
1032 | obj = acpi_evaluate_dsm_typed(handle: xcc_info->handle, guid: &amd_xcc_dsm_guid, rev: 0, |
1033 | AMD_XCC_DSM_GET_NUM_FUNCS, NULL, |
1034 | ACPI_TYPE_INTEGER); |
1035 | |
1036 | if (!obj || obj->integer.value != AMD_XCC_DSM_NUM_FUNCS) |
1037 | goto out; |
1038 | ACPI_FREE(obj); |
1039 | |
1040 | /* Evaluate DSMs and fill XCC information */ |
1041 | obj = acpi_evaluate_dsm_typed(handle: xcc_info->handle, guid: &amd_xcc_dsm_guid, rev: 0, |
1042 | AMD_XCC_DSM_GET_VF_XCC_MAPPING, NULL, |
1043 | ACPI_TYPE_INTEGER); |
1044 | |
1045 | if (!obj) { |
1046 | acpi_handle_debug(xcc_info->handle, |
1047 | "_DSM function %d evaluation failed" , |
1048 | AMD_XCC_DSM_GET_VF_XCC_MAPPING); |
1049 | ret = -EINVAL; |
1050 | goto out; |
1051 | } |
1052 | |
1053 | /* PF xcc id [39:32] */ |
1054 | xcc_info->phy_id = (obj->integer.value >> 32) & 0xFF; |
1055 | /* xcp node of this xcc [47:40] */ |
1056 | xcc_info->xcp_node = (obj->integer.value >> 40) & 0xFF; |
1057 | /* PF domain of this xcc [31:16] */ |
1058 | *sbdf = (obj->integer.value) & 0xFFFF0000; |
1059 | /* PF bus/dev/fn of this xcc [63:48] */ |
1060 | *sbdf |= (obj->integer.value >> 48) & 0xFFFF; |
1061 | ACPI_FREE(obj); |
1062 | obj = NULL; |
1063 | |
1064 | status = |
1065 | amdgpu_acpi_get_node_id(handle: xcc_info->handle, numa_info: &xcc_info->numa_info); |
1066 | |
1067 | /* TODO: check if this check is required */ |
1068 | if (ACPI_SUCCESS(status)) |
1069 | ret = 0; |
1070 | out: |
1071 | if (obj) |
1072 | ACPI_FREE(obj); |
1073 | |
1074 | return ret; |
1075 | } |
1076 | |
1077 | static int amdgpu_acpi_enumerate_xcc(void) |
1078 | { |
1079 | struct amdgpu_acpi_dev_info *dev_info = NULL; |
1080 | struct amdgpu_acpi_xcc_info *xcc_info; |
1081 | struct acpi_device *acpi_dev; |
1082 | char hid[ACPI_ID_LEN]; |
1083 | int ret, id; |
1084 | u32 sbdf; |
1085 | |
1086 | INIT_LIST_HEAD(list: &amdgpu_acpi_dev_list); |
1087 | xa_init(xa: &numa_info_xa); |
1088 | |
1089 | for (id = 0; id < AMD_XCC_MAX_HID; id++) { |
1090 | sprintf(buf: hid, fmt: "%s%d" , "AMD" , AMD_XCC_HID_START + id); |
1091 | acpi_dev = acpi_dev_get_first_match_dev(hid, NULL, hrv: -1); |
1092 | /* These ACPI objects are expected to be in sequential order. If |
1093 | * one is not found, no need to check the rest. |
1094 | */ |
1095 | if (!acpi_dev) { |
1096 | DRM_DEBUG_DRIVER("No matching acpi device found for %s" , |
1097 | hid); |
1098 | break; |
1099 | } |
1100 | |
1101 | xcc_info = kzalloc(size: sizeof(struct amdgpu_acpi_xcc_info), |
1102 | GFP_KERNEL); |
1103 | if (!xcc_info) { |
1104 | DRM_ERROR("Failed to allocate memory for xcc info\n" ); |
1105 | return -ENOMEM; |
1106 | } |
1107 | |
1108 | INIT_LIST_HEAD(list: &xcc_info->list); |
1109 | xcc_info->handle = acpi_device_handle(adev: acpi_dev); |
1110 | acpi_dev_put(adev: acpi_dev); |
1111 | |
1112 | ret = amdgpu_acpi_get_xcc_info(xcc_info, sbdf: &sbdf); |
1113 | if (ret) { |
1114 | kfree(objp: xcc_info); |
1115 | continue; |
1116 | } |
1117 | |
1118 | dev_info = amdgpu_acpi_get_dev(sbdf); |
1119 | |
1120 | if (!dev_info) |
1121 | ret = amdgpu_acpi_dev_init(dev_info: &dev_info, xcc_info, sbdf); |
1122 | |
1123 | if (ret == -ENOMEM) |
1124 | return ret; |
1125 | |
1126 | if (!dev_info) { |
1127 | kfree(objp: xcc_info); |
1128 | continue; |
1129 | } |
1130 | |
1131 | list_add_tail(new: &xcc_info->list, head: &dev_info->xcc_list); |
1132 | } |
1133 | |
1134 | return 0; |
1135 | } |
1136 | |
1137 | int amdgpu_acpi_get_tmr_info(struct amdgpu_device *adev, u64 *tmr_offset, |
1138 | u64 *tmr_size) |
1139 | { |
1140 | struct amdgpu_acpi_dev_info *dev_info; |
1141 | u32 sbdf; |
1142 | |
1143 | if (!tmr_offset || !tmr_size) |
1144 | return -EINVAL; |
1145 | |
1146 | sbdf = (pci_domain_nr(bus: adev->pdev->bus) << 16); |
1147 | sbdf |= pci_dev_id(dev: adev->pdev); |
1148 | dev_info = amdgpu_acpi_get_dev(sbdf); |
1149 | if (!dev_info) |
1150 | return -ENOENT; |
1151 | |
1152 | *tmr_offset = dev_info->tmr_base; |
1153 | *tmr_size = dev_info->tmr_size; |
1154 | |
1155 | return 0; |
1156 | } |
1157 | |
1158 | int amdgpu_acpi_get_mem_info(struct amdgpu_device *adev, int xcc_id, |
1159 | struct amdgpu_numa_info *numa_info) |
1160 | { |
1161 | struct amdgpu_acpi_dev_info *dev_info; |
1162 | struct amdgpu_acpi_xcc_info *xcc_info; |
1163 | u32 sbdf; |
1164 | |
1165 | if (!numa_info) |
1166 | return -EINVAL; |
1167 | |
1168 | sbdf = (pci_domain_nr(bus: adev->pdev->bus) << 16); |
1169 | sbdf |= pci_dev_id(dev: adev->pdev); |
1170 | dev_info = amdgpu_acpi_get_dev(sbdf); |
1171 | if (!dev_info) |
1172 | return -ENOENT; |
1173 | |
1174 | list_for_each_entry(xcc_info, &dev_info->xcc_list, list) { |
1175 | if (xcc_info->phy_id == xcc_id) { |
1176 | memcpy(numa_info, xcc_info->numa_info, |
1177 | sizeof(*numa_info)); |
1178 | return 0; |
1179 | } |
1180 | } |
1181 | |
1182 | return -ENOENT; |
1183 | } |
1184 | |
1185 | /** |
1186 | * amdgpu_acpi_event - handle notify events |
1187 | * |
1188 | * @nb: notifier block |
1189 | * @val: val |
1190 | * @data: acpi event |
1191 | * |
1192 | * Calls relevant amdgpu functions in response to various |
1193 | * acpi events. |
1194 | * Returns NOTIFY code |
1195 | */ |
1196 | static int amdgpu_acpi_event(struct notifier_block *nb, |
1197 | unsigned long val, |
1198 | void *data) |
1199 | { |
1200 | struct amdgpu_device *adev = container_of(nb, struct amdgpu_device, acpi_nb); |
1201 | struct acpi_bus_event *entry = (struct acpi_bus_event *)data; |
1202 | |
1203 | if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { |
1204 | if (power_supply_is_system_supplied() > 0) |
1205 | DRM_DEBUG_DRIVER("pm: AC\n" ); |
1206 | else |
1207 | DRM_DEBUG_DRIVER("pm: DC\n" ); |
1208 | |
1209 | amdgpu_pm_acpi_event_handler(adev); |
1210 | } |
1211 | |
1212 | /* Check for pending SBIOS requests */ |
1213 | return amdgpu_atif_handler(adev, event: entry); |
1214 | } |
1215 | |
1216 | /* Call all ACPI methods here */ |
1217 | /** |
1218 | * amdgpu_acpi_init - init driver acpi support |
1219 | * |
1220 | * @adev: amdgpu_device pointer |
1221 | * |
1222 | * Verifies the AMD ACPI interfaces and registers with the acpi |
1223 | * notifier chain (all asics). |
1224 | * Returns 0 on success, error on failure. |
1225 | */ |
1226 | int amdgpu_acpi_init(struct amdgpu_device *adev) |
1227 | { |
1228 | struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif; |
1229 | |
1230 | if (atif->notifications.brightness_change) { |
1231 | if (adev->dc_enabled) { |
1232 | #if defined(CONFIG_DRM_AMD_DC) |
1233 | struct amdgpu_display_manager *dm = &adev->dm; |
1234 | |
1235 | if (dm->backlight_dev[0]) |
1236 | atif->bd = dm->backlight_dev[0]; |
1237 | #endif |
1238 | } else { |
1239 | struct drm_encoder *tmp; |
1240 | |
1241 | /* Find the encoder controlling the brightness */ |
1242 | list_for_each_entry(tmp, &adev_to_drm(adev)->mode_config.encoder_list, |
1243 | head) { |
1244 | struct amdgpu_encoder *enc = to_amdgpu_encoder(tmp); |
1245 | |
1246 | if ((enc->devices & (ATOM_DEVICE_LCD_SUPPORT)) && |
1247 | enc->enc_priv) { |
1248 | struct amdgpu_encoder_atom_dig *dig = enc->enc_priv; |
1249 | |
1250 | if (dig->bl_dev) { |
1251 | atif->bd = dig->bl_dev; |
1252 | break; |
1253 | } |
1254 | } |
1255 | } |
1256 | } |
1257 | } |
1258 | adev->acpi_nb.notifier_call = amdgpu_acpi_event; |
1259 | register_acpi_notifier(&adev->acpi_nb); |
1260 | |
1261 | return 0; |
1262 | } |
1263 | |
1264 | void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps) |
1265 | { |
1266 | struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif; |
1267 | |
1268 | caps->caps_valid = atif->backlight_caps.caps_valid; |
1269 | caps->min_input_signal = atif->backlight_caps.min_input_signal; |
1270 | caps->max_input_signal = atif->backlight_caps.max_input_signal; |
1271 | } |
1272 | |
1273 | /** |
1274 | * amdgpu_acpi_fini - tear down driver acpi support |
1275 | * |
1276 | * @adev: amdgpu_device pointer |
1277 | * |
1278 | * Unregisters with the acpi notifier chain (all asics). |
1279 | */ |
1280 | void amdgpu_acpi_fini(struct amdgpu_device *adev) |
1281 | { |
1282 | unregister_acpi_notifier(&adev->acpi_nb); |
1283 | } |
1284 | |
1285 | /** |
1286 | * amdgpu_atif_pci_probe_handle - look up the ATIF handle |
1287 | * |
1288 | * @pdev: pci device |
1289 | * |
1290 | * Look up the ATIF handles (all asics). |
1291 | * Returns true if the handle is found, false if not. |
1292 | */ |
1293 | static bool amdgpu_atif_pci_probe_handle(struct pci_dev *pdev) |
1294 | { |
1295 | char acpi_method_name[255] = { 0 }; |
1296 | struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; |
1297 | acpi_handle dhandle, atif_handle; |
1298 | acpi_status status; |
1299 | int ret; |
1300 | |
1301 | dhandle = ACPI_HANDLE(&pdev->dev); |
1302 | if (!dhandle) |
1303 | return false; |
1304 | |
1305 | status = acpi_get_handle(parent: dhandle, pathname: "ATIF" , ret_handle: &atif_handle); |
1306 | if (ACPI_FAILURE(status)) |
1307 | return false; |
1308 | |
1309 | amdgpu_acpi_priv.atif.handle = atif_handle; |
1310 | acpi_get_name(object: amdgpu_acpi_priv.atif.handle, ACPI_FULL_PATHNAME, ret_path_ptr: &buffer); |
1311 | DRM_DEBUG_DRIVER("Found ATIF handle %s\n" , acpi_method_name); |
1312 | ret = amdgpu_atif_verify_interface(atif: &amdgpu_acpi_priv.atif); |
1313 | if (ret) { |
1314 | amdgpu_acpi_priv.atif.handle = 0; |
1315 | return false; |
1316 | } |
1317 | return true; |
1318 | } |
1319 | |
1320 | /** |
1321 | * amdgpu_atcs_pci_probe_handle - look up the ATCS handle |
1322 | * |
1323 | * @pdev: pci device |
1324 | * |
1325 | * Look up the ATCS handles (all asics). |
1326 | * Returns true if the handle is found, false if not. |
1327 | */ |
1328 | static bool amdgpu_atcs_pci_probe_handle(struct pci_dev *pdev) |
1329 | { |
1330 | char acpi_method_name[255] = { 0 }; |
1331 | struct acpi_buffer buffer = { sizeof(acpi_method_name), acpi_method_name }; |
1332 | acpi_handle dhandle, atcs_handle; |
1333 | acpi_status status; |
1334 | int ret; |
1335 | |
1336 | dhandle = ACPI_HANDLE(&pdev->dev); |
1337 | if (!dhandle) |
1338 | return false; |
1339 | |
1340 | status = acpi_get_handle(parent: dhandle, pathname: "ATCS" , ret_handle: &atcs_handle); |
1341 | if (ACPI_FAILURE(status)) |
1342 | return false; |
1343 | |
1344 | amdgpu_acpi_priv.atcs.handle = atcs_handle; |
1345 | acpi_get_name(object: amdgpu_acpi_priv.atcs.handle, ACPI_FULL_PATHNAME, ret_path_ptr: &buffer); |
1346 | DRM_DEBUG_DRIVER("Found ATCS handle %s\n" , acpi_method_name); |
1347 | ret = amdgpu_atcs_verify_interface(atcs: &amdgpu_acpi_priv.atcs); |
1348 | if (ret) { |
1349 | amdgpu_acpi_priv.atcs.handle = 0; |
1350 | return false; |
1351 | } |
1352 | return true; |
1353 | } |
1354 | |
1355 | |
1356 | /** |
1357 | * amdgpu_acpi_should_gpu_reset |
1358 | * |
1359 | * @adev: amdgpu_device_pointer |
1360 | * |
1361 | * returns true if should reset GPU, false if not |
1362 | */ |
1363 | bool amdgpu_acpi_should_gpu_reset(struct amdgpu_device *adev) |
1364 | { |
1365 | if ((adev->flags & AMD_IS_APU) && |
1366 | adev->gfx.imu.funcs) /* Not need to do mode2 reset for IMU enabled APUs */ |
1367 | return false; |
1368 | |
1369 | if ((adev->flags & AMD_IS_APU) && |
1370 | amdgpu_acpi_is_s3_active(adev)) |
1371 | return false; |
1372 | |
1373 | if (amdgpu_sriov_vf(adev)) |
1374 | return false; |
1375 | |
1376 | #if IS_ENABLED(CONFIG_SUSPEND) |
1377 | return pm_suspend_target_state != PM_SUSPEND_TO_IDLE; |
1378 | #else |
1379 | return true; |
1380 | #endif |
1381 | } |
1382 | |
1383 | /* |
1384 | * amdgpu_acpi_detect - detect ACPI ATIF/ATCS methods |
1385 | * |
1386 | * Check if we have the ATIF/ATCS methods and populate |
1387 | * the structures in the driver. |
1388 | */ |
1389 | void amdgpu_acpi_detect(void) |
1390 | { |
1391 | struct amdgpu_atif *atif = &amdgpu_acpi_priv.atif; |
1392 | struct amdgpu_atcs *atcs = &amdgpu_acpi_priv.atcs; |
1393 | struct pci_dev *pdev = NULL; |
1394 | int ret; |
1395 | |
1396 | while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, from: pdev))) { |
1397 | if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) && |
1398 | (pdev->class != PCI_CLASS_DISPLAY_OTHER << 8)) |
1399 | continue; |
1400 | |
1401 | if (!atif->handle) |
1402 | amdgpu_atif_pci_probe_handle(pdev); |
1403 | if (!atcs->handle) |
1404 | amdgpu_atcs_pci_probe_handle(pdev); |
1405 | } |
1406 | |
1407 | if (atif->functions.sbios_requests && !atif->functions.system_params) { |
1408 | /* XXX check this workraround, if sbios request function is |
1409 | * present we have to see how it's configured in the system |
1410 | * params |
1411 | */ |
1412 | atif->functions.system_params = true; |
1413 | } |
1414 | |
1415 | if (atif->functions.system_params) { |
1416 | ret = amdgpu_atif_get_notification_params(atif); |
1417 | if (ret) { |
1418 | DRM_DEBUG_DRIVER("Call to GET_SYSTEM_PARAMS failed: %d\n" , |
1419 | ret); |
1420 | /* Disable notification */ |
1421 | atif->notification_cfg.enabled = false; |
1422 | } |
1423 | } |
1424 | |
1425 | if (atif->functions.query_backlight_transfer_characteristics) { |
1426 | ret = amdgpu_atif_query_backlight_caps(atif); |
1427 | if (ret) { |
1428 | DRM_DEBUG_DRIVER("Call to QUERY_BACKLIGHT_TRANSFER_CHARACTERISTICS failed: %d\n" , |
1429 | ret); |
1430 | atif->backlight_caps.caps_valid = false; |
1431 | } |
1432 | } else { |
1433 | atif->backlight_caps.caps_valid = false; |
1434 | } |
1435 | |
1436 | amdgpu_acpi_enumerate_xcc(); |
1437 | } |
1438 | |
1439 | void amdgpu_acpi_release(void) |
1440 | { |
1441 | struct amdgpu_acpi_dev_info *dev_info, *dev_tmp; |
1442 | struct amdgpu_acpi_xcc_info *xcc_info, *xcc_tmp; |
1443 | struct amdgpu_numa_info *numa_info; |
1444 | unsigned long index; |
1445 | |
1446 | xa_for_each(&numa_info_xa, index, numa_info) { |
1447 | kfree(objp: numa_info); |
1448 | xa_erase(&numa_info_xa, index); |
1449 | } |
1450 | |
1451 | if (list_empty(head: &amdgpu_acpi_dev_list)) |
1452 | return; |
1453 | |
1454 | list_for_each_entry_safe(dev_info, dev_tmp, &amdgpu_acpi_dev_list, |
1455 | list) { |
1456 | list_for_each_entry_safe(xcc_info, xcc_tmp, &dev_info->xcc_list, |
1457 | list) { |
1458 | list_del(entry: &xcc_info->list); |
1459 | kfree(objp: xcc_info); |
1460 | } |
1461 | |
1462 | list_del(entry: &dev_info->list); |
1463 | kfree(objp: dev_info); |
1464 | } |
1465 | } |
1466 | |
1467 | #if IS_ENABLED(CONFIG_SUSPEND) |
1468 | /** |
1469 | * amdgpu_acpi_is_s3_active |
1470 | * |
1471 | * @adev: amdgpu_device_pointer |
1472 | * |
1473 | * returns true if supported, false if not. |
1474 | */ |
1475 | bool amdgpu_acpi_is_s3_active(struct amdgpu_device *adev) |
1476 | { |
1477 | return !(adev->flags & AMD_IS_APU) || |
1478 | (pm_suspend_target_state == PM_SUSPEND_MEM); |
1479 | } |
1480 | |
1481 | /** |
1482 | * amdgpu_acpi_is_s0ix_active |
1483 | * |
1484 | * @adev: amdgpu_device_pointer |
1485 | * |
1486 | * returns true if supported, false if not. |
1487 | */ |
1488 | bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) |
1489 | { |
1490 | if (!(adev->flags & AMD_IS_APU) || |
1491 | (pm_suspend_target_state != PM_SUSPEND_TO_IDLE)) |
1492 | return false; |
1493 | |
1494 | if (adev->asic_type < CHIP_RAVEN) |
1495 | return false; |
1496 | |
1497 | if (!(adev->pm.pp_feature & PP_GFXOFF_MASK)) |
1498 | return false; |
1499 | |
1500 | /* |
1501 | * If ACPI_FADT_LOW_POWER_S0 is not set in the FADT, it is generally |
1502 | * risky to do any special firmware-related preparations for entering |
1503 | * S0ix even though the system is suspending to idle, so return false |
1504 | * in that case. |
1505 | */ |
1506 | if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) { |
1507 | dev_err_once(adev->dev, |
1508 | "Power consumption will be higher as BIOS has not been configured for suspend-to-idle.\n" |
1509 | "To use suspend-to-idle change the sleep mode in BIOS setup.\n" ); |
1510 | return false; |
1511 | } |
1512 | |
1513 | #if !IS_ENABLED(CONFIG_AMD_PMC) |
1514 | dev_err_once(adev->dev, |
1515 | "Power consumption will be higher as the kernel has not been compiled with CONFIG_AMD_PMC.\n" ); |
1516 | return false; |
1517 | #else |
1518 | return true; |
1519 | #endif /* CONFIG_AMD_PMC */ |
1520 | } |
1521 | |
1522 | /** |
1523 | * amdgpu_choose_low_power_state |
1524 | * |
1525 | * @adev: amdgpu_device_pointer |
1526 | * |
1527 | * Choose the target low power state for the GPU |
1528 | */ |
1529 | void amdgpu_choose_low_power_state(struct amdgpu_device *adev) |
1530 | { |
1531 | if (adev->in_runpm) |
1532 | return; |
1533 | |
1534 | if (amdgpu_acpi_is_s0ix_active(adev)) |
1535 | adev->in_s0ix = true; |
1536 | else if (amdgpu_acpi_is_s3_active(adev)) |
1537 | adev->in_s3 = true; |
1538 | } |
1539 | |
1540 | #endif /* CONFIG_SUSPEND */ |
1541 | |