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
Unified · Split
| @@ -67,7 +67,7 @@ static struct cpuidle_driver cpuidle_driver = { · 66 unmodified lines | |||
| 67 | .enter = cpuidle_sleep_enter, | 67 | .enter = cpuidle_sleep_enter, |
| 68 | .name = "C2", | 68 | .name = "C2", |
| 69 | .desc = "SuperH Sleep Mode [SF]", | 69 | .desc = "SuperH Sleep Mode [SF]", |
| 70 | .disabled = true, | 70 | .flags = CPUIDLE_FLAG_UNUSABLE, |
| 71 | }, | 71 | }, |
| 72 | { | 72 | { |
| 73 | .exit_latency = 2300, | 73 | .exit_latency = 2300, |
| @@ -76,7 +76,7 @@ static struct cpuidle_driver cpuidle_driver = { · 2 unmodified lines | |||
| 76 | .enter = cpuidle_sleep_enter, | 76 | .enter = cpuidle_sleep_enter, |
| 77 | .name = "C3", | 77 | .name = "C3", |
| 78 | .desc = "SuperH Mobile Standby Mode [SF]", | 78 | .desc = "SuperH Mobile Standby Mode [SF]", |
| 79 | .disabled = true, | 79 | .flags = CPUIDLE_FLAG_UNUSABLE, |
| 80 | }, | 80 | }, |
| 81 | }, | 81 | }, |
| 82 | .safe_state_index = 0, | 82 | .safe_state_index = 0, |
| @@ -86,10 +86,10 @@ static struct cpuidle_driver cpuidle_driver = { · 3 unmodified lines | |||
| 86 | int __init sh_mobile_setup_cpuidle(void) | 86 | int __init sh_mobile_setup_cpuidle(void) |
| 87 | { | 87 | { |
| 88 | if (sh_mobile_sleep_supported & SUSP_SH_SF) | 88 | if (sh_mobile_sleep_supported & SUSP_SH_SF) |
| 89 | cpuidle_driver.states[1].disabled = false; | 89 | cpuidle_driver.states[1].flags = CPUIDLE_FLAG_NONE; |
| 90 | 90 | ||
| 91 | if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) | 91 | if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) |
| 92 | cpuidle_driver.states[2].disabled = false; | 92 | cpuidle_driver.states[2].flags = CPUIDLE_FLAG_NONE; |
| 93 | 93 | ||
| 94 | return cpuidle_register(&cpuidle_driver, NULL); | 94 | return cpuidle_register(&cpuidle_driver, NULL); |
| 95 | } | 95 | } |
| @@ -533,26 +533,10 @@ static void acpi_ec_enable_event(struct acpi_ec *ec) · 532 unmodified lines | |||
| 533 | } | 533 | } |
| 534 | 534 | ||
| 535 | #ifdef CONFIG_PM_SLEEP | 535 | #ifdef CONFIG_PM_SLEEP |
| 536 | static bool acpi_ec_query_flushed(struct acpi_ec *ec) | 536 | static void __acpi_ec_flush_work(void) |
| 537 | { | 537 | { |
| 538 | bool flushed; | 538 | flush_scheduled_work(); /* flush ec->work */ |
| 539 | unsigned long flags; | 539 | flush_workqueue(ec_query_wq); /* flush queries */ |
| 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); | ||
| 556 | } | 540 | } |
| 557 | 541 | ||
| 558 | static void acpi_ec_disable_event(struct acpi_ec *ec) | 542 | static void acpi_ec_disable_event(struct acpi_ec *ec) |
| @@ -562,15 +546,21 @@ static void acpi_ec_disable_event(struct acpi_ec *ec) · 3 unmodified lines | |||
| 562 | spin_lock_irqsave(&ec->lock, flags); | 546 | spin_lock_irqsave(&ec->lock, flags); |
| 563 | __acpi_ec_disable_event(ec); | 547 | __acpi_ec_disable_event(ec); |
| 564 | spin_unlock_irqrestore(&ec->lock, flags); | 548 | 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(); | ||
| 566 | } | 555 | } |
| 567 | 556 | ||
| 568 | void acpi_ec_flush_work(void) | 557 | void acpi_ec_flush_work(void) |
| 569 | { | 558 | { |
| 570 | if (first_ec) | 559 | /* Without ec_query_wq there is nothing to flush. */ |
| 571 | __acpi_ec_flush_event(first_ec); | 560 | if (!ec_query_wq) |
| 561 | return; | ||
| 572 | 562 | ||
| 573 | flush_scheduled_work(); | 563 | __acpi_ec_flush_work(); |
| 574 | } | 564 | } |
| 575 | #endif /* CONFIG_PM_SLEEP */ | 565 | #endif /* CONFIG_PM_SLEEP */ |
| 576 | 566 | ||
| @@ -977,6 +977,16 @@ static int acpi_s2idle_prepare_late(void) · 976 unmodified lines | |||
| 977 | return 0; | 977 | return 0; |
| 978 | } | 978 | } |
| 979 | 979 | ||
| 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 | |||
| 980 | static void acpi_s2idle_wake(void) | 990 | static void acpi_s2idle_wake(void) |
| 981 | { | 991 | { |
| 982 | /* | 992 | /* |
| @@ -1001,13 +1011,8 @@ static void acpi_s2idle_wake(void) · 18 unmodified lines | |||
| 1001 | * should be missed by canceling the wakeup here. | 1011 | * should be missed by canceling the wakeup here. |
| 1002 | */ | 1012 | */ |
| 1003 | pm_system_cancel_wakeup(); | 1013 | pm_system_cancel_wakeup(); |
| 1004 | /* | 1014 | |
| 1005 | * The EC driver uses the system workqueue and an additional | 1015 | acpi_s2idle_sync(); |
| 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 */ | ||
| 1011 | 1016 | ||
| 1012 | rearm_wake_irq(acpi_sci_irq); | 1017 | rearm_wake_irq(acpi_sci_irq); |
| 1013 | } | 1018 | } |
| @@ -1024,6 +1029,13 @@ static void acpi_s2idle_restore_early(void) · 10 unmodified lines | |||
| 1024 | 1029 | ||
| 1025 | static void acpi_s2idle_restore(void) | 1030 | static void acpi_s2idle_restore(void) |
| 1026 | { | 1031 | { |
| 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 | |||
| 1027 | s2idle_wakeup = false; | 1039 | s2idle_wakeup = false; |
| 1028 | 1040 | ||
| 1029 | acpi_enable_all_runtime_gpes(); | 1041 | acpi_enable_all_runtime_gpes(); |
| @@ -148,6 +148,10 @@ config DEBUG_TEST_DRIVER_REMOVE · 147 unmodified lines | |||
| 148 | unusable. You should say N here unless you are explicitly looking to | 148 | unusable. You should say N here unless you are explicitly looking to |
| 149 | test this functionality. | 149 | test this functionality. |
| 150 | 150 | ||
| 151 | config PM_QOS_KUNIT_TEST | ||
| 152 | bool "KUnit Test for PM QoS features" | ||
| 153 | depends on KUNIT | ||
| 154 | |||
| 151 | config HMEM_REPORTING | 155 | config HMEM_REPORTING |
| 152 | bool | 156 | bool |
| 153 | default n | 157 | default n |
| @@ -4,5 +4,6 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o wakeup_stats.o · 3 unmodified lines | |||
| 4 | obj-$(CONFIG_PM_TRACE_RTC) += trace.o | 4 | obj-$(CONFIG_PM_TRACE_RTC) += trace.o |
| 5 | obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o | 5 | obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o |
| 6 | obj-$(CONFIG_HAVE_CLK) += clock_ops.o | 6 | obj-$(CONFIG_HAVE_CLK) += clock_ops.o |
| 7 | obj-$(CONFIG_PM_QOS_KUNIT_TEST) += qos-test.o | ||
| 7 | 8 | ||
| 8 | ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG | 9 | ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG |
| @@ -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); | ||
| @@ -115,10 +115,20 @@ s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type) · 114 unmodified lines | |||
| 115 | 115 | ||
| 116 | spin_lock_irqsave(&dev->power.lock, flags); | 116 | spin_lock_irqsave(&dev->power.lock, flags); |
| 117 | 117 | ||
| 118 | if (type == DEV_PM_QOS_RESUME_LATENCY) { | 118 | switch (type) { |
| 119 | case DEV_PM_QOS_RESUME_LATENCY: | ||
| 119 | ret = IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT | 120 | ret = IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT |
| 120 | : pm_qos_read_value(&qos->resume_latency); | 121 | : pm_qos_read_value(&qos->resume_latency); |
| 121 | } else { | 122 | break; |
| 123 | case DEV_PM_QOS_MIN_FREQUENCY: | ||
| 124 | ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE | ||
| 125 | : freq_qos_read_value(&qos->freq, FREQ_QOS_MIN); | ||
| 126 | break; | ||
| 127 | case DEV_PM_QOS_MAX_FREQUENCY: | ||
| 128 | ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE | ||
| 129 | : freq_qos_read_value(&qos->freq, FREQ_QOS_MAX); | ||
| 130 | break; | ||
| 131 | default: | ||
| 122 | WARN_ON(1); | 132 | WARN_ON(1); |
| 123 | ret = 0; | 133 | ret = 0; |
| 124 | } | 134 | } |
| @@ -159,6 +169,10 @@ static int apply_constraint(struct dev_pm_qos_request *req, · 34 unmodified lines | |||
| 159 | req->dev->power.set_latency_tolerance(req->dev, value); | 169 | req->dev->power.set_latency_tolerance(req->dev, value); |
| 160 | } | 170 | } |
| 161 | break; | 171 | break; |
| 172 | case DEV_PM_QOS_MIN_FREQUENCY: | ||
| 173 | case DEV_PM_QOS_MAX_FREQUENCY: | ||
| 174 | ret = freq_qos_apply(&req->data.freq, action, value); | ||
| 175 | break; | ||
| 162 | case DEV_PM_QOS_FLAGS: | 176 | case DEV_PM_QOS_FLAGS: |
| 163 | ret = pm_qos_update_flags(&qos->flags, &req->data.flr, | 177 | ret = pm_qos_update_flags(&qos->flags, &req->data.flr, |
| 164 | action, value); | 178 | action, value); |
| @@ -209,6 +223,8 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) · 44 unmodified lines | |||
| 209 | c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT; | 223 | c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT; |
| 210 | c->type = PM_QOS_MIN; | 224 | c->type = PM_QOS_MIN; |
| 211 | 225 | ||
| 226 | freq_constraints_init(&qos->freq); | ||
| 227 | |||
| 212 | INIT_LIST_HEAD(&qos->flags.list); | 228 | INIT_LIST_HEAD(&qos->flags.list); |
| 213 | 229 | ||
| 214 | spin_lock_irq(&dev->power.lock); | 230 | spin_lock_irq(&dev->power.lock); |
| @@ -269,6 +285,20 @@ void dev_pm_qos_constraints_destroy(struct device *dev) · 54 unmodified lines | |||
| 269 | memset(req, 0, sizeof(*req)); | 285 | memset(req, 0, sizeof(*req)); |
| 270 | } | 286 | } |
| 271 | 287 | ||
| 288 | c = &qos->freq.min_freq; | ||
| 289 | plist_for_each_entry_safe(req, tmp, &c->list, data.freq.pnode) { | ||
| 290 | apply_constraint(req, PM_QOS_REMOVE_REQ, | ||
| 291 | PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE); | ||
| 292 | memset(req, 0, sizeof(*req)); | ||
| 293 | } | ||
| 294 | |||
| 295 | c = &qos->freq.max_freq; | ||
| 296 | plist_for_each_entry_safe(req, tmp, &c->list, data.freq.pnode) { | ||
| 297 | apply_constraint(req, PM_QOS_REMOVE_REQ, | ||
| 298 | PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE); | ||
| 299 | memset(req, 0, sizeof(*req)); | ||
| 300 | } | ||
| 301 | |||
| 272 | f = &qos->flags; | 302 | f = &qos->flags; |
| 273 | list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) { | 303 | list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) { |
| 274 | apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); | 304 | apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); |
| @@ -314,11 +344,22 @@ static int __dev_pm_qos_add_request(struct device *dev, · 39 unmodified lines | |||
| 314 | ret = dev_pm_qos_constraints_allocate(dev); | 344 | ret = dev_pm_qos_constraints_allocate(dev); |
| 315 | 345 | ||
| 316 | trace_dev_pm_qos_add_request(dev_name(dev), type, value); | 346 | trace_dev_pm_qos_add_request(dev_name(dev), type, value); |
| 317 | if (!ret) { | 347 | if (ret) |
| 318 | req->dev = dev; | 348 | return ret; |
| 319 | req->type = type; | 349 | |
| 350 | req->dev = dev; | ||
| 351 | req->type = type; | ||
| 352 | if (req->type == DEV_PM_QOS_MIN_FREQUENCY) | ||
| 353 | ret = freq_qos_add_request(&dev->power.qos->freq, | ||
| 354 | &req->data.freq, | ||
| 355 | FREQ_QOS_MIN, value); | ||
| 356 | else if (req->type == DEV_PM_QOS_MAX_FREQUENCY) | ||
| 357 | ret = freq_qos_add_request(&dev->power.qos->freq, | ||
| 358 | &req->data.freq, | ||
| 359 | FREQ_QOS_MAX, value); | ||
| 360 | else | ||
| 320 | ret = apply_constraint(req, PM_QOS_ADD_REQ, value); | 361 | ret = apply_constraint(req, PM_QOS_ADD_REQ, value); |
| 321 | } | 362 | |
| 322 | return ret; | 363 | return ret; |
| 323 | } | 364 | } |
| 324 | 365 | ||
| @@ -382,6 +423,10 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req, · 57 unmodified lines | |||
| 382 | case DEV_PM_QOS_LATENCY_TOLERANCE: | 423 | case DEV_PM_QOS_LATENCY_TOLERANCE: |
| 383 | curr_value = req->data.pnode.prio; | 424 | curr_value = req->data.pnode.prio; |
| 384 | break; | 425 | break; |
| 426 | case DEV_PM_QOS_MIN_FREQUENCY: | ||
| 427 | case DEV_PM_QOS_MAX_FREQUENCY: | ||
| 428 | curr_value = req->data.freq.pnode.prio; | ||
| 429 | break; | ||
| 385 | case DEV_PM_QOS_FLAGS: | 430 | case DEV_PM_QOS_FLAGS: |
| 386 | curr_value = req->data.flr.flags; | 431 | curr_value = req->data.flr.flags; |
| 387 | break; | 432 | break; |
| @@ -507,6 +552,14 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier, · 119 unmodified lines | |||
| 507 | ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers, | 552 | ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers, |
| 508 | notifier); | 553 | notifier); |
| 509 | break; | 554 | break; |
| 555 | case DEV_PM_QOS_MIN_FREQUENCY: | ||
| 556 | ret = freq_qos_add_notifier(&dev->power.qos->freq, | ||
| 557 | FREQ_QOS_MIN, notifier); | ||
| 558 | break; | ||
| 559 | case DEV_PM_QOS_MAX_FREQUENCY: | ||
| 560 | ret = freq_qos_add_notifier(&dev->power.qos->freq, | ||
| 561 | FREQ_QOS_MAX, notifier); | ||
| 562 | break; | ||
| 510 | default: | 563 | default: |
| 511 | WARN_ON(1); | 564 | WARN_ON(1); |
| 512 | ret = -EINVAL; | 565 | ret = -EINVAL; |
| @@ -546,6 +599,14 @@ int dev_pm_qos_remove_notifier(struct device *dev, · 33 unmodified lines | |||
| 546 | ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers, | 599 | ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers, |
| 547 | notifier); | 600 | notifier); |
| 548 | break; | 601 | break; |
| 602 | case DEV_PM_QOS_MIN_FREQUENCY: | ||
| 603 | ret = freq_qos_remove_notifier(&dev->power.qos->freq, | ||
| 604 | FREQ_QOS_MIN, notifier); | ||
| 605 | break; | ||
| 606 | case DEV_PM_QOS_MAX_FREQUENCY: | ||
| 607 | ret = freq_qos_remove_notifier(&dev->power.qos->freq, | ||
| 608 | FREQ_QOS_MAX, notifier); | ||
| 609 | break; | ||
| 549 | default: | 610 | default: |
| 550 | WARN_ON(1); | 611 | WARN_ON(1); |
| 551 | ret = -EINVAL; | 612 | ret = -EINVAL; |
| @@ -48,9 +48,9 @@ config PPC_PASEMI_CPUFREQ · 47 unmodified lines | |||
| 48 | PWRficient processors. | 48 | PWRficient processors. |
| 49 | 49 | ||
| 50 | config POWERNV_CPUFREQ | 50 | config POWERNV_CPUFREQ |
| 51 | tristate "CPU frequency scaling for IBM POWERNV platform" | 51 | tristate "CPU frequency scaling for IBM POWERNV platform" |
| 52 | depends on PPC_POWERNV | 52 | depends on PPC_POWERNV |
| 53 | default y | 53 | default y |
| 54 | help | 54 | help |
| 55 | This adds support for CPU frequency switching on IBM POWERNV | 55 | This adds support for CPU frequency switching on IBM POWERNV |
| 56 | platform | 56 | platform |
| @@ -4,17 +4,17 @@ · 3 unmodified lines | |||
| 4 | # | 4 | # |
| 5 | 5 | ||
| 6 | config X86_INTEL_PSTATE | 6 | config X86_INTEL_PSTATE |
| 7 | bool "Intel P state control" | 7 | bool "Intel P state control" |
| 8 | depends on X86 | 8 | depends on X86 |
| 9 | select ACPI_PROCESSOR if ACPI | 9 | select ACPI_PROCESSOR if ACPI |
| 10 | select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO | 10 | select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO |
| 11 | help | 11 | help |
| 12 | This driver provides a P state for Intel core processors. | 12 | This driver provides a P state for Intel core processors. |
| 13 | The driver implements an internal governor and will become | 13 | The driver implements an internal governor and will become |
| 14 | the scaling driver and governor for Sandy bridge processors. | 14 | the scaling driver and governor for Sandy bridge processors. |
| 15 | 15 | ||
| 16 | When this driver is enabled it will become the preferred | 16 | When this driver is enabled it will become the preferred |
| 17 | scaling driver for Sandy bridge processors. | 17 | scaling driver for Sandy bridge processors. |
| 18 | 18 | ||
| 19 | If in doubt, say N. | 19 | If in doubt, say N. |
| 20 | 20 | ||
| @@ -16,7 +16,7 @@ config CPU_IDLE · 15 unmodified lines | |||
| 16 | if CPU_IDLE | 16 | if CPU_IDLE |
| 17 | 17 | ||
| 18 | config CPU_IDLE_MULTIPLE_DRIVERS | 18 | config CPU_IDLE_MULTIPLE_DRIVERS |
| 19 | bool | 19 | bool |
| 20 | 20 | ||
| 21 | config CPU_IDLE_GOV_LADDER | 21 | config CPU_IDLE_GOV_LADDER |
| 22 | bool "Ladder governor (for periodic timer tick)" | 22 | bool "Ladder governor (for periodic timer tick)" |
| @@ -63,13 +63,13 @@ source "drivers/cpuidle/Kconfig.powerpc" · 40 unmodified lines | |||
| 63 | endmenu | 63 | endmenu |
| 64 | 64 | ||
| 65 | config HALTPOLL_CPUIDLE | 65 | config HALTPOLL_CPUIDLE |
| 66 | tristate "Halt poll cpuidle driver" | 66 | tristate "Halt poll cpuidle driver" |
| 67 | depends on X86 && KVM_GUEST | 67 | depends on X86 && KVM_GUEST |
| 68 | default y | 68 | default y |
| 69 | help | 69 | help |
| 70 | This option enables halt poll cpuidle driver, which allows to poll | 70 | This option enables halt poll cpuidle driver, which allows to poll |
| 71 | before halting in the guest (more efficient than polling in the | 71 | before halting in the guest (more efficient than polling in the |
| 72 | host via halt_poll_ns for some scenarios). | 72 | host via halt_poll_ns for some scenarios). |
| 73 | 73 | ||
| 74 | endif | 74 | endif |
| 75 | 75 | ||
| @@ -3,15 +3,15 @@ · 2 unmodified lines | |||
| 3 | # ARM CPU Idle drivers | 3 | # ARM CPU Idle drivers |
| 4 | # | 4 | # |
| 5 | config ARM_CPUIDLE | 5 | config ARM_CPUIDLE |
| 6 | bool "Generic ARM/ARM64 CPU idle Driver" | 6 | bool "Generic ARM/ARM64 CPU idle Driver" |
| 7 | select DT_IDLE_STATES | 7 | select DT_IDLE_STATES |
| 8 | select CPU_IDLE_MULTIPLE_DRIVERS | 8 | select CPU_IDLE_MULTIPLE_DRIVERS |
| 9 | help | 9 | help |
| 10 | Select this to enable generic cpuidle driver for ARM. | 10 | Select this to enable generic cpuidle driver for ARM. |
| 11 | It provides a generic idle driver whose idle states are configured | 11 | It provides a generic idle driver whose idle states are configured |
| 12 | at run-time through DT nodes. The CPUidle suspend backend is | 12 | at run-time through DT nodes. The CPUidle suspend backend is |
| 13 | initialized by calling the CPU operations init idle hook | 13 | initialized by calling the CPU operations init idle hook |
| 14 | provided by architecture code. | 14 | provided by architecture code. |
| 15 | 15 | ||
| 16 | config ARM_PSCI_CPUIDLE | 16 | config ARM_PSCI_CPUIDLE |
| 17 | bool "PSCI CPU idle Driver" | 17 | bool "PSCI CPU idle Driver" |
| @@ -65,21 +65,21 @@ config ARM_U8500_CPUIDLE · 47 unmodified lines | |||
| 65 | bool "Cpu Idle Driver for the ST-E u8500 processors" | 65 | bool "Cpu Idle Driver for the ST-E u8500 processors" |
| 66 | depends on ARCH_U8500 && !ARM64 | 66 | depends on ARCH_U8500 && !ARM64 |
| 67 | help | 67 | help |
| 68 | Select this to enable cpuidle for ST-E u8500 processors | 68 | Select this to enable cpuidle for ST-E u8500 processors. |
| 69 | 69 | ||
| 70 | config ARM_AT91_CPUIDLE | 70 | config ARM_AT91_CPUIDLE |
| 71 | bool "Cpu Idle Driver for the AT91 processors" | 71 | bool "Cpu Idle Driver for the AT91 processors" |
| 72 | default y | 72 | default y |
| 73 | depends on ARCH_AT91 && !ARM64 | 73 | depends on ARCH_AT91 && !ARM64 |
| 74 | help | 74 | help |
| 75 | Select this to enable cpuidle for AT91 processors | 75 | Select this to enable cpuidle for AT91 processors. |
| 76 | 76 | ||
| 77 | config ARM_EXYNOS_CPUIDLE | 77 | config ARM_EXYNOS_CPUIDLE |
| 78 | bool "Cpu Idle Driver for the Exynos processors" | 78 | bool "Cpu Idle Driver for the Exynos processors" |
| 79 | depends on ARCH_EXYNOS && !ARM64 | 79 | depends on ARCH_EXYNOS && !ARM64 |
| 80 | select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP | 80 | select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP |
| 81 | help | 81 | help |
| 82 | Select this to enable cpuidle for Exynos processors | 82 | Select this to enable cpuidle for Exynos processors. |
| 83 | 83 | ||
| 84 | config ARM_MVEBU_V7_CPUIDLE | 84 | config ARM_MVEBU_V7_CPUIDLE |
| 85 | bool "CPU Idle Driver for mvebu v7 family processors" | 85 | bool "CPU Idle Driver for mvebu v7 family processors" |
| @@ -572,7 +572,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) · 571 unmodified lines | |||
| 572 | return -EINVAL; | 572 | return -EINVAL; |
| 573 | 573 | ||
| 574 | for (i = 0; i < drv->state_count; i++) | 574 | for (i = 0; i < drv->state_count; i++) |
| 575 | if (drv->states[i].disabled) | 575 | if (drv->states[i].flags & CPUIDLE_FLAG_UNUSABLE) |
| 576 | dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER; | 576 | dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER; |
| 577 | 577 | ||
| 578 | per_cpu(cpuidle_devices, dev->cpu) = dev; | 578 | per_cpu(cpuidle_devices, dev->cpu) = dev; |
| @@ -53,7 +53,6 @@ void cpuidle_poll_state_init(struct cpuidle_driver *drv) · 52 unmodified lines | |||
| 53 | state->target_residency_ns = 0; | 53 | state->target_residency_ns = 0; |
| 54 | state->power_usage = -1; | 54 | state->power_usage = -1; |
| 55 | state->enter = poll_idle; | 55 | state->enter = poll_idle; |
| 56 | state->disabled = false; | ||
| 57 | state->flags = CPUIDLE_FLAG_POLLING; | 56 | state->flags = CPUIDLE_FLAG_POLLING; |
| 58 | } | 57 | } |
| 59 | EXPORT_SYMBOL_GPL(cpuidle_poll_state_init); | 58 | EXPORT_SYMBOL_GPL(cpuidle_poll_state_init); |
| @@ -921,7 +921,9 @@ int devfreq_suspend_device(struct devfreq *devfreq) · 920 unmodified lines | |||
| 921 | } | 921 | } |
| 922 | 922 | ||
| 923 | if (devfreq->suspend_freq) { | 923 | if (devfreq->suspend_freq) { |
| 924 | mutex_lock(&devfreq->lock); | ||
| 924 | ret = devfreq_set_target(devfreq, devfreq->suspend_freq, 0); | 925 | ret = devfreq_set_target(devfreq, devfreq->suspend_freq, 0); |
| 926 | mutex_unlock(&devfreq->lock); | ||
| 925 | if (ret) | 927 | if (ret) |
| 926 | return ret; | 928 | return ret; |
| 927 | } | 929 | } |
| @@ -949,7 +951,9 @@ int devfreq_resume_device(struct devfreq *devfreq) · 21 unmodified lines | |||
| 949 | return 0; | 951 | return 0; |
| 950 | 952 | ||
| 951 | if (devfreq->resume_freq) { | 953 | if (devfreq->resume_freq) { |
| 954 | mutex_lock(&devfreq->lock); | ||
| 952 | ret = devfreq_set_target(devfreq, devfreq->resume_freq, 0); | 955 | ret = devfreq_set_target(devfreq, devfreq->resume_freq, 0); |
| 956 | mutex_unlock(&devfreq->lock); | ||
| 953 | if (ret) | 957 | if (ret) |
| 954 | return ret; | 958 | return ret; |
| 955 | } | 959 | } |
| @@ -1291,8 +1291,8 @@ static void sklh_idle_state_table_update(void) · 1290 unmodified lines | |||
| 1291 | return; | 1291 | return; |
| 1292 | } | 1292 | } |
| 1293 | 1293 | ||
| 1294 | skl_cstates[5].disabled = 1; /* C8-SKL */ | 1294 | skl_cstates[5].flags |= CPUIDLE_FLAG_UNUSABLE; /* C8-SKL */ |
| 1295 | skl_cstates[6].disabled = 1; /* C9-SKL */ | 1295 | skl_cstates[6].flags |= CPUIDLE_FLAG_UNUSABLE; /* C9-SKL */ |
| 1296 | } | 1296 | } |
| 1297 | /* | 1297 | /* |
| 1298 | * intel_idle_state_table_update() | 1298 | * intel_idle_state_table_update() |
| @@ -1355,7 +1355,7 @@ static void __init intel_idle_cpuidle_driver_init(void) · 56 unmodified lines | |||
| 1355 | continue; | 1355 | continue; |
| 1356 | 1356 | ||
| 1357 | /* if state marked as disabled, skip it */ | 1357 | /* if state marked as disabled, skip it */ |
| 1358 | if (cpuidle_state_table[cstate].disabled != 0) { | 1358 | if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_UNUSABLE) { |
| 1359 | pr_debug("state %s is disabled\n", | 1359 | pr_debug("state %s is disabled\n", |
| 1360 | cpuidle_state_table[cstate].name); | 1360 | cpuidle_state_table[cstate].name); |
| 1361 | continue; | 1361 | continue; |
| @@ -13,9 +13,9 @@ menuconfig POWER_AVS · 12 unmodified lines | |||
| 13 | Say Y here to enable Adaptive Voltage Scaling class support. | 13 | Say Y here to enable Adaptive Voltage Scaling class support. |
| 14 | 14 | ||
| 15 | config ROCKCHIP_IODOMAIN | 15 | config ROCKCHIP_IODOMAIN |
| 16 | tristate "Rockchip IO domain support" | 16 | tristate "Rockchip IO domain support" |
| 17 | depends on POWER_AVS && ARCH_ROCKCHIP && OF | 17 | depends on POWER_AVS && ARCH_ROCKCHIP && OF |
| 18 | help | 18 | help |
| 19 | Say y here to enable support io domains on Rockchip SoCs. It is | 19 | Say y here to enable support io domains on Rockchip SoCs. It is |
| 20 | necessary for the io domain setting of the SoC to match the | 20 | necessary for the io domain setting of the SoC to match the |
| 21 | voltage supplied by the regulators. | 21 | voltage supplied by the regulators. |
| @@ -54,7 +54,6 @@ struct cpuidle_state { · 53 unmodified lines | |||
| 54 | unsigned int exit_latency; /* in US */ | 54 | unsigned int exit_latency; /* in US */ |
| 55 | int power_usage; /* in mW */ | 55 | int power_usage; /* in mW */ |
| 56 | unsigned int target_residency; /* in US */ | 56 | unsigned int target_residency; /* in US */ |
| 57 | bool disabled; /* disabled on all CPUs */ | ||
| 58 | 57 | ||
| 59 | int (*enter) (struct cpuidle_device *dev, | 58 | int (*enter) (struct cpuidle_device *dev, |
| 60 | struct cpuidle_driver *drv, | 59 | struct cpuidle_driver *drv, |
| @@ -77,6 +76,7 @@ struct cpuidle_state { · 16 unmodified lines | |||
| 77 | #define CPUIDLE_FLAG_POLLING BIT(0) /* polling state */ | 76 | #define CPUIDLE_FLAG_POLLING BIT(0) /* polling state */ |
| 78 | #define CPUIDLE_FLAG_COUPLED BIT(1) /* state applies to multiple cpus */ | 77 | #define CPUIDLE_FLAG_COUPLED BIT(1) /* state applies to multiple cpus */ |
| 79 | #define CPUIDLE_FLAG_TIMER_STOP BIT(2) /* timer is stopped on this state */ | 78 | #define CPUIDLE_FLAG_TIMER_STOP BIT(2) /* timer is stopped on this state */ |
| 79 | #define CPUIDLE_FLAG_UNUSABLE BIT(3) /* avoid using this state */ | ||
| 80 | 80 | ||
| 81 | struct cpuidle_device_kobj; | 81 | struct cpuidle_device_kobj; |
| 82 | struct cpuidle_state_kobj; | 82 | struct cpuidle_state_kobj; |
| @@ -34,6 +34,8 @@ enum pm_qos_flags_status { · 33 unmodified lines | |||
| 34 | #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT PM_QOS_LATENCY_ANY | 34 | #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT PM_QOS_LATENCY_ANY |
| 35 | #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS PM_QOS_LATENCY_ANY_NS | 35 | #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS PM_QOS_LATENCY_ANY_NS |
| 36 | #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0 | 36 | #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0 |
| 37 | #define PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE 0 | ||
| 38 | #define PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE FREQ_QOS_MAX_DEFAULT_VALUE | ||
| 37 | #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1) | 39 | #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1) |
| 38 | 40 | ||
| 39 | #define PM_QOS_FLAG_NO_POWER_OFF (1 << 0) | 41 | #define PM_QOS_FLAG_NO_POWER_OFF (1 << 0) |
| @@ -49,21 +51,6 @@ struct pm_qos_flags_request { · 9 unmodified lines | |||
| 49 | s32 flags; /* Do not change to 64 bit */ | 51 | s32 flags; /* Do not change to 64 bit */ |
| 50 | }; | 52 | }; |
| 51 | 53 | ||
| 52 | enum dev_pm_qos_req_type { | ||
| 53 | DEV_PM_QOS_RESUME_LATENCY = 1, | ||
| 54 | DEV_PM_QOS_LATENCY_TOLERANCE, | ||
| 55 | DEV_PM_QOS_FLAGS, | ||
| 56 | }; | ||
| 57 | |||
| 58 | struct dev_pm_qos_request { | ||
| 59 | enum dev_pm_qos_req_type type; | ||
| 60 | union { | ||
| 61 | struct plist_node pnode; | ||
| 62 | struct pm_qos_flags_request flr; | ||
| 63 | } data; | ||
| 64 | struct device *dev; | ||
| 65 | }; | ||
| 66 | |||
| 67 | enum pm_qos_type { | 54 | enum pm_qos_type { |
| 68 | PM_QOS_UNITIALIZED, | 55 | PM_QOS_UNITIALIZED, |
| 69 | PM_QOS_MAX, /* return the largest value */ | 56 | PM_QOS_MAX, /* return the largest value */ |
| @@ -90,9 +77,51 @@ struct pm_qos_flags { · 20 unmodified lines | |||
| 90 | s32 effective_flags; /* Do not change to 64 bit */ | 77 | s32 effective_flags; /* Do not change to 64 bit */ |
| 91 | }; | 78 | }; |
| 92 | 79 | ||
| 80 | |||
| 81 | #define FREQ_QOS_MIN_DEFAULT_VALUE 0 | ||
| 82 | #define FREQ_QOS_MAX_DEFAULT_VALUE S32_MAX | ||
| 83 | |||
| 84 | enum freq_qos_req_type { | ||
| 85 | FREQ_QOS_MIN = 1, | ||
| 86 | FREQ_QOS_MAX, | ||
| 87 | }; | ||
| 88 | |||
| 89 | struct freq_constraints { | ||
| 90 | struct pm_qos_constraints min_freq; | ||
| 91 | struct blocking_notifier_head min_freq_notifiers; | ||
| 92 | struct pm_qos_constraints max_freq; | ||
| 93 | struct blocking_notifier_head max_freq_notifiers; | ||
| 94 | }; | ||
| 95 | |||
| 96 | struct freq_qos_request { | ||
| 97 | enum freq_qos_req_type type; | ||
| 98 | struct plist_node pnode; | ||
| 99 | struct freq_constraints *qos; | ||
| 100 | }; | ||
| 101 | |||
| 102 | |||
| 103 | enum dev_pm_qos_req_type { | ||
| 104 | DEV_PM_QOS_RESUME_LATENCY = 1, | ||
| 105 | DEV_PM_QOS_LATENCY_TOLERANCE, | ||
| 106 | DEV_PM_QOS_MIN_FREQUENCY, | ||
| 107 | DEV_PM_QOS_MAX_FREQUENCY, | ||
| 108 | DEV_PM_QOS_FLAGS, | ||
| 109 | }; | ||
| 110 | |||
| 111 | struct dev_pm_qos_request { | ||
| 112 | enum dev_pm_qos_req_type type; | ||
| 113 | union { | ||
| 114 | struct plist_node pnode; | ||
| 115 | struct pm_qos_flags_request flr; | ||
| 116 | struct freq_qos_request freq; | ||
| 117 | } data; | ||
| 118 | struct device *dev; | ||
| 119 | }; | ||
| 120 | |||
| 93 | struct dev_pm_qos { | 121 | struct dev_pm_qos { |
| 94 | struct pm_qos_constraints resume_latency; | 122 | struct pm_qos_constraints resume_latency; |
| 95 | struct pm_qos_constraints latency_tolerance; | 123 | struct pm_qos_constraints latency_tolerance; |
| 124 | struct freq_constraints freq; | ||
| 96 | struct pm_qos_flags flags; | 125 | struct pm_qos_flags flags; |
| 97 | struct dev_pm_qos_request *resume_latency_req; | 126 | struct dev_pm_qos_request *resume_latency_req; |
| 98 | struct dev_pm_qos_request *latency_tolerance_req; | 127 | struct dev_pm_qos_request *latency_tolerance_req; |
| @@ -191,6 +220,10 @@ static inline s32 dev_pm_qos_read_value(struct device *dev, · 92 unmodified lines | |||
| 191 | switch (type) { | 220 | switch (type) { |
| 192 | case DEV_PM_QOS_RESUME_LATENCY: | 221 | case DEV_PM_QOS_RESUME_LATENCY: |
| 193 | return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; | 222 | return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; |
| 223 | case DEV_PM_QOS_MIN_FREQUENCY: | ||
| 224 | return PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE; | ||
| 225 | case DEV_PM_QOS_MAX_FREQUENCY: | ||
| 226 | return PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE; | ||
| 194 | default: | 227 | default: |
| 195 | WARN_ON(1); | 228 | WARN_ON(1); |
| 196 | return 0; | 229 | return 0; |
| @@ -255,27 +288,6 @@ static inline s32 dev_pm_qos_raw_resume_latency(struct device *dev) · 58 unmodified lines | |||
| 255 | } | 288 | } |
| 256 | #endif | 289 | #endif |
| 257 | 290 | ||
| 258 | #define FREQ_QOS_MIN_DEFAULT_VALUE 0 | ||
| 259 | #define FREQ_QOS_MAX_DEFAULT_VALUE (-1) | ||
| 260 | |||
| 261 | enum freq_qos_req_type { | ||
| 262 | FREQ_QOS_MIN = 1, | ||
| 263 | FREQ_QOS_MAX, | ||
| 264 | }; | ||
| 265 | |||
| 266 | struct freq_constraints { | ||
| 267 | struct pm_qos_constraints min_freq; | ||
| 268 | struct blocking_notifier_head min_freq_notifiers; | ||
| 269 | struct pm_qos_constraints max_freq; | ||
| 270 | struct blocking_notifier_head max_freq_notifiers; | ||
| 271 | }; | ||
| 272 | |||
| 273 | struct freq_qos_request { | ||
| 274 | enum freq_qos_req_type type; | ||
| 275 | struct plist_node pnode; | ||
| 276 | struct freq_constraints *qos; | ||
| 277 | }; | ||
| 278 | |||
| 279 | static inline int freq_qos_request_active(struct freq_qos_request *req) | 291 | static inline int freq_qos_request_active(struct freq_qos_request *req) |
| 280 | { | 292 | { |
| 281 | return !IS_ERR_OR_NULL(req->qos); | 293 | return !IS_ERR_OR_NULL(req->qos); |
| @@ -291,6 +303,8 @@ int freq_qos_add_request(struct freq_constraints *qos, · 9 unmodified lines | |||
| 291 | enum freq_qos_req_type type, s32 value); | 303 | enum freq_qos_req_type type, s32 value); |
| 292 | int freq_qos_update_request(struct freq_qos_request *req, s32 new_value); | 304 | int freq_qos_update_request(struct freq_qos_request *req, s32 new_value); |
| 293 | int freq_qos_remove_request(struct freq_qos_request *req); | 305 | int freq_qos_remove_request(struct freq_qos_request *req); |
| 306 | int freq_qos_apply(struct freq_qos_request *req, | ||
| 307 | enum pm_qos_req_action action, s32 value); | ||
| 294 | 308 | ||
| 295 | int freq_qos_add_notifier(struct freq_constraints *qos, | 309 | int freq_qos_add_notifier(struct freq_constraints *qos, |
| 296 | enum freq_qos_req_type type, | 310 | enum freq_qos_req_type type, |
| @@ -714,8 +714,10 @@ s32 freq_qos_read_value(struct freq_constraints *qos, · 713 unmodified lines | |||
| 714 | * @req: Constraint request to apply. | 714 | * @req: Constraint request to apply. |
| 715 | * @action: Action to perform (add/update/remove). | 715 | * @action: Action to perform (add/update/remove). |
| 716 | * @value: Value to assign to the QoS request. | 716 | * @value: Value to assign to the QoS request. |
| 717 | * | ||
| 718 | * This is only meant to be called from inside pm_qos, not drivers. | ||
| 717 | */ | 719 | */ |
| 718 | static int freq_qos_apply(struct freq_qos_request *req, | 720 | int freq_qos_apply(struct freq_qos_request *req, |
| 719 | enum pm_qos_req_action action, s32 value) | 721 | enum pm_qos_req_action action, s32 value) |
| 720 | { | 722 | { |
| 721 | int ret; | 723 | int ret; |