aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/ac_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'xen/common/ac_timer.c')
-rw-r--r--xen/common/ac_timer.c166
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 */