diff options
Diffstat (limited to 'kernel/timer.c')
-rw-r--r-- | kernel/timer.c | 93 |
1 files changed, 80 insertions, 13 deletions
diff --git a/kernel/timer.c b/kernel/timer.c index eb97371b87d8..524c7f638365 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -792,24 +792,93 @@ u64 current_tick_length(void) | |||
792 | return ((u64) delta_nsec << (SHIFT_SCALE - 10)) + time_adj; | 792 | return ((u64) delta_nsec << (SHIFT_SCALE - 10)) + time_adj; |
793 | } | 793 | } |
794 | 794 | ||
795 | /* XXX - all of this timekeeping code should be later moved to time.c */ | ||
796 | #include <linux/clocksource.h> | ||
797 | static struct clocksource *clock; /* pointer to current clocksource */ | ||
798 | static cycle_t last_clock_cycle; /* cycle value at last update_wall_time */ | ||
795 | /* | 799 | /* |
796 | * Using a loop looks inefficient, but "ticks" is | 800 | * timekeeping_init - Initializes the clocksource and common timekeeping values |
797 | * usually just one (we shouldn't be losing ticks, | ||
798 | * we're doing this this way mainly for interrupt | ||
799 | * latency reasons, not because we think we'll | ||
800 | * have lots of lost timer ticks | ||
801 | */ | 801 | */ |
802 | static void update_wall_time(unsigned long ticks) | 802 | void __init timekeeping_init(void) |
803 | { | 803 | { |
804 | do { | 804 | unsigned long flags; |
805 | ticks--; | 805 | |
806 | write_seqlock_irqsave(&xtime_lock, flags); | ||
807 | clock = get_next_clocksource(); | ||
808 | calculate_clocksource_interval(clock, tick_nsec); | ||
809 | last_clock_cycle = read_clocksource(clock); | ||
810 | ntp_clear(); | ||
811 | write_sequnlock_irqrestore(&xtime_lock, flags); | ||
812 | } | ||
813 | |||
814 | |||
815 | /* | ||
816 | * timekeeping_resume - Resumes the generic timekeeping subsystem. | ||
817 | * @dev: unused | ||
818 | * | ||
819 | * This is for the generic clocksource timekeeping. | ||
820 | * xtime/wall_to_monotonic/jiffies/wall_jiffies/etc are | ||
821 | * still managed by arch specific suspend/resume code. | ||
822 | */ | ||
823 | static int timekeeping_resume(struct sys_device *dev) | ||
824 | { | ||
825 | unsigned long flags; | ||
826 | |||
827 | write_seqlock_irqsave(&xtime_lock, flags); | ||
828 | /* restart the last cycle value */ | ||
829 | last_clock_cycle = read_clocksource(clock); | ||
830 | write_sequnlock_irqrestore(&xtime_lock, flags); | ||
831 | return 0; | ||
832 | } | ||
833 | |||
834 | /* sysfs resume/suspend bits for timekeeping */ | ||
835 | static struct sysdev_class timekeeping_sysclass = { | ||
836 | .resume = timekeeping_resume, | ||
837 | set_kset_name("timekeeping"), | ||
838 | }; | ||
839 | |||
840 | static struct sys_device device_timer = { | ||
841 | .id = 0, | ||
842 | .cls = &timekeeping_sysclass, | ||
843 | }; | ||
844 | |||
845 | static int __init timekeeping_init_device(void) | ||
846 | { | ||
847 | int error = sysdev_class_register(&timekeeping_sysclass); | ||
848 | if (!error) | ||
849 | error = sysdev_register(&device_timer); | ||
850 | return error; | ||
851 | } | ||
852 | |||
853 | device_initcall(timekeeping_init_device); | ||
854 | |||
855 | /* | ||
856 | * update_wall_time - Uses the current clocksource to increment the wall time | ||
857 | * | ||
858 | * Called from the timer interrupt, must hold a write on xtime_lock. | ||
859 | */ | ||
860 | static void update_wall_time(void) | ||
861 | { | ||
862 | cycle_t now, offset; | ||
863 | |||
864 | now = read_clocksource(clock); | ||
865 | offset = (now - last_clock_cycle)&clock->mask; | ||
866 | |||
867 | /* normally this loop will run just once, however in the | ||
868 | * case of lost or late ticks, it will accumulate correctly. | ||
869 | */ | ||
870 | while (offset > clock->interval_cycles) { | ||
871 | /* accumulate one interval */ | ||
872 | last_clock_cycle += clock->interval_cycles; | ||
873 | offset -= clock->interval_cycles; | ||
874 | |||
806 | update_wall_time_one_tick(); | 875 | update_wall_time_one_tick(); |
807 | if (xtime.tv_nsec >= 1000000000) { | 876 | if (xtime.tv_nsec >= 1000000000) { |
808 | xtime.tv_nsec -= 1000000000; | 877 | xtime.tv_nsec -= 1000000000; |
809 | xtime.tv_sec++; | 878 | xtime.tv_sec++; |
810 | second_overflow(); | 879 | second_overflow(); |
811 | } | 880 | } |
812 | } while (ticks); | 881 | } |
813 | } | 882 | } |
814 | 883 | ||
815 | /* | 884 | /* |
@@ -915,10 +984,8 @@ static inline void update_times(void) | |||
915 | unsigned long ticks; | 984 | unsigned long ticks; |
916 | 985 | ||
917 | ticks = jiffies - wall_jiffies; | 986 | ticks = jiffies - wall_jiffies; |
918 | if (ticks) { | 987 | wall_jiffies += ticks; |
919 | wall_jiffies += ticks; | 988 | update_wall_time(); |
920 | update_wall_time(ticks); | ||
921 | } | ||
922 | calc_load(ticks); | 989 | calc_load(ticks); |
923 | } | 990 | } |
924 | 991 | ||