diff options
| -rw-r--r-- | drivers/cpuidle/cpuidle.c | 49 | ||||
| -rw-r--r-- | include/linux/cpuidle.h | 2 | ||||
| -rw-r--r-- | kernel/sched/idle.c | 56 |
3 files changed, 56 insertions, 51 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 1506d69b3f0f..166a7322a2b6 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c | |||
| @@ -173,55 +173,6 @@ void cpuidle_reflect(struct cpuidle_device *dev, int index) | |||
| 173 | } | 173 | } |
| 174 | 174 | ||
| 175 | /** | 175 | /** |
| 176 | * cpuidle_idle_call - the main idle loop | ||
| 177 | * | ||
| 178 | * NOTE: no locks or semaphores should be used here | ||
| 179 | * return non-zero on failure | ||
| 180 | */ | ||
| 181 | int cpuidle_idle_call(void) | ||
| 182 | { | ||
| 183 | struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); | ||
| 184 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); | ||
| 185 | int next_state, entered_state, ret; | ||
| 186 | bool broadcast; | ||
| 187 | |||
| 188 | ret = cpuidle_enabled(drv, dev); | ||
| 189 | if (ret < 0) | ||
| 190 | return ret; | ||
| 191 | |||
| 192 | /* ask the governor for the next state */ | ||
| 193 | next_state = cpuidle_select(drv, dev); | ||
| 194 | |||
| 195 | if (need_resched()) { | ||
| 196 | dev->last_residency = 0; | ||
| 197 | /* give the governor an opportunity to reflect on the outcome */ | ||
| 198 | cpuidle_reflect(dev, next_state); | ||
| 199 | local_irq_enable(); | ||
| 200 | return 0; | ||
| 201 | } | ||
| 202 | |||
| 203 | broadcast = !!(drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP); | ||
| 204 | |||
| 205 | if (broadcast && | ||
| 206 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu)) | ||
| 207 | return -EBUSY; | ||
| 208 | |||
| 209 | trace_cpu_idle_rcuidle(next_state, dev->cpu); | ||
| 210 | |||
| 211 | entered_state = cpuidle_enter(drv, dev, next_state); | ||
| 212 | |||
| 213 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); | ||
| 214 | |||
| 215 | if (broadcast) | ||
| 216 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); | ||
| 217 | |||
| 218 | /* give the governor an opportunity to reflect on the outcome */ | ||
| 219 | cpuidle_reflect(dev, entered_state); | ||
| 220 | |||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | /** | ||
| 225 | * cpuidle_install_idle_handler - installs the cpuidle idle loop handler | 176 | * cpuidle_install_idle_handler - installs the cpuidle idle loop handler |
| 226 | */ | 177 | */ |
| 227 | void cpuidle_install_idle_handler(void) | 178 | void cpuidle_install_idle_handler(void) |
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index accc2dd72049..8d97962d6d64 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h | |||
| @@ -128,7 +128,6 @@ extern int cpuidle_enter(struct cpuidle_driver *drv, | |||
| 128 | struct cpuidle_device *dev, int index); | 128 | struct cpuidle_device *dev, int index); |
| 129 | extern void cpuidle_reflect(struct cpuidle_device *dev, int index); | 129 | extern void cpuidle_reflect(struct cpuidle_device *dev, int index); |
| 130 | 130 | ||
| 131 | extern int cpuidle_idle_call(void); | ||
| 132 | extern int cpuidle_register_driver(struct cpuidle_driver *drv); | 131 | extern int cpuidle_register_driver(struct cpuidle_driver *drv); |
| 133 | extern struct cpuidle_driver *cpuidle_get_driver(void); | 132 | extern struct cpuidle_driver *cpuidle_get_driver(void); |
| 134 | extern struct cpuidle_driver *cpuidle_driver_ref(void); | 133 | extern struct cpuidle_driver *cpuidle_driver_ref(void); |
| @@ -160,7 +159,6 @@ static inline int cpuidle_enter(struct cpuidle_driver *drv, | |||
| 160 | struct cpuidle_device *dev, int index) | 159 | struct cpuidle_device *dev, int index) |
| 161 | {return -ENODEV; } | 160 | {return -ENODEV; } |
| 162 | static inline void cpuidle_reflect(struct cpuidle_device *dev, int index) { } | 161 | static inline void cpuidle_reflect(struct cpuidle_device *dev, int index) { } |
| 163 | static inline int cpuidle_idle_call(void) { return -ENODEV; } | ||
| 164 | static inline int cpuidle_register_driver(struct cpuidle_driver *drv) | 162 | static inline int cpuidle_register_driver(struct cpuidle_driver *drv) |
| 165 | {return -ENODEV; } | 163 | {return -ENODEV; } |
| 166 | static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; } | 164 | static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; } |
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index b7976a127178..d5aaf5eb4531 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c | |||
| @@ -63,6 +63,62 @@ void __weak arch_cpu_idle(void) | |||
| 63 | local_irq_enable(); | 63 | local_irq_enable(); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | #ifdef CONFIG_CPU_IDLE | ||
| 67 | /** | ||
| 68 | * cpuidle_idle_call - the main idle function | ||
| 69 | * | ||
| 70 | * NOTE: no locks or semaphores should be used here | ||
| 71 | * return non-zero on failure | ||
| 72 | */ | ||
| 73 | static int cpuidle_idle_call(void) | ||
| 74 | { | ||
| 75 | struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); | ||
| 76 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); | ||
| 77 | int next_state, entered_state, ret; | ||
| 78 | bool broadcast; | ||
| 79 | |||
| 80 | ret = cpuidle_enabled(drv, dev); | ||
| 81 | if (ret < 0) | ||
| 82 | return ret; | ||
| 83 | |||
| 84 | /* ask the governor for the next state */ | ||
| 85 | next_state = cpuidle_select(drv, dev); | ||
| 86 | |||
| 87 | if (need_resched()) { | ||
| 88 | dev->last_residency = 0; | ||
| 89 | /* give the governor an opportunity to reflect on the outcome */ | ||
| 90 | cpuidle_reflect(dev, next_state); | ||
| 91 | local_irq_enable(); | ||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | broadcast = !!(drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP); | ||
| 96 | |||
| 97 | if (broadcast && | ||
| 98 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu)) | ||
| 99 | return -EBUSY; | ||
| 100 | |||
| 101 | trace_cpu_idle_rcuidle(next_state, dev->cpu); | ||
| 102 | |||
| 103 | entered_state = cpuidle_enter(drv, dev, next_state); | ||
| 104 | |||
| 105 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); | ||
| 106 | |||
| 107 | if (broadcast) | ||
| 108 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); | ||
| 109 | |||
| 110 | /* give the governor an opportunity to reflect on the outcome */ | ||
| 111 | cpuidle_reflect(dev, entered_state); | ||
| 112 | |||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | #else | ||
| 116 | static inline int cpuidle_idle_call(void) | ||
| 117 | { | ||
| 118 | return -ENODEV; | ||
| 119 | } | ||
| 120 | #endif | ||
| 121 | |||
| 66 | /* | 122 | /* |
| 67 | * Generic idle loop implementation | 123 | * Generic idle loop implementation |
| 68 | */ | 124 | */ |
