Skip to content

Commit ef867c1

Browse files
committed
Merge tag 'pm-5.5-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull additional power management updates from Rafael Wysocki: "These fix an ACPI EC driver bug exposed by the recent rework of the suspend-to-idle code flow, reintroduce frequency constraints into device PM QoS (in preparation for adding QoS support to devfreq), drop a redundant field from struct cpuidle_state and clean up Kconfig in some places. Specifics: - Avoid a race condition in the ACPI EC driver that may cause systems to be unable to leave suspend-to-idle (Rafael Wysocki) - Drop the "disabled" field, which is redundant, from struct cpuidle_state (Rafael Wysocki) - Reintroduce device PM QoS frequency constraints (temporarily introduced and than dropped during the 5.4 cycle) in preparation for adding QoS support to devfreq (Leonard Crestez) - Clean up indentation (in multiple places) and the cpuidle drivers help text in Kconfig (Krzysztof Kozlowski, Randy Dunlap)" * tag 'pm-5.5-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI: PM: s2idle: Rework ACPI events synchronization ACPI: EC: Rework flushing of pending work PM / devfreq: Add missing locking while setting suspend_freq PM / QoS: Restore DEV_PM_QOS_MIN/MAX_FREQUENCY PM / QoS: Reorder pm_qos/freq_qos/dev_pm_qos structs PM / QoS: Initial kunit test PM / QoS: Redefine FREQ_QOS_MAX_DEFAULT_VALUE to S32_MAX power: avs: Fix Kconfig indentation cpufreq: Fix Kconfig indentation cpuidle: minor Kconfig help text fixes cpuidle: Drop disabled field from struct cpuidle_state cpuidle: Fix Kconfig indentation
2 parents 63de374 + 1e4230f commit ef867c1

File tree

19 files changed

+324
-120
lines changed

19 files changed

+324
-120
lines changed

arch/sh/kernel/cpu/shmobile/cpuidle.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ static struct cpuidle_driver cpuidle_driver = {
6767
.enter = cpuidle_sleep_enter,
6868
.name = "C2",
6969
.desc = "SuperH Sleep Mode [SF]",
70-
.disabled = true,
70+
.flags = CPUIDLE_FLAG_UNUSABLE,
7171
},
7272
{
7373
.exit_latency = 2300,
@@ -76,7 +76,7 @@ static struct cpuidle_driver cpuidle_driver = {
7676
.enter = cpuidle_sleep_enter,
7777
.name = "C3",
7878
.desc = "SuperH Mobile Standby Mode [SF]",
79-
.disabled = true,
79+
.flags = CPUIDLE_FLAG_UNUSABLE,
8080
},
8181
},
8282
.safe_state_index = 0,
@@ -86,10 +86,10 @@ static struct cpuidle_driver cpuidle_driver = {
8686
int __init sh_mobile_setup_cpuidle(void)
8787
{
8888
if (sh_mobile_sleep_supported & SUSP_SH_SF)
89-
cpuidle_driver.states[1].disabled = false;
89+
cpuidle_driver.states[1].flags = CPUIDLE_FLAG_NONE;
9090

9191
if (sh_mobile_sleep_supported & SUSP_SH_STANDBY)
92-
cpuidle_driver.states[2].disabled = false;
92+
cpuidle_driver.states[2].flags = CPUIDLE_FLAG_NONE;
9393

9494
return cpuidle_register(&cpuidle_driver, NULL);
9595
}

drivers/acpi/ec.c

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -533,26 +533,10 @@ static void acpi_ec_enable_event(struct acpi_ec *ec)
533533
}
534534

535535
#ifdef CONFIG_PM_SLEEP
536-
static bool acpi_ec_query_flushed(struct acpi_ec *ec)
536+
static void __acpi_ec_flush_work(void)
537537
{
538-
bool flushed;
539-
unsigned long flags;
540-
541-
spin_lock_irqsave(&ec->lock, flags);
542-
flushed = !ec->nr_pending_queries;
543-
spin_unlock_irqrestore(&ec->lock, flags);
544-
return flushed;
545-
}
546-
547-
static void __acpi_ec_flush_event(struct acpi_ec *ec)
548-
{
549-
/*
550-
* When ec_freeze_events is true, we need to flush events in
551-
* the proper position before entering the noirq stage.
552-
*/
553-
wait_event(ec->wait, acpi_ec_query_flushed(ec));
554-
if (ec_query_wq)
555-
flush_workqueue(ec_query_wq);
538+
flush_scheduled_work(); /* flush ec->work */
539+
flush_workqueue(ec_query_wq); /* flush queries */
556540
}
557541

558542
static void acpi_ec_disable_event(struct acpi_ec *ec)
@@ -562,15 +546,21 @@ static void acpi_ec_disable_event(struct acpi_ec *ec)
562546
spin_lock_irqsave(&ec->lock, flags);
563547
__acpi_ec_disable_event(ec);
564548
spin_unlock_irqrestore(&ec->lock, flags);
565-
__acpi_ec_flush_event(ec);
549+
550+
/*
551+
* When ec_freeze_events is true, we need to flush events in
552+
* the proper position before entering the noirq stage.
553+
*/
554+
__acpi_ec_flush_work();
566555
}
567556

568557
void acpi_ec_flush_work(void)
569558
{
570-
if (first_ec)
571-
__acpi_ec_flush_event(first_ec);
559+
/* Without ec_query_wq there is nothing to flush. */
560+
if (!ec_query_wq)
561+
return;
572562

573-
flush_scheduled_work();
563+
__acpi_ec_flush_work();
574564
}
575565
#endif /* CONFIG_PM_SLEEP */
576566

drivers/acpi/sleep.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,16 @@ static int acpi_s2idle_prepare_late(void)
977977
return 0;
978978
}
979979

980+
static void acpi_s2idle_sync(void)
981+
{
982+
/*
983+
* The EC driver uses the system workqueue and an additional special
984+
* one, so those need to be flushed too.
985+
*/
986+
acpi_ec_flush_work();
987+
acpi_os_wait_events_complete(); /* synchronize Notify handling */
988+
}
989+
980990
static void acpi_s2idle_wake(void)
981991
{
982992
/*
@@ -1001,13 +1011,8 @@ static void acpi_s2idle_wake(void)
10011011
* should be missed by canceling the wakeup here.
10021012
*/
10031013
pm_system_cancel_wakeup();
1004-
/*
1005-
* The EC driver uses the system workqueue and an additional
1006-
* special one, so those need to be flushed too.
1007-
*/
1008-
acpi_os_wait_events_complete(); /* synchronize EC GPE processing */
1009-
acpi_ec_flush_work();
1010-
acpi_os_wait_events_complete(); /* synchronize Notify handling */
1014+
1015+
acpi_s2idle_sync();
10111016

10121017
rearm_wake_irq(acpi_sci_irq);
10131018
}
@@ -1024,6 +1029,13 @@ static void acpi_s2idle_restore_early(void)
10241029

10251030
static void acpi_s2idle_restore(void)
10261031
{
1032+
/*
1033+
* Drain pending events before restoring the working-state configuration
1034+
* of GPEs.
1035+
*/
1036+
acpi_os_wait_events_complete(); /* synchronize GPE processing */
1037+
acpi_s2idle_sync();
1038+
10271039
s2idle_wakeup = false;
10281040

10291041
acpi_enable_all_runtime_gpes();

drivers/base/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ config DEBUG_TEST_DRIVER_REMOVE
148148
unusable. You should say N here unless you are explicitly looking to
149149
test this functionality.
150150

151+
config PM_QOS_KUNIT_TEST
152+
bool "KUnit Test for PM QoS features"
153+
depends on KUNIT
154+
151155
config HMEM_REPORTING
152156
bool
153157
default n

drivers/base/power/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o wakeup_stats.o
44
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
55
obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o
66
obj-$(CONFIG_HAVE_CLK) += clock_ops.o
7+
obj-$(CONFIG_PM_QOS_KUNIT_TEST) += qos-test.o
78

89
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG

drivers/base/power/qos-test.c

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright 2019 NXP
4+
*/
5+
#include <kunit/test.h>
6+
#include <linux/pm_qos.h>
7+
8+
/* Basic test for aggregating two "min" requests */
9+
static void freq_qos_test_min(struct kunit *test)
10+
{
11+
struct freq_constraints qos;
12+
struct freq_qos_request req1, req2;
13+
int ret;
14+
15+
freq_constraints_init(&qos);
16+
memset(&req1, 0, sizeof(req1));
17+
memset(&req2, 0, sizeof(req2));
18+
19+
ret = freq_qos_add_request(&qos, &req1, FREQ_QOS_MIN, 1000);
20+
KUNIT_EXPECT_EQ(test, ret, 1);
21+
ret = freq_qos_add_request(&qos, &req2, FREQ_QOS_MIN, 2000);
22+
KUNIT_EXPECT_EQ(test, ret, 1);
23+
24+
KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN), 2000);
25+
26+
ret = freq_qos_remove_request(&req2);
27+
KUNIT_EXPECT_EQ(test, ret, 1);
28+
KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN), 1000);
29+
30+
ret = freq_qos_remove_request(&req1);
31+
KUNIT_EXPECT_EQ(test, ret, 1);
32+
KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN),
33+
FREQ_QOS_MIN_DEFAULT_VALUE);
34+
}
35+
36+
/* Test that requests for MAX_DEFAULT_VALUE have no effect */
37+
static void freq_qos_test_maxdef(struct kunit *test)
38+
{
39+
struct freq_constraints qos;
40+
struct freq_qos_request req1, req2;
41+
int ret;
42+
43+
freq_constraints_init(&qos);
44+
memset(&req1, 0, sizeof(req1));
45+
memset(&req2, 0, sizeof(req2));
46+
KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MAX),
47+
FREQ_QOS_MAX_DEFAULT_VALUE);
48+
49+
ret = freq_qos_add_request(&qos, &req1, FREQ_QOS_MAX,
50+
FREQ_QOS_MAX_DEFAULT_VALUE);
51+
KUNIT_EXPECT_EQ(test, ret, 0);
52+
ret = freq_qos_add_request(&qos, &req2, FREQ_QOS_MAX,
53+
FREQ_QOS_MAX_DEFAULT_VALUE);
54+
KUNIT_EXPECT_EQ(test, ret, 0);
55+
56+
/* Add max 1000 */
57+
ret = freq_qos_update_request(&req1, 1000);
58+
KUNIT_EXPECT_EQ(test, ret, 1);
59+
KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MAX), 1000);
60+
61+
/* Add max 2000, no impact */
62+
ret = freq_qos_update_request(&req2, 2000);
63+
KUNIT_EXPECT_EQ(test, ret, 0);
64+
KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MAX), 1000);
65+
66+
/* Remove max 1000, new max 2000 */
67+
ret = freq_qos_remove_request(&req1);
68+
KUNIT_EXPECT_EQ(test, ret, 1);
69+
KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MAX), 2000);
70+
}
71+
72+
/*
73+
* Test that a freq_qos_request can be added again after removal
74+
*
75+
* This issue was solved by commit 05ff1ba412fd ("PM: QoS: Invalidate frequency
76+
* QoS requests after removal")
77+
*/
78+
static void freq_qos_test_readd(struct kunit *test)
79+
{
80+
struct freq_constraints qos;
81+
struct freq_qos_request req;
82+
int ret;
83+
84+
freq_constraints_init(&qos);
85+
memset(&req, 0, sizeof(req));
86+
KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN),
87+
FREQ_QOS_MIN_DEFAULT_VALUE);
88+
89+
/* Add */
90+
ret = freq_qos_add_request(&qos, &req, FREQ_QOS_MIN, 1000);
91+
KUNIT_EXPECT_EQ(test, ret, 1);
92+
KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN), 1000);
93+
94+
/* Remove */
95+
ret = freq_qos_remove_request(&req);
96+
KUNIT_EXPECT_EQ(test, ret, 1);
97+
KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN),
98+
FREQ_QOS_MIN_DEFAULT_VALUE);
99+
100+
/* Add again */
101+
ret = freq_qos_add_request(&qos, &req, FREQ_QOS_MIN, 2000);
102+
KUNIT_EXPECT_EQ(test, ret, 1);
103+
KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN), 2000);
104+
}
105+
106+
static struct kunit_case pm_qos_test_cases[] = {
107+
KUNIT_CASE(freq_qos_test_min),
108+
KUNIT_CASE(freq_qos_test_maxdef),
109+
KUNIT_CASE(freq_qos_test_readd),
110+
{},
111+
};
112+
113+
static struct kunit_suite pm_qos_test_module = {
114+
.name = "qos-kunit-test",
115+
.test_cases = pm_qos_test_cases,
116+
};
117+
kunit_test_suite(pm_qos_test_module);

0 commit comments

Comments
 (0)