diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-04 19:08:13 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-04 19:08:13 -0700 |
commit | 4b8447184ae85de4ce710e5f561fbaada21b8394 (patch) | |
tree | 71aed2c654a6d8d83beff480bc84d9e63b366858 /arch/parisc/kernel/time.c | |
parent | a43cdf08a1b1ab3c013059b5fa4c1b7561e53cb7 (diff) | |
parent | 1604f31895dcdb42edf6511ce7ef0546ff92c8e5 (diff) | |
download | op-kernel-dev-4b8447184ae85de4ce710e5f561fbaada21b8394.zip op-kernel-dev-4b8447184ae85de4ce710e5f561fbaada21b8394.tar.gz |
Merge master.kernel.org:/pub/scm/linux/kernel/git/willy/parisc-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/willy/parisc-2.6:
[PA-RISC] Fix time.c for new do_timer() calling convention
[PA-RISC] Fix must_check warnings in drivers.c
[PA-RISC] Fix parisc_newuname()
[PA-RISC] Remove warning from pci.c
[PA-RISC] Fix filldir warnings
[PA-RISC] Fix sys32_sysctl
[PA-RISC] Fix sba_iommu compilation
Diffstat (limited to 'arch/parisc/kernel/time.c')
-rw-r--r-- | arch/parisc/kernel/time.c | 37 |
1 files changed, 23 insertions, 14 deletions
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index b3496b5..1d58ce0e 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -38,11 +38,28 @@ static unsigned long clocktick __read_mostly; /* timer cycles per tick */ extern void smp_do_timer(struct pt_regs *regs); #endif +/* + * We keep time on PA-RISC Linux by using the Interval Timer which is + * a pair of registers; one is read-only and one is write-only; both + * accessed through CR16. The read-only register is 32 or 64 bits wide, + * and increments by 1 every CPU clock tick. The architecture only + * guarantees us a rate between 0.5 and 2, but all implementations use a + * rate of 1. The write-only register is 32-bits wide. When the lowest + * 32 bits of the read-only register compare equal to the write-only + * register, it raises a maskable external interrupt. Each processor has + * an Interval Timer of its own and they are not synchronised. + * + * We want to generate an interrupt every 1/HZ seconds. So we program + * CR16 to interrupt every @clocktick cycles. The it_value in cpu_data + * is programmed with the intended time of the next tick. We can be + * held off for an arbitrarily long period of time by interrupts being + * disabled, so we may miss one or more ticks. + */ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long now; unsigned long next_tick; - unsigned long cycles_elapsed; + unsigned long cycles_elapsed, ticks_elapsed; unsigned long cycles_remainder; unsigned int cpu = smp_processor_id(); @@ -67,11 +84,14 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * of the more expensive div/mul method */ cycles_remainder = cycles_elapsed; + ticks_elapsed = 1; while (cycles_remainder > cpt) { cycles_remainder -= cpt; + ticks_elapsed++; } } else { cycles_remainder = cycles_elapsed % cpt; + ticks_elapsed = 1 + cycles_elapsed / cpt; } /* Can we differentiate between "early CR16" (aka Scenario 1) and @@ -81,18 +101,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) * cycles after the IT fires. But it's arbitrary how much time passes * before we call it "late". I've picked one second. */ -/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */ -#if HZ == 1000 - if (cycles_elapsed > (cpt << 10) ) -#elif HZ == 250 - if (cycles_elapsed > (cpt << 8) ) -#elif HZ == 100 - if (cycles_elapsed > (cpt << 7) ) -#else -#warn WTF is HZ set to anyway? - if (cycles_elapsed > (HZ * cpt) ) -#endif - { + if (ticks_elapsed > HZ) { /* Scenario 3: very long delay? bad in any case */ printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!" " cycles %lX rem %lX " @@ -136,7 +145,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) #endif if (cpu == 0) { write_seqlock(&xtime_lock); - do_timer(regs); + do_timer(ticks_elapsed); write_sequnlock(&xtime_lock); } |