diff options
Diffstat (limited to 'arch/i386/kernel/time.c')
-rw-r--r-- | arch/i386/kernel/time.c | 153 |
1 files changed, 19 insertions, 134 deletions
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 796e5faa6ca7..2a6ab86ffc15 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c | |||
@@ -82,7 +82,8 @@ extern unsigned long wall_jiffies; | |||
82 | DEFINE_SPINLOCK(rtc_lock); | 82 | DEFINE_SPINLOCK(rtc_lock); |
83 | EXPORT_SYMBOL(rtc_lock); | 83 | EXPORT_SYMBOL(rtc_lock); |
84 | 84 | ||
85 | struct timer_opts *cur_timer __read_mostly = &timer_none; | 85 | /* XXX - necessary to keep things compiling. to be removed later */ |
86 | u32 pmtmr_ioport; | ||
86 | 87 | ||
87 | /* | 88 | /* |
88 | * This is a special lock that is owned by the CPU and holds the index | 89 | * This is a special lock that is owned by the CPU and holds the index |
@@ -113,99 +114,19 @@ void rtc_cmos_write(unsigned char val, unsigned char addr) | |||
113 | } | 114 | } |
114 | EXPORT_SYMBOL(rtc_cmos_write); | 115 | EXPORT_SYMBOL(rtc_cmos_write); |
115 | 116 | ||
116 | /* | ||
117 | * This version of gettimeofday has microsecond resolution | ||
118 | * and better than microsecond precision on fast x86 machines with TSC. | ||
119 | */ | ||
120 | void do_gettimeofday(struct timeval *tv) | ||
121 | { | ||
122 | unsigned long seq; | ||
123 | unsigned long usec, sec; | ||
124 | unsigned long max_ntp_tick; | ||
125 | |||
126 | do { | ||
127 | unsigned long lost; | ||
128 | |||
129 | seq = read_seqbegin(&xtime_lock); | ||
130 | |||
131 | usec = cur_timer->get_offset(); | ||
132 | lost = jiffies - wall_jiffies; | ||
133 | |||
134 | /* | ||
135 | * If time_adjust is negative then NTP is slowing the clock | ||
136 | * so make sure not to go into next possible interval. | ||
137 | * Better to lose some accuracy than have time go backwards.. | ||
138 | */ | ||
139 | if (unlikely(time_adjust < 0)) { | ||
140 | max_ntp_tick = (USEC_PER_SEC / HZ) - tickadj; | ||
141 | usec = min(usec, max_ntp_tick); | ||
142 | |||
143 | if (lost) | ||
144 | usec += lost * max_ntp_tick; | ||
145 | } | ||
146 | else if (unlikely(lost)) | ||
147 | usec += lost * (USEC_PER_SEC / HZ); | ||
148 | |||
149 | sec = xtime.tv_sec; | ||
150 | usec += (xtime.tv_nsec / 1000); | ||
151 | } while (read_seqretry(&xtime_lock, seq)); | ||
152 | |||
153 | while (usec >= 1000000) { | ||
154 | usec -= 1000000; | ||
155 | sec++; | ||
156 | } | ||
157 | |||
158 | tv->tv_sec = sec; | ||
159 | tv->tv_usec = usec; | ||
160 | } | ||
161 | |||
162 | EXPORT_SYMBOL(do_gettimeofday); | ||
163 | |||
164 | int do_settimeofday(struct timespec *tv) | ||
165 | { | ||
166 | time_t wtm_sec, sec = tv->tv_sec; | ||
167 | long wtm_nsec, nsec = tv->tv_nsec; | ||
168 | |||
169 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | ||
170 | return -EINVAL; | ||
171 | |||
172 | write_seqlock_irq(&xtime_lock); | ||
173 | /* | ||
174 | * This is revolting. We need to set "xtime" correctly. However, the | ||
175 | * value in this location is the value at the most recent update of | ||
176 | * wall time. Discover what correction gettimeofday() would have | ||
177 | * made, and then undo it! | ||
178 | */ | ||
179 | nsec -= cur_timer->get_offset() * NSEC_PER_USEC; | ||
180 | nsec -= (jiffies - wall_jiffies) * TICK_NSEC; | ||
181 | |||
182 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | ||
183 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); | ||
184 | |||
185 | set_normalized_timespec(&xtime, sec, nsec); | ||
186 | set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); | ||
187 | |||
188 | ntp_clear(); | ||
189 | write_sequnlock_irq(&xtime_lock); | ||
190 | clock_was_set(); | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | EXPORT_SYMBOL(do_settimeofday); | ||
195 | |||
196 | static int set_rtc_mmss(unsigned long nowtime) | 117 | static int set_rtc_mmss(unsigned long nowtime) |
197 | { | 118 | { |
198 | int retval; | 119 | int retval; |
199 | 120 | unsigned long flags; | |
200 | WARN_ON(irqs_disabled()); | ||
201 | 121 | ||
202 | /* gets recalled with irq locally disabled */ | 122 | /* gets recalled with irq locally disabled */ |
203 | spin_lock_irq(&rtc_lock); | 123 | /* XXX - does irqsave resolve this? -johnstul */ |
124 | spin_lock_irqsave(&rtc_lock, flags); | ||
204 | if (efi_enabled) | 125 | if (efi_enabled) |
205 | retval = efi_set_rtc_mmss(nowtime); | 126 | retval = efi_set_rtc_mmss(nowtime); |
206 | else | 127 | else |
207 | retval = mach_set_rtc_mmss(nowtime); | 128 | retval = mach_set_rtc_mmss(nowtime); |
208 | spin_unlock_irq(&rtc_lock); | 129 | spin_unlock_irqrestore(&rtc_lock, flags); |
209 | 130 | ||
210 | return retval; | 131 | return retval; |
211 | } | 132 | } |
@@ -213,16 +134,6 @@ static int set_rtc_mmss(unsigned long nowtime) | |||
213 | 134 | ||
214 | int timer_ack; | 135 | int timer_ack; |
215 | 136 | ||
216 | /* monotonic_clock(): returns # of nanoseconds passed since time_init() | ||
217 | * Note: This function is required to return accurate | ||
218 | * time even in the absence of multiple timer ticks. | ||
219 | */ | ||
220 | unsigned long long monotonic_clock(void) | ||
221 | { | ||
222 | return cur_timer->monotonic_clock(); | ||
223 | } | ||
224 | EXPORT_SYMBOL(monotonic_clock); | ||
225 | |||
226 | #if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER) | 137 | #if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER) |
227 | unsigned long profile_pc(struct pt_regs *regs) | 138 | unsigned long profile_pc(struct pt_regs *regs) |
228 | { | 139 | { |
@@ -237,11 +148,21 @@ EXPORT_SYMBOL(profile_pc); | |||
237 | #endif | 148 | #endif |
238 | 149 | ||
239 | /* | 150 | /* |
240 | * timer_interrupt() needs to keep up the real-time clock, | 151 | * This is the same as the above, except we _also_ save the current |
241 | * as well as call the "do_timer()" routine every clocktick | 152 | * Time Stamp Counter value at the time of the timer interrupt, so that |
153 | * we later on can estimate the time of day more exactly. | ||
242 | */ | 154 | */ |
243 | static inline void do_timer_interrupt(int irq, struct pt_regs *regs) | 155 | irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
244 | { | 156 | { |
157 | /* | ||
158 | * Here we are in the timer irq handler. We just have irqs locally | ||
159 | * disabled but we don't know if the timer_bh is running on the other | ||
160 | * CPU. We need to avoid to SMP race with it. NOTE: we don' t need | ||
161 | * the irq version of write_lock because as just said we have irq | ||
162 | * locally disabled. -arca | ||
163 | */ | ||
164 | write_seqlock(&xtime_lock); | ||
165 | |||
245 | #ifdef CONFIG_X86_IO_APIC | 166 | #ifdef CONFIG_X86_IO_APIC |
246 | if (timer_ack) { | 167 | if (timer_ack) { |
247 | /* | 168 | /* |
@@ -274,27 +195,6 @@ static inline void do_timer_interrupt(int irq, struct pt_regs *regs) | |||
274 | irq = inb_p( 0x61 ); /* read the current state */ | 195 | irq = inb_p( 0x61 ); /* read the current state */ |
275 | outb_p( irq|0x80, 0x61 ); /* reset the IRQ */ | 196 | outb_p( irq|0x80, 0x61 ); /* reset the IRQ */ |
276 | } | 197 | } |
277 | } | ||
278 | |||
279 | /* | ||
280 | * This is the same as the above, except we _also_ save the current | ||
281 | * Time Stamp Counter value at the time of the timer interrupt, so that | ||
282 | * we later on can estimate the time of day more exactly. | ||
283 | */ | ||
284 | irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
285 | { | ||
286 | /* | ||
287 | * Here we are in the timer irq handler. We just have irqs locally | ||
288 | * disabled but we don't know if the timer_bh is running on the other | ||
289 | * CPU. We need to avoid to SMP race with it. NOTE: we don' t need | ||
290 | * the irq version of write_lock because as just said we have irq | ||
291 | * locally disabled. -arca | ||
292 | */ | ||
293 | write_seqlock(&xtime_lock); | ||
294 | |||
295 | cur_timer->mark_offset(); | ||
296 | |||
297 | do_timer_interrupt(irq, regs); | ||
298 | 198 | ||
299 | write_sequnlock(&xtime_lock); | 199 | write_sequnlock(&xtime_lock); |
300 | 200 | ||
@@ -375,7 +275,6 @@ void notify_arch_cmos_timer(void) | |||
375 | 275 | ||
376 | static long clock_cmos_diff, sleep_start; | 276 | static long clock_cmos_diff, sleep_start; |
377 | 277 | ||
378 | static struct timer_opts *last_timer; | ||
379 | static int timer_suspend(struct sys_device *dev, pm_message_t state) | 278 | static int timer_suspend(struct sys_device *dev, pm_message_t state) |
380 | { | 279 | { |
381 | /* | 280 | /* |
@@ -384,10 +283,6 @@ static int timer_suspend(struct sys_device *dev, pm_message_t state) | |||
384 | clock_cmos_diff = -get_cmos_time(); | 283 | clock_cmos_diff = -get_cmos_time(); |
385 | clock_cmos_diff += get_seconds(); | 284 | clock_cmos_diff += get_seconds(); |
386 | sleep_start = get_cmos_time(); | 285 | sleep_start = get_cmos_time(); |
387 | last_timer = cur_timer; | ||
388 | cur_timer = &timer_none; | ||
389 | if (last_timer->suspend) | ||
390 | last_timer->suspend(state); | ||
391 | return 0; | 286 | return 0; |
392 | } | 287 | } |
393 | 288 | ||
@@ -410,10 +305,6 @@ static int timer_resume(struct sys_device *dev) | |||
410 | jiffies_64 += sleep_length; | 305 | jiffies_64 += sleep_length; |
411 | wall_jiffies += sleep_length; | 306 | wall_jiffies += sleep_length; |
412 | write_sequnlock_irqrestore(&xtime_lock, flags); | 307 | write_sequnlock_irqrestore(&xtime_lock, flags); |
413 | if (last_timer->resume) | ||
414 | last_timer->resume(); | ||
415 | cur_timer = last_timer; | ||
416 | last_timer = NULL; | ||
417 | touch_softlockup_watchdog(); | 308 | touch_softlockup_watchdog(); |
418 | return 0; | 309 | return 0; |
419 | } | 310 | } |
@@ -455,9 +346,6 @@ static void __init hpet_time_init(void) | |||
455 | printk("Using HPET for base-timer\n"); | 346 | printk("Using HPET for base-timer\n"); |
456 | } | 347 | } |
457 | 348 | ||
458 | cur_timer = select_timer(); | ||
459 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); | ||
460 | |||
461 | time_init_hook(); | 349 | time_init_hook(); |
462 | } | 350 | } |
463 | #endif | 351 | #endif |
@@ -479,8 +367,5 @@ void __init time_init(void) | |||
479 | set_normalized_timespec(&wall_to_monotonic, | 367 | set_normalized_timespec(&wall_to_monotonic, |
480 | -xtime.tv_sec, -xtime.tv_nsec); | 368 | -xtime.tv_sec, -xtime.tv_nsec); |
481 | 369 | ||
482 | cur_timer = select_timer(); | ||
483 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); | ||
484 | |||
485 | time_init_hook(); | 370 | time_init_hook(); |
486 | } | 371 | } |