diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-01-03 17:49:53 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-01-03 17:49:53 +0000 |
commit | eb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (patch) | |
tree | 5746fea1605ff013be9b78a1556aaad7615d664a /arch/alpha/kernel/time.c | |
parent | 80ea5b1e15398277650e1197957053b5a71c08bc (diff) |
Merge with Linux 2.1.131 plus some more MIPS goodies.
Diffstat (limited to 'arch/alpha/kernel/time.c')
-rw-r--r-- | arch/alpha/kernel/time.c | 79 |
1 files changed, 46 insertions, 33 deletions
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index e0a7e1153..acbb76896 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -60,13 +60,17 @@ static struct { unsigned long scaled_ticks_per_cycle; /* last time the CMOS clock got updated */ time_t last_rtc_update; + /* partial unused tick */ + unsigned long partial_tick; } state; +unsigned long est_cycle_freq; + static inline __u32 rpcc(void) { __u32 result; - asm volatile ("rpcc %0" : "r="(result)); + asm volatile ("rpcc %0" : "=r"(result)); return result; } @@ -77,8 +81,6 @@ static inline __u32 rpcc(void) */ void timer_interrupt(int irq, void *dev, struct pt_regs * regs) { - const unsigned long half = 1UL << (FIX_SHIFT - 1); - const unsigned long mask = (1UL << (FIX_SHIFT + 1)) - 1; unsigned long delta; __u32 now; long nticks; @@ -94,22 +96,21 @@ void timer_interrupt(int irq, void *dev, struct pt_regs * regs) #endif /* - * Estimate how many ticks have passed since the last update. - * Round the result, .5 to even. When we loose ticks due to - * say using IDE, the clock has been seen to run up to 15% slow - * if we truncate. + * Calculate how many ticks have passed since the last update, + * including any previous partial leftover. Save any resulting + * fraction for the next pass. */ now = rpcc(); delta = now - state.last_time; state.last_time = now; - delta = delta * state.scaled_ticks_per_cycle; - if ((delta & mask) != half) - delta += half; + delta = delta * state.scaled_ticks_per_cycle + state.partial_tick; + state.partial_tick = delta & ((1UL << FIX_SHIFT) - 1); nticks = delta >> FIX_SHIFT; - do { + while (nticks > 0) { do_timer(regs); - } while (--nticks > 0); + nticks--; + } /* * If we have an externally synchronized Linux clock, then update @@ -162,7 +163,7 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon, * drivers depend on them being initialized (e.g., joystick driver). */ -/* It is (normally) only counter 1 that presents config problems, so +/* It is (normally) only counter 0 that presents config problems, so provide this support function to do the rest of the job. */ void inline @@ -184,12 +185,20 @@ init_pit_rest(void) static inline void rtc_init_pit (void) { + unsigned char control; + /* Setup interval timer if /dev/rtc is being used */ outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ outb(LATCH & 0xff, 0x40); /* LSB */ outb(LATCH >> 8, 0x40); /* MSB */ request_region(0x40, 0x20, "timer"); /* reserve pit */ + /* Turn off RTC interrupts before /dev/rtc is initialized */ + control = CMOS_READ(RTC_CONTROL); + control &= ~(RTC_PIE | RTC_AIE | RTC_UIE); + CMOS_WRITE(control, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + init_pit_rest(); } #endif @@ -197,11 +206,25 @@ rtc_init_pit (void) void generic_init_pit (void) { - int x; - if ((x = (CMOS_READ(RTC_FREQ_SELECT) & 0x3f)) != 0x26) { + unsigned char x; + + /* Reset periodic interrupt frequency. */ + x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f; + if (x != 0x26 && x != 0x19 && x != 0x06) { printk("Setting RTC_FREQ to 1024 Hz (%x)\n", x); CMOS_WRITE(0x26, RTC_FREQ_SELECT); } + + /* Turn on periodic interrupts. */ + x = CMOS_READ(RTC_CONTROL); + if (!(x & RTC_PIE)) { + printk("Turning on RTC interrupts.\n"); + x |= RTC_PIE; + x &= ~(RTC_AIE | RTC_UIE); + CMOS_WRITE(x, RTC_CONTROL); + } + CMOS_READ(RTC_INTR_FLAGS); + request_region(RTC_PORT(0), 0x10, "timer"); /* reserve rtc */ /* Turn off the PIT. */ @@ -223,11 +246,9 @@ generic_init_pit (void) void time_init(void) { -#ifdef CONFIG_RTC - unsigned char save_control; -#endif void (*irq_handler)(int, void *, struct pt_regs *); unsigned int year, mon, day, hour, min, sec, cc1, cc2; + unsigned long cycle_freq; /* Initialize the timers. */ init_pit(); @@ -246,16 +267,17 @@ time_init(void) /* If our cycle frequency isn't valid, go another round and give a guess at what it should be. */ - if (hwrpb->cycle_freq == 0) { + cycle_freq = hwrpb->cycle_freq; + if (cycle_freq == 0) { printk("HWRPB cycle frequency bogus. Estimating... "); do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); cc2 = rpcc(); - hwrpb->cycle_freq = cc2 - cc1; + est_cycle_freq = cycle_freq = cc2 - cc1; cc1 = cc2; - printk("%lu Hz\n", hwrpb->cycle_freq); + printk("%lu Hz\n", cycle_freq); } /* From John Bowman <bowman@math.ualberta.ca>: allow the values @@ -300,18 +322,9 @@ time_init(void) state.last_time = cc1; state.scaled_ticks_per_cycle - = ((unsigned long) HZ << FIX_SHIFT) / hwrpb->cycle_freq; + = ((unsigned long) HZ << FIX_SHIFT) / cycle_freq; state.last_rtc_update = 0; - -#ifdef CONFIG_RTC - /* turn off RTC interrupts before /dev/rtc is initialized */ - save_control = CMOS_READ(RTC_CONTROL); - save_control &= ~RTC_PIE; - save_control &= ~RTC_AIE; - save_control &= ~RTC_UIE; - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); -#endif + state.partial_tick = 0L; /* setup timer */ irq_handler = timer_interrupt; @@ -353,7 +366,7 @@ do_gettimeofday(struct timeval *tv) */ delta_usec = delta_cycles * state.scaled_ticks_per_cycle * 15625; - delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6)) * HZ)) + 1) / 2; + delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2; usec += delta_usec; if (usec >= 1000000) { |