diff options
author | Chris Zankel <chris@zankel.net> | 2007-08-05 13:26:30 -0400 |
---|---|---|
committer | Chris Zankel <chris@zankel.net> | 2007-08-27 16:53:37 -0400 |
commit | 2b8aea74e78e977b1f9987e23e3e59f3ef4359f4 (patch) | |
tree | 920ad1edaf51eccbabae05110101a1d65b8c0580 /arch | |
parent | bc671aa9838f234ccfc794a77325628f1e41e083 (diff) |
[XTENSA] Fix timer instabilities.
The timer code could have missed a tick.
Signed-off-by: Chris Zankel <chris@zankel.net>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/xtensa/kernel/time.c | 46 |
1 files changed, 29 insertions, 17 deletions
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c index 22949be4a5d8..60d29fe0b1bd 100644 --- a/arch/xtensa/kernel/time.c +++ b/arch/xtensa/kernel/time.c | |||
@@ -32,12 +32,20 @@ EXPORT_SYMBOL(rtc_lock); | |||
32 | 32 | ||
33 | #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT | 33 | #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT |
34 | unsigned long ccount_per_jiffy; /* per 1/HZ */ | 34 | unsigned long ccount_per_jiffy; /* per 1/HZ */ |
35 | unsigned long ccount_nsec; /* nsec per ccount increment */ | 35 | unsigned long nsec_per_ccount; /* nsec per ccount increment */ |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | unsigned int last_ccount_stamp; | ||
39 | static long last_rtc_update = 0; | 38 | static long last_rtc_update = 0; |
40 | 39 | ||
40 | /* | ||
41 | * Scheduler clock - returns current tim in nanosec units. | ||
42 | */ | ||
43 | |||
44 | unsigned long long sched_clock(void) | ||
45 | { | ||
46 | return (unsigned long long)jiffies * (1000000000 / HZ); | ||
47 | } | ||
48 | |||
41 | static irqreturn_t timer_interrupt(int irq, void *dev_id); | 49 | static irqreturn_t timer_interrupt(int irq, void *dev_id); |
42 | static struct irqaction timer_irqaction = { | 50 | static struct irqaction timer_irqaction = { |
43 | .handler = timer_interrupt, | 51 | .handler = timer_interrupt, |
@@ -69,7 +77,6 @@ void __init time_init(void) | |||
69 | 77 | ||
70 | xtime.tv_nsec = 0; | 78 | xtime.tv_nsec = 0; |
71 | last_rtc_update = xtime.tv_sec = sec_n; | 79 | last_rtc_update = xtime.tv_sec = sec_n; |
72 | last_ccount_stamp = get_ccount(); | ||
73 | 80 | ||
74 | set_normalized_timespec(&wall_to_monotonic, | 81 | set_normalized_timespec(&wall_to_monotonic, |
75 | -xtime.tv_sec, -xtime.tv_nsec); | 82 | -xtime.tv_sec, -xtime.tv_nsec); |
@@ -85,7 +92,7 @@ int do_settimeofday(struct timespec *tv) | |||
85 | { | 92 | { |
86 | time_t wtm_sec, sec = tv->tv_sec; | 93 | time_t wtm_sec, sec = tv->tv_sec; |
87 | long wtm_nsec, nsec = tv->tv_nsec; | 94 | long wtm_nsec, nsec = tv->tv_nsec; |
88 | unsigned long ccount; | 95 | unsigned long delta; |
89 | 96 | ||
90 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | 97 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) |
91 | return -EINVAL; | 98 | return -EINVAL; |
@@ -97,8 +104,10 @@ int do_settimeofday(struct timespec *tv) | |||
97 | * wall time. Discover what correction gettimeofday() would have | 104 | * wall time. Discover what correction gettimeofday() would have |
98 | * made, and then undo it! | 105 | * made, and then undo it! |
99 | */ | 106 | */ |
100 | ccount = get_ccount(); | 107 | |
101 | nsec -= (ccount - last_ccount_stamp) * CCOUNT_NSEC; | 108 | delta = CCOUNT_PER_JIFFY; |
109 | delta += get_ccount() - get_linux_timer(); | ||
110 | nsec -= delta * NSEC_PER_CCOUNT; | ||
102 | 111 | ||
103 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | 112 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); |
104 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); | 113 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); |
@@ -117,17 +126,21 @@ EXPORT_SYMBOL(do_settimeofday); | |||
117 | void do_gettimeofday(struct timeval *tv) | 126 | void do_gettimeofday(struct timeval *tv) |
118 | { | 127 | { |
119 | unsigned long flags; | 128 | unsigned long flags; |
120 | unsigned long sec, usec, delta, seq; | 129 | unsigned long volatile sec, usec, delta, seq; |
121 | 130 | ||
122 | do { | 131 | do { |
123 | seq = read_seqbegin_irqsave(&xtime_lock, flags); | 132 | seq = read_seqbegin_irqsave(&xtime_lock, flags); |
124 | 133 | ||
125 | delta = get_ccount() - last_ccount_stamp; | ||
126 | sec = xtime.tv_sec; | 134 | sec = xtime.tv_sec; |
127 | usec = (xtime.tv_nsec / NSEC_PER_USEC); | 135 | usec = (xtime.tv_nsec / NSEC_PER_USEC); |
136 | |||
137 | delta = get_linux_timer() - get_ccount(); | ||
138 | |||
128 | } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); | 139 | } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); |
129 | 140 | ||
130 | usec += (delta * CCOUNT_NSEC) / NSEC_PER_USEC; | 141 | usec += (((unsigned long) CCOUNT_PER_JIFFY - delta) |
142 | * (unsigned long) NSEC_PER_CCOUNT) / NSEC_PER_USEC; | ||
143 | |||
131 | for (; usec >= 1000000; sec++, usec -= 1000000) | 144 | for (; usec >= 1000000; sec++, usec -= 1000000) |
132 | ; | 145 | ; |
133 | 146 | ||
@@ -158,9 +171,12 @@ again: | |||
158 | 171 | ||
159 | write_seqlock(&xtime_lock); | 172 | write_seqlock(&xtime_lock); |
160 | 173 | ||
161 | last_ccount_stamp = next; | 174 | do_timer(1); /* Linux handler in kernel/timer.c */ |
175 | |||
176 | /* Note that writing CCOMPARE clears the interrupt. */ | ||
177 | |||
162 | next += CCOUNT_PER_JIFFY; | 178 | next += CCOUNT_PER_JIFFY; |
163 | do_timer (1); /* Linux handler in kernel/timer.c */ | 179 | set_linux_timer(next); |
164 | 180 | ||
165 | if (ntp_synced() && | 181 | if (ntp_synced() && |
166 | xtime.tv_sec - last_rtc_update >= 659 && | 182 | xtime.tv_sec - last_rtc_update >= 659 && |
@@ -175,19 +191,15 @@ again: | |||
175 | write_sequnlock(&xtime_lock); | 191 | write_sequnlock(&xtime_lock); |
176 | } | 192 | } |
177 | 193 | ||
178 | /* NOTE: writing CCOMPAREn clears the interrupt. */ | 194 | /* Allow platform to do something useful (Wdog). */ |
179 | 195 | ||
180 | set_linux_timer (next); | 196 | platform_heartbeat(); |
181 | 197 | ||
182 | /* Make sure we didn't miss any tick... */ | 198 | /* Make sure we didn't miss any tick... */ |
183 | 199 | ||
184 | if ((signed long)(get_ccount() - next) > 0) | 200 | if ((signed long)(get_ccount() - next) > 0) |
185 | goto again; | 201 | goto again; |
186 | 202 | ||
187 | /* Allow platform to do something useful (Wdog). */ | ||
188 | |||
189 | platform_heartbeat(); | ||
190 | |||
191 | return IRQ_HANDLED; | 203 | return IRQ_HANDLED; |
192 | } | 204 | } |
193 | 205 | ||