diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2005-12-09 12:29:38 +0000 |
---|---|---|
committer | <ralf@denk.linux-mips.net> | 2006-01-10 13:39:07 +0000 |
commit | ba339c03e2e8ede8ccd37ed6c4e564e3b1545495 (patch) | |
tree | 1a7bbfd15a9c46d5300d2d5a1890d748b81dbce2 | |
parent | 0401572a9b9b2f368176b6e53f53004fd048a566 (diff) | |
download | kernel_samsung_crespo-ba339c03e2e8ede8ccd37ed6c4e564e3b1545495.zip kernel_samsung_crespo-ba339c03e2e8ede8ccd37ed6c4e564e3b1545495.tar.gz kernel_samsung_crespo-ba339c03e2e8ede8ccd37ed6c4e564e3b1545495.tar.bz2 |
MIPS: Oprofile: Fixup the loose ends in the plumbing.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r-- | arch/mips/kernel/time.c | 26 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/time.c | 20 | ||||
-rw-r--r-- | arch/mips/oprofile/op_impl.h | 4 | ||||
-rw-r--r-- | arch/mips/oprofile/op_model_mipsxx.c | 6 |
4 files changed, 49 insertions, 7 deletions
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 07e125c..7050b4f 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -507,14 +507,38 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } +int null_perf_irq(struct pt_regs *regs) +{ + return 0; +} + +int (*perf_irq)(struct pt_regs *regs) = null_perf_irq; + +EXPORT_SYMBOL(null_perf_irq); +EXPORT_SYMBOL(perf_irq); + asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs) { + int r2 = cpu_has_mips_r2; + irq_enter(); kstat_this_cpu.irqs[irq]++; + /* + * Suckage alert: + * Before R2 of the architecture there was no way to see if a + * performance counter interrupt was pending, so we have to run the + * performance counter interrupt handler anyway. + */ + if (!r2 || (read_c0_cause() & (1 << 26))) + if (perf_irq(regs)) + goto out; + /* we keep interrupt disabled all the time */ - timer_interrupt(irq, NULL, regs); + if (!r2 || (read_c0_cause() & (1 << 30))) + timer_interrupt(irq, NULL, regs); +out: irq_exit(); } diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 2830f65..93f3bf2 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -75,16 +75,29 @@ static void mips_timer_dispatch (struct pt_regs *regs) do_IRQ (mips_cpu_timer_irq, regs); } +extern int null_perf_irq(struct pt_regs *regs); + +extern int (*perf_irq)(struct pt_regs *regs); + irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + int r2 = cpu_has_mips_r2; int cpu = smp_processor_id(); if (cpu == 0) { /* - * CPU 0 handles the global timer interrupt job and process accounting - * resets count/compare registers to trigger next timer int. + * CPU 0 handles the global timer interrupt job and process + * accounting resets count/compare registers to trigger next + * timer int. */ - timer_interrupt(irq, dev_id, regs); + if (!r2 || (read_c0_cause() & (1 << 26))) + if (perf_irq(regs)) + goto out; + + /* we keep interrupt disabled all the time */ + if (!r2 || (read_c0_cause() & (1 << 30))) + timer_interrupt(irq, NULL, regs); + scroll_display_message(); } else { /* Everyone else needs to reset the timer int here as @@ -101,6 +114,7 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) local_timer_interrupt (irq, dev_id, regs); } +out: return IRQ_HANDLED; } diff --git a/arch/mips/oprofile/op_impl.h b/arch/mips/oprofile/op_impl.h index f012155..5cfce7d 100644 --- a/arch/mips/oprofile/op_impl.h +++ b/arch/mips/oprofile/op_impl.h @@ -12,8 +12,8 @@ struct pt_regs; -extern void null_perf_irq(struct pt_regs *regs); -extern void (*perf_irq)(struct pt_regs *regs); +extern int null_perf_irq(struct pt_regs *regs); +extern int (*perf_irq)(struct pt_regs *regs); /* Per-counter configuration as set via oprofilefs. */ struct op_counter_config { diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index d36b64d..a4a4aa9 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -114,11 +114,12 @@ static void mipsxx_cpu_stop(void *args) } } -static void mipsxx_perfcount_handler(struct pt_regs *regs) +static int mipsxx_perfcount_handler(struct pt_regs *regs) { unsigned int counters = op_model_mipsxx.num_counters; unsigned int control; unsigned int counter; + int handled = 0; switch (counters) { #define HANDLE_COUNTER(n) \ @@ -129,12 +130,15 @@ static void mipsxx_perfcount_handler(struct pt_regs *regs) (counter & M_COUNTER_OVERFLOW)) { \ oprofile_add_sample(regs, n); \ write_c0_perfcntr ## n(reg.counter[n]); \ + handled = 1; \ } HANDLE_COUNTER(3) HANDLE_COUNTER(2) HANDLE_COUNTER(1) HANDLE_COUNTER(0) } + + return handled; } #define M_CONFIG1_PC (1 << 4) |