Skip to content

Commit 4e03e4e

Browse files
committed
Merge tag 'pm-5.6-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
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
2 parents 81f3011 + 3629ac5 commit 4e03e4e

File tree

10 files changed

+177
-42
lines changed

10 files changed

+177
-42
lines changed

drivers/acpi/acpica/achware.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void);
101101

102102
acpi_status acpi_hw_enable_all_wakeup_gpes(void);
103103

104+
u8 acpi_hw_check_all_gpes(void);
105+
104106
acpi_status
105107
acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
106108
struct acpi_gpe_block_info *gpe_block,

drivers/acpi/acpica/evxfgpe.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,38 @@ acpi_status acpi_enable_all_wakeup_gpes(void)
795795

796796
ACPI_EXPORT_SYMBOL(acpi_enable_all_wakeup_gpes)
797797

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+
798830
/*******************************************************************************
799831
*
800832
* FUNCTION: acpi_install_gpe_block

drivers/acpi/acpica/hwgpe.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,53 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
444444
return (AE_OK);
445445
}
446446

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+
447494
/******************************************************************************
448495
*
449496
* FUNCTION: acpi_hw_disable_all_gpes
@@ -510,4 +557,28 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void)
510557
return_ACPI_STATUS(status);
511558
}
512559

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+
513584
#endif /* !ACPI_REDUCED_HARDWARE */

drivers/acpi/ec.c

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ EXPORT_SYMBOL(first_ec);
179179

180180
static struct acpi_ec *boot_ec;
181181
static bool boot_ec_is_ecdt = false;
182+
static struct workqueue_struct *ec_wq;
182183
static struct workqueue_struct *ec_query_wq;
183184

184185
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)
469470
ec_dbg_evt("Command(%s) submitted/blocked",
470471
acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
471472
ec->nr_pending_queries++;
472-
schedule_work(&ec->work);
473+
queue_work(ec_wq, &ec->work);
473474
}
474475
}
475476

@@ -535,7 +536,7 @@ static void acpi_ec_enable_event(struct acpi_ec *ec)
535536
#ifdef CONFIG_PM_SLEEP
536537
static void __acpi_ec_flush_work(void)
537538
{
538-
flush_scheduled_work(); /* flush ec->work */
539+
drain_workqueue(ec_wq); /* flush ec->work */
539540
flush_workqueue(ec_query_wq); /* flush queries */
540541
}
541542

@@ -556,8 +557,8 @@ static void acpi_ec_disable_event(struct acpi_ec *ec)
556557

557558
void acpi_ec_flush_work(void)
558559
{
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)
561562
return;
562563

563564
__acpi_ec_flush_work();
@@ -2107,25 +2108,33 @@ static struct acpi_driver acpi_ec_driver = {
21072108
.drv.pm = &acpi_ec_pm,
21082109
};
21092110

2110-
static inline int acpi_ec_query_init(void)
2111+
static void acpi_ec_destroy_workqueues(void)
21112112
{
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;
21172116
}
2118-
return 0;
2119-
}
2120-
2121-
static inline void acpi_ec_query_exit(void)
2122-
{
21232117
if (ec_query_wq) {
21242118
destroy_workqueue(ec_query_wq);
21252119
ec_query_wq = NULL;
21262120
}
21272121
}
21282122

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+
21292138
static const struct dmi_system_id acpi_ec_no_wakeup[] = {
21302139
{
21312140
.ident = "Thinkpad X1 Carbon 6th",
@@ -2156,8 +2165,7 @@ int __init acpi_ec_init(void)
21562165
int result;
21572166
int ecdt_fail, dsdt_fail;
21582167

2159-
/* register workqueue for _Qxx evaluations */
2160-
result = acpi_ec_query_init();
2168+
result = acpi_ec_init_workqueues();
21612169
if (result)
21622170
return result;
21632171

@@ -2188,6 +2196,6 @@ static void __exit acpi_ec_exit(void)
21882196
{
21892197

21902198
acpi_bus_unregister_driver(&acpi_ec_driver);
2191-
acpi_ec_query_exit();
2199+
acpi_ec_destroy_workqueues();
21922200
}
21932201
#endif /* 0 */

drivers/acpi/sleep.c

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -990,21 +990,34 @@ static void acpi_s2idle_sync(void)
990990
acpi_os_wait_events_complete(); /* synchronize Notify handling */
991991
}
992992

993-
static void acpi_s2idle_wake(void)
993+
static bool acpi_s2idle_wake(void)
994994
{
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;
10021020

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()) {
10081021
/*
10091022
* Cancel the wakeup and process all pending events in case
10101023
* there are any wakeup ones in there.
@@ -1017,8 +1030,19 @@ static void acpi_s2idle_wake(void)
10171030

10181031
acpi_s2idle_sync();
10191032

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+
10201042
rearm_wake_irq(acpi_sci_irq);
10211043
}
1044+
1045+
return false;
10221046
}
10231047

10241048
static void acpi_s2idle_restore_early(void)

drivers/cpufreq/cpufreq.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ bool have_governor_per_policy(void)
105105
}
106106
EXPORT_SYMBOL_GPL(have_governor_per_policy);
107107

108+
static struct kobject *cpufreq_global_kobject;
109+
108110
struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
109111
{
110112
if (have_governor_per_policy())
@@ -2745,9 +2747,6 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
27452747
}
27462748
EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
27472749

2748-
struct kobject *cpufreq_global_kobject;
2749-
EXPORT_SYMBOL(cpufreq_global_kobject);
2750-
27512750
static int __init cpufreq_core_init(void)
27522751
{
27532752
if (cpufreq_disabled())

include/acpi/acpixf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_dispatch_gpe(acpi_handle gpe_device, u3
752752
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void))
753753
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void))
754754
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))
755756

756757
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
757758
acpi_get_gpe_device(u32 gpe_index,

include/linux/cpufreq.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,6 @@ static inline bool policy_is_shared(struct cpufreq_policy *policy)
201201
return cpumask_weight(policy->cpus) > 1;
202202
}
203203

204-
/* /sys/devices/system/cpu/cpufreq: entry point for global variables */
205-
extern struct kobject *cpufreq_global_kobject;
206-
207204
#ifdef CONFIG_CPU_FREQ
208205
unsigned int cpufreq_get(unsigned int cpu);
209206
unsigned int cpufreq_quick_get(unsigned int cpu);

include/linux/suspend.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ struct platform_s2idle_ops {
191191
int (*begin)(void);
192192
int (*prepare)(void);
193193
int (*prepare_late)(void);
194-
void (*wake)(void);
194+
bool (*wake)(void);
195195
void (*restore_early)(void);
196196
void (*restore)(void);
197197
void (*end)(void);

kernel/power/suspend.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,12 @@ static void s2idle_loop(void)
131131
* to avoid them upfront.
132132
*/
133133
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()) {
138138
break;
139+
}
139140

140141
pm_wakeup_clear(false);
141142

0 commit comments

Comments
 (0)