aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/time.c')
-rw-r--r--arch/arm/kernel/time.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index c232f24f4a60..1b7fcd50c3e2 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -381,6 +381,99 @@ static struct sysdev_class timer_sysclass = {
381 .resume = timer_resume, 381 .resume = timer_resume,
382}; 382};
383 383
384#ifdef CONFIG_NO_IDLE_HZ
385static int timer_dyn_tick_enable(void)
386{
387 struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
388 unsigned long flags;
389 int ret = -ENODEV;
390
391 if (dyn_tick) {
392 write_seqlock_irqsave(&xtime_lock, flags);
393 ret = 0;
394 if (!(dyn_tick->state & DYN_TICK_ENABLED)) {
395 ret = dyn_tick->enable();
396
397 if (ret == 0)
398 dyn_tick->state |= DYN_TICK_ENABLED;
399 }
400 write_sequnlock_irqrestore(&xtime_lock, flags);
401 }
402
403 return ret;
404}
405
406static int timer_dyn_tick_disable(void)
407{
408 struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
409 unsigned long flags;
410 int ret = -ENODEV;
411
412 if (dyn_tick) {
413 write_seqlock_irqsave(&xtime_lock, flags);
414 ret = 0;
415 if (dyn_tick->state & DYN_TICK_ENABLED) {
416 ret = dyn_tick->disable();
417
418 if (ret == 0)
419 dyn_tick->state &= ~DYN_TICK_ENABLED;
420 }
421 write_sequnlock_irqrestore(&xtime_lock, flags);
422 }
423
424 return ret;
425}
426
427/*
428 * Reprogram the system timer for at least the calculated time interval.
429 * This function should be called from the idle thread with IRQs disabled,
430 * immediately before sleeping.
431 */
432void timer_dyn_reprogram(void)
433{
434 struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
435
436 write_seqlock(&xtime_lock);
437 if (dyn_tick->state & DYN_TICK_ENABLED)
438 dyn_tick->reprogram(next_timer_interrupt() - jiffies);
439 write_sequnlock(&xtime_lock);
440}
441
442static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
443{
444 return sprintf(buf, "%i\n",
445 (system_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);
446}
447
448static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf,
449 size_t count)
450{
451 unsigned int enable = simple_strtoul(buf, NULL, 2);
452
453 if (enable)
454 timer_dyn_tick_enable();
455 else
456 timer_dyn_tick_disable();
457
458 return count;
459}
460static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick);
461
462/*
463 * dyntick=enable|disable
464 */
465static char dyntick_str[4] __initdata = "";
466
467static int __init dyntick_setup(char *str)
468{
469 if (str)
470 strlcpy(dyntick_str, str, sizeof(dyntick_str));
471 return 1;
472}
473
474__setup("dyntick=", dyntick_setup);
475#endif
476
384static int __init timer_init_sysfs(void) 477static int __init timer_init_sysfs(void)
385{ 478{
386 int ret = sysdev_class_register(&timer_sysclass); 479 int ret = sysdev_class_register(&timer_sysclass);
@@ -388,6 +481,20 @@ static int __init timer_init_sysfs(void)
388 system_timer->dev.cls = &timer_sysclass; 481 system_timer->dev.cls = &timer_sysclass;
389 ret = sysdev_register(&system_timer->dev); 482 ret = sysdev_register(&system_timer->dev);
390 } 483 }
484
485#ifdef CONFIG_NO_IDLE_HZ
486 if (ret == 0 && system_timer->dyn_tick) {
487 ret = sysdev_create_file(&system_timer->dev, &attr_dyn_tick);
488
489 /*
490 * Turn on dynamic tick after calibrate delay
491 * for correct bogomips
492 */
493 if (ret == 0 && dyntick_str[0] == 'e')
494 ret = timer_dyn_tick_enable();
495 }
496#endif
497
391 return ret; 498 return ret;
392} 499}
393 500