|
17 | 17 |
|
18 | 18 | #include <linux/acpi.h> |
19 | 19 | #include <linux/device.h> |
| 20 | +#include <linux/dmi.h> |
20 | 21 | #include <linux/suspend.h> |
21 | 22 |
|
22 | 23 | #include "../sleep.h" |
@@ -363,40 +364,76 @@ static int validate_dsm(acpi_handle handle, const char *uuid, int rev, guid_t *d |
363 | 364 | return ret; |
364 | 365 | } |
365 | 366 |
|
| 367 | +struct amd_lps0_hid_device_data { |
| 368 | + const bool check_off_by_one; |
| 369 | +}; |
| 370 | + |
| 371 | +static const struct amd_lps0_hid_device_data amd_picasso = { |
| 372 | + .check_off_by_one = true, |
| 373 | +}; |
| 374 | + |
| 375 | +static const struct amd_lps0_hid_device_data amd_cezanne = { |
| 376 | + .check_off_by_one = false, |
| 377 | +}; |
| 378 | + |
| 379 | +static const struct acpi_device_id amd_hid_ids[] = { |
| 380 | + {"AMD0004", (kernel_ulong_t)&amd_picasso, }, |
| 381 | + {"AMD0005", (kernel_ulong_t)&amd_picasso, }, |
| 382 | + {"AMDI0005", (kernel_ulong_t)&amd_picasso, }, |
| 383 | + {"AMDI0006", (kernel_ulong_t)&amd_cezanne, }, |
| 384 | + {} |
| 385 | +}; |
| 386 | + |
| 387 | +static int lps0_prefer_amd(const struct dmi_system_id *id) |
| 388 | +{ |
| 389 | + pr_debug("Using AMD GUID w/ _REV 2.\n"); |
| 390 | + rev_id = 2; |
| 391 | + return 0; |
| 392 | +} |
| 393 | +static const struct dmi_system_id s2idle_dmi_table[] __initconst = { |
| 394 | + { |
| 395 | + /* |
| 396 | + * AMD Rembrandt based HP EliteBook 835/845/865 G9 |
| 397 | + * Contains specialized AML in AMD/_REV 2 path to avoid |
| 398 | + * triggering a bug in Qualcomm WLAN firmware. This may be |
| 399 | + * removed in the future if that firmware is fixed. |
| 400 | + */ |
| 401 | + .callback = lps0_prefer_amd, |
| 402 | + .matches = { |
| 403 | + DMI_MATCH(DMI_BOARD_VENDOR, "HP"), |
| 404 | + DMI_MATCH(DMI_BOARD_NAME, "8990"), |
| 405 | + }, |
| 406 | + }, |
| 407 | + {} |
| 408 | +}; |
| 409 | + |
366 | 410 | static int lps0_device_attach(struct acpi_device *adev, |
367 | 411 | const struct acpi_device_id *not_used) |
368 | 412 | { |
369 | 413 | if (lps0_device_handle) |
370 | 414 | return 0; |
371 | 415 |
|
| 416 | + lps0_dsm_func_mask_microsoft = validate_dsm(adev->handle, |
| 417 | + ACPI_LPS0_DSM_UUID_MICROSOFT, 0, |
| 418 | + &lps0_dsm_guid_microsoft); |
372 | 419 | if (acpi_s2idle_vendor_amd()) { |
373 | | - /* AMD0004, AMD0005, AMDI0005: |
374 | | - * - Should use rev_id 0x0 |
375 | | - * - function mask > 0x3: Should use AMD method, but has off by one bug |
376 | | - * - function mask = 0x3: Should use Microsoft method |
377 | | - * AMDI0006: |
378 | | - * - should use rev_id 0x0 |
379 | | - * - function mask = 0x3: Should use Microsoft method |
380 | | - * AMDI0007: |
381 | | - * - Should use rev_id 0x2 |
382 | | - * - Should only use AMD method |
383 | | - */ |
384 | | - const char *hid = acpi_device_hid(adev); |
385 | | - rev_id = strcmp(hid, "AMDI0007") ? 0 : 2; |
| 420 | + static const struct acpi_device_id *dev_id; |
| 421 | + const struct amd_lps0_hid_device_data *data; |
| 422 | + |
| 423 | + for (dev_id = &amd_hid_ids[0]; dev_id->id[0]; dev_id++) |
| 424 | + if (acpi_dev_hid_uid_match(adev, dev_id->id, NULL)) |
| 425 | + break; |
| 426 | + if (dev_id->id[0]) |
| 427 | + data = (const struct amd_lps0_hid_device_data *) dev_id->driver_data; |
| 428 | + else |
| 429 | + data = &amd_cezanne; |
386 | 430 | lps0_dsm_func_mask = validate_dsm(adev->handle, |
387 | 431 | ACPI_LPS0_DSM_UUID_AMD, rev_id, &lps0_dsm_guid); |
388 | | - lps0_dsm_func_mask_microsoft = validate_dsm(adev->handle, |
389 | | - ACPI_LPS0_DSM_UUID_MICROSOFT, 0, |
390 | | - &lps0_dsm_guid_microsoft); |
391 | | - if (lps0_dsm_func_mask > 0x3 && (!strcmp(hid, "AMD0004") || |
392 | | - !strcmp(hid, "AMD0005") || |
393 | | - !strcmp(hid, "AMDI0005"))) { |
| 432 | + if (lps0_dsm_func_mask > 0x3 && data->check_off_by_one) { |
394 | 433 | lps0_dsm_func_mask = (lps0_dsm_func_mask << 1) | 0x1; |
395 | 434 | acpi_handle_debug(adev->handle, "_DSM UUID %s: Adjusted function mask: 0x%x\n", |
396 | 435 | ACPI_LPS0_DSM_UUID_AMD, lps0_dsm_func_mask); |
397 | | - } else if (lps0_dsm_func_mask_microsoft > 0 && |
398 | | - (!strcmp(hid, "AMDI0007") || |
399 | | - !strcmp(hid, "AMDI0008"))) { |
| 436 | + } else if (lps0_dsm_func_mask_microsoft > 0 && rev_id) { |
400 | 437 | lps0_dsm_func_mask_microsoft = -EINVAL; |
401 | 438 | acpi_handle_debug(adev->handle, "_DSM Using AMD method\n"); |
402 | 439 | } |
@@ -486,6 +523,19 @@ int acpi_s2idle_prepare_late(void) |
486 | 523 | return 0; |
487 | 524 | } |
488 | 525 |
|
| 526 | +void acpi_s2idle_check(void) |
| 527 | +{ |
| 528 | + struct acpi_s2idle_dev_ops *handler; |
| 529 | + |
| 530 | + if (!lps0_device_handle || sleep_no_lps0) |
| 531 | + return; |
| 532 | + |
| 533 | + list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node) { |
| 534 | + if (handler->check) |
| 535 | + handler->check(); |
| 536 | + } |
| 537 | +} |
| 538 | + |
489 | 539 | void acpi_s2idle_restore_early(void) |
490 | 540 | { |
491 | 541 | struct acpi_s2idle_dev_ops *handler; |
@@ -527,14 +577,16 @@ static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = { |
527 | 577 | .begin = acpi_s2idle_begin, |
528 | 578 | .prepare = acpi_s2idle_prepare, |
529 | 579 | .prepare_late = acpi_s2idle_prepare_late, |
| 580 | + .check = acpi_s2idle_check, |
530 | 581 | .wake = acpi_s2idle_wake, |
531 | 582 | .restore_early = acpi_s2idle_restore_early, |
532 | 583 | .restore = acpi_s2idle_restore, |
533 | 584 | .end = acpi_s2idle_end, |
534 | 585 | }; |
535 | 586 |
|
536 | | -void acpi_s2idle_setup(void) |
| 587 | +void __init acpi_s2idle_setup(void) |
537 | 588 | { |
| 589 | + dmi_check_system(s2idle_dmi_table); |
538 | 590 | acpi_scan_add_handler(&lps0_handler); |
539 | 591 | s2idle_set_ops(&acpi_s2idle_ops_lps0); |
540 | 592 | } |
|
0 commit comments