diff -Nru linux/arch/mips64/kernel/time.c.orig linux/arch/mips64/kernel/time.c --- linux/arch/mips64/kernel/time.c.orig Thu Jan 24 15:14:25 2002 +++ linux/arch/mips64/kernel/time.c Thu Apr 18 17:53:35 2002 @@ -39,6 +39,11 @@ extern volatile unsigned long wall_jiffies; /* + * whether we emulate local_timer_interrupts for SMP machines. + */ +int emulate_local_timer_interrupt; + +/* * By default we provide the null RTC ops */ static unsigned long null_rtc_get_time(void) @@ -283,6 +288,42 @@ /* + * local_timer_interrupt() does profiling and process accounting + * on a per-CPU basis. + * + * In UP mode, it is invoked from the (global) timer_interrupt. + * + * In SMP mode, it might invoked by per-CPU timer interrupt, or + * a broadcasted inter-processor interrupt which itself is triggered + * by the global timer interrupt. + */ +void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + if(!user_mode(regs)) { + if (prof_buffer && current->pid) { + extern int _stext; + unsigned long pc = regs->cp0_epc; + + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + /* + * Dont ignore out-of-bounds pc values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (pc > prof_len-1) + pc = prof_len-1; + atomic_inc((atomic_t *)&prof_buffer[pc]); + } + } + +#if defined(CONFIG_SMP) + /* in UP mode, update_process_times() is invoked by do_timer() */ + update_process_times(user_mode(regs)); +#endif +} + +/* * high-level timer interrupt service routines. This function * is set as irqaction->handler and is invoked through do_IRQ. */ @@ -309,24 +350,6 @@ } - if(!user_mode(regs)) { - if (prof_buffer && current->pid) { - extern int _stext; - unsigned long pc = regs->cp0_epc; - - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - /* - * Dont ignore out-of-bounds pc values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len-1) - pc = prof_len-1; - atomic_inc((atomic_t *)&prof_buffer[pc]); - } - } - /* * call the generic timer interrupt handling */ @@ -359,6 +382,31 @@ if (!jiffies) { timerhi = timerlo = 0; } + +#if !defined(CONFIG_SMP) + /* + * In UP mode, we call local_timer_interrupt() to do profiling + * and process accouting. + * + * In SMP mode, local_timer_interrupt() is invoked by appropriate + * low-level local timer interrupt handler. + */ + local_timer_interrupt(0, NULL, regs); + +#else /* CONFIG_SMP */ + + if (emulate_local_timer_interrupt) { + /* + * this is the place where we send out inter-process + * interrupts and let each CPU do its own profiling + * and process accouting. + * + * Obviously we need to call local_timer_interrupt() for + * the current CPU too. + */ + panic("Not implemented yet!!!"); + } +#endif /* CONFIG_SMP */ } asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs) @@ -377,6 +425,21 @@ do_softirq(); } +asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; + + /* we keep interrupt disabled all the time */ + local_timer_interrupt(irq, NULL, regs); + + irq_exit(cpu, irq); + + if (softirq_pending(cpu)) + do_softirq(); +} /* * time_init() - it does the following things. diff -Nru linux/include/asm-mips64/time.h.orig linux/include/asm-mips64/time.h --- linux/include/asm-mips64/time.h.orig Thu Apr 18 17:42:02 2002 +++ linux/include/asm-mips64/time.h Thu Apr 18 18:13:29 2002 @@ -1,5 +1,5 @@ /* - * Copyright 2001 MontaVista Software Inc. + * Copyright (C) 2001, 2002, MontaVista Software Inc. * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net * * include/asm-mips/time.h @@ -59,6 +59,12 @@ * the corresponding low-level timer interrupt routine. */ asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs); + +/* + * profiling and process accouting is done separately in local_timer_interrupt + */ +void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs); +asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs); /* * board specific routines required by time_init().