diff options
Diffstat (limited to 'arch/parisc/kernel/time.c')
-rw-r--r-- | arch/parisc/kernel/time.c | 112 |
1 files changed, 29 insertions, 83 deletions
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 325f30d82b64..4215f5596c8b 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -59,10 +59,9 @@ static unsigned long clocktick __read_mostly; /* timer cycles per tick */ */ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id) { - unsigned long now, now2; + unsigned long now; unsigned long next_tick; - unsigned long cycles_elapsed, ticks_elapsed = 1; - unsigned long cycles_remainder; + unsigned long ticks_elapsed = 0; unsigned int cpu = smp_processor_id(); struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu); @@ -71,102 +70,49 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id) profile_tick(CPU_PROFILING); - /* Initialize next_tick to the expected tick time. */ + /* Initialize next_tick to the old expected tick time. */ next_tick = cpuinfo->it_value; - /* Get current cycle counter (Control Register 16). */ - now = mfctl(16); - - cycles_elapsed = now - next_tick; - - if ((cycles_elapsed >> 6) < cpt) { - /* use "cheap" math (add/subtract) instead - * of the more expensive div/mul method - */ - cycles_remainder = cycles_elapsed; - while (cycles_remainder > cpt) { - cycles_remainder -= cpt; - ticks_elapsed++; - } - } else { - /* TODO: Reduce this to one fdiv op */ - cycles_remainder = cycles_elapsed % cpt; - ticks_elapsed += cycles_elapsed / cpt; - } - - /* convert from "division remainder" to "remainder of clock tick" */ - cycles_remainder = cpt - cycles_remainder; - - /* Determine when (in CR16 cycles) next IT interrupt will fire. - * We want IT to fire modulo clocktick even if we miss/skip some. - * But those interrupts don't in fact get delivered that regularly. - */ - next_tick = now + cycles_remainder; + /* Calculate how many ticks have elapsed. */ + do { + ++ticks_elapsed; + next_tick += cpt; + now = mfctl(16); + } while (next_tick - now > cpt); + /* Store (in CR16 cycles) up to when we are accounting right now. */ cpuinfo->it_value = next_tick; - /* Program the IT when to deliver the next interrupt. - * Only bottom 32-bits of next_tick are writable in CR16! - */ - mtctl(next_tick, 16); + /* Go do system house keeping. */ + if (cpu == 0) + xtime_update(ticks_elapsed); + + update_process_times(user_mode(get_irq_regs())); - /* Skip one clocktick on purpose if we missed next_tick. + /* Skip clockticks on purpose if we know we would miss those. * The new CR16 must be "later" than current CR16 otherwise * itimer would not fire until CR16 wrapped - e.g 4 seconds * later on a 1Ghz processor. We'll account for the missed - * tick on the next timer interrupt. + * ticks on the next timer interrupt. + * We want IT to fire modulo clocktick even if we miss/skip some. + * But those interrupts don't in fact get delivered that regularly. * * "next_tick - now" will always give the difference regardless * if one or the other wrapped. If "now" is "bigger" we'll end up * with a very large unsigned number. */ - now2 = mfctl(16); - if (next_tick - now2 > cpt) - mtctl(next_tick+cpt, 16); + while (next_tick - mfctl(16) > cpt) + next_tick += cpt; -#if 1 -/* - * GGG: DEBUG code for how many cycles programming CR16 used. - */ - if (unlikely(now2 - now > 0x3000)) /* 12K cycles */ - printk (KERN_CRIT "timer_interrupt(CPU %d): SLOW! 0x%lx cycles!" - " cyc %lX rem %lX " - " next/now %lX/%lX\n", - cpu, now2 - now, cycles_elapsed, cycles_remainder, - next_tick, now ); -#endif - - /* Can we differentiate between "early CR16" (aka Scenario 1) and - * "long delay" (aka Scenario 3)? I don't think so. - * - * Timer_interrupt will be delivered at least a few hundred cycles - * after the IT fires. But it's arbitrary how much time passes - * before we call it "late". I've picked one second. - * - * It's important NO printk's are between reading CR16 and - * setting up the next value. May introduce huge variance. - */ - if (unlikely(ticks_elapsed > HZ)) { - /* Scenario 3: very long delay? bad in any case */ - printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!" - " cycles %lX rem %lX " - " next/now %lX/%lX\n", - cpu, - cycles_elapsed, cycles_remainder, - next_tick, now ); - } - - /* Done mucking with unreliable delivery of interrupts. - * Go do system house keeping. + /* Program the IT when to deliver the next interrupt. + * Only bottom 32-bits of next_tick are writable in CR16! + * Timer interrupt will be delivered at least a few hundred cycles + * after the IT fires, so if we are too close (<= 500 cycles) to the + * next cycle, simply skip it. */ - - if (!--cpuinfo->prof_counter) { - cpuinfo->prof_counter = cpuinfo->prof_multiplier; - update_process_times(user_mode(get_irq_regs())); - } - - if (cpu == 0) - xtime_update(ticks_elapsed); + if (next_tick - mfctl(16) <= 500) + next_tick += cpt; + mtctl(next_tick, 16); return IRQ_HANDLED; } |