aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-02-17 17:17:51 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-17 17:17:51 -0500
commit99fa0ad92c4fd8b529c89b3640b42323984be761 (patch)
treeba4ef84ab54c2c5636521c1b1ae4e9056d46c75c
parent1d9e71404e2c3f37387991534983dcb2ab05660d (diff)
parent5f5081852038d9a7b309190730bfb724b413235e (diff)
Merge tag 'suspend-to-idle-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull suspend-to-idle updates from Rafael Wysocki: "Suspend-to-idle timer quiescing support for v3.20-rc1 Until now suspend-to-idle has not been able to save much more energy than runtime PM because of timer interrupts that periodically bring CPUs out of idle while they are waiting for a wakeup interrupt. Of course, the timer interrupts are not wakeup ones, so the handling of them can be deferred until a real wakeup interrupt happens, but at the same time we don't want to mass-expire timers at that point. The solution is to suspend the entire timekeeping when the last CPU is entering an idle state and resume it when the first CPU goes out of idle. That has to be done with care, though, so as to avoid accessing suspended clocksources etc. end we need extra support from idle drivers for that. This series of commits adds support for quiescing timers during suspend-to-idle and adds the requisite callbacks to intel_idle and the ACPI cpuidle driver" * tag 'suspend-to-idle-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI / idle: Implement ->enter_freeze callback routine intel_idle: Add ->enter_freeze callbacks PM / sleep: Make it possible to quiesce timers during suspend-to-idle timekeeping: Make it safe to use the fast timekeeper while suspended timekeeping: Pass readout base to update_fast_timekeeper() PM / sleep: Re-implement suspend-to-idle handling
-rw-r--r--drivers/acpi/processor_idle.c48
-rw-r--r--drivers/cpuidle/cpuidle.c94
-rw-r--r--drivers/idle/intel_idle.c179
-rw-r--r--include/linux/cpuidle.h13
-rw-r--r--include/linux/suspend.h16
-rw-r--r--include/linux/tick.h6
-rw-r--r--kernel/power/suspend.c43
-rw-r--r--kernel/sched/idle.c16
-rw-r--r--kernel/time/tick-common.c50
-rw-r--r--kernel/time/timekeeping.c48
-rw-r--r--kernel/time/timekeeping.h2
11 files changed, 407 insertions, 108 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index c256bd7fbd78..c6bb9f1257c9 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -732,9 +732,8 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
732 732
733static bool acpi_idle_fallback_to_c1(struct acpi_processor *pr) 733static bool acpi_idle_fallback_to_c1(struct acpi_processor *pr)
734{ 734{
735 return IS_ENABLED(CONFIG_HOTPLUG_CPU) && num_online_cpus() > 1 && 735 return IS_ENABLED(CONFIG_HOTPLUG_CPU) && !pr->flags.has_cst &&
736 !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED) && 736 !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED);
737 !pr->flags.has_cst;
738} 737}
739 738
740static int c3_cpu_count; 739static int c3_cpu_count;
@@ -744,9 +743,10 @@ static DEFINE_RAW_SPINLOCK(c3_lock);
744 * acpi_idle_enter_bm - enters C3 with proper BM handling 743 * acpi_idle_enter_bm - enters C3 with proper BM handling
745 * @pr: Target processor 744 * @pr: Target processor
746 * @cx: Target state context 745 * @cx: Target state context
746 * @timer_bc: Whether or not to change timer mode to broadcast
747 */ 747 */
748static void acpi_idle_enter_bm(struct acpi_processor *pr, 748static void acpi_idle_enter_bm(struct acpi_processor *pr,
749 struct acpi_processor_cx *cx) 749 struct acpi_processor_cx *cx, bool timer_bc)
750{ 750{
751 acpi_unlazy_tlb(smp_processor_id()); 751 acpi_unlazy_tlb(smp_processor_id());
752 752
@@ -754,7 +754,8 @@ static void acpi_idle_enter_bm(struct acpi_processor *pr,
754 * Must be done before busmaster disable as we might need to 754 * Must be done before busmaster disable as we might need to
755 * access HPET ! 755 * access HPET !
756 */ 756 */
757 lapic_timer_state_broadcast(pr, cx, 1); 757 if (timer_bc)
758 lapic_timer_state_broadcast(pr, cx, 1);
758 759
759 /* 760 /*
760 * disable bus master 761 * disable bus master
@@ -784,7 +785,8 @@ static void acpi_idle_enter_bm(struct acpi_processor *pr,
784 raw_spin_unlock(&c3_lock); 785 raw_spin_unlock(&c3_lock);
785 } 786 }
786 787
787 lapic_timer_state_broadcast(pr, cx, 0); 788 if (timer_bc)
789 lapic_timer_state_broadcast(pr, cx, 0);
788} 790}
789 791
790static int acpi_idle_enter(struct cpuidle_device *dev, 792static int acpi_idle_enter(struct cpuidle_device *dev,
@@ -798,12 +800,12 @@ static int acpi_idle_enter(struct cpuidle_device *dev,
798 return -EINVAL; 800 return -EINVAL;
799 801
800 if (cx->type != ACPI_STATE_C1) { 802 if (cx->type != ACPI_STATE_C1) {
801 if (acpi_idle_fallback_to_c1(pr)) { 803 if (acpi_idle_fallback_to_c1(pr) && num_online_cpus() > 1) {
802 index = CPUIDLE_DRIVER_STATE_START; 804 index = CPUIDLE_DRIVER_STATE_START;
803 cx = per_cpu(acpi_cstate[index], dev->cpu); 805 cx = per_cpu(acpi_cstate[index], dev->cpu);
804 } else if (cx->type == ACPI_STATE_C3 && pr->flags.bm_check) { 806 } else if (cx->type == ACPI_STATE_C3 && pr->flags.bm_check) {
805 if (cx->bm_sts_skip || !acpi_idle_bm_check()) { 807 if (cx->bm_sts_skip || !acpi_idle_bm_check()) {
806 acpi_idle_enter_bm(pr, cx); 808 acpi_idle_enter_bm(pr, cx, true);
807 return index; 809 return index;
808 } else if (drv->safe_state_index >= 0) { 810 } else if (drv->safe_state_index >= 0) {
809 index = drv->safe_state_index; 811 index = drv->safe_state_index;
@@ -827,6 +829,27 @@ static int acpi_idle_enter(struct cpuidle_device *dev,
827 return index; 829 return index;
828} 830}
829 831
832static void acpi_idle_enter_freeze(struct cpuidle_device *dev,
833 struct cpuidle_driver *drv, int index)
834{
835 struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
836
837 if (cx->type == ACPI_STATE_C3) {
838 struct acpi_processor *pr = __this_cpu_read(processors);
839
840 if (unlikely(!pr))
841 return;
842
843 if (pr->flags.bm_check) {
844 acpi_idle_enter_bm(pr, cx, false);
845 return;
846 } else {
847 ACPI_FLUSH_CPU_CACHE();
848 }
849 }
850 acpi_idle_do_entry(cx);
851}
852
830struct cpuidle_driver acpi_idle_driver = { 853struct cpuidle_driver acpi_idle_driver = {
831 .name = "acpi_idle", 854 .name = "acpi_idle",
832 .owner = THIS_MODULE, 855 .owner = THIS_MODULE,
@@ -925,6 +948,15 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
925 state->enter_dead = acpi_idle_play_dead; 948 state->enter_dead = acpi_idle_play_dead;
926 drv->safe_state_index = count; 949 drv->safe_state_index = count;
927 } 950 }
951 /*
952 * Halt-induced C1 is not good for ->enter_freeze, because it
953 * re-enables interrupts on exit. Moreover, C1 is generally not
954 * particularly interesting from the suspend-to-idle angle, so
955 * avoid C1 and the situations in which we may need to fall back
956 * to it altogether.
957 */
958 if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr))
959 state->enter_freeze = acpi_idle_enter_freeze;
928 960
929 count++; 961 count++;
930 if (count == CPUIDLE_STATE_MAX) 962 if (count == CPUIDLE_STATE_MAX)
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 125150dc6e81..4d534582514e 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -19,6 +19,8 @@
19#include <linux/ktime.h> 19#include <linux/ktime.h>
20#include <linux/hrtimer.h> 20#include <linux/hrtimer.h>
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/suspend.h>
23#include <linux/tick.h>
22#include <trace/events/power.h> 24#include <trace/events/power.h>
23 25
24#include "cpuidle.h" 26#include "cpuidle.h"
@@ -32,7 +34,6 @@ LIST_HEAD(cpuidle_detected_devices);
32static int enabled_devices; 34static int enabled_devices;
33static int off __read_mostly; 35static int off __read_mostly;
34static int initialized __read_mostly; 36static int initialized __read_mostly;
35static bool use_deepest_state __read_mostly;
36 37
37int cpuidle_disabled(void) 38int cpuidle_disabled(void)
38{ 39{
@@ -66,36 +67,23 @@ int cpuidle_play_dead(void)
66} 67}
67 68
68/** 69/**
69 * cpuidle_use_deepest_state - Enable/disable the "deepest idle" mode. 70 * cpuidle_find_deepest_state - Find deepest state meeting specific conditions.
70 * @enable: Whether enable or disable the feature. 71 * @drv: cpuidle driver for the given CPU.
71 * 72 * @dev: cpuidle device for the given CPU.
72 * If the "deepest idle" mode is enabled, cpuidle will ignore the governor and 73 * @freeze: Whether or not the state should be suitable for suspend-to-idle.
73 * always use the state with the greatest exit latency (out of the states that
74 * are not disabled).
75 *
76 * This function can only be called after cpuidle_pause() to avoid races.
77 */
78void cpuidle_use_deepest_state(bool enable)
79{
80 use_deepest_state = enable;
81}
82
83/**
84 * cpuidle_find_deepest_state - Find the state of the greatest exit latency.
85 * @drv: cpuidle driver for a given CPU.
86 * @dev: cpuidle device for a given CPU.
87 */ 74 */
88static int cpuidle_find_deepest_state(struct cpuidle_driver *drv, 75static int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
89 struct cpuidle_device *dev) 76 struct cpuidle_device *dev, bool freeze)
90{ 77{
91 unsigned int latency_req = 0; 78 unsigned int latency_req = 0;
92 int i, ret = CPUIDLE_DRIVER_STATE_START - 1; 79 int i, ret = freeze ? -1 : CPUIDLE_DRIVER_STATE_START - 1;
93 80
94 for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { 81 for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
95 struct cpuidle_state *s = &drv->states[i]; 82 struct cpuidle_state *s = &drv->states[i];
96 struct cpuidle_state_usage *su = &dev->states_usage[i]; 83 struct cpuidle_state_usage *su = &dev->states_usage[i];
97 84
98 if (s->disabled || su->disable || s->exit_latency <= latency_req) 85 if (s->disabled || su->disable || s->exit_latency <= latency_req
86 || (freeze && !s->enter_freeze))
99 continue; 87 continue;
100 88
101 latency_req = s->exit_latency; 89 latency_req = s->exit_latency;
@@ -104,6 +92,63 @@ static int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
104 return ret; 92 return ret;
105} 93}
106 94
95static void enter_freeze_proper(struct cpuidle_driver *drv,
96 struct cpuidle_device *dev, int index)
97{
98 tick_freeze();
99 /*
100 * The state used here cannot be a "coupled" one, because the "coupled"
101 * cpuidle mechanism enables interrupts and doing that with timekeeping
102 * suspended is generally unsafe.
103 */
104 drv->states[index].enter_freeze(dev, drv, index);
105 WARN_ON(!irqs_disabled());
106 /*
107 * timekeeping_resume() that will be called by tick_unfreeze() for the
108 * last CPU executing it calls functions containing RCU read-side
109 * critical sections, so tell RCU about that.
110 */
111 RCU_NONIDLE(tick_unfreeze());
112}
113
114/**
115 * cpuidle_enter_freeze - Enter an idle state suitable for suspend-to-idle.
116 *
117 * If there are states with the ->enter_freeze callback, find the deepest of
118 * them and enter it with frozen tick. Otherwise, find the deepest state
119 * available and enter it normally.
120 */
121void cpuidle_enter_freeze(void)
122{
123 struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
124 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
125 int index;
126
127 /*
128 * Find the deepest state with ->enter_freeze present, which guarantees
129 * that interrupts won't be enabled when it exits and allows the tick to
130 * be frozen safely.
131 */
132 index = cpuidle_find_deepest_state(drv, dev, true);
133 if (index >= 0) {
134 enter_freeze_proper(drv, dev, index);
135 return;
136 }
137
138 /*
139 * It is not safe to freeze the tick, find the deepest state available
140 * at all and try to enter it normally.
141 */
142 index = cpuidle_find_deepest_state(drv, dev, false);
143 if (index >= 0)
144 cpuidle_enter(drv, dev, index);
145 else
146 arch_cpu_idle();
147
148 /* Interrupts are enabled again here. */
149 local_irq_disable();
150}
151
107/** 152/**
108 * cpuidle_enter_state - enter the state and update stats 153 * cpuidle_enter_state - enter the state and update stats
109 * @dev: cpuidle device for this cpu 154 * @dev: cpuidle device for this cpu
@@ -166,9 +211,6 @@ int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
166 if (!drv || !dev || !dev->enabled) 211 if (!drv || !dev || !dev->enabled)
167 return -EBUSY; 212 return -EBUSY;
168 213
169 if (unlikely(use_deepest_state))
170 return cpuidle_find_deepest_state(drv, dev);
171
172 return cpuidle_curr_governor->select(drv, dev); 214 return cpuidle_curr_governor->select(drv, dev);
173} 215}
174 216
@@ -200,7 +242,7 @@ int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev,
200 */ 242 */
201void cpuidle_reflect(struct cpuidle_device *dev, int index) 243void cpuidle_reflect(struct cpuidle_device *dev, int index)
202{ 244{
203 if (cpuidle_curr_governor->reflect && !unlikely(use_deepest_state)) 245 if (cpuidle_curr_governor->reflect)
204 cpuidle_curr_governor->reflect(dev, index); 246 cpuidle_curr_governor->reflect(dev, index);
205} 247}
206 248
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 1bc0c170f12a..b0e58522780d 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -97,6 +97,8 @@ static const struct idle_cpu *icpu;
97static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; 97static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
98static int intel_idle(struct cpuidle_device *dev, 98static int intel_idle(struct cpuidle_device *dev,
99 struct cpuidle_driver *drv, int index); 99 struct cpuidle_driver *drv, int index);
100static void intel_idle_freeze(struct cpuidle_device *dev,
101 struct cpuidle_driver *drv, int index);
100static int intel_idle_cpu_init(int cpu); 102static int intel_idle_cpu_init(int cpu);
101 103
102static struct cpuidle_state *cpuidle_state_table; 104static struct cpuidle_state *cpuidle_state_table;
@@ -131,28 +133,32 @@ static struct cpuidle_state nehalem_cstates[] = {
131 .flags = MWAIT2flg(0x00), 133 .flags = MWAIT2flg(0x00),
132 .exit_latency = 3, 134 .exit_latency = 3,
133 .target_residency = 6, 135 .target_residency = 6,
134 .enter = &intel_idle }, 136 .enter = &intel_idle,
137 .enter_freeze = intel_idle_freeze, },
135 { 138 {
136 .name = "C1E-NHM", 139 .name = "C1E-NHM",
137 .desc = "MWAIT 0x01", 140 .desc = "MWAIT 0x01",
138 .flags = MWAIT2flg(0x01), 141 .flags = MWAIT2flg(0x01),
139 .exit_latency = 10, 142 .exit_latency = 10,
140 .target_residency = 20, 143 .target_residency = 20,
141 .enter = &intel_idle }, 144 .enter = &intel_idle,
145 .enter_freeze = intel_idle_freeze, },
142 { 146 {
143 .name = "C3-NHM", 147 .name = "C3-NHM",
144 .desc = "MWAIT 0x10", 148 .desc = "MWAIT 0x10",
145 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, 149 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
146 .exit_latency = 20, 150 .exit_latency = 20,
147 .target_residency = 80, 151 .target_residency = 80,
148 .enter = &intel_idle }, 152 .enter = &intel_idle,
153 .enter_freeze = intel_idle_freeze, },
149 { 154 {
150 .name = "C6-NHM", 155 .name = "C6-NHM",
151 .desc = "MWAIT 0x20", 156 .desc = "MWAIT 0x20",
152 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, 157 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
153 .exit_latency = 200, 158 .exit_latency = 200,
154 .target_residency = 800, 159 .target_residency = 800,
155 .enter = &intel_idle }, 160 .enter = &intel_idle,
161 .enter_freeze = intel_idle_freeze, },
156 { 162 {
157 .enter = NULL } 163 .enter = NULL }
158}; 164};
@@ -164,35 +170,40 @@ static struct cpuidle_state snb_cstates[] = {
164 .flags = MWAIT2flg(0x00), 170 .flags = MWAIT2flg(0x00),
165 .exit_latency = 2, 171 .exit_latency = 2,
166 .target_residency = 2, 172 .target_residency = 2,
167 .enter = &intel_idle }, 173 .enter = &intel_idle,
174 .enter_freeze = intel_idle_freeze, },
168 { 175 {
169 .name = "C1E-SNB", 176 .name = "C1E-SNB",
170 .desc = "MWAIT 0x01", 177 .desc = "MWAIT 0x01",
171 .flags = MWAIT2flg(0x01), 178 .flags = MWAIT2flg(0x01),
172 .exit_latency = 10, 179 .exit_latency = 10,
173 .target_residency = 20, 180 .target_residency = 20,
174 .enter = &intel_idle }, 181 .enter = &intel_idle,
182 .enter_freeze = intel_idle_freeze, },
175 { 183 {
176 .name = "C3-SNB", 184 .name = "C3-SNB",
177 .desc = "MWAIT 0x10", 185 .desc = "MWAIT 0x10",
178 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, 186 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
179 .exit_latency = 80, 187 .exit_latency = 80,
180 .target_residency = 211, 188 .target_residency = 211,
181 .enter = &intel_idle }, 189 .enter = &intel_idle,
190 .enter_freeze = intel_idle_freeze, },
182 { 191 {
183 .name = "C6-SNB", 192 .name = "C6-SNB",
184 .desc = "MWAIT 0x20", 193 .desc = "MWAIT 0x20",
185 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, 194 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
186 .exit_latency = 104, 195 .exit_latency = 104,
187 .target_residency = 345, 196 .target_residency = 345,
188 .enter = &intel_idle }, 197 .enter = &intel_idle,
198 .enter_freeze = intel_idle_freeze, },
189 { 199 {
190 .name = "C7-SNB", 200 .name = "C7-SNB",
191 .desc = "MWAIT 0x30", 201 .desc = "MWAIT 0x30",
192 .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED, 202 .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED,
193 .exit_latency = 109, 203 .exit_latency = 109,
194 .target_residency = 345, 204 .target_residency = 345,
195 .enter = &intel_idle }, 205 .enter = &intel_idle,
206 .enter_freeze = intel_idle_freeze, },
196 { 207 {
197 .enter = NULL } 208 .enter = NULL }
198}; 209};
@@ -204,42 +215,48 @@ static struct cpuidle_state byt_cstates[] = {
204 .flags = MWAIT2flg(0x00), 215 .flags = MWAIT2flg(0x00),
205 .exit_latency = 1, 216 .exit_latency = 1,
206 .target_residency = 1, 217 .target_residency = 1,
207 .enter = &intel_idle }, 218 .enter = &intel_idle,
219 .enter_freeze = intel_idle_freeze, },
208 { 220 {
209 .name = "C1E-BYT", 221 .name = "C1E-BYT",
210 .desc = "MWAIT 0x01", 222 .desc = "MWAIT 0x01",
211 .flags = MWAIT2flg(0x01), 223 .flags = MWAIT2flg(0x01),
212 .exit_latency = 15, 224 .exit_latency = 15,
213 .target_residency = 30, 225 .target_residency = 30,
214 .enter = &intel_idle }, 226 .enter = &intel_idle,
227 .enter_freeze = intel_idle_freeze, },
215 { 228 {
216 .name = "C6N-BYT", 229 .name = "C6N-BYT",
217 .desc = "MWAIT 0x58", 230 .desc = "MWAIT 0x58",
218 .flags = MWAIT2flg(0x58) | CPUIDLE_FLAG_TLB_FLUSHED, 231 .flags = MWAIT2flg(0x58) | CPUIDLE_FLAG_TLB_FLUSHED,
219 .exit_latency = 40, 232 .exit_latency = 40,
220 .target_residency = 275, 233 .target_residency = 275,
221 .enter = &intel_idle }, 234 .enter = &intel_idle,
235 .enter_freeze = intel_idle_freeze, },
222 { 236 {
223 .name = "C6S-BYT", 237 .name = "C6S-BYT",
224 .desc = "MWAIT 0x52", 238 .desc = "MWAIT 0x52",
225 .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED, 239 .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED,
226 .exit_latency = 140, 240 .exit_latency = 140,
227 .target_residency = 560, 241 .target_residency = 560,
228 .enter = &intel_idle }, 242 .enter = &intel_idle,
243 .enter_freeze = intel_idle_freeze, },
229 { 244 {
230 .name = "C7-BYT", 245 .name = "C7-BYT",
231 .desc = "MWAIT 0x60", 246 .desc = "MWAIT 0x60",
232 .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, 247 .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
233 .exit_latency = 1200, 248 .exit_latency = 1200,
234 .target_residency = 1500, 249 .target_residency = 1500,
235 .enter = &intel_idle }, 250 .enter = &intel_idle,
251 .enter_freeze = intel_idle_freeze, },
236 { 252 {
237 .name = "C7S-BYT", 253 .name = "C7S-BYT",
238 .desc = "MWAIT 0x64", 254 .desc = "MWAIT 0x64",
239 .flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TLB_FLUSHED, 255 .flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TLB_FLUSHED,
240 .exit_latency = 10000, 256 .exit_latency = 10000,
241 .target_residency = 20000, 257 .target_residency = 20000,
242 .enter = &intel_idle }, 258 .enter = &intel_idle,
259 .enter_freeze = intel_idle_freeze, },
243 { 260 {
244 .enter = NULL } 261 .enter = NULL }
245}; 262};
@@ -251,35 +268,40 @@ static struct cpuidle_state ivb_cstates[] = {
251 .flags = MWAIT2flg(0x00), 268 .flags = MWAIT2flg(0x00),
252 .exit_latency = 1, 269 .exit_latency = 1,
253 .target_residency = 1, 270 .target_residency = 1,
254 .enter = &intel_idle }, 271 .enter = &intel_idle,
272 .enter_freeze = intel_idle_freeze, },
255 { 273 {
256 .name = "C1E-IVB", 274 .name = "C1E-IVB",
257 .desc = "MWAIT 0x01", 275 .desc = "MWAIT 0x01",
258 .flags = MWAIT2flg(0x01), 276 .flags = MWAIT2flg(0x01),
259 .exit_latency = 10, 277 .exit_latency = 10,
260 .target_residency = 20, 278 .target_residency = 20,
261 .enter = &intel_idle }, 279 .enter = &intel_idle,
280 .enter_freeze = intel_idle_freeze, },
262 { 281 {
263 .name = "C3-IVB", 282 .name = "C3-IVB",
264 .desc = "MWAIT 0x10", 283 .desc = "MWAIT 0x10",
265 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, 284 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
266 .exit_latency = 59, 285 .exit_latency = 59,
267 .target_residency = 156, 286 .target_residency = 156,
268 .enter = &intel_idle }, 287 .enter = &intel_idle,
288 .enter_freeze = intel_idle_freeze, },
269 { 289 {
270 .name = "C6-IVB", 290 .name = "C6-IVB",
271 .desc = "MWAIT 0x20", 291 .desc = "MWAIT 0x20",
272 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, 292 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
273 .exit_latency = 80, 293 .exit_latency = 80,
274 .target_residency = 300, 294 .target_residency = 300,
275 .enter = &intel_idle }, 295 .enter = &intel_idle,
296 .enter_freeze = intel_idle_freeze, },
276 { 297 {
277 .name = "C7-IVB", 298 .name = "C7-IVB",
278 .desc = "MWAIT 0x30", 299 .desc = "MWAIT 0x30",
279 .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED, 300 .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED,
280 .exit_latency = 87, 301 .exit_latency = 87,
281 .target_residency = 300, 302 .target_residency = 300,
282 .enter = &intel_idle }, 303 .enter = &intel_idle,
304 .enter_freeze = intel_idle_freeze, },
283 { 305 {
284 .enter = NULL } 306 .enter = NULL }
285}; 307};
@@ -291,28 +313,32 @@ static struct cpuidle_state ivt_cstates[] = {
291 .flags = MWAIT2flg(0x00), 313 .flags = MWAIT2flg(0x00),
292 .exit_latency = 1, 314 .exit_latency = 1,
293 .target_residency = 1, 315 .target_residency = 1,
294 .enter = &intel_idle }, 316 .enter = &intel_idle,
317 .enter_freeze = intel_idle_freeze, },
295 { 318 {
296 .name = "C1E-IVT", 319 .name = "C1E-IVT",
297 .desc = "MWAIT 0x01", 320 .desc = "MWAIT 0x01",
298 .flags = MWAIT2flg(0x01), 321 .flags = MWAIT2flg(0x01),
299 .exit_latency = 10, 322 .exit_latency = 10,
300 .target_residency = 80, 323 .target_residency = 80,
301 .enter = &intel_idle }, 324 .enter = &intel_idle,
325 .enter_freeze = intel_idle_freeze, },
302 { 326 {
303 .name = "C3-IVT", 327 .name = "C3-IVT",
304 .desc = "MWAIT 0x10", 328 .desc = "MWAIT 0x10",
305 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, 329 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
306 .exit_latency = 59, 330 .exit_latency = 59,
307 .target_residency = 156, 331 .target_residency = 156,
308 .enter = &intel_idle }, 332 .enter = &intel_idle,
333 .enter_freeze = intel_idle_freeze, },
309 { 334 {
310 .name = "C6-IVT", 335 .name = "C6-IVT",
311 .desc = "MWAIT 0x20", 336 .desc = "MWAIT 0x20",
312 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, 337 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
313 .exit_latency = 82, 338 .exit_latency = 82,
314 .target_residency = 300, 339 .target_residency = 300,
315 .enter = &intel_idle }, 340 .enter = &intel_idle,
341 .enter_freeze = intel_idle_freeze, },
316 { 342 {
317 .enter = NULL } 343 .enter = NULL }
318}; 344};
@@ -324,28 +350,32 @@ static struct cpuidle_state ivt_cstates_4s[] = {
324 .flags = MWAIT2flg(0x00), 350 .flags = MWAIT2flg(0x00),
325 .exit_latency = 1, 351 .exit_latency = 1,
326 .target_residency = 1, 352 .target_residency = 1,
327 .enter = &intel_idle }, 353 .enter = &intel_idle,
354 .enter_freeze = intel_idle_freeze, },
328 { 355 {
329 .name = "C1E-IVT-4S", 356 .name = "C1E-IVT-4S",
330 .desc = "MWAIT 0x01", 357 .desc = "MWAIT 0x01",
331 .flags = MWAIT2flg(0x01), 358 .flags = MWAIT2flg(0x01),
332 .exit_latency = 10, 359 .exit_latency = 10,
333 .target_residency = 250, 360 .target_residency = 250,
334 .enter = &intel_idle }, 361 .enter = &intel_idle,
362 .enter_freeze = intel_idle_freeze, },
335 { 363 {
336 .name = "C3-IVT-4S", 364 .name = "C3-IVT-4S",
337 .desc = "MWAIT 0x10", 365 .desc = "MWAIT 0x10",
338 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, 366 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
339 .exit_latency = 59, 367 .exit_latency = 59,
340 .target_residency = 300, 368 .target_residency = 300,
341 .enter = &intel_idle }, 369 .enter = &intel_idle,
370 .enter_freeze = intel_idle_freeze, },
342 { 371 {
343 .name = "C6-IVT-4S", 372 .name = "C6-IVT-4S",
344 .desc = "MWAIT 0x20", 373 .desc = "MWAIT 0x20",
345 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, 374 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
346 .exit_latency = 84, 375 .exit_latency = 84,
347 .target_residency = 400, 376 .target_residency = 400,
348 .enter = &intel_idle }, 377 .enter = &intel_idle,
378 .enter_freeze = intel_idle_freeze, },
349 { 379 {
350 .enter = NULL } 380 .enter = NULL }
351}; 381};
@@ -357,28 +387,32 @@ static struct cpuidle_state ivt_cstates_8s[] = {
357 .flags = MWAIT2flg(0x00), 387 .flags = MWAIT2flg(0x00),
358 .exit_latency = 1, 388 .exit_latency = 1,
359 .target_residency = 1, 389 .target_residency = 1,
360 .enter = &intel_idle }, 390 .enter = &intel_idle,
391 .enter_freeze = intel_idle_freeze, },
361 { 392 {
362 .name = "C1E-IVT-8S", 393 .name = "C1E-IVT-8S",
363 .desc = "MWAIT 0x01", 394 .desc = "MWAIT 0x01",
364 .flags = MWAIT2flg(0x01), 395 .flags = MWAIT2flg(0x01),
365 .exit_latency = 10, 396 .exit_latency = 10,
366 .target_residency = 500, 397 .target_residency = 500,
367 .enter = &intel_idle }, 398 .enter = &intel_idle,
399 .enter_freeze = intel_idle_freeze, },
368 { 400 {
369 .name = "C3-IVT-8S", 401 .name = "C3-IVT-8S",
370 .desc = "MWAIT 0x10", 402 .desc = "MWAIT 0x10",
371 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, 403 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
372 .exit_latency = 59, 404 .exit_latency = 59,
373 .target_residency = 600, 405 .target_residency = 600,
374 .enter = &intel_idle }, 406 .enter = &intel_idle,
407 .enter_freeze = intel_idle_freeze, },
375 { 408 {
376 .name = "C6-IVT-8S", 409 .name = "C6-IVT-8S",
377 .desc = "MWAIT 0x20", 410 .desc = "MWAIT 0x20",
378 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, 411 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
379 .exit_latency = 88, 412 .exit_latency = 88,
380 .target_residency = 700, 413 .target_residency = 700,
381 .enter = &intel_idle }, 414 .enter = &intel_idle,
415 .enter_freeze = intel_idle_freeze, },
382 { 416 {
383 .enter = NULL } 417 .enter = NULL }
384}; 418};
@@ -390,56 +424,64 @@ static struct cpuidle_state hsw_cstates[] = {
390 .flags = MWAIT2flg(0x00), 424 .flags = MWAIT2flg(0x00),
391 .exit_latency = 2, 425 .exit_latency = 2,
392 .target_residency = 2, 426 .target_residency = 2,
393 .enter = &intel_idle }, 427 .enter = &intel_idle,
428 .enter_freeze = intel_idle_freeze, },
394 { 429 {
395 .name = "C1E-HSW", 430 .name = "C1E-HSW",
396 .desc = "MWAIT 0x01", 431 .desc = "MWAIT 0x01",
397 .flags = MWAIT2flg(0x01), 432 .flags = MWAIT2flg(0x01),
398 .exit_latency = 10, 433 .exit_latency = 10,
399 .target_residency = 20, 434 .target_residency = 20,
400 .enter = &intel_idle }, 435 .enter = &intel_idle,
436 .enter_freeze = intel_idle_freeze, },
401 { 437 {
402 .name = "C3-HSW", 438 .name = "C3-HSW",
403 .desc = "MWAIT 0x10", 439 .desc = "MWAIT 0x10",
404 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, 440 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
405 .exit_latency = 33, 441 .exit_latency = 33,
406 .target_residency = 100, 442 .target_residency = 100,
407 .enter = &intel_idle }, 443 .enter = &intel_idle,
444 .enter_freeze = intel_idle_freeze, },
408 { 445 {
409 .name = "C6-HSW", 446 .name = "C6-HSW",
410 .desc = "MWAIT 0x20", 447 .desc = "MWAIT 0x20",
411 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, 448 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
412 .exit_latency = 133, 449 .exit_latency = 133,
413 .target_residency = 400, 450 .target_residency = 400,
414 .enter = &intel_idle }, 451 .enter = &intel_idle,
452 .enter_freeze = intel_idle_freeze, },
415 { 453 {
416 .name = "C7s-HSW", 454 .name = "C7s-HSW",
417 .desc = "MWAIT 0x32", 455 .desc = "MWAIT 0x32",
418 .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TLB_FLUSHED, 456 .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TLB_FLUSHED,
419 .exit_latency = 166, 457 .exit_latency = 166,
420 .target_residency = 500, 458 .target_residency = 500,
421 .enter = &intel_idle }, 459 .enter = &intel_idle,
460 .enter_freeze = intel_idle_freeze, },
422 { 461 {
423 .name = "C8-HSW", 462 .name = "C8-HSW",
424 .desc = "MWAIT 0x40", 463 .desc = "MWAIT 0x40",
425 .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED, 464 .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED,
426 .exit_latency = 300, 465 .exit_latency = 300,
427 .target_residency = 900, 466 .target_residency = 900,
428 .enter = &intel_idle }, 467 .enter = &intel_idle,
468 .enter_freeze = intel_idle_freeze, },
429 { 469 {
430 .name = "C9-HSW", 470 .name = "C9-HSW",
431 .desc = "MWAIT 0x50", 471 .desc = "MWAIT 0x50",
432 .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED, 472 .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED,
433 .exit_latency = 600, 473 .exit_latency = 600,
434 .target_residency = 1800, 474 .target_residency = 1800,
435 .enter = &intel_idle }, 475 .enter = &intel_idle,
476 .enter_freeze = intel_idle_freeze, },
436 { 477 {
437 .name = "C10-HSW", 478 .name = "C10-HSW",
438 .desc = "MWAIT 0x60", 479 .desc = "MWAIT 0x60",
439 .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, 480 .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
440 .exit_latency = 2600, 481 .exit_latency = 2600,
441 .target_residency = 7700, 482 .target_residency = 7700,
442 .enter = &intel_idle }, 483 .enter = &intel_idle,
484 .enter_freeze = intel_idle_freeze, },
443 { 485 {
444 .enter = NULL } 486 .enter = NULL }
445}; 487};
@@ -450,56 +492,64 @@ static struct cpuidle_state bdw_cstates[] = {
450 .flags = MWAIT2flg(0x00), 492 .flags = MWAIT2flg(0x00),
451 .exit_latency = 2, 493 .exit_latency = 2,
452 .target_residency = 2, 494 .target_residency = 2,
453 .enter = &intel_idle }, 495 .enter = &intel_idle,
496 .enter_freeze = intel_idle_freeze, },
454 { 497 {
455 .name = "C1E-BDW", 498 .name = "C1E-BDW",
456 .desc = "MWAIT 0x01", 499 .desc = "MWAIT 0x01",
457 .flags = MWAIT2flg(0x01), 500 .flags = MWAIT2flg(0x01),
458 .exit_latency = 10, 501 .exit_latency = 10,
459 .target_residency = 20, 502 .target_residency = 20,
460 .enter = &intel_idle }, 503 .enter = &intel_idle,
504 .enter_freeze = intel_idle_freeze, },
461 { 505 {
462 .name = "C3-BDW", 506 .name = "C3-BDW",
463 .desc = "MWAIT 0x10", 507 .desc = "MWAIT 0x10",
464 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED, 508 .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
465 .exit_latency = 40, 509 .exit_latency = 40,
466 .target_residency = 100, 510 .target_residency = 100,
467 .enter = &intel_idle }, 511 .enter = &intel_idle,
512 .enter_freeze = intel_idle_freeze, },
468 { 513 {
469 .name = "C6-BDW", 514 .name = "C6-BDW",
470 .desc = "MWAIT 0x20", 515 .desc = "MWAIT 0x20",
471 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, 516 .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
472 .exit_latency = 133, 517 .exit_latency = 133,
473 .target_residency = 400, 518 .target_residency = 400,
474 .enter = &intel_idle }, 519 .enter = &intel_idle,
520 .enter_freeze = intel_idle_freeze, },
475 { 521 {
476 .name = "C7s-BDW", 522 .name = "C7s-BDW",
477 .desc = "MWAIT 0x32", 523 .desc = "MWAIT 0x32",
478 .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TLB_FLUSHED, 524 .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TLB_FLUSHED,
479 .exit_latency = 166, 525 .exit_latency = 166,
480 .target_residency = 500, 526 .target_residency = 500,
481 .enter = &intel_idle }, 527 .enter = &intel_idle,
528 .enter_freeze = intel_idle_freeze, },
482 { 529 {
483 .name = "C8-BDW", 530 .name = "C8-BDW",
484 .desc = "MWAIT 0x40", 531 .desc = "MWAIT 0x40",
485 .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED, 532 .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED,
486 .exit_latency = 300, 533 .exit_latency = 300,
487 .target_residency = 900, 534 .target_residency = 900,
488 .enter = &intel_idle }, 535 .enter = &intel_idle,
536 .enter_freeze = intel_idle_freeze, },
489 { 537 {
490 .name = "C9-BDW", 538 .name = "C9-BDW",
491 .desc = "MWAIT 0x50", 539 .desc = "MWAIT 0x50",
492 .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED, 540 .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED,
493 .exit_latency = 600, 541 .exit_latency = 600,
494 .target_residency = 1800, 542 .target_residency = 1800,
495 .enter = &intel_idle }, 543 .enter = &intel_idle,
544 .enter_freeze = intel_idle_freeze, },
496 { 545 {
497 .name = "C10-BDW", 546 .name = "C10-BDW",
498 .desc = "MWAIT 0x60", 547 .desc = "MWAIT 0x60",
499 .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, 548 .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
500 .exit_latency = 2600, 549 .exit_latency = 2600,
501 .target_residency = 7700, 550 .target_residency = 7700,
502 .enter = &intel_idle }, 551 .enter = &intel_idle,
552 .enter_freeze = intel_idle_freeze, },
503 { 553 {
504 .enter = NULL } 554 .enter = NULL }
505}; 555};
@@ -511,28 +561,32 @@ static struct cpuidle_state atom_cstates[] = {
511 .flags = MWAIT2flg(0x00), 561 .flags = MWAIT2flg(0x00),
512 .exit_latency = 10, 562 .exit_latency = 10,
513 .target_residency = 20, 563 .target_residency = 20,
514 .enter = &intel_idle }, 564 .enter = &intel_idle,
565 .enter_freeze = intel_idle_freeze, },
515 { 566 {
516 .name = "C2-ATM", 567 .name = "C2-ATM",
517 .desc = "MWAIT 0x10", 568 .desc = "MWAIT 0x10",
518 .flags = MWAIT2flg(0x10), 569 .flags = MWAIT2flg(0x10),
519 .exit_latency = 20, 570 .exit_latency = 20,
520 .target_residency = 80, 571 .target_residency = 80,
521 .enter = &intel_idle }, 572 .enter = &intel_idle,
573 .enter_freeze = intel_idle_freeze, },
522 { 574 {
523 .name = "C4-ATM", 575 .name = "C4-ATM",
524 .desc = "MWAIT 0x30", 576 .desc = "MWAIT 0x30",
525 .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED, 577 .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED,
526 .exit_latency = 100, 578 .exit_latency = 100,
527 .target_residency = 400, 579 .target_residency = 400,
528 .enter = &intel_idle }, 580 .enter = &intel_idle,
581 .enter_freeze = intel_idle_freeze, },
529 { 582 {
530 .name = "C6-ATM", 583 .name = "C6-ATM",
531 .desc = "MWAIT 0x52", 584 .desc = "MWAIT 0x52",
532 .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED, 585 .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED,
533 .exit_latency = 140, 586 .exit_latency = 140,
534 .target_residency = 560, 587 .target_residency = 560,
535 .enter = &intel_idle }, 588 .enter = &intel_idle,
589 .enter_freeze = intel_idle_freeze, },
536 { 590 {
537 .enter = NULL } 591 .enter = NULL }
538}; 592};
@@ -543,14 +597,16 @@ static struct cpuidle_state avn_cstates[] = {
543 .flags = MWAIT2flg(0x00), 597 .flags = MWAIT2flg(0x00),
544 .exit_latency = 2, 598 .exit_latency = 2,
545 .target_residency = 2, 599 .target_residency = 2,
546 .enter = &intel_idle }, 600 .enter = &intel_idle,
601 .enter_freeze = intel_idle_freeze, },
547 { 602 {
548 .name = "C6-AVN", 603 .name = "C6-AVN",
549 .desc = "MWAIT 0x51", 604 .desc = "MWAIT 0x51",
550 .flags = MWAIT2flg(0x51) | CPUIDLE_FLAG_TLB_FLUSHED, 605 .flags = MWAIT2flg(0x51) | CPUIDLE_FLAG_TLB_FLUSHED,
551 .exit_latency = 15, 606 .exit_latency = 15,
552 .target_residency = 45, 607 .target_residency = 45,
553 .enter = &intel_idle }, 608 .enter = &intel_idle,
609 .enter_freeze = intel_idle_freeze, },
554 { 610 {
555 .enter = NULL } 611 .enter = NULL }
556}; 612};
@@ -592,6 +648,21 @@ static int intel_idle(struct cpuidle_device *dev,
592 return index; 648 return index;
593} 649}
594 650
651/**
652 * intel_idle_freeze - simplified "enter" callback routine for suspend-to-idle
653 * @dev: cpuidle_device
654 * @drv: cpuidle driver
655 * @index: state index
656 */
657static void intel_idle_freeze(struct cpuidle_device *dev,
658 struct cpuidle_driver *drv, int index)
659{
660 unsigned long ecx = 1; /* break on interrupt flag */
661 unsigned long eax = flg2MWAIT(drv->states[index].flags);
662
663 mwait_idle_with_hints(eax, ecx);
664}
665
595static void __setup_broadcast_timer(void *arg) 666static void __setup_broadcast_timer(void *arg)
596{ 667{
597 unsigned long reason = (unsigned long)arg; 668 unsigned long reason = (unsigned long)arg;
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index ab70f3bc44ad..f551a9299ac9 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -50,6 +50,15 @@ struct cpuidle_state {
50 int index); 50 int index);
51 51
52 int (*enter_dead) (struct cpuidle_device *dev, int index); 52 int (*enter_dead) (struct cpuidle_device *dev, int index);
53
54 /*
55 * CPUs execute ->enter_freeze with the local tick or entire timekeeping
56 * suspended, so it must not re-enable interrupts at any point (even
57 * temporarily) or attempt to change states of clock event devices.
58 */
59 void (*enter_freeze) (struct cpuidle_device *dev,
60 struct cpuidle_driver *drv,
61 int index);
53}; 62};
54 63
55/* Idle State Flags */ 64/* Idle State Flags */
@@ -141,7 +150,7 @@ extern void cpuidle_resume(void);
141extern int cpuidle_enable_device(struct cpuidle_device *dev); 150extern int cpuidle_enable_device(struct cpuidle_device *dev);
142extern void cpuidle_disable_device(struct cpuidle_device *dev); 151extern void cpuidle_disable_device(struct cpuidle_device *dev);
143extern int cpuidle_play_dead(void); 152extern int cpuidle_play_dead(void);
144extern void cpuidle_use_deepest_state(bool enable); 153extern void cpuidle_enter_freeze(void);
145 154
146extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev); 155extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev);
147#else 156#else
@@ -174,7 +183,7 @@ static inline int cpuidle_enable_device(struct cpuidle_device *dev)
174{return -ENODEV; } 183{return -ENODEV; }
175static inline void cpuidle_disable_device(struct cpuidle_device *dev) { } 184static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
176static inline int cpuidle_play_dead(void) {return -ENODEV; } 185static inline int cpuidle_play_dead(void) {return -ENODEV; }
177static inline void cpuidle_use_deepest_state(bool enable) {} 186static inline void cpuidle_enter_freeze(void) { }
178static inline struct cpuidle_driver *cpuidle_get_cpu_driver( 187static inline struct cpuidle_driver *cpuidle_get_cpu_driver(
179 struct cpuidle_device *dev) {return NULL; } 188 struct cpuidle_device *dev) {return NULL; }
180#endif 189#endif
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 3388c1b6f7d8..5efe743ce1e8 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -201,6 +201,21 @@ struct platform_freeze_ops {
201 */ 201 */
202extern void suspend_set_ops(const struct platform_suspend_ops *ops); 202extern void suspend_set_ops(const struct platform_suspend_ops *ops);
203extern int suspend_valid_only_mem(suspend_state_t state); 203extern int suspend_valid_only_mem(suspend_state_t state);
204
205/* Suspend-to-idle state machnine. */
206enum freeze_state {
207 FREEZE_STATE_NONE, /* Not suspended/suspending. */
208 FREEZE_STATE_ENTER, /* Enter suspend-to-idle. */
209 FREEZE_STATE_WAKE, /* Wake up from suspend-to-idle. */
210};
211
212extern enum freeze_state __read_mostly suspend_freeze_state;
213
214static inline bool idle_should_freeze(void)
215{
216 return unlikely(suspend_freeze_state == FREEZE_STATE_ENTER);
217}
218
204extern void freeze_set_ops(const struct platform_freeze_ops *ops); 219extern void freeze_set_ops(const struct platform_freeze_ops *ops);
205extern void freeze_wake(void); 220extern void freeze_wake(void);
206 221
@@ -228,6 +243,7 @@ extern int pm_suspend(suspend_state_t state);
228 243
229static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {} 244static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {}
230static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; } 245static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; }
246static inline bool idle_should_freeze(void) { return false; }
231static inline void freeze_set_ops(const struct platform_freeze_ops *ops) {} 247static inline void freeze_set_ops(const struct platform_freeze_ops *ops) {}
232static inline void freeze_wake(void) {} 248static inline void freeze_wake(void) {}
233#endif /* !CONFIG_SUSPEND */ 249#endif /* !CONFIG_SUSPEND */
diff --git a/include/linux/tick.h b/include/linux/tick.h
index eda850ca757a..9c085dc12ae9 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -79,6 +79,9 @@ extern void __init tick_init(void);
79extern int tick_is_oneshot_available(void); 79extern int tick_is_oneshot_available(void);
80extern struct tick_device *tick_get_device(int cpu); 80extern struct tick_device *tick_get_device(int cpu);
81 81
82extern void tick_freeze(void);
83extern void tick_unfreeze(void);
84
82# ifdef CONFIG_HIGH_RES_TIMERS 85# ifdef CONFIG_HIGH_RES_TIMERS
83extern int tick_init_highres(void); 86extern int tick_init_highres(void);
84extern int tick_program_event(ktime_t expires, int force); 87extern int tick_program_event(ktime_t expires, int force);
@@ -119,6 +122,8 @@ static inline int tick_oneshot_mode_active(void) { return 0; }
119 122
120#else /* CONFIG_GENERIC_CLOCKEVENTS */ 123#else /* CONFIG_GENERIC_CLOCKEVENTS */
121static inline void tick_init(void) { } 124static inline void tick_init(void) { }
125static inline void tick_freeze(void) { }
126static inline void tick_unfreeze(void) { }
122static inline void tick_cancel_sched_timer(int cpu) { } 127static inline void tick_cancel_sched_timer(int cpu) { }
123static inline void tick_clock_notify(void) { } 128static inline void tick_clock_notify(void) { }
124static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } 129static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
@@ -226,5 +231,4 @@ static inline void tick_nohz_task_switch(struct task_struct *tsk)
226 __tick_nohz_task_switch(tsk); 231 __tick_nohz_task_switch(tsk);
227} 232}
228 233
229
230#endif 234#endif
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index c347e3ce3a55..b7d6b3a721b1 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -37,7 +37,9 @@ const char *pm_states[PM_SUSPEND_MAX];
37static const struct platform_suspend_ops *suspend_ops; 37static const struct platform_suspend_ops *suspend_ops;
38static const struct platform_freeze_ops *freeze_ops; 38static const struct platform_freeze_ops *freeze_ops;
39static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head); 39static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head);
40static bool suspend_freeze_wake; 40
41enum freeze_state __read_mostly suspend_freeze_state;
42static DEFINE_SPINLOCK(suspend_freeze_lock);
41 43
42void freeze_set_ops(const struct platform_freeze_ops *ops) 44void freeze_set_ops(const struct platform_freeze_ops *ops)
43{ 45{
@@ -48,22 +50,49 @@ void freeze_set_ops(const struct platform_freeze_ops *ops)
48 50
49static void freeze_begin(void) 51static void freeze_begin(void)
50{ 52{
51 suspend_freeze_wake = false; 53 suspend_freeze_state = FREEZE_STATE_NONE;
52} 54}
53 55
54static void freeze_enter(void) 56static void freeze_enter(void)
55{ 57{
56 cpuidle_use_deepest_state(true); 58 spin_lock_irq(&suspend_freeze_lock);
59 if (pm_wakeup_pending())
60 goto out;
61
62 suspend_freeze_state = FREEZE_STATE_ENTER;
63 spin_unlock_irq(&suspend_freeze_lock);
64
65 get_online_cpus();
57 cpuidle_resume(); 66 cpuidle_resume();
58 wait_event(suspend_freeze_wait_head, suspend_freeze_wake); 67
68 /* Push all the CPUs into the idle loop. */
69 wake_up_all_idle_cpus();
70 pr_debug("PM: suspend-to-idle\n");
71 /* Make the current CPU wait so it can enter the idle loop too. */
72 wait_event(suspend_freeze_wait_head,
73 suspend_freeze_state == FREEZE_STATE_WAKE);
74 pr_debug("PM: resume from suspend-to-idle\n");
75
59 cpuidle_pause(); 76 cpuidle_pause();
60 cpuidle_use_deepest_state(false); 77 put_online_cpus();
78
79 spin_lock_irq(&suspend_freeze_lock);
80
81 out:
82 suspend_freeze_state = FREEZE_STATE_NONE;
83 spin_unlock_irq(&suspend_freeze_lock);
61} 84}
62 85
63void freeze_wake(void) 86void freeze_wake(void)
64{ 87{
65 suspend_freeze_wake = true; 88 unsigned long flags;
66 wake_up(&suspend_freeze_wait_head); 89
90 spin_lock_irqsave(&suspend_freeze_lock, flags);
91 if (suspend_freeze_state > FREEZE_STATE_NONE) {
92 suspend_freeze_state = FREEZE_STATE_WAKE;
93 wake_up(&suspend_freeze_wait_head);
94 }
95 spin_unlock_irqrestore(&suspend_freeze_lock, flags);
67} 96}
68EXPORT_SYMBOL_GPL(freeze_wake); 97EXPORT_SYMBOL_GPL(freeze_wake);
69 98
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index aaf1c1d5cf5d..94b2d7b88a27 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -7,6 +7,7 @@
7#include <linux/tick.h> 7#include <linux/tick.h>
8#include <linux/mm.h> 8#include <linux/mm.h>
9#include <linux/stackprotector.h> 9#include <linux/stackprotector.h>
10#include <linux/suspend.h>
10 11
11#include <asm/tlb.h> 12#include <asm/tlb.h>
12 13
@@ -105,6 +106,21 @@ static void cpuidle_idle_call(void)
105 rcu_idle_enter(); 106 rcu_idle_enter();
106 107
107 /* 108 /*
109 * Suspend-to-idle ("freeze") is a system state in which all user space
110 * has been frozen, all I/O devices have been suspended and the only
111 * activity happens here and in iterrupts (if any). In that case bypass
112 * the cpuidle governor and go stratight for the deepest idle state
113 * available. Possibly also suspend the local tick and the entire
114 * timekeeping to prevent timer interrupts from kicking us out of idle
115 * until a proper wakeup interrupt happens.
116 */
117 if (idle_should_freeze()) {
118 cpuidle_enter_freeze();
119 local_irq_enable();
120 goto exit_idle;
121 }
122
123 /*
108 * Ask the cpuidle framework to choose a convenient idle state. 124 * Ask the cpuidle framework to choose a convenient idle state.
109 * Fall back to the default arch idle method on errors. 125 * Fall back to the default arch idle method on errors.
110 */ 126 */
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index 7efeedf53ebd..f7c515595b42 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -394,6 +394,56 @@ void tick_resume(void)
394 } 394 }
395} 395}
396 396
397static DEFINE_RAW_SPINLOCK(tick_freeze_lock);
398static unsigned int tick_freeze_depth;
399
400/**
401 * tick_freeze - Suspend the local tick and (possibly) timekeeping.
402 *
403 * Check if this is the last online CPU executing the function and if so,
404 * suspend timekeeping. Otherwise suspend the local tick.
405 *
406 * Call with interrupts disabled. Must be balanced with %tick_unfreeze().
407 * Interrupts must not be enabled before the subsequent %tick_unfreeze().
408 */
409void tick_freeze(void)
410{
411 raw_spin_lock(&tick_freeze_lock);
412
413 tick_freeze_depth++;
414 if (tick_freeze_depth == num_online_cpus()) {
415 timekeeping_suspend();
416 } else {
417 tick_suspend();
418 tick_suspend_broadcast();
419 }
420
421 raw_spin_unlock(&tick_freeze_lock);
422}
423
424/**
425 * tick_unfreeze - Resume the local tick and (possibly) timekeeping.
426 *
427 * Check if this is the first CPU executing the function and if so, resume
428 * timekeeping. Otherwise resume the local tick.
429 *
430 * Call with interrupts disabled. Must be balanced with %tick_freeze().
431 * Interrupts must not be enabled after the preceding %tick_freeze().
432 */
433void tick_unfreeze(void)
434{
435 raw_spin_lock(&tick_freeze_lock);
436
437 if (tick_freeze_depth == num_online_cpus())
438 timekeeping_resume();
439 else
440 tick_resume();
441
442 tick_freeze_depth--;
443
444 raw_spin_unlock(&tick_freeze_lock);
445}
446
397/** 447/**
398 * tick_init - initialize the tick control 448 * tick_init - initialize the tick control
399 */ 449 */
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index b124af259800..91db94136c10 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -230,9 +230,7 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
230 230
231/** 231/**
232 * update_fast_timekeeper - Update the fast and NMI safe monotonic timekeeper. 232 * update_fast_timekeeper - Update the fast and NMI safe monotonic timekeeper.
233 * @tk: The timekeeper from which we take the update 233 * @tkr: Timekeeping readout base from which we take the update
234 * @tkf: The fast timekeeper to update
235 * @tbase: The time base for the fast timekeeper (mono/raw)
236 * 234 *
237 * We want to use this from any context including NMI and tracing / 235 * We want to use this from any context including NMI and tracing /
238 * instrumenting the timekeeping code itself. 236 * instrumenting the timekeeping code itself.
@@ -244,11 +242,11 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
244 * smp_wmb(); <- Ensure that the last base[1] update is visible 242 * smp_wmb(); <- Ensure that the last base[1] update is visible
245 * tkf->seq++; 243 * tkf->seq++;
246 * smp_wmb(); <- Ensure that the seqcount update is visible 244 * smp_wmb(); <- Ensure that the seqcount update is visible
247 * update(tkf->base[0], tk); 245 * update(tkf->base[0], tkr);
248 * smp_wmb(); <- Ensure that the base[0] update is visible 246 * smp_wmb(); <- Ensure that the base[0] update is visible
249 * tkf->seq++; 247 * tkf->seq++;
250 * smp_wmb(); <- Ensure that the seqcount update is visible 248 * smp_wmb(); <- Ensure that the seqcount update is visible
251 * update(tkf->base[1], tk); 249 * update(tkf->base[1], tkr);
252 * 250 *
253 * The reader side does: 251 * The reader side does:
254 * 252 *
@@ -269,7 +267,7 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
269 * slightly wrong timestamp (a few nanoseconds). See 267 * slightly wrong timestamp (a few nanoseconds). See
270 * @ktime_get_mono_fast_ns. 268 * @ktime_get_mono_fast_ns.
271 */ 269 */
272static void update_fast_timekeeper(struct timekeeper *tk) 270static void update_fast_timekeeper(struct tk_read_base *tkr)
273{ 271{
274 struct tk_read_base *base = tk_fast_mono.base; 272 struct tk_read_base *base = tk_fast_mono.base;
275 273
@@ -277,7 +275,7 @@ static void update_fast_timekeeper(struct timekeeper *tk)
277 raw_write_seqcount_latch(&tk_fast_mono.seq); 275 raw_write_seqcount_latch(&tk_fast_mono.seq);
278 276
279 /* Update base[0] */ 277 /* Update base[0] */
280 memcpy(base, &tk->tkr, sizeof(*base)); 278 memcpy(base, tkr, sizeof(*base));
281 279
282 /* Force readers back to base[0] */ 280 /* Force readers back to base[0] */
283 raw_write_seqcount_latch(&tk_fast_mono.seq); 281 raw_write_seqcount_latch(&tk_fast_mono.seq);
@@ -334,6 +332,35 @@ u64 notrace ktime_get_mono_fast_ns(void)
334} 332}
335EXPORT_SYMBOL_GPL(ktime_get_mono_fast_ns); 333EXPORT_SYMBOL_GPL(ktime_get_mono_fast_ns);
336 334
335/* Suspend-time cycles value for halted fast timekeeper. */
336static cycle_t cycles_at_suspend;
337
338static cycle_t dummy_clock_read(struct clocksource *cs)
339{
340 return cycles_at_suspend;
341}
342
343/**
344 * halt_fast_timekeeper - Prevent fast timekeeper from accessing clocksource.
345 * @tk: Timekeeper to snapshot.
346 *
347 * It generally is unsafe to access the clocksource after timekeeping has been
348 * suspended, so take a snapshot of the readout base of @tk and use it as the
349 * fast timekeeper's readout base while suspended. It will return the same
350 * number of cycles every time until timekeeping is resumed at which time the
351 * proper readout base for the fast timekeeper will be restored automatically.
352 */
353static void halt_fast_timekeeper(struct timekeeper *tk)
354{
355 static struct tk_read_base tkr_dummy;
356 struct tk_read_base *tkr = &tk->tkr;
357
358 memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy));
359 cycles_at_suspend = tkr->read(tkr->clock);
360 tkr_dummy.read = dummy_clock_read;
361 update_fast_timekeeper(&tkr_dummy);
362}
363
337#ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD 364#ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD
338 365
339static inline void update_vsyscall(struct timekeeper *tk) 366static inline void update_vsyscall(struct timekeeper *tk)
@@ -462,7 +489,7 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action)
462 memcpy(&shadow_timekeeper, &tk_core.timekeeper, 489 memcpy(&shadow_timekeeper, &tk_core.timekeeper,
463 sizeof(tk_core.timekeeper)); 490 sizeof(tk_core.timekeeper));
464 491
465 update_fast_timekeeper(tk); 492 update_fast_timekeeper(&tk->tkr);
466} 493}
467 494
468/** 495/**
@@ -1170,7 +1197,7 @@ void timekeeping_inject_sleeptime64(struct timespec64 *delta)
1170 * xtime/wall_to_monotonic/jiffies/etc are 1197 * xtime/wall_to_monotonic/jiffies/etc are
1171 * still managed by arch specific suspend/resume code. 1198 * still managed by arch specific suspend/resume code.
1172 */ 1199 */
1173static void timekeeping_resume(void) 1200void timekeeping_resume(void)
1174{ 1201{
1175 struct timekeeper *tk = &tk_core.timekeeper; 1202 struct timekeeper *tk = &tk_core.timekeeper;
1176 struct clocksource *clock = tk->tkr.clock; 1203 struct clocksource *clock = tk->tkr.clock;
@@ -1251,7 +1278,7 @@ static void timekeeping_resume(void)
1251 hrtimers_resume(); 1278 hrtimers_resume();
1252} 1279}
1253 1280
1254static int timekeeping_suspend(void) 1281int timekeeping_suspend(void)
1255{ 1282{
1256 struct timekeeper *tk = &tk_core.timekeeper; 1283 struct timekeeper *tk = &tk_core.timekeeper;
1257 unsigned long flags; 1284 unsigned long flags;
@@ -1296,6 +1323,7 @@ static int timekeeping_suspend(void)
1296 } 1323 }
1297 1324
1298 timekeeping_update(tk, TK_MIRROR); 1325 timekeeping_update(tk, TK_MIRROR);
1326 halt_fast_timekeeper(tk);
1299 write_seqcount_end(&tk_core.seq); 1327 write_seqcount_end(&tk_core.seq);
1300 raw_spin_unlock_irqrestore(&timekeeper_lock, flags); 1328 raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
1301 1329
diff --git a/kernel/time/timekeeping.h b/kernel/time/timekeeping.h
index adc1fc98bde3..1d91416055d5 100644
--- a/kernel/time/timekeeping.h
+++ b/kernel/time/timekeeping.h
@@ -16,5 +16,7 @@ extern int timekeeping_inject_offset(struct timespec *ts);
16extern s32 timekeeping_get_tai_offset(void); 16extern s32 timekeeping_get_tai_offset(void);
17extern void timekeeping_set_tai_offset(s32 tai_offset); 17extern void timekeeping_set_tai_offset(s32 tai_offset);
18extern void timekeeping_clocktai(struct timespec *ts); 18extern void timekeeping_clocktai(struct timespec *ts);
19extern int timekeeping_suspend(void);
20extern void timekeeping_resume(void);
19 21
20#endif 22#endif