.. | .. |
---|
155 | 155 | { |
---|
156 | 156 | int i; |
---|
157 | 157 | |
---|
158 | | - drv->refcnt = 0; |
---|
159 | | - |
---|
160 | 158 | /* |
---|
161 | 159 | * Use all possible CPUs as the default, because if the kernel boots |
---|
162 | 160 | * with some CPUs offline and then we online one of them, the CPU |
---|
.. | .. |
---|
165 | 163 | if (!drv->cpumask) |
---|
166 | 164 | drv->cpumask = (struct cpumask *)cpu_possible_mask; |
---|
167 | 165 | |
---|
168 | | - /* |
---|
169 | | - * Look for the timer stop flag in the different states, so that we know |
---|
170 | | - * if the broadcast timer has to be set up. The loop is in the reverse |
---|
171 | | - * order, because usually one of the deeper states have this flag set. |
---|
172 | | - */ |
---|
173 | | - for (i = drv->state_count - 1; i >= 0 ; i--) { |
---|
174 | | - if (drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP) { |
---|
| 166 | + for (i = 0; i < drv->state_count; i++) { |
---|
| 167 | + struct cpuidle_state *s = &drv->states[i]; |
---|
| 168 | + |
---|
| 169 | + /* |
---|
| 170 | + * Look for the timer stop flag in the different states and if |
---|
| 171 | + * it is found, indicate that the broadcast timer has to be set |
---|
| 172 | + * up. |
---|
| 173 | + */ |
---|
| 174 | + if (s->flags & CPUIDLE_FLAG_TIMER_STOP) |
---|
175 | 175 | drv->bctimer = 1; |
---|
176 | | - break; |
---|
177 | | - } |
---|
| 176 | + |
---|
| 177 | + /* |
---|
| 178 | + * The core will use the target residency and exit latency |
---|
| 179 | + * values in nanoseconds, but allow drivers to provide them in |
---|
| 180 | + * microseconds too. |
---|
| 181 | + */ |
---|
| 182 | + if (s->target_residency > 0) |
---|
| 183 | + s->target_residency_ns = s->target_residency * NSEC_PER_USEC; |
---|
| 184 | + |
---|
| 185 | + if (s->exit_latency > 0) |
---|
| 186 | + s->exit_latency_ns = s->exit_latency * NSEC_PER_USEC; |
---|
178 | 187 | } |
---|
179 | 188 | } |
---|
180 | 189 | |
---|
.. | .. |
---|
229 | 238 | */ |
---|
230 | 239 | static void __cpuidle_unregister_driver(struct cpuidle_driver *drv) |
---|
231 | 240 | { |
---|
232 | | - if (WARN_ON(drv->refcnt > 0)) |
---|
233 | | - return; |
---|
234 | | - |
---|
235 | 241 | if (drv->bctimer) { |
---|
236 | 242 | drv->bctimer = 0; |
---|
237 | 243 | on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer, |
---|
.. | .. |
---|
253 | 259 | */ |
---|
254 | 260 | int cpuidle_register_driver(struct cpuidle_driver *drv) |
---|
255 | 261 | { |
---|
| 262 | + struct cpuidle_governor *gov; |
---|
256 | 263 | int ret; |
---|
257 | 264 | |
---|
258 | 265 | spin_lock(&cpuidle_driver_lock); |
---|
259 | 266 | ret = __cpuidle_register_driver(drv); |
---|
260 | 267 | spin_unlock(&cpuidle_driver_lock); |
---|
| 268 | + |
---|
| 269 | + if (!ret && !strlen(param_governor) && drv->governor && |
---|
| 270 | + (cpuidle_get_driver() == drv)) { |
---|
| 271 | + mutex_lock(&cpuidle_lock); |
---|
| 272 | + gov = cpuidle_find_governor(drv->governor); |
---|
| 273 | + if (gov) { |
---|
| 274 | + cpuidle_prev_governor = cpuidle_curr_governor; |
---|
| 275 | + if (cpuidle_switch_governor(gov) < 0) |
---|
| 276 | + cpuidle_prev_governor = NULL; |
---|
| 277 | + } |
---|
| 278 | + mutex_unlock(&cpuidle_lock); |
---|
| 279 | + } |
---|
261 | 280 | |
---|
262 | 281 | return ret; |
---|
263 | 282 | } |
---|
.. | .. |
---|
273 | 292 | */ |
---|
274 | 293 | void cpuidle_unregister_driver(struct cpuidle_driver *drv) |
---|
275 | 294 | { |
---|
| 295 | + bool enabled = (cpuidle_get_driver() == drv); |
---|
| 296 | + |
---|
276 | 297 | spin_lock(&cpuidle_driver_lock); |
---|
277 | 298 | __cpuidle_unregister_driver(drv); |
---|
278 | 299 | spin_unlock(&cpuidle_driver_lock); |
---|
| 300 | + |
---|
| 301 | + if (!enabled) |
---|
| 302 | + return; |
---|
| 303 | + |
---|
| 304 | + mutex_lock(&cpuidle_lock); |
---|
| 305 | + if (cpuidle_prev_governor) { |
---|
| 306 | + if (!cpuidle_switch_governor(cpuidle_prev_governor)) |
---|
| 307 | + cpuidle_prev_governor = NULL; |
---|
| 308 | + } |
---|
| 309 | + mutex_unlock(&cpuidle_lock); |
---|
279 | 310 | } |
---|
280 | 311 | EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); |
---|
281 | 312 | |
---|
.. | .. |
---|
314 | 345 | EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver); |
---|
315 | 346 | |
---|
316 | 347 | /** |
---|
317 | | - * cpuidle_driver_ref - get a reference to the driver. |
---|
318 | | - * |
---|
319 | | - * Increment the reference counter of the cpuidle driver associated with |
---|
320 | | - * the current CPU. |
---|
321 | | - * |
---|
322 | | - * Returns a pointer to the driver, or NULL if the current CPU has no driver. |
---|
| 348 | + * cpuidle_driver_state_disabled - Disable or enable an idle state |
---|
| 349 | + * @drv: cpuidle driver owning the state |
---|
| 350 | + * @idx: State index |
---|
| 351 | + * @disable: Whether or not to disable the state |
---|
323 | 352 | */ |
---|
324 | | -struct cpuidle_driver *cpuidle_driver_ref(void) |
---|
| 353 | +void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx, |
---|
| 354 | + bool disable) |
---|
325 | 355 | { |
---|
326 | | - struct cpuidle_driver *drv; |
---|
| 356 | + unsigned int cpu; |
---|
| 357 | + |
---|
| 358 | + mutex_lock(&cpuidle_lock); |
---|
327 | 359 | |
---|
328 | 360 | spin_lock(&cpuidle_driver_lock); |
---|
329 | 361 | |
---|
330 | | - drv = cpuidle_get_driver(); |
---|
331 | | - if (drv) |
---|
332 | | - drv->refcnt++; |
---|
| 362 | + if (!drv->cpumask) { |
---|
| 363 | + drv->states[idx].flags |= CPUIDLE_FLAG_UNUSABLE; |
---|
| 364 | + goto unlock; |
---|
| 365 | + } |
---|
333 | 366 | |
---|
| 367 | + for_each_cpu(cpu, drv->cpumask) { |
---|
| 368 | + struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); |
---|
| 369 | + |
---|
| 370 | + if (!dev) |
---|
| 371 | + continue; |
---|
| 372 | + |
---|
| 373 | + if (disable) |
---|
| 374 | + dev->states_usage[idx].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER; |
---|
| 375 | + else |
---|
| 376 | + dev->states_usage[idx].disable &= ~CPUIDLE_STATE_DISABLED_BY_DRIVER; |
---|
| 377 | + } |
---|
| 378 | + |
---|
| 379 | +unlock: |
---|
334 | 380 | spin_unlock(&cpuidle_driver_lock); |
---|
335 | | - return drv; |
---|
| 381 | + |
---|
| 382 | + mutex_unlock(&cpuidle_lock); |
---|
336 | 383 | } |
---|
337 | | - |
---|
338 | | -/** |
---|
339 | | - * cpuidle_driver_unref - puts down the refcount for the driver |
---|
340 | | - * |
---|
341 | | - * Decrement the reference counter of the cpuidle driver associated with |
---|
342 | | - * the current CPU. |
---|
343 | | - */ |
---|
344 | | -void cpuidle_driver_unref(void) |
---|
345 | | -{ |
---|
346 | | - struct cpuidle_driver *drv; |
---|
347 | | - |
---|
348 | | - spin_lock(&cpuidle_driver_lock); |
---|
349 | | - |
---|
350 | | - drv = cpuidle_get_driver(); |
---|
351 | | - if (drv && !WARN_ON(drv->refcnt <= 0)) |
---|
352 | | - drv->refcnt--; |
---|
353 | | - |
---|
354 | | - spin_unlock(&cpuidle_driver_lock); |
---|
355 | | -} |
---|
| 384 | +EXPORT_SYMBOL_GPL(cpuidle_driver_state_disabled); |
---|