diff options
author | rn@wyvis.camb.intel-research.net <rn@wyvis.camb.intel-research.net> | 2003-02-15 18:02:55 +0000 |
---|---|---|
committer | rn@wyvis.camb.intel-research.net <rn@wyvis.camb.intel-research.net> | 2003-02-15 18:02:55 +0000 |
commit | 93e9e565c6fdf01518d45616c4be8d8c317cfe6e (patch) | |
tree | ffc7a175cea67cabc893e90434ae7461a0cf9f65 /xen-2.4.16 | |
parent | 6f9fc0c96168c2d12db534def94be23aba38df82 (diff) | |
parent | 2a4fc83e744d392f0afff613175e5a8bdb2427e4 (diff) | |
download | xen-93e9e565c6fdf01518d45616c4be8d8c317cfe6e.tar.gz xen-93e9e565c6fdf01518d45616c4be8d8c317cfe6e.tar.bz2 xen-93e9e565c6fdf01518d45616c4be8d8c317cfe6e.zip |
bitkeeper revision 1.41.1.1 (3e4e80cfbdyhVKkZcnejMmjBdH935A)
Merge wyvis.camb.intel-research.net:/home/rn/src/xeno/xeno
into wyvis.camb.intel-research.net:/home/rn/src/xeno/xeno-sched
Diffstat (limited to 'xen-2.4.16')
-rw-r--r-- | xen-2.4.16/arch/i386/apic.c | 28 | ||||
-rw-r--r-- | xen-2.4.16/arch/i386/i8259.c | 12 | ||||
-rw-r--r-- | xen-2.4.16/arch/i386/setup.c | 8 | ||||
-rw-r--r-- | xen-2.4.16/arch/i386/time.c | 98 | ||||
-rw-r--r-- | xen-2.4.16/common/ac_timer.c | 130 | ||||
-rw-r--r-- | xen-2.4.16/common/schedule.c | 30 | ||||
-rw-r--r-- | xen-2.4.16/common/timer.c | 15 | ||||
-rw-r--r-- | xen-2.4.16/include/asm-i386/time.h | 3 |
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 */ |