Pull power management fixes from Rafael Wysocki: "Fix three issues related to the handling of wakeup events signaled through the ACPI SCI while suspended to idle (Rafael Wysocki) and unexport an internal cpufreq variable (Yangtao Li)" * tag 'pm-5.6-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI: PM: s2idle: Prevent spurious SCIs from waking up the system ACPICA: Introduce acpi_any_gpe_status_set() ACPI: PM: s2idle: Avoid possible race related to the EC GPE ACPI: EC: Fix flushing of pending work cpufreq: Make cpufreq_global_kobject static
Unified · Split
| @@ -101,6 +101,8 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void); · 100 unmodified lines | ||
| 101 | 101 | |
| 102 | 102 | acpi_status acpi_hw_enable_all_wakeup_gpes(void); |
| 103 | 103 | |
| 104 | +u8 acpi_hw_check_all_gpes(void); | |
| 105 | + | |
| 104 | 106 | acpi_status |
| 105 | 107 | acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
| 106 | 108 | struct acpi_gpe_block_info *gpe_block, |
| @@ -795,6 +795,38 @@ acpi_status acpi_enable_all_wakeup_gpes(void) · 794 unmodified lines | ||
| 795 | 795 | |
| 796 | 796 | ACPI_EXPORT_SYMBOL(acpi_enable_all_wakeup_gpes) |
| 797 | 797 | |
| 798 | +/****************************************************************************** | |
| 799 | + * | |
| 800 | + * FUNCTION: acpi_any_gpe_status_set | |
| 801 | + * | |
| 802 | + * PARAMETERS: None | |
| 803 | + * | |
| 804 | + * RETURN: Whether or not the status bit is set for any GPE | |
| 805 | + * | |
| 806 | + * DESCRIPTION: Check the status bits of all enabled GPEs and return TRUE if any | |
| 807 | + * of them is set or FALSE otherwise. | |
| 808 | + * | |
| 809 | + ******************************************************************************/ | |
| 810 | +u32 acpi_any_gpe_status_set(void) | |
| 811 | +{ | |
| 812 | + acpi_status status; | |
| 813 | + u8 ret; | |
| 814 | + | |
| 815 | + ACPI_FUNCTION_TRACE(acpi_any_gpe_status_set); | |
| 816 | + | |
| 817 | + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); | |
| 818 | + if (ACPI_FAILURE(status)) { | |
| 819 | + return (FALSE); | |
| 820 | + } | |
| 821 | + | |
| 822 | + ret = acpi_hw_check_all_gpes(); | |
| 823 | + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); | |
| 824 | + | |
| 825 | + return (ret); | |
| 826 | +} | |
| 827 | + | |
| 828 | +ACPI_EXPORT_SYMBOL(acpi_any_gpe_status_set) | |
| 829 | + | |
| 798 | 830 | /******************************************************************************* |
| 799 | 831 | * |
| 800 | 832 | * FUNCTION: acpi_install_gpe_block |
| @@ -444,6 +444,53 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, · 443 unmodified lines | ||
| 444 | 444 | return (AE_OK); |
| 445 | 445 | } |
| 446 | 446 | |
| 447 | +/****************************************************************************** | |
| 448 | + * | |
| 449 | + * FUNCTION: acpi_hw_get_gpe_block_status | |
| 450 | + * | |
| 451 | + * PARAMETERS: gpe_xrupt_info - GPE Interrupt info | |
| 452 | + * gpe_block - Gpe Block info | |
| 453 | + * | |
| 454 | + * RETURN: Success | |
| 455 | + * | |
| 456 | + * DESCRIPTION: Produce a combined GPE status bits mask for the given block. | |
| 457 | + * | |
| 458 | + ******************************************************************************/ | |
| 459 | + | |
| 460 | +static acpi_status | |
| 461 | +acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info, | |
| 462 | + struct acpi_gpe_block_info *gpe_block, | |
| 463 | + void *ret_ptr) | |
| 464 | +{ | |
| 465 | + struct acpi_gpe_register_info *gpe_register_info; | |
| 466 | + u64 in_enable, in_status; | |
| 467 | + acpi_status status; | |
| 468 | + u8 *ret = ret_ptr; | |
| 469 | + u32 i; | |
| 470 | + | |
| 471 | + /* Examine each GPE Register within the block */ | |
| 472 | + | |
| 473 | + for (i = 0; i < gpe_block->register_count; i++) { | |
| 474 | + gpe_register_info = &gpe_block->register_info[i]; | |
| 475 | + | |
| 476 | + status = acpi_hw_read(&in_enable, | |
| 477 | + &gpe_register_info->enable_address); | |
| 478 | + if (ACPI_FAILURE(status)) { | |
| 479 | + continue; | |
| 480 | + } | |
| 481 | + | |
| 482 | + status = acpi_hw_read(&in_status, | |
| 483 | + &gpe_register_info->status_address); | |
| 484 | + if (ACPI_FAILURE(status)) { | |
| 485 | + continue; | |
| 486 | + } | |
| 487 | + | |
| 488 | + *ret |= in_enable & in_status; | |
| 489 | + } | |
| 490 | + | |
| 491 | + return (AE_OK); | |
| 492 | +} | |
| 493 | + | |
| 447 | 494 | /****************************************************************************** |
| 448 | 495 | * |
| 449 | 496 | * FUNCTION: acpi_hw_disable_all_gpes |
| @@ -510,4 +557,28 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void) · 60 unmodified lines | ||
| 510 | 557 | return_ACPI_STATUS(status); |
| 511 | 558 | } |
| 512 | 559 | |
| 560 | +/****************************************************************************** | |
| 561 | + * | |
| 562 | + * FUNCTION: acpi_hw_check_all_gpes | |
| 563 | + * | |
| 564 | + * PARAMETERS: None | |
| 565 | + * | |
| 566 | + * RETURN: Combined status of all GPEs | |
| 567 | + * | |
| 568 | + * DESCRIPTION: Check all enabled GPEs in all GPE blocks and return TRUE if the | |
| 569 | + * status bit is set for at least one of them of FALSE otherwise. | |
| 570 | + * | |
| 571 | + ******************************************************************************/ | |
| 572 | + | |
| 573 | +u8 acpi_hw_check_all_gpes(void) | |
| 574 | +{ | |
| 575 | + u8 ret = 0; | |
| 576 | + | |
| 577 | + ACPI_FUNCTION_TRACE(acpi_hw_check_all_gpes); | |
| 578 | + | |
| 579 | + (void)acpi_ev_walk_gpe_list(acpi_hw_get_gpe_block_status, &ret); | |
| 580 | + | |
| 581 | + return (ret != 0); | |
| 582 | +} | |
| 583 | + | |
| 513 | 584 | #endif /* !ACPI_REDUCED_HARDWARE */ |
| @@ -179,6 +179,7 @@ EXPORT_SYMBOL(first_ec); · 178 unmodified lines | ||
| 179 | 179 | |
| 180 | 180 | static struct acpi_ec *boot_ec; |
| 181 | 181 | static bool boot_ec_is_ecdt = false; |
| 182 | +static struct workqueue_struct *ec_wq; | |
| 182 | 183 | static struct workqueue_struct *ec_query_wq; |
| 183 | 184 | |
| 184 | 185 | static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ |
| @@ -469,7 +470,7 @@ static void acpi_ec_submit_query(struct acpi_ec *ec) · 284 unmodified lines | ||
| 469 | 470 | ec_dbg_evt("Command(%s) submitted/blocked", |
| 470 | 471 | acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY)); |
| 471 | 472 | ec->nr_pending_queries++; |
| 472 | − schedule_work(&ec->work); | |
| 473 | + queue_work(ec_wq, &ec->work); | |
| 473 | 474 | } |
| 474 | 475 | } |
| 475 | 476 | |
| @@ -535,7 +536,7 @@ static void acpi_ec_enable_event(struct acpi_ec *ec) · 59 unmodified lines | ||
| 535 | 536 | #ifdef CONFIG_PM_SLEEP |
| 536 | 537 | static void __acpi_ec_flush_work(void) |
| 537 | 538 | { |
| 538 | − flush_scheduled_work(); /* flush ec->work */ | |
| 539 | + drain_workqueue(ec_wq); /* flush ec->work */ | |
| 539 | 540 | flush_workqueue(ec_query_wq); /* flush queries */ |
| 540 | 541 | } |
| 541 | 542 | |
| @@ -556,8 +557,8 @@ static void acpi_ec_disable_event(struct acpi_ec *ec) · 14 unmodified lines | ||
| 556 | 557 | |
| 557 | 558 | void acpi_ec_flush_work(void) |
| 558 | 559 | { |
| 559 | − /* Without ec_query_wq there is nothing to flush. */ | |
| 560 | − if (!ec_query_wq) | |
| 560 | + /* Without ec_wq there is nothing to flush. */ | |
| 561 | + if (!ec_wq) | |
| 561 | 562 | return; |
| 562 | 563 | |
| 563 | 564 | __acpi_ec_flush_work(); |
| @@ -2107,25 +2108,33 @@ static struct acpi_driver acpi_ec_driver = { · 1543 unmodified lines | ||
| 2107 | 2108 | .drv.pm = &acpi_ec_pm, |
| 2108 | 2109 | }; |
| 2109 | 2110 | |
| 2110 | −static inline int acpi_ec_query_init(void) | |
| 2111 | +static void acpi_ec_destroy_workqueues(void) | |
| 2111 | 2112 | { |
| 2112 | − if (!ec_query_wq) { | |
| 2113 | − ec_query_wq = alloc_workqueue("kec_query", 0, | |
| 2114 | − ec_max_queries); | |
| 2115 | − if (!ec_query_wq) | |
| 2116 | − return -ENODEV; | |
| 2113 | + if (ec_wq) { | |
| 2114 | + destroy_workqueue(ec_wq); | |
| 2115 | + ec_wq = NULL; | |
| 2117 | 2116 | } |
| 2118 | − return 0; | |
| 2119 | −} | |
| 2120 | − | |
| 2121 | −static inline void acpi_ec_query_exit(void) | |
| 2122 | −{ | |
| 2123 | 2117 | if (ec_query_wq) { |
| 2124 | 2118 | destroy_workqueue(ec_query_wq); |
| 2125 | 2119 | ec_query_wq = NULL; |
| 2126 | 2120 | } |
| 2127 | 2121 | } |
| 2128 | 2122 | |
| 2123 | +static int acpi_ec_init_workqueues(void) | |
| 2124 | +{ | |
| 2125 | + if (!ec_wq) | |
| 2126 | + ec_wq = alloc_ordered_workqueue("kec", 0); | |
| 2127 | + | |
| 2128 | + if (!ec_query_wq) | |
| 2129 | + ec_query_wq = alloc_workqueue("kec_query", 0, ec_max_queries); | |
| 2130 | + | |
| 2131 | + if (!ec_wq || !ec_query_wq) { | |
| 2132 | + acpi_ec_destroy_workqueues(); | |
| 2133 | + return -ENODEV; | |
| 2134 | + } | |
| 2135 | + return 0; | |
| 2136 | +} | |
| 2137 | + | |
| 2129 | 2138 | static const struct dmi_system_id acpi_ec_no_wakeup[] = { |
| 2130 | 2139 | { |
| 2131 | 2140 | .ident = "Thinkpad X1 Carbon 6th", |
| @@ -2156,8 +2165,7 @@ int __init acpi_ec_init(void) · 24 unmodified lines | ||
| 2156 | 2165 | int result; |
| 2157 | 2166 | int ecdt_fail, dsdt_fail; |
| 2158 | 2167 | |
| 2159 | − /* register workqueue for _Qxx evaluations */ | |
| 2160 | − result = acpi_ec_query_init(); | |
| 2168 | + result = acpi_ec_init_workqueues(); | |
| 2161 | 2169 | if (result) |
| 2162 | 2170 | return result; |
| 2163 | 2171 | |
| @@ -2188,6 +2196,6 @@ static void __exit acpi_ec_exit(void) · 24 unmodified lines | ||
| 2188 | 2196 | { |
| 2189 | 2197 | |
| 2190 | 2198 | acpi_bus_unregister_driver(&acpi_ec_driver); |
| 2191 | − acpi_ec_query_exit(); | |
| 2199 | + acpi_ec_destroy_workqueues(); | |
| 2192 | 2200 | } |
| 2193 | 2201 | #endif /* 0 */ |
| @@ -990,21 +990,34 @@ static void acpi_s2idle_sync(void) · 989 unmodified lines | ||
| 990 | 990 | acpi_os_wait_events_complete(); /* synchronize Notify handling */ |
| 991 | 991 | } |
| 992 | 992 | |
| 993 | −static void acpi_s2idle_wake(void) | |
| 993 | +static bool acpi_s2idle_wake(void) | |
| 994 | 994 | { |
| 995 | − /* | |
| 996 | − * If IRQD_WAKEUP_ARMED is set for the SCI at this point, the SCI has | |
| 997 | − * not triggered while suspended, so bail out. | |
| 998 | − */ | |
| 999 | − if (!acpi_sci_irq_valid() || | |
| 1000 | − irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) | |
| 1001 | − return; | |
| 995 | + if (!acpi_sci_irq_valid()) | |
| 996 | + return pm_wakeup_pending(); | |
| 997 | + | |
| 998 | + while (pm_wakeup_pending()) { | |
| 999 | + /* | |
| 1000 | + * If IRQD_WAKEUP_ARMED is set for the SCI at this point, the | |
| 1001 | + * SCI has not triggered while suspended, so bail out (the | |
| 1002 | + * wakeup is pending anyway and the SCI is not the source of | |
| 1003 | + * it). | |
| 1004 | + */ | |
| 1005 | + if (irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) | |
| 1006 | + return true; | |
| 1007 | + | |
| 1008 | + /* | |
| 1009 | + * If there are no EC events to process and at least one of the | |
| 1010 | + * other enabled GPEs is active, the wakeup is regarded as a | |
| 1011 | + * genuine one. | |
| 1012 | + * | |
| 1013 | + * Note that the checks below must be carried out in this order | |
| 1014 | + * to avoid returning prematurely due to a change of the EC GPE | |
| 1015 | + * status bit from unset to set between the checks with the | |
| 1016 | + * status bits of all the other GPEs unset. | |
| 1017 | + */ | |
| 1018 | + if (acpi_any_gpe_status_set() && !acpi_ec_dispatch_gpe()) | |
| 1019 | + return true; | |
| 1002 | 1020 | |
| 1003 | − /* | |
| 1004 | − * If there are EC events to process, the wakeup may be a spurious one | |
| 1005 | − * coming from the EC. | |
| 1006 | − */ | |
| 1007 | − if (acpi_ec_dispatch_gpe()) { | |
| 1008 | 1021 | /* |
| 1009 | 1022 | * Cancel the wakeup and process all pending events in case |
| 1010 | 1023 | * there are any wakeup ones in there. |
| @@ -1017,8 +1030,19 @@ static void acpi_s2idle_wake(void) · 6 unmodified lines | ||
| 1017 | 1030 | |
| 1018 | 1031 | acpi_s2idle_sync(); |
| 1019 | 1032 | |
| 1033 | + /* | |
| 1034 | + * The SCI is in the "suspended" state now and it cannot produce | |
| 1035 | + * new wakeup events till the rearming below, so if any of them | |
| 1036 | + * are pending here, they must be resulting from the processing | |
| 1037 | + * of EC events above or coming from somewhere else. | |
| 1038 | + */ | |
| 1039 | + if (pm_wakeup_pending()) | |
| 1040 | + return true; | |
| 1041 | + | |
| 1020 | 1042 | rearm_wake_irq(acpi_sci_irq); |
| 1021 | 1043 | } |
| 1044 | + | |
| 1045 | + return false; | |
| 1022 | 1046 | } |
| 1023 | 1047 | |
| 1024 | 1048 | static void acpi_s2idle_restore_early(void) |
| @@ -105,6 +105,8 @@ bool have_governor_per_policy(void) · 104 unmodified lines | ||
| 105 | 105 | } |
| 106 | 106 | EXPORT_SYMBOL_GPL(have_governor_per_policy); |
| 107 | 107 | |
| 108 | +static struct kobject *cpufreq_global_kobject; | |
| 109 | + | |
| 108 | 110 | struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy) |
| 109 | 111 | { |
| 110 | 112 | if (have_governor_per_policy()) |
| @@ -2745,9 +2747,6 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) · 2634 unmodified lines | ||
| 2745 | 2747 | } |
| 2746 | 2748 | EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); |
| 2747 | 2749 | |
| 2748 | −struct kobject *cpufreq_global_kobject; | |
| 2749 | −EXPORT_SYMBOL(cpufreq_global_kobject); | |
| 2750 | − | |
| 2751 | 2750 | static int __init cpufreq_core_init(void) |
| 2752 | 2751 | { |
| 2753 | 2752 | if (cpufreq_disabled()) |
| @@ -752,6 +752,7 @@ ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_dispatch_gpe(acpi_handle gpe_device, u3 · 751 unmodified lines | ||
| 752 | 752 | ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void)) |
| 753 | 753 | ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void)) |
| 754 | 754 | ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_wakeup_gpes(void)) |
| 755 | +ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_any_gpe_status_set(void)) | |
| 755 | 756 | |
| 756 | 757 | ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status |
| 757 | 758 | acpi_get_gpe_device(u32 gpe_index, |
| @@ -201,9 +201,6 @@ static inline bool policy_is_shared(struct cpufreq_policy *policy) · 200 unmodified lines | ||
| 201 | 201 | return cpumask_weight(policy->cpus) > 1; |
| 202 | 202 | } |
| 203 | 203 | |
| 204 | −/* /sys/devices/system/cpu/cpufreq: entry point for global variables */ | |
| 205 | −extern struct kobject *cpufreq_global_kobject; | |
| 206 | − | |
| 207 | 204 | #ifdef CONFIG_CPU_FREQ |
| 208 | 205 | unsigned int cpufreq_get(unsigned int cpu); |
| 209 | 206 | unsigned int cpufreq_quick_get(unsigned int cpu); |
| @@ -191,7 +191,7 @@ struct platform_s2idle_ops { · 190 unmodified lines | ||
| 191 | 191 | int (*begin)(void); |
| 192 | 192 | int (*prepare)(void); |
| 193 | 193 | int (*prepare_late)(void); |
| 194 | − void (*wake)(void); | |
| 194 | + bool (*wake)(void); | |
| 195 | 195 | void (*restore_early)(void); |
| 196 | 196 | void (*restore)(void); |
| 197 | 197 | void (*end)(void); |
| @@ -131,11 +131,12 @@ static void s2idle_loop(void) · 130 unmodified lines | ||
| 131 | 131 | * to avoid them upfront. |
| 132 | 132 | */ |
| 133 | 133 | for (;;) { |
| 134 | − if (s2idle_ops && s2idle_ops->wake) | |
| 135 | − s2idle_ops->wake(); | |
| 136 | − | |
| 137 | − if (pm_wakeup_pending()) | |
| 134 | + if (s2idle_ops && s2idle_ops->wake) { | |
| 135 | + if (s2idle_ops->wake()) | |
| 136 | + break; | |
| 137 | + } else if (pm_wakeup_pending()) { | |
| 138 | 138 | break; |
| 139 | + } | |
| 139 | 140 | |
| 140 | 141 | pm_wakeup_clear(false); |
| 141 | 142 | |