aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/mips-boards/generic/time.c
diff options
context:
space:
mode:
authorKevin D. Kissell <kevink@mips.com>2006-09-12 06:08:08 -0400
committerRalf Baechle <ralf@linux-mips.org>2006-09-27 08:37:41 -0400
commit846acaa2b4974ae2e28038d024dedcfc184efbb7 (patch)
treec721a4fe21a658508f410898ec9a358710e31caa /arch/mips/mips-boards/generic/time.c
parent60a6c3777ec607c5b19df9eac35088db4e142a6b (diff)
[MIPS] Patch to arch/mips/mips-boards/generic/time.c
In hooking up the perf counter overflow interrupt to the experimental deprecated-real-soon-now /proc/perf interface last night, I had to revisit arch/mips/mips-boards/generic/time.c, and discovered that when the 2.6.9-based SMTC prototype was merged with the more recent tree, it was missed that arch/mips/kernel/time.c had changed so that even in SMP kernels, timer_interrupt() calls local_timer_interrupt(), so there is no longer a need to invoke it directly from mips_timer_interrupt() in those cases where timer_interrupt() has been called. So I got rid of that, and added the invocation of perf_irq() if Cause.PCI is set, more-or-less following the same logic as in the non-SMTC case, with the modifications that (a) a runtime check for Release 2 isn't done, because it's redundant in SMTC), and (b) we check for a clock interrupt regardless of the value returned by the perf counter service - I don't understand why we'd want to control that with perf_irq(), but maybe one of you knows the story. I also got rid of the stupid warning about the unused variable when compiled for SMTC (another artifact of the merge). The result hasn't been beaten to death, but boots, seems stable, and supports extended precision event counting. Signed-off-by: Kevin D. Kissell <kevink@mips.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/mips-boards/generic/time.c')
-rw-r--r--arch/mips/mips-boards/generic/time.c57
1 files changed, 36 insertions, 21 deletions
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index 557bf961f36a..de5798e1e015 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -92,10 +92,9 @@ extern int (*perf_irq)(struct pt_regs *regs);
92irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 92irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
93{ 93{
94 int cpu = smp_processor_id(); 94 int cpu = smp_processor_id();
95 int r2 = cpu_has_mips_r2;
96 95
97#ifdef CONFIG_MIPS_MT_SMTC 96#ifdef CONFIG_MIPS_MT_SMTC
98 /* 97 /*
99 * In an SMTC system, one Count/Compare set exists per VPE. 98 * In an SMTC system, one Count/Compare set exists per VPE.
100 * Which TC within a VPE gets the interrupt is essentially 99 * Which TC within a VPE gets the interrupt is essentially
101 * random - we only know that it shouldn't be one with 100 * random - we only know that it shouldn't be one with
@@ -108,29 +107,46 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
108 * the general MIPS timer_interrupt routine. 107 * the general MIPS timer_interrupt routine.
109 */ 108 */
110 109
110 int vpflags;
111
111 /* 112 /*
112 * DVPE is necessary so long as cross-VPE interrupts 113 * We could be here due to timer interrupt,
113 * are done via read-modify-write of Cause register. 114 * perf counter overflow, or both.
114 */ 115 */
115 int vpflags = dvpe(); 116 if (read_c0_cause() & (1 << 26))
116 write_c0_compare (read_c0_count() - 1); 117 perf_irq(regs);
117 clear_c0_cause(CPUCTR_IMASKBIT);
118 evpe(vpflags);
119
120 if (cpu_data[cpu].vpe_id == 0) {
121 timer_interrupt(irq, dev_id, regs);
122 scroll_display_message();
123 } else
124 write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
125 smtc_timer_broadcast(cpu_data[cpu].vpe_id);
126 118
127 if (cpu != 0) 119 if (read_c0_cause() & (1 << 30)) {
120 /* If timer interrupt, make it de-assert */
121 write_c0_compare (read_c0_count() - 1);
128 /* 122 /*
129 * Other CPUs should do profiling and process accounting 123 * DVPE is necessary so long as cross-VPE interrupts
124 * are done via read-modify-write of Cause register.
130 */ 125 */
131 local_timer_interrupt(irq, dev_id, regs); 126 vpflags = dvpe();
132 127 clear_c0_cause(CPUCTR_IMASKBIT);
128 evpe(vpflags);
129 /*
130 * There are things we only want to do once per tick
131 * in an "MP" system. One TC of each VPE will take
132 * the actual timer interrupt. The others will get
133 * timer broadcast IPIs. We use whoever it is that takes
134 * the tick on VPE 0 to run the full timer_interrupt().
135 */
136 if (cpu_data[cpu].vpe_id == 0) {
137 timer_interrupt(irq, NULL, regs);
138 smtc_timer_broadcast(cpu_data[cpu].vpe_id);
139 scroll_display_message();
140 } else {
141 write_c0_compare(read_c0_count() +
142 (mips_hpt_frequency/HZ));
143 local_timer_interrupt(irq, dev_id, regs);
144 smtc_timer_broadcast(cpu_data[cpu].vpe_id);
145 }
146 }
133#else /* CONFIG_MIPS_MT_SMTC */ 147#else /* CONFIG_MIPS_MT_SMTC */
148 int r2 = cpu_has_mips_r2;
149
134 if (cpu == 0) { 150 if (cpu == 0) {
135 /* 151 /*
136 * CPU 0 handles the global timer interrupt job and process 152 * CPU 0 handles the global timer interrupt job and process
@@ -161,9 +177,8 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
161 */ 177 */
162 local_timer_interrupt(irq, dev_id, regs); 178 local_timer_interrupt(irq, dev_id, regs);
163 } 179 }
164#endif /* CONFIG_MIPS_MT_SMTC */
165
166out: 180out:
181#endif /* CONFIG_MIPS_MT_SMTC */
167 return IRQ_HANDLED; 182 return IRQ_HANDLED;
168} 183}
169 184