summaryrefslogtreecommitdiffstats
path: root/arch/alpha/kernel/time.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-01-03 17:49:53 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-01-03 17:49:53 +0000
commiteb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (patch)
tree5746fea1605ff013be9b78a1556aaad7615d664a /arch/alpha/kernel/time.c
parent80ea5b1e15398277650e1197957053b5a71c08bc (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.c79
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) {