aboutsummaryrefslogtreecommitdiffstats
path: root/xen-2.4.16
diff options
context:
space:
mode:
authorrn@wyvis.camb.intel-research.net <rn@wyvis.camb.intel-research.net>2003-02-15 18:02:39 +0000
committerrn@wyvis.camb.intel-research.net <rn@wyvis.camb.intel-research.net>2003-02-15 18:02:39 +0000
commit2a4fc83e744d392f0afff613175e5a8bdb2427e4 (patch)
tree191624de234b53e70844f2e076fab17b73f5ba79 /xen-2.4.16
parentce62d9e7f6d76422b025939279a2a51b5262a06d (diff)
downloadxen-2a4fc83e744d392f0afff613175e5a8bdb2427e4.tar.gz
xen-2a4fc83e744d392f0afff613175e5a8bdb2427e4.tar.bz2
xen-2a4fc83e744d392f0afff613175e5a8bdb2427e4.zip
bitkeeper revision 1.33.2.1 (3e4e80bfKovSGNhpWOvbDx2coqfMIw)
clean up of time/timer code: No PIT timer anymore and bugfixes to timer code
Diffstat (limited to 'xen-2.4.16')
-rw-r--r--xen-2.4.16/arch/i386/apic.c28
-rw-r--r--xen-2.4.16/arch/i386/i8259.c12
-rw-r--r--xen-2.4.16/arch/i386/setup.c8
-rw-r--r--xen-2.4.16/arch/i386/time.c98
-rw-r--r--xen-2.4.16/common/ac_timer.c130
-rw-r--r--xen-2.4.16/common/schedule.c30
-rw-r--r--xen-2.4.16/common/timer.c15
-rw-r--r--xen-2.4.16/include/asm-i386/time.h3
8 files changed, 209 insertions, 115 deletions
diff --git a/xen-2.4.16/arch/i386/apic.c b/xen-2.4.16/arch/i386/apic.c
index 1fe5c16371..691240ad61 100644
--- a/xen-2.4.16/arch/i386/apic.c
+++ b/xen-2.4.16/arch/i386/apic.c
@@ -697,37 +697,29 @@ int reprogram_ac_timer(s_time_t timeout)
* the timer APIC on CPU does not go off every 10ms or so the linux
* timers loose accuracy, but that shouldn't be a problem.
*/
-//static s_time_t last_cpu0_tirq = 0;
+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;
+ s_time_t diff, now;
+
/* if CPU 0 do old timer stuff */
if (cpu == 0) {
- /*
- * XXX RN: the following code should be moved here or somewhere
- * else. It's currently done using the 8255 timer interrupt, which
- * I'd like to disable. But, APIC initialisation relies on it,
- * e.g., timer interrupts coming in, jiffies going up, etc. Need to
- * clean this up. Also see ./arch/i386/time.c
- */
-#if 0
- //update_time();/* XXX should use a timer for this */
now = NOW();
diff = now - last_cpu0_tirq;
- /* this uses three 64bit divisions which should be avoided!! */
- if (diff >= MILLISECS(10)) {
- /* update jiffies */
- (*(unsigned long *)&jiffies) += diff / MILLISECS(10);
+ if (diff <= 0) {
+ printk ("System Time went backwards: %lld\n", diff);
+ return;
+ }
- /* do traditional linux timers */
+ while (diff >= MILLISECS(10)) {
do_timer(regs);
- last_cpu0_tirq = now;
+ diff -= MILLISECS(10);
+ last_cpu0_tirq += MILLISECS(10);
}
-#endif
}
/* call accurate timer function */
do_ac_timer();
diff --git a/xen-2.4.16/arch/i386/i8259.c b/xen-2.4.16/arch/i386/i8259.c
index 9c6ccc2d93..645b7b0fef 100644
--- a/xen-2.4.16/arch/i386/i8259.c
+++ b/xen-2.4.16/arch/i386/i8259.c
@@ -467,3 +467,15 @@ void __init init_IRQ(void)
setup_irq(2, &irq2);
}
+
+/*
+ * we only need the timer interrupt for callibrating the tsc<->time<->bus cycle
+ * mappings. After this all timeing related functions should be run of the
+ * APIC timers. This function allows us to disable the
+ */
+void __init disable_pit(void)
+{
+ printk("Disable PIT. Not needed anymore\n");
+ /* This is not the most elegant way, but hey. */
+ disable_irq(0);
+}
diff --git a/xen-2.4.16/arch/i386/setup.c b/xen-2.4.16/arch/i386/setup.c
index 63dac2cbe3..ad33a1e843 100644
--- a/xen-2.4.16/arch/i386/setup.c
+++ b/xen-2.4.16/arch/i386/setup.c
@@ -280,6 +280,7 @@ void __init start_of_day(void)
extern void tqueue_bh(void);
extern void immediate_bh(void);
extern void init_timervecs(void);
+ extern void disable_pit(void);
extern void ac_timer_init(void);
extern int setup_network_devices(void);
extern void net_init(void);
@@ -329,8 +330,11 @@ void __init start_of_day(void)
* fall thru to 8259A if we have to (but slower).
*/
#endif
- init_xeno_time(); /* initialise the time */
+ initialize_keytable(); /* call back handling for key codes */
+
+ disable_pit(); /* not needed anymore */
ac_timer_init(); /* init accurate timers */
+ init_xeno_time(); /* initialise the time */
schedulers_start(); /* start scheduler for each CPU */
sti();
@@ -343,7 +347,7 @@ void __init start_of_day(void)
#endif
do_initcalls();
- initialize_keytable(); /* call back handling for key codes */
+
initialize_serial(); /* setup serial 'driver' (for debugging) */
initialize_keyboard(); /* setup keyboard (also for debugging) */
diff --git a/xen-2.4.16/arch/i386/time.c b/xen-2.4.16/arch/i386/time.c
index d090fe46bc..ef9417e88a 100644
--- a/xen-2.4.16/arch/i386/time.c
+++ b/xen-2.4.16/arch/i386/time.c
@@ -31,6 +31,7 @@
#include <xeno/init.h>
#include <xeno/interrupt.h>
#include <xeno/time.h>
+#include <xeno/ac_timer.h>
#include <asm/io.h>
#include <xeno/smp.h>
@@ -74,15 +75,12 @@ static inline void do_timer_interrupt(int irq,
spin_unlock(&i8259A_lock);
}
#endif
-
- /* XXX RN: Want to remove this but APIC-SMP code seems to rely on it */
do_timer(regs);
}
/*
- * This is the same as the above, except we _also_ save the current
- * Time Stamp Counter value at the time of the timer interrupt, so that
- * we later on can estimate the time of day more exactly.
+ * This is only temporarily. Once the APIC s up and running this
+ * timer interrupt is turned off.
*/
static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
@@ -303,8 +301,34 @@ void do_settimeofday(struct timeval *tv)
/***************************************************************************
* Update times
***************************************************************************/
-/* update hypervisors notion of time */
-void update_time(void) {
+
+/* update a domains notion of time */
+void update_dom_time(shared_info_t *si)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&stime_lock, flags);
+ si->system_time = stime_now;
+ si->st_timestamp = stime_pcc;
+ spin_unlock_irqrestore(&stime_lock, flags);
+
+ spin_lock_irqsave(&wctime_lock, flags);
+ si->tv_sec = wall_clock_time.tv_sec;
+ si->tv_usec = wall_clock_time.tv_usec;
+ si->wc_timestamp = wctime_st;
+ si->wc_version++;
+ spin_unlock_irqrestore(&wctime_lock, flags);
+
+ TRC(printk(" 0x%08X%08X\n", (u32)(wctime_st>>32), (u32)wctime_st));
+}
+
+/*
+ * Update hypervisors notion of time
+ * This is done periodically of it's own timer
+ */
+static struct ac_timer update_timer;
+static void update_time(unsigned long foo)
+{
unsigned long flags;
u32 new_pcc;
s_time_t new_st;
@@ -336,26 +360,12 @@ void update_time(void) {
TRC(printk("TIME[%02d] update time: stime_now=%lld now=%lld,wct=%ld:%ld\n",
smp_processor_id(), stime_now, new_st, wall_clock_time.tv_sec,
wall_clock_time.tv_usec));
-}
-
-/* update a domains notion of time */
-void update_dom_time(shared_info_t *si)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&stime_lock, flags);
- si->system_time = stime_now;
- si->st_timestamp = stime_pcc;
- spin_unlock_irqrestore(&stime_lock, flags);
-
- spin_lock_irqsave(&wctime_lock, flags);
- si->tv_sec = wall_clock_time.tv_sec;
- si->tv_usec = wall_clock_time.tv_usec;
- si->wc_timestamp = wctime_st;
- si->wc_version++;
- spin_unlock_irqrestore(&wctime_lock, flags);
-
- TRC(printk(" 0x%08X%08X\n", (u32)(wctime_st>>32), (u32)wctime_st));
+ /* reload timer */
+ again:
+ update_timer.expires = new_st + MILLISECS(200);
+ if(add_ac_timer(&update_timer) == 1) {
+ goto again;
+ }
}
/***************************************************************************
@@ -364,13 +374,15 @@ void update_dom_time(shared_info_t *si)
***************************************************************************/
int __init init_xeno_time()
{
- int cpu = smp_processor_id();
- u32 cpu_cycle; /* time of one cpu cyle in pico-seconds */
- u64 scale;
+ int cpu = smp_processor_id();
+ u32 cpu_cycle; /* time of one cpu cyle in pico-seconds */
+ u64 scale; /* scale factor */
spin_lock_init(&stime_lock);
spin_lock_init(&wctime_lock);
+ printk("Init Time[%02d]:\n", cpu);
+
/* System Time */
cpu_cycle = (u32) (1000000000LL/cpu_khz); /* in pico seconds */
scale = 1000000000LL << 32;
@@ -378,24 +390,30 @@ int __init init_xeno_time()
st_scale_f = scale & 0xffffffff;
st_scale_i = scale >> 32;
- stime_now = (s_time_t)0;
- rdtscl(stime_pcc);
-
- printk("Init Time[%02d]:\n", cpu);
- printk(".... System Time: %lldns\n", NOW());
- printk(".....cpu_cycle: %u ps\n", cpu_cycle);
- printk(".... st_scale_f: %X\n", st_scale_f);
- printk(".... st_scale_i: %X\n", st_scale_i);
- printk(".... stime_pcc: %u\n", stime_pcc);
-
/* Wall Clock time */
wall_clock_time.tv_sec = get_cmos_time();
wall_clock_time.tv_usec = 0;
+
+ /* set starting times */
+ stime_now = (s_time_t)0;
+ rdtscl(stime_pcc);
wctime_st = NOW();
+ /* start timer to update time periodically */
+ init_ac_timer(&update_timer);
+ update_timer.function = &update_time;
+ update_time(0);
+
+ printk(".... System Time: %lldns\n", NOW());
+ printk(".....cpu_cycle: %u ps\n", cpu_cycle);
+ printk(".... st_scale_f: %X\n", st_scale_f);
+ printk(".... st_scale_i: %X\n", st_scale_i);
+ printk(".... stime_pcc: %u\n", stime_pcc);
+
printk(".... Wall Clock: %lds %ldus\n", wall_clock_time.tv_sec,
wall_clock_time.tv_usec);
printk(".... wctime_st: %lld\n", wctime_st);
+
return 0;
}
diff --git a/xen-2.4.16/common/ac_timer.c b/xen-2.4.16/common/ac_timer.c
index b20efc94c9..a46ec53d44 100644
--- a/xen-2.4.16/common/ac_timer.c
+++ b/xen-2.4.16/common/ac_timer.c
@@ -29,6 +29,7 @@
#include <xeno/time.h>
#include <xeno/ac_timer.h>
+#include <xeno/keyhandler.h>
#include <asm/system.h>
#include <asm/desc.h>
@@ -80,8 +81,6 @@ int add_ac_timer(struct ac_timer *timer)
{
int cpu = smp_processor_id();
unsigned long flags;
- struct list_head *tmp, *prev;
- struct ac_timer *t;
s_time_t now;
/* sanity checks */
@@ -96,42 +95,54 @@ int add_ac_timer(struct ac_timer *timer)
(u32)(timer->expires>>32), (u32)timer->expires);
return 1;
}
-
- local_irq_save(flags);
-
- /* check if timer would be inserted at start of list */
- if ((list_empty(&ac_timers[cpu].timers)) ||
- (timer->expires <
- (list_entry(&ac_timers[cpu].timers,
- struct ac_timer, timer_list))->expires)) {
-
- TRC(printk("ACT [%02d] add(): add at head\n", cpu));
+ 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 */
- TRC(printk("ACT [%02d] add(): add at head failed\n", cpu));
- local_irq_restore(flags);
+ 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 {
- /* find correct entry and add timer */
- prev = &ac_timers[cpu].timers;
- list_for_each(tmp, &ac_timers[cpu].timers) {
- t = list_entry(tmp, struct ac_timer, timer_list);
- if (t->expires < timer->expires) {
- list_add(&timer->timer_list, prev);
- TRC(printk("ACT [%02d] add(): added between %lld and %lld\n",
- cpu,
- list_entry(prev,struct ac_timer,timer_list)->expires,
- list_entry(tmp,struct ac_timer,timer_list)->expires));
+ 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;
}
- prev = tmp;
+ 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));
}
+
}
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
return 0;
}
@@ -158,16 +169,17 @@ static int detach_ac_timer(struct ac_timer *timer)
*/
int rem_ac_timer(struct ac_timer *timer)
{
- int res;
+ int cpu = smp_processor_id();
+ int res;
unsigned long flags;
- TRC(int cpu = smp_processor_id());
TRC(printk("ACT [%02d] remove(): timo=%lld \n", cpu, timer->expires));
/* sanity checks */
- local_irq_save(flags);
+ spin_lock_irqsave(&ac_timers[cpu].lock, flags);
res = detach_ac_timer(timer);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
+
return res;
}
@@ -199,7 +211,7 @@ void do_ac_timer(void)
struct ac_timer *t;
struct list_head *tmp;
- local_irq_save(flags);
+ spin_lock_irqsave(&ac_timers[cpu].lock, flags);
do_timer_again:
@@ -210,7 +222,7 @@ void do_ac_timer(void)
/* empty time list */
if (list_empty(&ac_timers[cpu].timers)) {
printk("ACT[%02d] do_ac_timer(): timer irq without timer\n", cpu);
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
return;
}
@@ -219,6 +231,8 @@ void do_ac_timer(void)
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);
+
#ifdef AC_TIMER_STATS
{
@@ -258,6 +272,9 @@ void do_ac_timer(void)
/* 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);
@@ -265,8 +282,10 @@ void do_ac_timer(void)
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));
@@ -286,7 +305,47 @@ void do_ac_timer(void)
}
}
}
- local_irq_restore(flags);
+ 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;
+ int loop = 0;
+ 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);
+ printk (" %s %d : %lx ex=0x%08X%08X %lu n: %lx, p: %lx\n",
+ name, loop++,
+ (unsigned long)list,
+ (u32)(t->expires>>32), (u32)t->expires, t->data,
+ (unsigned long)list->next, (unsigned long)list->prev);
+ }
+ return;
+}
+
+
+static void dump_timerq(u_char key, void *dev_id, struct pt_regs *regs)
+{
+ u_long flags;
+ s_time_t now = NOW();
+
+ printk("Dumping ac_timer queues for cpu 0: NOW=0x%08X%08X\n",
+ (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");
+ return;
}
/*
@@ -303,5 +362,6 @@ void __init ac_timer_init(void)
INIT_LIST_HEAD(&ac_timers[i].timers);
spin_lock_init(&ac_timers[i].lock);
}
- /* ac_timer_debug(0); */
+
+ add_key_handler('a', dump_timerq, "dump ac_timer queues");
}
diff --git a/xen-2.4.16/common/schedule.c b/xen-2.4.16/common/schedule.c
index a1c0c406ee..289e69374b 100644
--- a/xen-2.4.16/common/schedule.c
+++ b/xen-2.4.16/common/schedule.c
@@ -282,6 +282,9 @@ asmlinkage void schedule(void)
return;
}
+/*
+ * The scheduling timer.
+ */
static __cacheline_aligned int count[NR_CPUS];
static void sched_timer(unsigned long foo)
{
@@ -290,14 +293,35 @@ static void sched_timer(unsigned long foo)
s_time_t now;
int res;
+ /* reschedule after each 5 ticks */
if (count[cpu] >= 5) {
set_bit(_HYP_EVENT_NEED_RESCHED, &curr->hyp_events);
count[cpu] = 0;
- if (cpu == 0)
- update_time(); /* XXX RN: Should be moved on its own timer */
}
count[cpu]++;
+ /*
+ * deliver virtual timer interrups to domains if we are CPU 0
+ * XXX RN: We don't have a per CPU list of domains yet. Otherwise
+ * would use that. Plus, this should be removed anyway once
+ * Domains "know" about virtual time and timeouts. But, it's better
+ * here then where it was before.
+ */
+ if (cpu == 0) {
+ struct task_struct *p;
+ unsigned long cpu_mask = 0;
+
+ /* send virtual timer interrupt */
+ read_lock(&tasklist_lock);
+ p = &idle0_task;
+ do {
+ cpu_mask |= mark_guest_event(p, _EVENT_TIMER);
+ }
+ while ( (p = p->next_task) != &idle0_task );
+ read_unlock(&tasklist_lock);
+ guest_event_notify(cpu_mask);
+ }
+
again:
now = NOW();
s_timer[cpu].expires = now + MILLISECS(10);
@@ -310,6 +334,8 @@ static void sched_timer(unsigned long foo)
goto again;
}
+
+
/*
* Initialise the data structures
*/
diff --git a/xen-2.4.16/common/timer.c b/xen-2.4.16/common/timer.c
index da0452249e..20d45ccbe6 100644
--- a/xen-2.4.16/common/timer.c
+++ b/xen-2.4.16/common/timer.c
@@ -586,27 +586,12 @@ void timer_bh(void)
void do_timer(struct pt_regs *regs)
{
- struct task_struct *p;
- shared_info_t *s;
- unsigned long cpu_mask = 0;
(*(unsigned long *)&jiffies)++;
if ( !using_apic_timer )
update_process_times(user_mode(regs));
- /* XXX RN: Move this for virtual domain time timer interrupts */
- read_lock(&tasklist_lock);
- p = &idle0_task;
- do {
- s = p->shared_info;
- cpu_mask |= mark_guest_event(p, _EVENT_TIMER);
- }
- while ( (p = p->next_task) != &idle0_task );
- read_unlock(&tasklist_lock);
-
- guest_event_notify(cpu_mask);
-
mark_bh(TIMER_BH);
if (TQ_ACTIVE(tq_timer))
mark_bh(TQUEUE_BH);
diff --git a/xen-2.4.16/include/asm-i386/time.h b/xen-2.4.16/include/asm-i386/time.h
index 9825847be1..2f834908a7 100644
--- a/xen-2.4.16/include/asm-i386/time.h
+++ b/xen-2.4.16/include/asm-i386/time.h
@@ -41,9 +41,6 @@ typedef s64 s_time_t; /* System time */
extern u32 stime_pcc; /* cycle counter value at last timer irq */
extern s_time_t stime_now; /* time in ns at last timer IRQ */
-/* update time variables once in a while */
-extern void update_time(void);
-
/*
* Domain Virtual Time
*/