diff options
Diffstat (limited to 'xen/common/ac_timer.c')
-rw-r--r-- | xen/common/ac_timer.c | 166 |
1 files changed, 107 insertions, 59 deletions
diff --git a/xen/common/ac_timer.c b/xen/common/ac_timer.c index dc70de4e0c..73ac893e08 100644 --- a/xen/common/ac_timer.c +++ b/xen/common/ac_timer.c @@ -23,7 +23,6 @@ #include <xeno/errno.h> #include <xeno/sched.h> #include <xeno/lib.h> -#include <xeno/config.h> #include <xeno/smp.h> #include <xeno/perfc.h> @@ -41,10 +40,10 @@ #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 */ @@ -58,30 +57,29 @@ static ac_timers_t ac_timers[NR_CPUS]; /* local prototypes */ static int detach_ac_timer(struct ac_timer *timer); -/*static void ac_timer_debug(unsigned long);*/ -/* + +/***************************************************************************** * add a timer. * return value: * 0: success * 1: failure, timer in the past or timeout value to small * -1: failure, timer uninitialised * fail - */ + *****************************************************************************/ int add_ac_timer(struct ac_timer *timer) { - int cpu = smp_processor_id(); - unsigned long flags; - s_time_t now; + 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); + if (timer->expires <= now) { + TRC(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); @@ -90,71 +88,57 @@ int add_ac_timer(struct ac_timer *timer) * 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); + printk("ACT[%02d] add at head failed\n", cpu); spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - return 1; + return 1; /* failed */ } 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) { + struct ac_timer *t; + + list_for_each(pos, &ac_timers[cpu].timers) { t = list_entry(pos, struct ac_timer, timer_list); if (t->expires > timer->expires) break; } + list_add (&(timer->timer_list), pos->prev); - if (pos->prev == &ac_timers[cpu].timers) { - /* added to head, reprogramm timer */ + if (timer->timer_list.prev == &ac_timers[cpu].timers) { + /* added at head */ if (!reprogram_ac_timer(timer->expires)) { - /* failed */ - TRC(printk("ACT [%02d] add(): add at head failed\n", cpu)); + printk("ACT[%02d] add at head failed\n", cpu); + detach_ac_timer(timer); spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); - return 1; + return 1; /* failed */ } - 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; } -/* - * remove a timer +/***************************************************************************** + * detach a timer (no locking) * return values: * 0: success * -1: bogus 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; } -/* +/***************************************************************************** * remove a timer * return values: * 0: success * -1: bogus timer - */ + *****************************************************************************/ int rem_ac_timer(struct ac_timer *timer) { int cpu = smp_processor_id(); @@ -163,19 +147,30 @@ int rem_ac_timer(struct ac_timer *timer) TRC(printk("ACT [%02d] remove(): timo=%lld \n", cpu, timer->expires)); spin_lock_irqsave(&ac_timers[cpu].lock, flags); - if (timer->timer_list.next) - res = detach_ac_timer(timer); + if (timer->timer_list.next) { + res = detach_ac_timer(timer); + + if (timer->timer_list.prev == &ac_timers[cpu].timers) { + /* just removed the head */ + if (list_empty(&ac_timers[cpu].timers)) { + reprogram_ac_timer((s_time_t) 0); + } + /* XXX should actaully reprogramm APIC to new head */ + } + } else + res = -1; + spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); return res; } -/* +/***************************************************************************** * modify a timer, i.e., set a new timeout value * return value: * 0: sucess * -1: error - */ + *****************************************************************************/ int mod_ac_timer(struct ac_timer *timer, s_time_t new_time) { if (rem_ac_timer(timer) != 0) @@ -186,10 +181,10 @@ int mod_ac_timer(struct ac_timer *timer, s_time_t new_time) return 0; } -/* +/***************************************************************************** * do_ac_timer * deal with timeouts and run the handlers - */ + *****************************************************************************/ void do_ac_timer(void) { int cpu = smp_processor_id(); @@ -206,15 +201,21 @@ void do_ac_timer(void) /* 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); + /* + * XXX RN: This shouldn't happen, but does! Two possibilities: + * - Race condition between removing and reseting APIC + * - setting an APIC timeout value of 0 causes an immediate + * timer interrupt to fire. + * None of these should be critical! + */ + spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); return; } /* 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); + t = list_entry(ac_timers[cpu].timers.next,struct ac_timer, timer_list); if ( t->expires > (NOW() + TIMER_SLOP) ) break; /* do some stats */ @@ -232,8 +233,7 @@ void do_ac_timer(void) /* 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); + 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)); @@ -243,16 +243,18 @@ void do_ac_timer(void) goto do_timer_again; } } + } else { + reprogram_ac_timer((s_time_t) 0); } spin_unlock_irqrestore(&ac_timers[cpu].lock, flags); TRC(printk("ACT [%02d] do(): end\n", cpu)); } -/* +/***************************************************************************** * debug dump_queue * arguments: queue head, name of queue - */ + *****************************************************************************/ static void dump_tqueue(struct list_head *queue, char *name) { struct list_head *list; @@ -272,7 +274,6 @@ static void dump_tqueue(struct list_head *queue, char *name) return; } - void dump_timerq(u_char key, void *dev_id, struct pt_regs *regs) { u_long flags; @@ -304,3 +305,50 @@ void __init ac_timer_init(void) spin_lock_init(&ac_timers[i].lock); } } + +/***************************************************************************** + * GRAVEYARD + *****************************************************************************/ + +#if 0 + +#ifdef AC_TIMER_STATS +#define BUCKETS 1000 +#define MAX_STATS +typedef struct act_stats_st +{ + u32 count; + u32 times[2*(BUCKETS)]; +} __cacheline_aligned act_stats_t; +static act_stats_t act_stats[NR_CPUS]; + +#endif + +#ifdef AC_TIMER_STATS + { + XXX this is at the wrong place + 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"); + } + } +#endif + +#endif /* 0 */ |