MIPS: Oprofile: Fixup the loose ends in the plumbing. Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

authored by

Ralf Baechle and committed by
ba339c03 0401572a

+50 -8
+26 -2
arch/mips/kernel/time.c
··· 507 507 return IRQ_HANDLED; 508 508 } 509 509 510 + int null_perf_irq(struct pt_regs *regs) 511 + { 512 + return 0; 513 + } 514 + 515 + int (*perf_irq)(struct pt_regs *regs) = null_perf_irq; 516 + 517 + EXPORT_SYMBOL(null_perf_irq); 518 + EXPORT_SYMBOL(perf_irq); 519 + 510 520 asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs) 511 521 { 522 + int r2 = cpu_has_mips_r2; 523 + 512 524 irq_enter(); 513 525 kstat_this_cpu.irqs[irq]++; 514 526 515 - /* we keep interrupt disabled all the time */ 516 - timer_interrupt(irq, NULL, regs); 527 + /* 528 + * Suckage alert: 529 + * Before R2 of the architecture there was no way to see if a 530 + * performance counter interrupt was pending, so we have to run the 531 + * performance counter interrupt handler anyway. 532 + */ 533 + if (!r2 || (read_c0_cause() & (1 << 26))) 534 + if (perf_irq(regs)) 535 + goto out; 517 536 537 + /* we keep interrupt disabled all the time */ 538 + if (!r2 || (read_c0_cause() & (1 << 30))) 539 + timer_interrupt(irq, NULL, regs); 540 + 541 + out: 518 542 irq_exit(); 519 543 } 520 544
+17 -3
arch/mips/mips-boards/generic/time.c
··· 75 75 do_IRQ (mips_cpu_timer_irq, regs); 76 76 } 77 77 78 + extern int null_perf_irq(struct pt_regs *regs); 79 + 80 + extern int (*perf_irq)(struct pt_regs *regs); 81 + 78 82 irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 79 83 { 84 + int r2 = cpu_has_mips_r2; 80 85 int cpu = smp_processor_id(); 81 86 82 87 if (cpu == 0) { 83 88 /* 84 - * CPU 0 handles the global timer interrupt job and process accounting 85 - * resets count/compare registers to trigger next timer int. 89 + * CPU 0 handles the global timer interrupt job and process 90 + * accounting resets count/compare registers to trigger next 91 + * timer int. 86 92 */ 87 - timer_interrupt(irq, dev_id, regs); 93 + if (!r2 || (read_c0_cause() & (1 << 26))) 94 + if (perf_irq(regs)) 95 + goto out; 96 + 97 + /* we keep interrupt disabled all the time */ 98 + if (!r2 || (read_c0_cause() & (1 << 30))) 99 + timer_interrupt(irq, NULL, regs); 100 + 88 101 scroll_display_message(); 89 102 } else { 90 103 /* Everyone else needs to reset the timer int here as ··· 114 101 local_timer_interrupt (irq, dev_id, regs); 115 102 } 116 103 104 + out: 117 105 return IRQ_HANDLED; 118 106 } 119 107
+2 -2
arch/mips/oprofile/op_impl.h
··· 12 12 13 13 struct pt_regs; 14 14 15 - extern void null_perf_irq(struct pt_regs *regs); 16 - extern void (*perf_irq)(struct pt_regs *regs); 15 + extern int null_perf_irq(struct pt_regs *regs); 16 + extern int (*perf_irq)(struct pt_regs *regs); 17 17 18 18 /* Per-counter configuration as set via oprofilefs. */ 19 19 struct op_counter_config {
+5 -1
arch/mips/oprofile/op_model_mipsxx.c
··· 114 114 } 115 115 } 116 116 117 - static void mipsxx_perfcount_handler(struct pt_regs *regs) 117 + static int mipsxx_perfcount_handler(struct pt_regs *regs) 118 118 { 119 119 unsigned int counters = op_model_mipsxx.num_counters; 120 120 unsigned int control; 121 121 unsigned int counter; 122 + int handled = 0; 122 123 123 124 switch (counters) { 124 125 #define HANDLE_COUNTER(n) \ ··· 130 129 (counter & M_COUNTER_OVERFLOW)) { \ 131 130 oprofile_add_sample(regs, n); \ 132 131 write_c0_perfcntr ## n(reg.counter[n]); \ 132 + handled = 1; \ 133 133 } 134 134 HANDLE_COUNTER(3) 135 135 HANDLE_COUNTER(2) 136 136 HANDLE_COUNTER(1) 137 137 HANDLE_COUNTER(0) 138 138 } 139 + 140 + return handled; 139 141 } 140 142 141 143 #define M_CONFIG1_PC (1 << 4)