diff options
Diffstat (limited to 'kernel/hrtimer.c')
| -rw-r--r-- | kernel/hrtimer.c | 83 |
1 files changed, 47 insertions, 36 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index f1c4155b49ac..5ae51f1bc7c8 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
| @@ -21,6 +21,12 @@ | |||
| 21 | * Credits: | 21 | * Credits: |
| 22 | * based on kernel/timer.c | 22 | * based on kernel/timer.c |
| 23 | * | 23 | * |
| 24 | * Help, testing, suggestions, bugfixes, improvements were | ||
| 25 | * provided by: | ||
| 26 | * | ||
| 27 | * George Anzinger, Andrew Morton, Steven Rostedt, Roman Zippel | ||
| 28 | * et. al. | ||
| 29 | * | ||
| 24 | * For licencing details see kernel-base/COPYING | 30 | * For licencing details see kernel-base/COPYING |
| 25 | */ | 31 | */ |
| 26 | 32 | ||
| @@ -66,6 +72,12 @@ EXPORT_SYMBOL_GPL(ktime_get_real); | |||
| 66 | 72 | ||
| 67 | /* | 73 | /* |
| 68 | * The timer bases: | 74 | * The timer bases: |
| 75 | * | ||
| 76 | * Note: If we want to add new timer bases, we have to skip the two | ||
| 77 | * clock ids captured by the cpu-timers. We do this by holding empty | ||
| 78 | * entries rather than doing math adjustment of the clock ids. | ||
| 79 | * This ensures that we capture erroneous accesses to these clock ids | ||
| 80 | * rather than moving them into the range of valid clock id's. | ||
| 69 | */ | 81 | */ |
| 70 | 82 | ||
| 71 | #define MAX_HRTIMER_BASES 2 | 83 | #define MAX_HRTIMER_BASES 2 |
| @@ -406,8 +418,19 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) | |||
| 406 | /* Switch the timer base, if necessary: */ | 418 | /* Switch the timer base, if necessary: */ |
| 407 | new_base = switch_hrtimer_base(timer, base); | 419 | new_base = switch_hrtimer_base(timer, base); |
| 408 | 420 | ||
| 409 | if (mode == HRTIMER_REL) | 421 | if (mode == HRTIMER_REL) { |
| 410 | tim = ktime_add(tim, new_base->get_time()); | 422 | tim = ktime_add(tim, new_base->get_time()); |
| 423 | /* | ||
| 424 | * CONFIG_TIME_LOW_RES is a temporary way for architectures | ||
| 425 | * to signal that they simply return xtime in | ||
| 426 | * do_gettimeoffset(). In this case we want to round up by | ||
| 427 | * resolution when starting a relative timer, to avoid short | ||
| 428 | * timeouts. This will go away with the GTOD framework. | ||
| 429 | */ | ||
| 430 | #ifdef CONFIG_TIME_LOW_RES | ||
| 431 | tim = ktime_add(tim, base->resolution); | ||
| 432 | #endif | ||
| 433 | } | ||
| 411 | timer->expires = tim; | 434 | timer->expires = tim; |
| 412 | 435 | ||
| 413 | enqueue_hrtimer(timer, new_base); | 436 | enqueue_hrtimer(timer, new_base); |
| @@ -483,29 +506,25 @@ ktime_t hrtimer_get_remaining(const struct hrtimer *timer) | |||
| 483 | } | 506 | } |
| 484 | 507 | ||
| 485 | /** | 508 | /** |
| 486 | * hrtimer_rebase - rebase an initialized hrtimer to a different base | 509 | * hrtimer_init - initialize a timer to the given clock |
| 487 | * | 510 | * |
| 488 | * @timer: the timer to be rebased | 511 | * @timer: the timer to be initialized |
| 489 | * @clock_id: the clock to be used | 512 | * @clock_id: the clock to be used |
| 513 | * @mode: timer mode abs/rel | ||
| 490 | */ | 514 | */ |
| 491 | void hrtimer_rebase(struct hrtimer *timer, const clockid_t clock_id) | 515 | void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, |
| 516 | enum hrtimer_mode mode) | ||
| 492 | { | 517 | { |
| 493 | struct hrtimer_base *bases; | 518 | struct hrtimer_base *bases; |
| 494 | 519 | ||
| 520 | memset(timer, 0, sizeof(struct hrtimer)); | ||
| 521 | |||
| 495 | bases = per_cpu(hrtimer_bases, raw_smp_processor_id()); | 522 | bases = per_cpu(hrtimer_bases, raw_smp_processor_id()); |
| 496 | timer->base = &bases[clock_id]; | ||
| 497 | } | ||
| 498 | 523 | ||
| 499 | /** | 524 | if (clock_id == CLOCK_REALTIME && mode != HRTIMER_ABS) |
| 500 | * hrtimer_init - initialize a timer to the given clock | 525 | clock_id = CLOCK_MONOTONIC; |
| 501 | * | 526 | |
| 502 | * @timer: the timer to be initialized | 527 | timer->base = &bases[clock_id]; |
| 503 | * @clock_id: the clock to be used | ||
| 504 | */ | ||
| 505 | void hrtimer_init(struct hrtimer *timer, const clockid_t clock_id) | ||
| 506 | { | ||
| 507 | memset(timer, 0, sizeof(struct hrtimer)); | ||
| 508 | hrtimer_rebase(timer, clock_id); | ||
| 509 | } | 528 | } |
| 510 | 529 | ||
| 511 | /** | 530 | /** |
| @@ -550,6 +569,7 @@ static inline void run_hrtimer_queue(struct hrtimer_base *base) | |||
| 550 | fn = timer->function; | 569 | fn = timer->function; |
| 551 | data = timer->data; | 570 | data = timer->data; |
| 552 | set_curr_timer(base, timer); | 571 | set_curr_timer(base, timer); |
| 572 | timer->state = HRTIMER_RUNNING; | ||
| 553 | __remove_hrtimer(timer, base); | 573 | __remove_hrtimer(timer, base); |
| 554 | spin_unlock_irq(&base->lock); | 574 | spin_unlock_irq(&base->lock); |
| 555 | 575 | ||
| @@ -565,6 +585,10 @@ static inline void run_hrtimer_queue(struct hrtimer_base *base) | |||
| 565 | 585 | ||
| 566 | spin_lock_irq(&base->lock); | 586 | spin_lock_irq(&base->lock); |
| 567 | 587 | ||
| 588 | /* Another CPU has added back the timer */ | ||
| 589 | if (timer->state != HRTIMER_RUNNING) | ||
| 590 | continue; | ||
| 591 | |||
| 568 | if (restart == HRTIMER_RESTART) | 592 | if (restart == HRTIMER_RESTART) |
| 569 | enqueue_hrtimer(timer, base); | 593 | enqueue_hrtimer(timer, base); |
| 570 | else | 594 | else |
| @@ -638,8 +662,7 @@ schedule_hrtimer_interruptible(struct hrtimer *timer, | |||
| 638 | return schedule_hrtimer(timer, mode); | 662 | return schedule_hrtimer(timer, mode); |
| 639 | } | 663 | } |
| 640 | 664 | ||
| 641 | static long __sched | 665 | static long __sched nanosleep_restart(struct restart_block *restart) |
| 642 | nanosleep_restart(struct restart_block *restart, clockid_t clockid) | ||
| 643 | { | 666 | { |
| 644 | struct timespec __user *rmtp; | 667 | struct timespec __user *rmtp; |
| 645 | struct timespec tu; | 668 | struct timespec tu; |
| @@ -649,7 +672,7 @@ nanosleep_restart(struct restart_block *restart, clockid_t clockid) | |||
| 649 | 672 | ||
| 650 | restart->fn = do_no_restart_syscall; | 673 | restart->fn = do_no_restart_syscall; |
| 651 | 674 | ||
| 652 | hrtimer_init(&timer, clockid); | 675 | hrtimer_init(&timer, (clockid_t) restart->arg3, HRTIMER_ABS); |
| 653 | 676 | ||
| 654 | timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0; | 677 | timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0; |
| 655 | 678 | ||
| @@ -669,16 +692,6 @@ nanosleep_restart(struct restart_block *restart, clockid_t clockid) | |||
| 669 | return -ERESTART_RESTARTBLOCK; | 692 | return -ERESTART_RESTARTBLOCK; |
| 670 | } | 693 | } |
| 671 | 694 | ||
| 672 | static long __sched nanosleep_restart_mono(struct restart_block *restart) | ||
| 673 | { | ||
| 674 | return nanosleep_restart(restart, CLOCK_MONOTONIC); | ||
| 675 | } | ||
| 676 | |||
| 677 | static long __sched nanosleep_restart_real(struct restart_block *restart) | ||
| 678 | { | ||
| 679 | return nanosleep_restart(restart, CLOCK_REALTIME); | ||
| 680 | } | ||
| 681 | |||
| 682 | long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, | 695 | long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, |
| 683 | const enum hrtimer_mode mode, const clockid_t clockid) | 696 | const enum hrtimer_mode mode, const clockid_t clockid) |
| 684 | { | 697 | { |
| @@ -687,7 +700,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, | |||
| 687 | struct timespec tu; | 700 | struct timespec tu; |
| 688 | ktime_t rem; | 701 | ktime_t rem; |
| 689 | 702 | ||
| 690 | hrtimer_init(&timer, clockid); | 703 | hrtimer_init(&timer, clockid, mode); |
| 691 | 704 | ||
| 692 | timer.expires = timespec_to_ktime(*rqtp); | 705 | timer.expires = timespec_to_ktime(*rqtp); |
| 693 | 706 | ||
| @@ -695,7 +708,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, | |||
| 695 | if (rem.tv64 <= 0) | 708 | if (rem.tv64 <= 0) |
| 696 | return 0; | 709 | return 0; |
| 697 | 710 | ||
| 698 | /* Absolute timers do not update the rmtp value: */ | 711 | /* Absolute timers do not update the rmtp value and restart: */ |
| 699 | if (mode == HRTIMER_ABS) | 712 | if (mode == HRTIMER_ABS) |
| 700 | return -ERESTARTNOHAND; | 713 | return -ERESTARTNOHAND; |
| 701 | 714 | ||
| @@ -705,11 +718,11 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, | |||
| 705 | return -EFAULT; | 718 | return -EFAULT; |
| 706 | 719 | ||
| 707 | restart = ¤t_thread_info()->restart_block; | 720 | restart = ¤t_thread_info()->restart_block; |
| 708 | restart->fn = (clockid == CLOCK_MONOTONIC) ? | 721 | restart->fn = nanosleep_restart; |
| 709 | nanosleep_restart_mono : nanosleep_restart_real; | ||
| 710 | restart->arg0 = timer.expires.tv64 & 0xFFFFFFFF; | 722 | restart->arg0 = timer.expires.tv64 & 0xFFFFFFFF; |
| 711 | restart->arg1 = timer.expires.tv64 >> 32; | 723 | restart->arg1 = timer.expires.tv64 >> 32; |
| 712 | restart->arg2 = (unsigned long) rmtp; | 724 | restart->arg2 = (unsigned long) rmtp; |
| 725 | restart->arg3 = (unsigned long) timer.base->index; | ||
| 713 | 726 | ||
| 714 | return -ERESTART_RESTARTBLOCK; | 727 | return -ERESTART_RESTARTBLOCK; |
| 715 | } | 728 | } |
| @@ -736,10 +749,8 @@ static void __devinit init_hrtimers_cpu(int cpu) | |||
| 736 | struct hrtimer_base *base = per_cpu(hrtimer_bases, cpu); | 749 | struct hrtimer_base *base = per_cpu(hrtimer_bases, cpu); |
| 737 | int i; | 750 | int i; |
| 738 | 751 | ||
| 739 | for (i = 0; i < MAX_HRTIMER_BASES; i++) { | 752 | for (i = 0; i < MAX_HRTIMER_BASES; i++, base++) |
| 740 | spin_lock_init(&base->lock); | 753 | spin_lock_init(&base->lock); |
| 741 | base++; | ||
| 742 | } | ||
| 743 | } | 754 | } |
| 744 | 755 | ||
| 745 | #ifdef CONFIG_HOTPLUG_CPU | 756 | #ifdef CONFIG_HOTPLUG_CPU |
