diff options
Diffstat (limited to 'kernel/sched/idle.c')
-rw-r--r-- | kernel/sched/idle.c | 54 |
1 files changed, 33 insertions, 21 deletions
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 94b2d7b88a27..80014a178342 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c | |||
@@ -82,6 +82,7 @@ static void cpuidle_idle_call(void) | |||
82 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); | 82 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); |
83 | int next_state, entered_state; | 83 | int next_state, entered_state; |
84 | unsigned int broadcast; | 84 | unsigned int broadcast; |
85 | bool reflect; | ||
85 | 86 | ||
86 | /* | 87 | /* |
87 | * Check if the idle task must be rescheduled. If it is the | 88 | * Check if the idle task must be rescheduled. If it is the |
@@ -105,6 +106,9 @@ static void cpuidle_idle_call(void) | |||
105 | */ | 106 | */ |
106 | rcu_idle_enter(); | 107 | rcu_idle_enter(); |
107 | 108 | ||
109 | if (cpuidle_not_available(drv, dev)) | ||
110 | goto use_default; | ||
111 | |||
108 | /* | 112 | /* |
109 | * Suspend-to-idle ("freeze") is a system state in which all user space | 113 | * 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 | 114 | * has been frozen, all I/O devices have been suspended and the only |
@@ -115,30 +119,24 @@ static void cpuidle_idle_call(void) | |||
115 | * until a proper wakeup interrupt happens. | 119 | * until a proper wakeup interrupt happens. |
116 | */ | 120 | */ |
117 | if (idle_should_freeze()) { | 121 | if (idle_should_freeze()) { |
118 | cpuidle_enter_freeze(); | 122 | entered_state = cpuidle_enter_freeze(drv, dev); |
119 | local_irq_enable(); | 123 | if (entered_state >= 0) { |
120 | goto exit_idle; | 124 | local_irq_enable(); |
121 | } | 125 | goto exit_idle; |
126 | } | ||
122 | 127 | ||
123 | /* | 128 | reflect = false; |
124 | * Ask the cpuidle framework to choose a convenient idle state. | 129 | next_state = cpuidle_find_deepest_state(drv, dev); |
125 | * Fall back to the default arch idle method on errors. | 130 | } else { |
126 | */ | 131 | reflect = true; |
127 | next_state = cpuidle_select(drv, dev); | ||
128 | if (next_state < 0) { | ||
129 | use_default: | ||
130 | /* | 132 | /* |
131 | * We can't use the cpuidle framework, let's use the default | 133 | * Ask the cpuidle framework to choose a convenient idle state. |
132 | * idle routine. | ||
133 | */ | 134 | */ |
134 | if (current_clr_polling_and_test()) | 135 | next_state = cpuidle_select(drv, dev); |
135 | local_irq_enable(); | ||
136 | else | ||
137 | arch_cpu_idle(); | ||
138 | |||
139 | goto exit_idle; | ||
140 | } | 136 | } |
141 | 137 | /* Fall back to the default arch idle method on errors. */ | |
138 | if (next_state < 0) | ||
139 | goto use_default; | ||
142 | 140 | ||
143 | /* | 141 | /* |
144 | * The idle task must be scheduled, it is pointless to | 142 | * The idle task must be scheduled, it is pointless to |
@@ -183,7 +181,8 @@ use_default: | |||
183 | /* | 181 | /* |
184 | * Give the governor an opportunity to reflect on the outcome | 182 | * Give the governor an opportunity to reflect on the outcome |
185 | */ | 183 | */ |
186 | cpuidle_reflect(dev, entered_state); | 184 | if (reflect) |
185 | cpuidle_reflect(dev, entered_state); | ||
187 | 186 | ||
188 | exit_idle: | 187 | exit_idle: |
189 | __current_set_polling(); | 188 | __current_set_polling(); |
@@ -196,6 +195,19 @@ exit_idle: | |||
196 | 195 | ||
197 | rcu_idle_exit(); | 196 | rcu_idle_exit(); |
198 | start_critical_timings(); | 197 | start_critical_timings(); |
198 | return; | ||
199 | |||
200 | use_default: | ||
201 | /* | ||
202 | * We can't use the cpuidle framework, let's use the default | ||
203 | * idle routine. | ||
204 | */ | ||
205 | if (current_clr_polling_and_test()) | ||
206 | local_irq_enable(); | ||
207 | else | ||
208 | arch_cpu_idle(); | ||
209 | |||
210 | goto exit_idle; | ||
199 | } | 211 | } |
200 | 212 | ||
201 | /* | 213 | /* |