aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/time.c124
1 files changed, 123 insertions, 1 deletions
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
index c55d6f217a46..1b91c7214979 100644
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time.c
@@ -174,6 +174,108 @@ static struct sysdev_class timer_sysclass = {
174 .resume = timer_resume, 174 .resume = timer_resume,
175}; 175};
176 176
177#ifdef CONFIG_NO_IDLE_HZ
178static int timer_dyn_tick_enable(void)
179{
180 struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
181 unsigned long flags;
182 int ret = -ENODEV;
183
184 if (dyn_tick) {
185 spin_lock_irqsave(&dyn_tick->lock, flags);
186 ret = 0;
187 if (!(dyn_tick->state & DYN_TICK_ENABLED)) {
188 ret = dyn_tick->enable();
189
190 if (ret == 0)
191 dyn_tick->state |= DYN_TICK_ENABLED;
192 }
193 spin_unlock_irqrestore(&dyn_tick->lock, flags);
194 }
195
196 return ret;
197}
198
199static int timer_dyn_tick_disable(void)
200{
201 struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
202 unsigned long flags;
203 int ret = -ENODEV;
204
205 if (dyn_tick) {
206 spin_lock_irqsave(&dyn_tick->lock, flags);
207 ret = 0;
208 if (dyn_tick->state & DYN_TICK_ENABLED) {
209 ret = dyn_tick->disable();
210
211 if (ret == 0)
212 dyn_tick->state &= ~DYN_TICK_ENABLED;
213 }
214 spin_unlock_irqrestore(&dyn_tick->lock, flags);
215 }
216
217 return ret;
218}
219
220/*
221 * Reprogram the system timer for at least the calculated time interval.
222 * This function should be called from the idle thread with IRQs disabled,
223 * immediately before sleeping.
224 */
225void timer_dyn_reprogram(void)
226{
227 struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
228 unsigned long next, seq, flags;
229
230 if (!dyn_tick)
231 return;
232
233 spin_lock_irqsave(&dyn_tick->lock, flags);
234 if (dyn_tick->state & DYN_TICK_ENABLED) {
235 next = next_timer_interrupt();
236 do {
237 seq = read_seqbegin(&xtime_lock);
238 dyn_tick->reprogram(next - jiffies);
239 } while (read_seqretry(&xtime_lock, seq));
240 }
241 spin_unlock_irqrestore(&dyn_tick->lock, flags);
242}
243
244static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
245{
246 return sprintf(buf, "%i\n",
247 (sys_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);
248}
249
250static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf,
251 size_t count)
252{
253 unsigned int enable = simple_strtoul(buf, NULL, 2);
254
255 if (enable)
256 timer_dyn_tick_enable();
257 else
258 timer_dyn_tick_disable();
259
260 return count;
261}
262static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick);
263
264/*
265 * dyntick=enable|disable
266 */
267static char dyntick_str[4] __initdata = "";
268
269static int __init dyntick_setup(char *str)
270{
271 if (str)
272 strlcpy(dyntick_str, str, sizeof(dyntick_str));
273 return 1;
274}
275
276__setup("dyntick=", dyntick_setup);
277#endif
278
177static int __init timer_init_sysfs(void) 279static int __init timer_init_sysfs(void)
178{ 280{
179 int ret = sysdev_class_register(&timer_sysclass); 281 int ret = sysdev_class_register(&timer_sysclass);
@@ -181,7 +283,22 @@ static int __init timer_init_sysfs(void)
181 return ret; 283 return ret;
182 284
183 sys_timer->dev.cls = &timer_sysclass; 285 sys_timer->dev.cls = &timer_sysclass;
184 return sysdev_register(&sys_timer->dev); 286 ret = sysdev_register(&sys_timer->dev);
287
288#ifdef CONFIG_NO_IDLE_HZ
289 if (ret == 0 && sys_timer->dyn_tick) {
290 ret = sysdev_create_file(&sys_timer->dev, &attr_dyn_tick);
291
292 /*
293 * Turn on dynamic tick after calibrate delay
294 * for correct bogomips
295 */
296 if (ret == 0 && dyntick_str[0] == 'e')
297 ret = timer_dyn_tick_enable();
298 }
299#endif
300
301 return ret;
185} 302}
186device_initcall(timer_init_sysfs); 303device_initcall(timer_init_sysfs);
187 304
@@ -205,6 +322,11 @@ void __init time_init(void)
205 sys_timer = get_sys_timer(); 322 sys_timer = get_sys_timer();
206 printk(KERN_INFO "Using %s for system timer\n", sys_timer->name); 323 printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
207 324
325#ifdef CONFIG_NO_IDLE_HZ
326 if (sys_timer->dyn_tick)
327 spin_lock_init(&sys_timer->dyn_tick->lock);
328#endif
329
208#if defined(CONFIG_SH_KGDB) 330#if defined(CONFIG_SH_KGDB)
209 /* 331 /*
210 * Set up kgdb as requested. We do it here because the serial 332 * Set up kgdb as requested. We do it here because the serial