diff options
Diffstat (limited to 'arch/arm/kernel/time.c')
-rw-r--r-- | arch/arm/kernel/time.c | 107 |
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 | ||
385 | static 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 | |||
406 | static 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 | */ | ||
432 | void 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 | |||
442 | static 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 | |||
448 | static 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 | } | ||
460 | static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick); | ||
461 | |||
462 | /* | ||
463 | * dyntick=enable|disable | ||
464 | */ | ||
465 | static char dyntick_str[4] __initdata = ""; | ||
466 | |||
467 | static 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 | |||
384 | static int __init timer_init_sysfs(void) | 477 | static 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 | ||