aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/parisc/kernel/time.c37
1 files changed, 23 insertions, 14 deletions
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
index b3496b592a2d..1d58ce0e37ad 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 */
38extern void smp_do_timer(struct pt_regs *regs); 38extern void smp_do_timer(struct pt_regs *regs);
39#endif 39#endif
40 40
41/*
42 * We keep time on PA-RISC Linux by using the Interval Timer which is
43 * a pair of registers; one is read-only and one is write-only; both
44 * accessed through CR16. The read-only register is 32 or 64 bits wide,
45 * and increments by 1 every CPU clock tick. The architecture only
46 * guarantees us a rate between 0.5 and 2, but all implementations use a
47 * rate of 1. The write-only register is 32-bits wide. When the lowest
48 * 32 bits of the read-only register compare equal to the write-only
49 * register, it raises a maskable external interrupt. Each processor has
50 * an Interval Timer of its own and they are not synchronised.
51 *
52 * We want to generate an interrupt every 1/HZ seconds. So we program
53 * CR16 to interrupt every @clocktick cycles. The it_value in cpu_data
54 * is programmed with the intended time of the next tick. We can be
55 * held off for an arbitrarily long period of time by interrupts being
56 * disabled, so we may miss one or more ticks.
57 */
41irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 58irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
42{ 59{
43 unsigned long now; 60 unsigned long now;
44 unsigned long next_tick; 61 unsigned long next_tick;
45 unsigned long cycles_elapsed; 62 unsigned long cycles_elapsed, ticks_elapsed;
46 unsigned long cycles_remainder; 63 unsigned long cycles_remainder;
47 unsigned int cpu = smp_processor_id(); 64 unsigned int cpu = smp_processor_id();
48 65
@@ -67,11 +84,14 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
67 * of the more expensive div/mul method 84 * of the more expensive div/mul method
68 */ 85 */
69 cycles_remainder = cycles_elapsed; 86 cycles_remainder = cycles_elapsed;
87 ticks_elapsed = 1;
70 while (cycles_remainder > cpt) { 88 while (cycles_remainder > cpt) {
71 cycles_remainder -= cpt; 89 cycles_remainder -= cpt;
90 ticks_elapsed++;
72 } 91 }
73 } else { 92 } else {
74 cycles_remainder = cycles_elapsed % cpt; 93 cycles_remainder = cycles_elapsed % cpt;
94 ticks_elapsed = 1 + cycles_elapsed / cpt;
75 } 95 }
76 96
77 /* Can we differentiate between "early CR16" (aka Scenario 1) and 97 /* 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)
81 * cycles after the IT fires. But it's arbitrary how much time passes 101 * cycles after the IT fires. But it's arbitrary how much time passes
82 * before we call it "late". I've picked one second. 102 * before we call it "late". I've picked one second.
83 */ 103 */
84/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */ 104 if (ticks_elapsed > HZ) {
85#if HZ == 1000
86 if (cycles_elapsed > (cpt << 10) )
87#elif HZ == 250
88 if (cycles_elapsed > (cpt << 8) )
89#elif HZ == 100
90 if (cycles_elapsed > (cpt << 7) )
91#else
92#warn WTF is HZ set to anyway?
93 if (cycles_elapsed > (HZ * cpt) )
94#endif
95 {
96 /* Scenario 3: very long delay? bad in any case */ 105 /* Scenario 3: very long delay? bad in any case */
97 printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!" 106 printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!"
98 " cycles %lX rem %lX " 107 " cycles %lX rem %lX "
@@ -136,7 +145,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
136#endif 145#endif
137 if (cpu == 0) { 146 if (cpu == 0) {
138 write_seqlock(&xtime_lock); 147 write_seqlock(&xtime_lock);
139 do_timer(regs); 148 do_timer(ticks_elapsed);
140 write_sequnlock(&xtime_lock); 149 write_sequnlock(&xtime_lock);
141 } 150 }
142 151