From: Ralf Baechle <ralf@xxxxxxxxxxxxxx> --- arch/mips/au1000/common/irq.c | 3 +- arch/mips/au1000/common/time.c | 40 -------------- arch/mips/kernel/smtc.c | 2 +- arch/mips/kernel/time.c | 81 +++++++++++++++++++++++++--- arch/mips/mips-boards/generic/time.c | 97 ---------------------------------- arch/mips/mips-boards/sim/sim_time.c | 70 ------------------------ arch/mips/sgi-ip22/ip22-int.c | 3 +- arch/mips/sgi-ip22/ip22-time.c | 10 ---- arch/mips/sibyte/bcm1480/time.c | 13 +---- arch/mips/sibyte/sb1250/time.c | 13 +---- include/asm-mips/time.h | 5 +- 11 files changed, 80 insertions(+), 257 deletions(-) diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c index ea6e99f..cb33d9e 100644 --- a/arch/mips/au1000/common/irq.c +++ b/arch/mips/au1000/common/irq.c @@ -67,7 +67,6 @@ extern void set_debug_traps(void); extern irq_cpustat_t irq_stat [NR_CPUS]; -extern void mips_timer_interrupt(void); static void setup_local_irq(unsigned int irq, int type, int int_req); static void end_irq(unsigned int irq_nr); @@ -646,7 +645,7 @@ asmlinkage void plat_irq_dispatch(void) unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; if (pending & CAUSEF_IP7) - mips_timer_interrupt(); + ll_timer_interrupt(63); else if (pending & CAUSEF_IP2) intc0_req0_irqdispatch(); else if (pending & CAUSEF_IP3) diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index b32bf46..7028025 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -64,48 +64,8 @@ static unsigned long last_pc0, last_match20; static DEFINE_SPINLOCK(time_lock); -static inline void ack_r4ktimer(unsigned long newval) -{ - write_c0_compare(newval); -} - -/* - * There are a lot of conceptually broken versions of the MIPS timer interrupt - * handler floating around. This one is rather different, but the algorithm - * is provably more robust. - */ unsigned long wtimer; -void mips_timer_interrupt(void) -{ - int irq = 63; - - irq_enter(); - kstat_this_cpu.irqs[irq]++; - - if (r4k_offset == 0) - goto null; - - do { - kstat_this_cpu.irqs[irq]++; - do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif - r4k_cur += r4k_offset; - ack_r4ktimer(r4k_cur); - - } while (((unsigned long)read_c0_count() - - r4k_cur) < 0x7fffffff); - - irq_exit(); - return; - -null: - ack_r4ktimer(0); - irq_exit(); -} - #ifdef CONFIG_PM irqreturn_t counter0_irq(int irq, void *dev_id) { diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index 21eb599..8b95808 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -828,7 +828,7 @@ void ipi_decode(struct smtc_ipi *pipi) #ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG clock_hang_reported[dest_copy] = 0; #endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ - local_timer_interrupt(0, NULL); + local_timer_interrupt(0); irq_exit(); break; case LINUX_SMP_IPI: diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index d176e91..a75d63b 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -131,7 +131,7 @@ void (*mips_timer_ack)(void); * a broadcasted inter-processor interrupt which itself is triggered * by the global timer interrupt. */ -void local_timer_interrupt(int irq, void *dev_id) +void local_timer_interrupt(int irq) { profile_tick(CPU_PROFILING); update_process_times(user_mode(get_irq_regs())); @@ -161,7 +161,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) * In SMP mode, local_timer_interrupt() is invoked by appropriate * low-level local timer interrupt handler. */ - local_timer_interrupt(irq, dev_id); + local_timer_interrupt(irq); return IRQ_HANDLED; } @@ -171,9 +171,10 @@ int null_perf_irq(void) return 0; } +EXPORT_SYMBOL(null_perf_irq); + int (*perf_irq)(void) = null_perf_irq; -EXPORT_SYMBOL(null_perf_irq); EXPORT_SYMBOL(perf_irq); /* @@ -186,7 +187,7 @@ EXPORT_SYMBOL(mipsxx_perfcount_irq); * Possibly handle a performance counter interrupt. * Return true if the timer interrupt should not be checked */ -static inline int handle_perf_irq (int r2) +static inline int handle_perf_irq(int r2) { /* * The performance counter overflow interrupt may be shared with the @@ -200,25 +201,89 @@ static inline int handle_perf_irq (int r2) !r2; } -asmlinkage void ll_timer_interrupt(int irq) +extern void smtc_timer_broadcast(int); + +void ll_timer_interrupt(int irq) { + int cpu = smp_processor_id(); int r2 = cpu_has_mips_r2; irq_enter(); kstat_this_cpu.irqs[irq]++; +#ifdef CONFIG_MIPS_MT_SMTC + /* + * In an SMTC system, one Count/Compare set exists per VPE. + * Which TC within a VPE gets the interrupt is essentially + * random - we only know that it shouldn't be one with + * IXMT set. Whichever TC gets the interrupt needs to + * send special interprocessor interrupts to the other + * TCs to make sure that they schedule, etc. + * + * That code is specific to the SMTC kernel, not to + * the a particular platform, so it's invoked from + * the general MIPS timer_interrupt routine. + */ + + /* + * We could be here due to timer interrupt, + * perf counter overflow, or both. + */ + (void) handle_perf_irq(1); + + if (read_c0_cause() & (1 << 30)) { + /* + * There are things we only want to do once per tick + * in an "MP" system. One TC of each VPE will take + * the actual timer interrupt. The others will get + * timer broadcast IPIs. We use whoever it is that takes + * the tick on VPE 0 to run the full timer_interrupt(). + */ + if (cpu_data[cpu].vpe_id == 0) { + timer_interrupt(irq, NULL); + } else { + write_c0_compare(read_c0_count() + + (mips_hpt_frequency/HZ)); + local_timer_interrupt(irq); + } + smtc_timer_broadcast(cpu_data[cpu].vpe_id); + } +#else /* CONFIG_MIPS_MT_SMTC */ if (handle_perf_irq(r2)) goto out; if (r2 && ((read_c0_cause() & (1 << 30)) == 0)) goto out; - timer_interrupt(irq, NULL); - + if (cpu == 0) { + /* + * CPU 0 handles the global timer interrupt job and process + * accounting resets count/compare registers to trigger next + * timer int. + */ + timer_interrupt(irq, NULL); + } else { + /* Everyone else needs to reset the timer int here as + ll_local_timer_interrupt doesn't */ + /* + * FIXME: need to cope with counter underflow. + * More support needs to be added to kernel/time for + * counter/timer interrupts on multiple CPU's + */ + write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ)); + + /* + * Other CPUs should do profiling and process accounting + */ + local_timer_interrupt(irq); + } out: +#endif /* CONFIG_MIPS_MT_SMTC */ + irq_exit(); } + asmlinkage void ll_local_timer_interrupt(int irq) { irq_enter(); @@ -226,7 +291,7 @@ asmlinkage void ll_local_timer_interrupt(int irq) kstat_this_cpu.irqs[irq]++; /* we keep interrupt disabled all the time */ - local_timer_interrupt(irq, NULL); + local_timer_interrupt(irq); irq_exit(); } diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 67a0718..1470318 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -75,101 +75,6 @@ extern int null_perf_irq(void); extern int (*perf_irq)(void); /* - * Possibly handle a performance counter interrupt. - * Return true if the timer interrupt should not be checked - */ -static inline int handle_perf_irq (int r2) -{ - /* - * The performance counter overflow interrupt may be shared with the - * timer interrupt (mipsxx_perfcount_irq < 0). If it is and a - * performance counter has overflowed (perf_irq() == IRQ_HANDLED) - * and we can't reliably determine if a counter interrupt has also - * happened (!r2) then don't check for a timer interrupt. - */ - return (mipsxx_perfcount_irq < 0) && - perf_irq() == IRQ_HANDLED && - !r2; -} - -irqreturn_t mips_timer_interrupt(int irq, void *dev_id) -{ - int cpu = smp_processor_id(); - -#ifdef CONFIG_MIPS_MT_SMTC - /* - * In an SMTC system, one Count/Compare set exists per VPE. - * Which TC within a VPE gets the interrupt is essentially - * random - we only know that it shouldn't be one with - * IXMT set. Whichever TC gets the interrupt needs to - * send special interprocessor interrupts to the other - * TCs to make sure that they schedule, etc. - * - * That code is specific to the SMTC kernel, not to - * the a particular platform, so it's invoked from - * the general MIPS timer_interrupt routine. - */ - - /* - * We could be here due to timer interrupt, - * perf counter overflow, or both. - */ - (void) handle_perf_irq(1); - - if (read_c0_cause() & (1 << 30)) { - /* - * There are things we only want to do once per tick - * in an "MP" system. One TC of each VPE will take - * the actual timer interrupt. The others will get - * timer broadcast IPIs. We use whoever it is that takes - * the tick on VPE 0 to run the full timer_interrupt(). - */ - if (cpu_data[cpu].vpe_id == 0) { - timer_interrupt(irq, NULL); - } else { - write_c0_compare(read_c0_count() + - (mips_hpt_frequency/HZ)); - local_timer_interrupt(irq, dev_id); - } - smtc_timer_broadcast(cpu_data[cpu].vpe_id); - } -#else /* CONFIG_MIPS_MT_SMTC */ - int r2 = cpu_has_mips_r2; - - if (handle_perf_irq(r2)) - goto out; - - if (r2 && ((read_c0_cause() & (1 << 30)) == 0)) - goto out; - - if (cpu == 0) { - /* - * CPU 0 handles the global timer interrupt job and process - * accounting resets count/compare registers to trigger next - * timer int. - */ - timer_interrupt(irq, NULL); - } else { - /* Everyone else needs to reset the timer int here as - ll_local_timer_interrupt doesn't */ - /* - * FIXME: need to cope with counter underflow. - * More support needs to be added to kernel/time for - * counter/timer interrupts on multiple CPU's - */ - write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ)); - - /* - * Other CPUs should do profiling and process accounting - */ - local_timer_interrupt(irq, dev_id); - } -out: -#endif /* CONFIG_MIPS_MT_SMTC */ - return IRQ_HANDLED; -} - -/* * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect */ static unsigned int __init estimate_cpu_frequency(void) @@ -315,8 +220,6 @@ void __init plat_timer_setup(struct irqaction *irq) mips_cpu_timer_irq = MIPSCPU_INT_BASE + hwint; } - /* we are using the cpu counter for timer interrupts */ - irq->handler = mips_timer_interrupt; /* we use our own handler */ #ifdef CONFIG_MIPS_MT_SMTC setup_irq_smtc(mips_cpu_timer_irq, irq, 0x100 << hwint); #else diff --git a/arch/mips/mips-boards/sim/sim_time.c b/arch/mips/mips-boards/sim/sim_time.c index f8b8dff..32f2097 100644 --- a/arch/mips/mips-boards/sim/sim_time.c +++ b/arch/mips/mips-boards/sim/sim_time.c @@ -25,75 +25,6 @@ unsigned long cpu_khz; -irqreturn_t sim_timer_interrupt(int irq, void *dev_id) -{ -#ifdef CONFIG_SMP - int cpu = smp_processor_id(); - - /* - * CPU 0 handles the global timer interrupt job - * resets count/compare registers to trigger next timer int. - */ -#ifndef CONFIG_MIPS_MT_SMTC - if (cpu == 0) { - timer_interrupt(irq, dev_id); - } - else { - /* Everyone else needs to reset the timer int here as - ll_local_timer_interrupt doesn't */ - /* - * FIXME: need to cope with counter underflow. - * More support needs to be added to kernel/time for - * counter/timer interrupts on multiple CPU's - */ - write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ)); - } -#else /* SMTC */ - /* - * In SMTC system, one Count/Compare set exists per VPE. - * Which TC within a VPE gets the interrupt is essentially - * random - we only know that it shouldn't be one with - * IXMT set. Whichever TC gets the interrupt needs to - * send special interprocessor interrupts to the other - * TCs to make sure that they schedule, etc. - * - * That code is specific to the SMTC kernel, not to - * the simulation platform, so it's invoked from - * the general MIPS timer_interrupt routine. - * - * We have a problem in that the interrupt vector code - * had to turn off the timer IM bit to avoid redundant - * entries, but we may never get to mips_cpu_irq_end - * to turn it back on again if the scheduler gets - * involved. So we clear the pending timer here, - * and re-enable the mask... - */ - - int vpflags = dvpe(); - write_c0_compare (read_c0_count() - 1); - clear_c0_cause(0x100 << MIPSCPU_INT_CPUCTR); - set_c0_status(0x100 << MIPSCPU_INT_CPUCTR); - irq_enable_hazard(); - evpe(vpflags); - - if(cpu_data[cpu].vpe_id == 0) timer_interrupt(irq, dev_id); - else write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ)); - smtc_timer_broadcast(cpu_data[cpu].vpe_id); - -#endif /* CONFIG_MIPS_MT_SMTC */ - - /* - * every CPU should do profiling and process accounting - */ - local_timer_interrupt (irq, dev_id); - return IRQ_HANDLED; -#else - return timer_interrupt (irq, dev_id); -#endif -} - - - /* * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect */ @@ -188,7 +119,6 @@ void __init plat_timer_setup(struct irqaction *irq) } /* we are using the cpu counter for timer interrupts */ - irq->handler = sim_timer_interrupt; setup_irq(mips_cpu_timer_irq, irq); #ifdef CONFIG_SMP diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c index 1834832..790ccc5 100644 --- a/arch/mips/sgi-ip22/ip22-int.c +++ b/arch/mips/sgi-ip22/ip22-int.c @@ -204,7 +204,6 @@ static struct irqaction map1_cascade = { #define SGI_INTERRUPTS SGINT_LOCAL3 #endif -extern void indy_r4k_timer_interrupt(void); extern void indy_8254timer_irq(void); /* @@ -243,7 +242,7 @@ asmlinkage void plat_irq_dispatch(void) * First we check for r4k counter/timer IRQ. */ if (pending & CAUSEF_IP7) - indy_r4k_timer_interrupt(); + ll_timer_interrupt(SGI_TIMER_IRQ); else if (pending & CAUSEF_IP2) indy_local0_irqdispatch(); else if (pending & CAUSEF_IP3) diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c index 77f0c30..7f4e3b1 100644 --- a/arch/mips/sgi-ip22/ip22-time.c +++ b/arch/mips/sgi-ip22/ip22-time.c @@ -189,16 +189,6 @@ void indy_8254timer_irq(void) irq_exit(); } -void indy_r4k_timer_interrupt(void) -{ - int irq = SGI_TIMER_IRQ; - - irq_enter(); - kstat_this_cpu.irqs[irq]++; - timer_interrupt(irq, NULL); - irq_exit(); -} - void __init plat_timer_setup(struct irqaction *irq) { /* over-write the handler, we use our own way */ diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c index 6f3f71b..8519091 100644 --- a/arch/mips/sibyte/bcm1480/time.c +++ b/arch/mips/sibyte/bcm1480/time.c @@ -103,18 +103,7 @@ void bcm1480_timer_interrupt(void) __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); - if (cpu == 0) { - /* - * CPU 0 handles the global timer interrupt job - */ - ll_timer_interrupt(irq); - } - else { - /* - * other CPUs should just do profiling and process accounting - */ - ll_local_timer_interrupt(irq); - } + ll_timer_interrupt(irq); } static cycle_t bcm1480_hpt_read(void) diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c index 2efffe1..5bb83cd 100644 --- a/arch/mips/sibyte/sb1250/time.c +++ b/arch/mips/sibyte/sb1250/time.c @@ -125,18 +125,7 @@ void sb1250_timer_interrupt(void) ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); - if (cpu == 0) { - /* - * CPU 0 handles the global timer interrupt job - */ - ll_timer_interrupt(irq); - } - else { - /* - * other CPUs should just do profiling and process accounting - */ - ll_local_timer_interrupt(irq); - } + ll_timer_interrupt(irq); } /* diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h index 74ab331..9a49a93 100644 --- a/include/asm-mips/time.h +++ b/include/asm-mips/time.h @@ -63,13 +63,12 @@ extern irqreturn_t timer_interrupt(int irq, void *dev_id); /* * the corresponding low-level timer interrupt routine. */ -extern asmlinkage void ll_timer_interrupt(int irq); +extern void ll_timer_interrupt(int irq); /* * profiling and process accouting is done separately in local_timer_interrupt */ -extern void local_timer_interrupt(int irq, void *dev_id); -extern asmlinkage void ll_local_timer_interrupt(int irq); +extern void local_timer_interrupt(int irq); /* * board specific routines required by time_init(). -- 1.5.2.1