diff options
author | kaf24@labyrinth.cl.cam.ac.uk <kaf24@labyrinth.cl.cam.ac.uk> | 2003-02-21 16:04:44 +0000 |
---|---|---|
committer | kaf24@labyrinth.cl.cam.ac.uk <kaf24@labyrinth.cl.cam.ac.uk> | 2003-02-21 16:04:44 +0000 |
commit | ef170179d03e5746a20ebd33cc3785d2f8f827a9 (patch) | |
tree | 16cc72bd0ab89488cbeb75de14378ceeada38223 /xen-2.4.16 | |
parent | a75def4139bb25ec693d0575af28bb6443daa49d (diff) | |
download | xen-ef170179d03e5746a20ebd33cc3785d2f8f827a9.tar.gz xen-ef170179d03e5746a20ebd33cc3785d2f8f827a9.tar.bz2 xen-ef170179d03e5746a20ebd33cc3785d2f8f827a9.zip |
bitkeeper revision 1.88 (3e564e1cTiVK2rPAdHl9ccMD8nraEw)
ac_timer.c, apic.c:
Fix timer code to schedule alarm handlers with some slop.
Diffstat (limited to 'xen-2.4.16')
-rw-r--r-- | xen-2.4.16/arch/i386/apic.c | 153 | ||||
-rw-r--r-- | xen-2.4.16/common/ac_timer.c | 344 |
2 files changed, 229 insertions, 268 deletions
diff --git a/xen-2.4.16/arch/i386/apic.c b/xen-2.4.16/arch/i386/apic.c index b967934e3c..9b999df951 100644 --- a/xen-2.4.16/arch/i386/apic.c +++ b/xen-2.4.16/arch/i386/apic.c @@ -218,9 +218,7 @@ int __init verify_local_APIC(void) void __init sync_Arb_IDs(void) { - /* - * Wait for idle. - */ + /* Wait for idle. */ apic_wait_icr_idle(); Dprintk("Synchronizing Arb IDs.\n"); @@ -508,11 +506,11 @@ void __init wait_8254_wraparound(void) prev_count = curr_count; curr_count = get_8254_timer_count(); delta = curr_count-prev_count; - /* - * This limit for delta seems arbitrary, but it isn't, it's - * slightly above the level of error a buggy Mercury/Neptune - * chipset timer can cause. - */ + /* + * This limit for delta seems arbitrary, but it isn't, it's slightly + * above the level of error a buggy Mercury/Neptune chipset timer can + * cause. + */ } while (delta < 300); } @@ -581,7 +579,7 @@ int __init calibrate_APIC_clock(void) * counter running for calibration. */ __setup_APIC_LVTT(1000000000); - /* The timer chip counts down to zero. Let's wait + /* The timer chip counts down to zero. Let's wait * for a wraparound to start exact measurement: * (the current tick might have been already half done) */ wait_8254_wraparound(); @@ -611,18 +609,18 @@ int __init calibrate_APIC_clock(void) result/(1000000/HZ), result%(1000000/HZ)); - cpu_freq = (u64)(((t2-t1)/LOOPS)*HZ); + cpu_freq = (u64)(((t2-t1)/LOOPS)*HZ); - /* set up multipliers for accurate timer code */ - bus_freq = result*HZ; - bus_cycle = (u32) (1000000000000LL/bus_freq); /* in pico seconds */ - bus_scale = (1000*262144)/bus_cycle; + /* set up multipliers for accurate timer code */ + bus_freq = result*HZ; + bus_cycle = (u32) (1000000000000LL/bus_freq); /* in pico seconds */ + bus_scale = (1000*262144)/bus_cycle; - /* print results */ - printk("..... bus_freq = %u Hz\n", bus_freq); - printk("..... bus_cycle = %u ps\n", bus_cycle); - printk("..... bus_scale = %u \n", bus_scale); - /* reset APIC to zero timeout value */ + /* print results */ + printk("..... bus_freq = %u Hz\n", bus_freq); + printk("..... bus_cycle = %u ps\n", bus_cycle); + printk("..... bus_scale = %u \n", bus_scale); + /* reset APIC to zero timeout value */ __setup_APIC_LVTT(0); return result; } @@ -636,7 +634,7 @@ void __init setup_APIC_clocks (void) printk("Using local APIC timer interrupts.\n"); using_apic_timer = 1; __cli(); - /* calibrate CPU0 for CPU speed and BUS speed */ + /* calibrate CPU0 for CPU speed and BUS speed */ bus_freq = calibrate_APIC_clock(); /* Now set up the timer for real. */ setup_APIC_timer((void *)bus_freq); @@ -654,41 +652,38 @@ void __init setup_APIC_clocks (void) */ int reprogram_ac_timer(s_time_t timeout) { - int cpu = smp_processor_id(); - s_time_t now; - s_time_t expire; - u64 apic_tmict; - - now = NOW(); - expire = timeout - now; /* value from now */ - - - if (expire <= 0) { - TRC(printk("APICT[%02d] Timeout in the past 0x%08X%08X > 0x%08X%08X\n", - cpu, (u32)(now>>32), (u32)now, - (u32)(timeout>>32),(u32)timeout)); - return 0; /* timeout value in the past */ - } - - /* conversion to bus units */ - apic_tmict = (((u64)bus_scale) * expire)>>18; - - if (apic_tmict >= 0xffffffff) { - /* This is bad! */ - printk("APICT[%02d] Timeout value too large\n", cpu); - apic_tmict = 0xffffffff; - } - if (apic_tmict == 0) { - TRC(printk("APICT[%02d] timeout value too small\n", cpu)); - return 0; - } - - /* programm timer */ - apic_write(APIC_TMICT, (unsigned long)apic_tmict); - - TRC(printk("APICT[%02d] reprog(): expire=%lld %u\n", - cpu, expire, apic_tmict)); - return 1; + int cpu = smp_processor_id(); + s_time_t now; + s_time_t expire; + u64 apic_tmict; + + now = NOW(); + expire = timeout - now; /* value from now */ + + if (expire <= 0) { + printk("APICT[%02d] Timeout in the past 0x%08X%08X > 0x%08X%08X\n", + cpu, (u32)(now>>32), (u32)now, (u32)(timeout>>32),(u32)timeout); + return 0; /* timeout value in the past */ + } + + /* conversion to bus units */ + apic_tmict = (((u64)bus_scale) * expire)>>18; + + if (apic_tmict >= 0xffffffff) { + printk("APICT[%02d] Timeout value too large\n", cpu); + apic_tmict = 0xffffffff; + } + if (apic_tmict == 0) { + printk("APICT[%02d] timeout value too small\n", cpu); + return 0; + } + + /* programm timer */ + apic_write(APIC_TMICT, (unsigned long)apic_tmict); + + TRC(printk("APICT[%02d] reprog(): expire=%lld %u\n", + cpu, expire, apic_tmict)); + return 1; } /* @@ -702,29 +697,28 @@ int reprogram_ac_timer(s_time_t timeout) static s_time_t last_cpu0_tirq = 0; inline void smp_local_timer_interrupt(struct pt_regs * regs) { - int cpu = smp_processor_id(); - s_time_t diff, now; - + int cpu = smp_processor_id(); + s_time_t diff, now; /* if CPU 0 do old timer stuff */ - if (cpu == 0) { - - now = NOW(); - diff = now - last_cpu0_tirq; - - if (diff <= 0) { - printk ("System Time went backwards: %lld\n", diff); - return; - } - - while (diff >= MILLISECS(10)) { - do_timer(regs); - diff -= MILLISECS(10); - last_cpu0_tirq += MILLISECS(10); - } - } - /* call accurate timer function */ - do_ac_timer(); + if (cpu == 0) + { + now = NOW(); + diff = now - last_cpu0_tirq; + + if (diff <= 0) { + printk ("System Time went backwards: %lld\n", diff); + return; + } + + while (diff >= MILLISECS(10)) { + do_timer(regs); + diff -= MILLISECS(10); + last_cpu0_tirq += MILLISECS(10); + } + } + /* call accurate timer function */ + do_ac_timer(); } /* @@ -747,9 +741,8 @@ void smp_apic_timer_interrupt(struct pt_regs * regs) apic_timer_irqs[cpu]++; /* - * NOTE! We'd better ACK the irq immediately, - * because timer handling can be slow. - * XXX is this save? + * NOTE! We'd better ACK the irq immediately, because timer handling can + * be slow. XXX is this save? */ ack_APIC_irq(); @@ -825,7 +818,7 @@ int __init APIC_init_uniprocessor (void) * Complain if the BIOS pretends there is one. */ if (!cpu_has_apic&&APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) - { + { printk("BIOS bug, local APIC #%d not detected!...\n", boot_cpu_physical_apicid); return -1; diff --git a/xen-2.4.16/common/ac_timer.c b/xen-2.4.16/common/ac_timer.c index a46ec53d44..8f65ff7093 100644 --- a/xen-2.4.16/common/ac_timer.c +++ b/xen-2.4.16/common/ac_timer.c @@ -44,6 +44,12 @@ #define TRC(_x) #endif +/* + * We pull handlers off the timer list this far in future, + * rather than reprogramming the time hardware. + */ +#define TIMER_SLOP (50*1000) /* ns */ + /* A timer list per CPU */ typedef struct ac_timers_st { @@ -58,8 +64,8 @@ static ac_timers_t ac_timers[NR_CPUS]; #define MAX_STATS typedef struct act_stats_st { - u32 count; - u32 times[2*(BUCKETS)]; + u32 count; + u32 times[2*(BUCKETS)]; } __cacheline_aligned act_stats_t; static act_stats_t act_stats[NR_CPUS]; @@ -79,71 +85,68 @@ static int detach_ac_timer(struct ac_timer *timer); */ int add_ac_timer(struct ac_timer *timer) { - int cpu = smp_processor_id(); - unsigned long flags; - s_time_t now; - - /* sanity checks */ - - /* make sure timeout value is in the future */ - now = NOW(); - TRC(printk("ACT [%02d] add(): now=%lld timo=%lld\n", - cpu, now, timer->expires)); - if (timer->expires <= now) { - printk("ACT[%02d] add_ac_timer: now=0x%08X%08X > expire=0x%08X%08X\n", - cpu, (u32)(now>>32), (u32)now, - (u32)(timer->expires>>32), (u32)timer->expires); - return 1; - } - spin_lock_irqsave(&ac_timers[cpu].lock, flags); - /* + int cpu = smp_processor_id(); + unsigned long flags; + s_time_t now; + + /* make sure timeout value is in the future */ + now = NOW(); + TRC(printk("ACT [%02d] add(): now=%lld timo=%lld\n", + cpu, now, timer->expires)); + if (timer->expires <= now) { + printk("ACT[%02d] add_ac_timer: now=0x%08X%08X > expire=0x%08X%08X\n", + cpu, (u32)(now>>32), (u32)now, + (u32)(timer->expires>>32), (u32)timer->expires); + return 1; + } + spin_lock_irqsave(&ac_timers[cpu].lock, flags); + /* * Add timer to the list. If it gets added to the front we have to * reprogramm the timer */ - if (list_empty(&ac_timers[cpu].timers)) { - /* Reprogramm and add to head of list */ - if (!reprogram_ac_timer(timer->expires)) { - /* failed */ - printk("ACT [%02d] add(): add at head failed\n", cpu); - spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - return 1; - } - list_add(&timer->timer_list, &ac_timers[cpu].timers); - TRC(printk("ACT [%02d] add(0x%08X%08X): added at head\n", cpu, - (u32)(timer->expires>>32), (u32)timer->expires)); - } else { - struct list_head *pos; - struct ac_timer *t; - for (pos = ac_timers[cpu].timers.next; - pos != &ac_timers[cpu].timers; - pos = pos->next) { - t = list_entry(pos, struct ac_timer, timer_list); - if (t->expires > timer->expires) - break; - } - - if (pos->prev == &ac_timers[cpu].timers) { - /* added to head, reprogramm timer */ - if (!reprogram_ac_timer(timer->expires)) { - /* failed */ - TRC(printk("ACT [%02d] add(): add at head failed\n", cpu)); - spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - return 1; - } - list_add (&(timer->timer_list), pos->prev); - TRC(printk("ACT [%02d] add(0x%08X%08X): added at head\n", cpu, - (u32)(timer->expires>>32), (u32)timer->expires)); - } else { - list_add (&(timer->timer_list), pos->prev); - TRC(printk("ACT [%02d] add(0x%08X%08X): add < exp=0x%08X%08X\n", - cpu, - (u32)(timer->expires>>32), (u32)timer->expires, - (u32)(t->expires>>32), (u32)t->expires)); - } - - } - spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - return 0; + if (list_empty(&ac_timers[cpu].timers)) { + /* Reprogramm and add to head of list */ + if (!reprogram_ac_timer(timer->expires)) { + /* failed */ + printk("ACT [%02d] add(): add at head failed\n", cpu); + spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); + return 1; + } + list_add(&timer->timer_list, &ac_timers[cpu].timers); + TRC(printk("ACT [%02d] add(0x%08X%08X): added at head\n", cpu, + (u32)(timer->expires>>32), (u32)timer->expires)); + } else { + struct list_head *pos; + struct ac_timer *t; + for (pos = ac_timers[cpu].timers.next; + pos != &ac_timers[cpu].timers; + pos = pos->next) { + t = list_entry(pos, struct ac_timer, timer_list); + if (t->expires > timer->expires) + break; + } + + if (pos->prev == &ac_timers[cpu].timers) { + /* added to head, reprogramm timer */ + if (!reprogram_ac_timer(timer->expires)) { + /* failed */ + TRC(printk("ACT [%02d] add(): add at head failed\n", cpu)); + spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); + return 1; + } + list_add (&(timer->timer_list), pos->prev); + TRC(printk("ACT [%02d] add(0x%08X%08X): added at head\n", cpu, + (u32)(timer->expires>>32), (u32)timer->expires)); + } else { + list_add (&(timer->timer_list), pos->prev); + TRC(printk("ACT [%02d] add(0x%08X%08X): add < exp=0x%08X%08X\n", + cpu, + (u32)(timer->expires>>32), (u32)timer->expires, + (u32)(t->expires>>32), (u32)t->expires)); + } + } + spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); + return 0; } /* @@ -154,11 +157,11 @@ int add_ac_timer(struct ac_timer *timer) */ static int detach_ac_timer(struct ac_timer *timer) { - TRC(int cpu = smp_processor_id()); - TRC(printk("ACT [%02d] detach(): \n", cpu)); - list_del(&timer->timer_list); - timer->timer_list.next = NULL; - return 0; + TRC(int cpu = smp_processor_id()); + TRC(printk("ACT [%02d] detach(): \n", cpu)); + list_del(&timer->timer_list); + timer->timer_list.next = NULL; + return 0; } /* @@ -169,18 +172,17 @@ static int detach_ac_timer(struct ac_timer *timer) */ int rem_ac_timer(struct ac_timer *timer) { - int cpu = smp_processor_id(); - int res; - unsigned long flags; + int cpu = smp_processor_id(); + int res; + unsigned long flags; - TRC(printk("ACT [%02d] remove(): timo=%lld \n", cpu, timer->expires)); - /* sanity checks */ + TRC(printk("ACT [%02d] remove(): timo=%lld \n", cpu, timer->expires)); - spin_lock_irqsave(&ac_timers[cpu].lock, flags); - res = detach_ac_timer(timer); - spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); + spin_lock_irqsave(&ac_timers[cpu].lock, flags); + res = detach_ac_timer(timer); + spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - return res; + return res; } /* @@ -191,12 +193,12 @@ int rem_ac_timer(struct ac_timer *timer) */ int mod_ac_timer(struct ac_timer *timer, s_time_t new_time) { - if (rem_ac_timer(timer) != 0) - return -1; - timer->expires = new_time; - if (add_ac_timer(timer) != 0) - return -1; - return 0; + if (rem_ac_timer(timer) != 0) + return -1; + timer->expires = new_time; + if (add_ac_timer(timer) != 0) + return -1; + return 0; } /* @@ -205,108 +207,76 @@ int mod_ac_timer(struct ac_timer *timer, s_time_t new_time) */ void do_ac_timer(void) { - int cpu = smp_processor_id(); - unsigned long flags; - s_time_t now; - struct ac_timer *t; - struct list_head *tmp; + int cpu = smp_processor_id(); + unsigned long flags; + struct ac_timer *t; - spin_lock_irqsave(&ac_timers[cpu].lock, flags); + spin_lock_irqsave(&ac_timers[cpu].lock, flags); do_timer_again: - now = NOW(); - TRC(printk("ACT [%02d] do(): now=%lld\n", cpu, now)); + TRC(printk("ACT [%02d] do(): now=%lld\n", cpu, NOW())); - /* Sanity checks */ - /* empty time list */ - if (list_empty(&ac_timers[cpu].timers)) { - printk("ACT[%02d] do_ac_timer(): timer irq without timer\n", cpu); - spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - return; - } - - - /* execute the head of timer queue */ - t = list_entry(ac_timers[cpu].timers.next, struct ac_timer, timer_list); - detach_ac_timer(t); - - spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - + /* Sanity: is the timer list empty? */ + if ( list_empty(&ac_timers[cpu].timers) ) + printk("ACT[%02d] do_ac_timer(): timer irq without timer\n", cpu); #ifdef AC_TIMER_STATS - { - s32 diff; - u32 i; - diff = ((s32)(now - t->expires)) / 1000; /* delta in us */ - if (diff < -BUCKETS) - diff = -BUCKETS; - else if (diff > BUCKETS) - diff = BUCKETS; - act_stats[cpu].times[diff+BUCKETS]++; - act_stats[cpu].count++; - - if (act_stats[cpu].count >= 5000) { - printk("ACT Stats\n"); + { + s32 diff; + u32 i; + diff = ((s32)(NOW() - t->expires)) / 1000; /* delta in us */ + if (diff < -BUCKETS) + diff = -BUCKETS; + else if (diff > BUCKETS) + diff = BUCKETS; + act_stats[cpu].times[diff+BUCKETS]++; + act_stats[cpu].count++; + + if (act_stats[cpu].count >= 5000) { + printk("ACT Stats\n"); for (i=0; i < 2*BUCKETS; i++) { if (act_stats[cpu].times[i] != 0) - printk("ACT [%02d]: %3dus: %5d\n", - cpu,i-BUCKETS, act_stats[cpu].times[i]); - act_stats[cpu].times[i]=0; - } - act_stats[cpu].count = 0; - printk("\n"); - } - } + printk("ACT [%02d]: %3dus: %5d\n", + cpu,i-BUCKETS, act_stats[cpu].times[i]); + act_stats[cpu].times[i]=0; + } + act_stats[cpu].count = 0; + printk("\n"); + } + } #endif - - - if (t->expires > now) { - //printk("ACT [%02d] do(): irq too early (%lld ns)\n", - // cpu, now - t->expires ); - } - if (t->function != NULL) - t->function(t->data); - - - /* check if there are other timer functions on the list */ - now = NOW(); - - spin_lock_irqsave(&ac_timers[cpu].lock, flags); - - if (!list_empty(&ac_timers[cpu].timers)) { - list_for_each(tmp, &ac_timers[cpu].timers) { - t = list_entry(tmp, struct ac_timer, timer_list); - TRC(printk("ACT [%02d] do(): now=%lld timo=%lld\n", - cpu, now, t->expires)); - if (t->expires <= now) { - detach_ac_timer(t); - spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - if (t->function != NULL) - t->function(t->data); - spin_lock_irqsave(&ac_timers[cpu].lock, flags); - now = NOW(); - } else { - TRC(printk("ACT [%02d] do(): break1\n", cpu)); - break; - } - } - } + /* Handle all timeouts in the near future. */ + while ( !list_empty(&ac_timers[cpu].timers) ) + { + t = list_entry(ac_timers[cpu].timers.next, + struct ac_timer, timer_list); + if ( t->expires > (NOW() + TIMER_SLOP) ) break; + detach_ac_timer(t); + spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); + if ( t->function != NULL ) t->function(t->data); + spin_lock_irqsave(&ac_timers[cpu].lock, flags); + } - /* If list not empty reprogramm timer to new head of list */ - if (!list_empty(&ac_timers[cpu].timers)) { - t = list_entry(ac_timers[cpu].timers.next,struct ac_timer,timer_list); - if (t->expires > 0) { - TRC(printk("ACT [%02d] do(): reprog timo=%lld\n",cpu,t->expires)); - if (!reprogram_ac_timer(t->expires)) { - TRC(printk("ACT [%02d] do(): again\n", cpu)); - goto do_timer_again; - } - } - } - spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - TRC(printk("ACT [%02d] do(): end\n", cpu)); + /* If list not empty then reprogram timer to new head of list */ + if ( !list_empty(&ac_timers[cpu].timers) ) + { + t = list_entry(ac_timers[cpu].timers.next, + struct ac_timer, timer_list); + if ( t->expires > 0 ) + { + TRC(printk("ACT [%02d] do(): reprog timo=%lld\n",cpu,t->expires)); + if ( !reprogram_ac_timer(t->expires) ) + { + TRC(printk("ACT [%02d] do(): again\n", cpu)); + goto do_timer_again; + } + } + } + + spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); + TRC(printk("ACT [%02d] do(): end\n", cpu)); } /* @@ -317,16 +287,16 @@ static void dump_tqueue(struct list_head *queue, char *name) { struct list_head *list; int loop = 0; - struct ac_timer *t; + struct ac_timer *t; printk ("QUEUE %s %lx n: %lx, p: %lx\n", name, (unsigned long)queue, (unsigned long) queue->next, (unsigned long) queue->prev); list_for_each (list, queue) { - t = list_entry(list, struct ac_timer, timer_list); + t = list_entry(list, struct ac_timer, timer_list); printk (" %s %d : %lx ex=0x%08X%08X %lu n: %lx, p: %lx\n", - name, loop++, + name, loop++, (unsigned long)list, - (u32)(t->expires>>32), (u32)t->expires, t->data, + (u32)(t->expires>>32), (u32)t->expires, t->data, (unsigned long)list->next, (unsigned long)list->prev); } return; @@ -336,32 +306,30 @@ static void dump_tqueue(struct list_head *queue, char *name) static void dump_timerq(u_char key, void *dev_id, struct pt_regs *regs) { u_long flags; - s_time_t now = NOW(); + s_time_t now = NOW(); printk("Dumping ac_timer queues for cpu 0: NOW=0x%08X%08X\n", - (u32)(now>>32), (u32)now); + (u32)(now>>32), (u32)now); spin_lock_irqsave(&ac_timers[0].lock, flags); dump_tqueue(&ac_timers[0].timers, "ac_time"); spin_unlock_irqrestore(&ac_timers[0].lock, flags); - printk("\n"); + printk("\n"); return; } -/* - * init - */ + void __init ac_timer_init(void) { int i; - printk ("ACT: Initialising Accurate timers\n"); + printk ("ACT: Initialising Accurate timers\n"); for (i = 0; i < NR_CPUS; i++) { - INIT_LIST_HEAD(&ac_timers[i].timers); - spin_lock_init(&ac_timers[i].lock); + INIT_LIST_HEAD(&ac_timers[i].timers); + spin_lock_init(&ac_timers[i].lock); } - add_key_handler('a', dump_timerq, "dump ac_timer queues"); + add_key_handler('a', dump_timerq, "dump ac_timer queues"); } |