aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2007-10-11 18:46:09 -0400
committerRalf Baechle <ralf@linux-mips.org>2007-10-11 18:46:09 -0400
commit91a2fcc88634663e9e13dcdfad0e4a860e64aeee (patch)
treea86b936f1057207d46e5a07ed826052ff640869a /arch/mips/kernel
parent90b02340dcc6ce00bf22c48f4865915f5989e5e4 (diff)
[MIPS] Consolidate all variants of MIPS cp0 timer interrupt handlers.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/smtc.c2
-rw-r--r--arch/mips/kernel/time.c93
2 files changed, 70 insertions, 25 deletions
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 137183bba54..a7afbf2c971 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -867,7 +867,7 @@ void ipi_decode(struct smtc_ipi *pipi)
867#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG 867#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG
868 clock_hang_reported[dest_copy] = 0; 868 clock_hang_reported[dest_copy] = 0;
869#endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */ 869#endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */
870 local_timer_interrupt(0, NULL); 870 local_timer_interrupt(0);
871 irq_exit(); 871 irq_exit();
872 break; 872 break;
873 case LINUX_SMP_IPI: 873 case LINUX_SMP_IPI:
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index c48ebd4b495..d23e6825e98 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -144,7 +144,7 @@ void local_timer_interrupt(int irq, void *dev_id)
144 * High-level timer interrupt service routines. This function 144 * High-level timer interrupt service routines. This function
145 * is set as irqaction->handler and is invoked through do_IRQ. 145 * is set as irqaction->handler and is invoked through do_IRQ.
146 */ 146 */
147irqreturn_t timer_interrupt(int irq, void *dev_id) 147static irqreturn_t timer_interrupt(int irq, void *dev_id)
148{ 148{
149 write_seqlock(&xtime_lock); 149 write_seqlock(&xtime_lock);
150 150
@@ -174,9 +174,10 @@ int null_perf_irq(void)
174 return 0; 174 return 0;
175} 175}
176 176
177EXPORT_SYMBOL(null_perf_irq);
178
177int (*perf_irq)(void) = null_perf_irq; 179int (*perf_irq)(void) = null_perf_irq;
178 180
179EXPORT_SYMBOL(null_perf_irq);
180EXPORT_SYMBOL(perf_irq); 181EXPORT_SYMBOL(perf_irq);
181 182
182/* 183/*
@@ -208,35 +209,79 @@ static inline int handle_perf_irq (int r2)
208 !r2; 209 !r2;
209} 210}
210 211
211asmlinkage void ll_timer_interrupt(int irq) 212void ll_timer_interrupt(int irq, void *dev_id)
212{ 213{
213 int r2 = cpu_has_mips_r2; 214 int cpu = smp_processor_id();
214 215
215 irq_enter(); 216#ifdef CONFIG_MIPS_MT_SMTC
216 kstat_this_cpu.irqs[irq]++; 217 /*
218 * In an SMTC system, one Count/Compare set exists per VPE.
219 * Which TC within a VPE gets the interrupt is essentially
220 * random - we only know that it shouldn't be one with
221 * IXMT set. Whichever TC gets the interrupt needs to
222 * send special interprocessor interrupts to the other
223 * TCs to make sure that they schedule, etc.
224 *
225 * That code is specific to the SMTC kernel, not to
226 * the a particular platform, so it's invoked from
227 * the general MIPS timer_interrupt routine.
228 */
229
230 /*
231 * We could be here due to timer interrupt,
232 * perf counter overflow, or both.
233 */
234 (void) handle_perf_irq(1);
235
236 if (read_c0_cause() & (1 << 30)) {
237 /*
238 * There are things we only want to do once per tick
239 * in an "MP" system. One TC of each VPE will take
240 * the actual timer interrupt. The others will get
241 * timer broadcast IPIs. We use whoever it is that takes
242 * the tick on VPE 0 to run the full timer_interrupt().
243 */
244 if (cpu_data[cpu].vpe_id == 0) {
245 timer_interrupt(irq, NULL);
246 } else {
247 write_c0_compare(read_c0_count() +
248 (mips_hpt_frequency/HZ));
249 local_timer_interrupt(irq, dev_id);
250 }
251 smtc_timer_broadcast(cpu_data[cpu].vpe_id);
252 }
253#else /* CONFIG_MIPS_MT_SMTC */
254 int r2 = cpu_has_mips_r2;
217 255
218 if (handle_perf_irq(r2)) 256 if (handle_perf_irq(r2))
219 goto out; 257 return;
220 258
221 if (r2 && ((read_c0_cause() & (1 << 30)) == 0)) 259 if (r2 && ((read_c0_cause() & (1 << 30)) == 0))
222 goto out; 260 return;
223
224 timer_interrupt(irq, NULL);
225
226out:
227 irq_exit();
228}
229
230asmlinkage void ll_local_timer_interrupt(int irq)
231{
232 irq_enter();
233 if (smp_processor_id() != 0)
234 kstat_this_cpu.irqs[irq]++;
235
236 /* we keep interrupt disabled all the time */
237 local_timer_interrupt(irq, NULL);
238 261
239 irq_exit(); 262 if (cpu == 0) {
263 /*
264 * CPU 0 handles the global timer interrupt job and process
265 * accounting resets count/compare registers to trigger next
266 * timer int.
267 */
268 timer_interrupt(irq, NULL);
269 } else {
270 /* Everyone else needs to reset the timer int here as
271 ll_local_timer_interrupt doesn't */
272 /*
273 * FIXME: need to cope with counter underflow.
274 * More support needs to be added to kernel/time for
275 * counter/timer interrupts on multiple CPU's
276 */
277 write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
278
279 /*
280 * Other CPUs should do profiling and process accounting
281 */
282 local_timer_interrupt(irq, dev_id);
283 }
284#endif /* CONFIG_MIPS_MT_SMTC */
240} 285}
241 286
242/* 287/*