aboutsummaryrefslogtreecommitdiffstats
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
commit7bcf7717b6a047c272410d0cd00213185fe6b99d (patch)
tree81c5d6bbc2130815713e22bb5408ea80b6e1c499
parent91a2fcc88634663e9e13dcdfad0e4a860e64aeee (diff)
[MIPS] Implement clockevents for R4000-style cp0 count/compare interrupt
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/Kconfig7
-rw-r--r--arch/mips/au1000/common/irq.c2
-rw-r--r--arch/mips/configs/bigsur_defconfig1
-rw-r--r--arch/mips/configs/sb1250-swarm_defconfig1
-rw-r--r--arch/mips/kernel/process.c3
-rw-r--r--arch/mips/kernel/smp.c2
-rw-r--r--arch/mips/kernel/smtc.c2
-rw-r--r--arch/mips/kernel/time.c256
-rw-r--r--arch/mips/mips-boards/generic/time.c26
-rw-r--r--arch/mips/qemu/q-irq.c4
-rw-r--r--arch/mips/qemu/q-setup.c1
-rw-r--r--arch/mips/sgi-ip22/ip22-int.c2
-rw-r--r--arch/mips/sgi-ip32/ip32-irq.c2
-rw-r--r--arch/mips/sibyte/Kconfig12
-rw-r--r--arch/mips/sibyte/bcm1480/irq.c13
-rw-r--r--arch/mips/sibyte/sb1250/irq.c50
-rw-r--r--arch/mips/sibyte/sb1250/time.c12
-rw-r--r--include/asm-mips/mach-ip27/irq.h2
-rw-r--r--include/asm-mips/qemu.h2
-rw-r--r--include/asm-mips/time.h10
20 files changed, 210 insertions, 200 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 0cd0f835b13d..ecce3aab1981 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -335,6 +335,7 @@ config QEMU
335 select GENERIC_ISA_DMA 335 select GENERIC_ISA_DMA
336 select HAVE_STD_PC_SERIAL_PORT 336 select HAVE_STD_PC_SERIAL_PORT
337 select I8259 337 select I8259
338 select IRQ_CPU
338 select ISA 339 select ISA
339 select PCSPEAKER 340 select PCSPEAKER
340 select SWAP_IO_SPACE 341 select SWAP_IO_SPACE
@@ -667,6 +668,10 @@ config GENERIC_CALIBRATE_DELAY
667 bool 668 bool
668 default y 669 default y
669 670
671config GENERIC_CLOCKEVENTS
672 bool
673 default y
674
670config GENERIC_TIME 675config GENERIC_TIME
671 bool 676 bool
672 default y 677 default y
@@ -901,6 +906,8 @@ config BOOT_ELF64
901 906
902menu "CPU selection" 907menu "CPU selection"
903 908
909source "kernel/time/Kconfig"
910
904choice 911choice
905 prompt "CPU type" 912 prompt "CPU type"
906 default CPU_R4X00 913 default CPU_R4X00
diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c
index 47949d6f2c10..a6640b998c6e 100644
--- a/arch/mips/au1000/common/irq.c
+++ b/arch/mips/au1000/common/irq.c
@@ -633,7 +633,7 @@ asmlinkage void plat_irq_dispatch(void)
633 unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; 633 unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
634 634
635 if (pending & CAUSEF_IP7) 635 if (pending & CAUSEF_IP7)
636 ll_timer_interrupt(63); 636 do_IRQ(63);
637 else if (pending & CAUSEF_IP2) 637 else if (pending & CAUSEF_IP2)
638 intc0_req0_irqdispatch(); 638 intc0_req0_irqdispatch();
639 else if (pending & CAUSEF_IP3) 639 else if (pending & CAUSEF_IP3)
diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig
index 700a3a2d688e..30f3e9a2466f 100644
--- a/arch/mips/configs/bigsur_defconfig
+++ b/arch/mips/configs/bigsur_defconfig
@@ -69,7 +69,6 @@ CONFIG_SIBYTE_SB1xxx_SOC=y
69CONFIG_SIBYTE_CFE=y 69CONFIG_SIBYTE_CFE=y
70# CONFIG_SIBYTE_CFE_CONSOLE is not set 70# CONFIG_SIBYTE_CFE_CONSOLE is not set
71# CONFIG_SIBYTE_BUS_WATCHER is not set 71# CONFIG_SIBYTE_BUS_WATCHER is not set
72# CONFIG_SIBYTE_SB1250_PROF is not set
73# CONFIG_SIBYTE_TBPROF is not set 72# CONFIG_SIBYTE_TBPROF is not set
74CONFIG_RWSEM_GENERIC_SPINLOCK=y 73CONFIG_RWSEM_GENERIC_SPINLOCK=y
75# CONFIG_ARCH_HAS_ILOG2_U32 is not set 74# CONFIG_ARCH_HAS_ILOG2_U32 is not set
diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig
index 93f9e8331ad7..3d1b6281d887 100644
--- a/arch/mips/configs/sb1250-swarm_defconfig
+++ b/arch/mips/configs/sb1250-swarm_defconfig
@@ -70,7 +70,6 @@ CONFIG_SIBYTE_HAS_LDT=y
70CONFIG_SIBYTE_CFE=y 70CONFIG_SIBYTE_CFE=y
71# CONFIG_SIBYTE_CFE_CONSOLE is not set 71# CONFIG_SIBYTE_CFE_CONSOLE is not set
72# CONFIG_SIBYTE_BUS_WATCHER is not set 72# CONFIG_SIBYTE_BUS_WATCHER is not set
73# CONFIG_SIBYTE_SB1250_PROF is not set
74# CONFIG_SIBYTE_TBPROF is not set 73# CONFIG_SIBYTE_TBPROF is not set
75CONFIG_RWSEM_GENERIC_SPINLOCK=y 74CONFIG_RWSEM_GENERIC_SPINLOCK=y
76# CONFIG_ARCH_HAS_ILOG2_U32 is not set 75# CONFIG_ARCH_HAS_ILOG2_U32 is not set
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index aadd2cd5778c..f99bb4085430 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -11,6 +11,7 @@
11#include <linux/errno.h> 11#include <linux/errno.h>
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/sched.h> 13#include <linux/sched.h>
14#include <linux/tick.h>
14#include <linux/kernel.h> 15#include <linux/kernel.h>
15#include <linux/mm.h> 16#include <linux/mm.h>
16#include <linux/stddef.h> 17#include <linux/stddef.h>
@@ -52,6 +53,7 @@ void __noreturn cpu_idle(void)
52{ 53{
53 /* endless idle loop with no priority at all */ 54 /* endless idle loop with no priority at all */
54 while (1) { 55 while (1) {
56 tick_nohz_stop_sched_tick();
55 while (!need_resched()) { 57 while (!need_resched()) {
56#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG 58#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG
57 extern void smtc_idle_loop_hook(void); 59 extern void smtc_idle_loop_hook(void);
@@ -61,6 +63,7 @@ void __noreturn cpu_idle(void)
61 if (cpu_wait) 63 if (cpu_wait)
62 (*cpu_wait)(); 64 (*cpu_wait)();
63 } 65 }
66 tick_nohz_restart_sched_tick();
64 preempt_enable_no_resched(); 67 preempt_enable_no_resched();
65 schedule(); 68 schedule();
66 preempt_disable(); 69 preempt_disable();
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 73b0dab02668..500a7ec2880f 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -38,6 +38,7 @@
38#include <asm/system.h> 38#include <asm/system.h>
39#include <asm/mmu_context.h> 39#include <asm/mmu_context.h>
40#include <asm/smp.h> 40#include <asm/smp.h>
41#include <asm/time.h>
41 42
42#ifdef CONFIG_MIPS_MT_SMTC 43#ifdef CONFIG_MIPS_MT_SMTC
43#include <asm/mipsmtregs.h> 44#include <asm/mipsmtregs.h>
@@ -70,6 +71,7 @@ asmlinkage __cpuinit void start_secondary(void)
70 cpu_probe(); 71 cpu_probe();
71 cpu_report(); 72 cpu_report();
72 per_cpu_trap_init(); 73 per_cpu_trap_init();
74 mips_clockevent_init();
73 prom_init_secondary(); 75 prom_init_secondary();
74 76
75 /* 77 /*
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index a7afbf2c9710..137183bba54f 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); 870 local_timer_interrupt(0, NULL);
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 d23e6825e988..35988847c98a 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -11,6 +11,7 @@
11 * Free Software Foundation; either version 2 of the License, or (at your 11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. 12 * option) any later version.
13 */ 13 */
14#include <linux/clockchips.h>
14#include <linux/types.h> 15#include <linux/types.h>
15#include <linux/kernel.h> 16#include <linux/kernel.h>
16#include <linux/init.h> 17#include <linux/init.h>
@@ -34,6 +35,8 @@
34#include <asm/sections.h> 35#include <asm/sections.h>
35#include <asm/time.h> 36#include <asm/time.h>
36 37
38#include <irq.h>
39
37/* 40/*
38 * The integer part of the number of usecs per jiffy is taken from tick, 41 * The integer part of the number of usecs per jiffy is taken from tick,
39 * but the fractional part is not recorded, so we calculate it using the 42 * but the fractional part is not recorded, so we calculate it using the
@@ -70,10 +73,6 @@ int update_persistent_clock(struct timespec now)
70/* how many counter cycles in a jiffy */ 73/* how many counter cycles in a jiffy */
71static unsigned long cycles_per_jiffy __read_mostly; 74static unsigned long cycles_per_jiffy __read_mostly;
72 75
73/* expirelo is the count value for next CPU timer interrupt */
74static unsigned int expirelo;
75
76
77/* 76/*
78 * Null timer ack for systems not needing one (e.g. i8254). 77 * Null timer ack for systems not needing one (e.g. i8254).
79 */ 78 */
@@ -92,18 +91,7 @@ static cycle_t null_hpt_read(void)
92 */ 91 */
93static void c0_timer_ack(void) 92static void c0_timer_ack(void)
94{ 93{
95 unsigned int count; 94 write_c0_compare(read_c0_compare());
96
97 /* Ack this timer interrupt and set the next one. */
98 expirelo += cycles_per_jiffy;
99 write_c0_compare(expirelo);
100
101 /* Check to see if we have missed any timer interrupts. */
102 while (((count = read_c0_count()) - expirelo) < 0x7fffffff) {
103 /* missed_timer_count++; */
104 expirelo = count + cycles_per_jiffy;
105 write_c0_compare(expirelo);
106 }
107} 95}
108 96
109/* 97/*
@@ -114,13 +102,6 @@ static cycle_t c0_hpt_read(void)
114 return read_c0_count(); 102 return read_c0_count();
115} 103}
116 104
117/* For use both as a high precision timer and an interrupt source. */
118static void __init c0_hpt_timer_init(void)
119{
120 expirelo = read_c0_count() + cycles_per_jiffy;
121 write_c0_compare(expirelo);
122}
123
124int (*mips_timer_state)(void); 105int (*mips_timer_state)(void);
125void (*mips_timer_ack)(void); 106void (*mips_timer_ack)(void);
126 107
@@ -140,35 +121,6 @@ void local_timer_interrupt(int irq, void *dev_id)
140 update_process_times(user_mode(get_irq_regs())); 121 update_process_times(user_mode(get_irq_regs()));
141} 122}
142 123
143/*
144 * High-level timer interrupt service routines. This function
145 * is set as irqaction->handler and is invoked through do_IRQ.
146 */
147static irqreturn_t timer_interrupt(int irq, void *dev_id)
148{
149 write_seqlock(&xtime_lock);
150
151 mips_timer_ack();
152
153 /*
154 * call the generic timer interrupt handling
155 */
156 do_timer(1);
157
158 write_sequnlock(&xtime_lock);
159
160 /*
161 * In UP mode, we call local_timer_interrupt() to do profiling
162 * and process accouting.
163 *
164 * In SMP mode, local_timer_interrupt() is invoked by appropriate
165 * low-level local timer interrupt handler.
166 */
167 local_timer_interrupt(irq, dev_id);
168
169 return IRQ_HANDLED;
170}
171
172int null_perf_irq(void) 124int null_perf_irq(void)
173{ 125{
174 return 0; 126 return 0;
@@ -209,81 +161,6 @@ static inline int handle_perf_irq (int r2)
209 !r2; 161 !r2;
210} 162}
211 163
212void ll_timer_interrupt(int irq, void *dev_id)
213{
214 int cpu = smp_processor_id();
215
216#ifdef CONFIG_MIPS_MT_SMTC
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;
255
256 if (handle_perf_irq(r2))
257 return;
258
259 if (r2 && ((read_c0_cause() & (1 << 30)) == 0))
260 return;
261
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 */
285}
286
287/* 164/*
288 * time_init() - it does the following things. 165 * time_init() - it does the following things.
289 * 166 *
@@ -301,12 +178,6 @@ void ll_timer_interrupt(int irq, void *dev_id)
301 178
302unsigned int mips_hpt_frequency; 179unsigned int mips_hpt_frequency;
303 180
304static struct irqaction timer_irqaction = {
305 .handler = timer_interrupt,
306 .flags = IRQF_DISABLED | IRQF_PERCPU,
307 .name = "timer",
308};
309
310static unsigned int __init calibrate_hpt(void) 181static unsigned int __init calibrate_hpt(void)
311{ 182{
312 cycle_t frequency, hpt_start, hpt_end, hpt_count, hz; 183 cycle_t frequency, hpt_start, hpt_end, hpt_count, hz;
@@ -355,6 +226,65 @@ struct clocksource clocksource_mips = {
355 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 226 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
356}; 227};
357 228
229static int mips_next_event(unsigned long delta,
230 struct clock_event_device *evt)
231{
232 unsigned int cnt;
233
234 cnt = read_c0_count();
235 cnt += delta;
236 write_c0_compare(cnt);
237
238 return ((long)(read_c0_count() - cnt ) > 0) ? -ETIME : 0;
239}
240
241static void mips_set_mode(enum clock_event_mode mode,
242 struct clock_event_device *evt)
243{
244 /* Nothing to do ... */
245}
246
247struct clock_event_device mips_clockevent;
248
249static struct clock_event_device *global_cd[NR_CPUS];
250static int cp0_timer_irq_installed;
251
252static irqreturn_t timer_interrupt(int irq, void *dev_id)
253{
254 const int r2 = cpu_has_mips_r2;
255 struct clock_event_device *cd;
256 int cpu = smp_processor_id();
257
258 /*
259 * Suckage alert:
260 * Before R2 of the architecture there was no way to see if a
261 * performance counter interrupt was pending, so we have to run
262 * the performance counter interrupt handler anyway.
263 */
264 if (handle_perf_irq(r2))
265 goto out;
266
267 /*
268 * The same applies to performance counter interrupts. But with the
269 * above we now know that the reason we got here must be a timer
270 * interrupt. Being the paranoiacs we are we check anyway.
271 */
272 if (!r2 || (read_c0_cause() & (1 << 30))) {
273 c0_timer_ack();
274 cd = global_cd[cpu];
275 cd->event_handler(cd);
276 }
277
278out:
279 return IRQ_HANDLED;
280}
281
282static struct irqaction timer_irqaction = {
283 .handler = timer_interrupt,
284 .flags = IRQF_DISABLED | IRQF_PERCPU,
285 .name = "timer",
286};
287
358static void __init init_mips_clocksource(void) 288static void __init init_mips_clocksource(void)
359{ 289{
360 u64 temp; 290 u64 temp;
@@ -382,6 +312,56 @@ void __init __weak plat_time_init(void)
382{ 312{
383} 313}
384 314
315void __init __weak plat_timer_setup(struct irqaction *irq)
316{
317}
318
319void __cpuinit mips_clockevent_init(void)
320{
321 uint64_t mips_freq = mips_hpt_frequency;
322 unsigned int cpu = smp_processor_id();
323 struct clock_event_device *cd;
324 unsigned int irq = MIPS_CPU_IRQ_BASE + 7;
325
326 if (!cpu_has_counter)
327 return;
328
329 if (cpu == 0)
330 cd = &mips_clockevent;
331 else
332 cd = kzalloc(sizeof(*cd), GFP_ATOMIC);
333 if (!cd)
334 return; /* We're probably roadkill ... */
335
336 cd->name = "MIPS";
337 cd->features = CLOCK_EVT_FEAT_ONESHOT;
338
339 /* Calculate the min / max delta */
340 cd->mult = div_sc((unsigned long) mips_freq, NSEC_PER_SEC, 32);
341 cd->shift = 32;
342 cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
343 cd->min_delta_ns = clockevent_delta2ns(0x30, cd);
344
345 cd->rating = 300;
346 cd->irq = irq;
347 cd->cpumask = cpumask_of_cpu(cpu);
348 cd->set_next_event = mips_next_event;
349 cd->set_mode = mips_set_mode;
350
351 global_cd[cpu] = cd;
352 clockevents_register_device(cd);
353
354 if (!cp0_timer_irq_installed) {
355#ifdef CONFIG_MIPS_MT_SMTC
356#define CPUCTR_IMASKBIT (0x100 << cp0_compare_irq)
357 setup_irq_smtc(irq, &timer_irqaction, CPUCTR_IMASKBIT);
358#else
359 setup_irq(irq, &timer_irqaction);
360#endif /* CONFIG_MIPS_MT_SMTC */
361 cp0_timer_irq_installed = 1;
362 }
363}
364
385void __init time_init(void) 365void __init time_init(void)
386{ 366{
387 plat_time_init(); 367 plat_time_init();
@@ -407,11 +387,6 @@ void __init time_init(void)
407 /* Calculate cache parameters. */ 387 /* Calculate cache parameters. */
408 cycles_per_jiffy = 388 cycles_per_jiffy =
409 (mips_hpt_frequency + HZ / 2) / HZ; 389 (mips_hpt_frequency + HZ / 2) / HZ;
410 /*
411 * This sets up the high precision
412 * timer for the first interrupt.
413 */
414 c0_hpt_timer_init();
415 } 390 }
416 } 391 }
417 if (!mips_hpt_frequency) 392 if (!mips_hpt_frequency)
@@ -421,6 +396,10 @@ void __init time_init(void)
421 printk("Using %u.%03u MHz high precision timer.\n", 396 printk("Using %u.%03u MHz high precision timer.\n",
422 ((mips_hpt_frequency + 500) / 1000) / 1000, 397 ((mips_hpt_frequency + 500) / 1000) / 1000,
423 ((mips_hpt_frequency + 500) / 1000) % 1000); 398 ((mips_hpt_frequency + 500) / 1000) % 1000);
399
400#ifdef CONFIG_IRQ_CPU
401 setup_irq(MIPS_CPU_IRQ_BASE + 7, &timer_irqaction);
402#endif
424 } 403 }
425 404
426 if (!mips_timer_ack) 405 if (!mips_timer_ack)
@@ -441,4 +420,5 @@ void __init time_init(void)
441 plat_timer_setup(&timer_irqaction); 420 plat_timer_setup(&timer_irqaction);
442 421
443 init_mips_clocksource(); 422 init_mips_clocksource();
423 mips_clockevent_init();
444} 424}
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index 345de881013c..2c8db3e0f4b7 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -144,20 +144,20 @@ void __init plat_time_init(void)
144 mips_scroll_message(); 144 mips_scroll_message();
145} 145}
146 146
147static irqreturn_t mips_perf_interrupt(int irq, void *dev_id) 147//static irqreturn_t mips_perf_interrupt(int irq, void *dev_id)
148{ 148//{
149 return perf_irq(); 149// return perf_irq();
150} 150//}
151 151
152static struct irqaction perf_irqaction = { 152//static struct irqaction perf_irqaction = {
153 .handler = mips_perf_interrupt, 153// .handler = mips_perf_interrupt,
154 .flags = IRQF_DISABLED | IRQF_PERCPU, 154// .flags = IRQF_DISABLED | IRQF_PERCPU,
155 .name = "performance", 155// .name = "performance",
156}; 156//};
157 157
158void __init plat_perf_setup(void) 158void __init plat_perf_setup(void)
159{ 159{
160 struct irqaction *irq = &perf_irqaction; 160// struct irqaction *irq = &perf_irqaction;
161 161
162 cp0_perfcount_irq = -1; 162 cp0_perfcount_irq = -1;
163 163
@@ -170,12 +170,6 @@ void __init plat_perf_setup(void)
170 if (cp0_perfcount_irq >= 0) { 170 if (cp0_perfcount_irq >= 0) {
171 if (cpu_has_vint) 171 if (cpu_has_vint)
172 set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); 172 set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
173#ifdef CONFIG_MIPS_MT_SMTC
174 setup_irq_smtc(cp0_perfcount_irq, irq,
175 0x100 << cp0_perfcount_irq);
176#else
177 setup_irq(cp0_perfcount_irq, irq);
178#endif /* CONFIG_MIPS_MT_SMTC */
179#ifdef CONFIG_SMP 173#ifdef CONFIG_SMP
180 set_irq_handler(cp0_perfcount_irq, handle_percpu_irq); 174 set_irq_handler(cp0_perfcount_irq, handle_percpu_irq);
181#endif 175#endif
diff --git a/arch/mips/qemu/q-irq.c b/arch/mips/qemu/q-irq.c
index 89891e984b3b..4681757460a1 100644
--- a/arch/mips/qemu/q-irq.c
+++ b/arch/mips/qemu/q-irq.c
@@ -2,6 +2,7 @@
2#include <linux/linkage.h> 2#include <linux/linkage.h>
3 3
4#include <asm/i8259.h> 4#include <asm/i8259.h>
5#include <asm/irq_cpu.h>
5#include <asm/mipsregs.h> 6#include <asm/mipsregs.h>
6#include <asm/qemu.h> 7#include <asm/qemu.h>
7#include <asm/system.h> 8#include <asm/system.h>
@@ -12,7 +13,7 @@ asmlinkage void plat_irq_dispatch(void)
12 unsigned int pending = read_c0_status() & read_c0_cause(); 13 unsigned int pending = read_c0_status() & read_c0_cause();
13 14
14 if (pending & 0x8000) { 15 if (pending & 0x8000) {
15 ll_timer_interrupt(Q_COUNT_COMPARE_IRQ); 16 do_IRQ(Q_COUNT_COMPARE_IRQ);
16 return; 17 return;
17 } 18 }
18 if (pending & 0x0400) { 19 if (pending & 0x0400) {
@@ -29,6 +30,7 @@ void __init arch_init_irq(void)
29{ 30{
30 mips_hpt_frequency = QEMU_C0_COUNTER_CLOCK; /* 100MHz */ 31 mips_hpt_frequency = QEMU_C0_COUNTER_CLOCK; /* 100MHz */
31 32
33 mips_cpu_irq_init();
32 init_i8259_irqs(); 34 init_i8259_irqs();
33 set_c0_status(0x8400); 35 set_c0_status(0x8400);
34} 36}
diff --git a/arch/mips/qemu/q-setup.c b/arch/mips/qemu/q-setup.c
index 841394336f00..89a207650ce9 100644
--- a/arch/mips/qemu/q-setup.c
+++ b/arch/mips/qemu/q-setup.c
@@ -17,7 +17,6 @@ void __init plat_timer_setup(struct irqaction *irq)
17 outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ 17 outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
18 outb_p(LATCH & 0xff , 0x40); /* LSB */ 18 outb_p(LATCH & 0xff , 0x40); /* LSB */
19 outb(LATCH >> 8 , 0x40); /* MSB */ 19 outb(LATCH >> 8 , 0x40); /* MSB */
20 setup_irq(0, irq);
21} 20}
22 21
23void __init plat_mem_setup(void) 22void __init plat_mem_setup(void)
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
index 338c0d706988..f199da7e49cf 100644
--- a/arch/mips/sgi-ip22/ip22-int.c
+++ b/arch/mips/sgi-ip22/ip22-int.c
@@ -242,7 +242,7 @@ asmlinkage void plat_irq_dispatch(void)
242 * First we check for r4k counter/timer IRQ. 242 * First we check for r4k counter/timer IRQ.
243 */ 243 */
244 if (pending & CAUSEF_IP7) 244 if (pending & CAUSEF_IP7)
245 ll_timer_interrupt(SGI_TIMER_IRQ, NULL); 245 do_IRQ(SGI_TIMER_IRQ);
246 else if (pending & CAUSEF_IP2) 246 else if (pending & CAUSEF_IP2)
247 indy_local0_irqdispatch(); 247 indy_local0_irqdispatch();
248 else if (pending & CAUSEF_IP3) 248 else if (pending & CAUSEF_IP3)
diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c
index 5bad1b744d0f..002095b364a3 100644
--- a/arch/mips/sgi-ip32/ip32-irq.c
+++ b/arch/mips/sgi-ip32/ip32-irq.c
@@ -457,7 +457,7 @@ static void ip32_irq4(void)
457 457
458static void ip32_irq5(void) 458static void ip32_irq5(void)
459{ 459{
460 ll_timer_interrupt(IP32_R4K_TIMER_IRQ); 460 do_IRQ(IP32_R4K_TIMER_IRQ);
461} 461}
462 462
463asmlinkage void plat_irq_dispatch(void) 463asmlinkage void plat_irq_dispatch(void)
diff --git a/arch/mips/sibyte/Kconfig b/arch/mips/sibyte/Kconfig
index 841b301c99f0..e8fb880272bd 100644
--- a/arch/mips/sibyte/Kconfig
+++ b/arch/mips/sibyte/Kconfig
@@ -1,6 +1,7 @@
1config SIBYTE_SB1250 1config SIBYTE_SB1250
2 bool 2 bool
3 select HW_HAS_PCI 3 select HW_HAS_PCI
4 select IRQ_CPU
4 select SIBYTE_ENABLE_LDT_IF_PCI 5 select SIBYTE_ENABLE_LDT_IF_PCI
5 select SIBYTE_HAS_ZBUS_PROFILING 6 select SIBYTE_HAS_ZBUS_PROFILING
6 select SIBYTE_SB1xxx_SOC 7 select SIBYTE_SB1xxx_SOC
@@ -8,6 +9,7 @@ config SIBYTE_SB1250
8 9
9config SIBYTE_BCM1120 10config SIBYTE_BCM1120
10 bool 11 bool
12 select IRQ_CPU
11 select SIBYTE_BCM112X 13 select SIBYTE_BCM112X
12 select SIBYTE_HAS_ZBUS_PROFILING 14 select SIBYTE_HAS_ZBUS_PROFILING
13 select SIBYTE_SB1xxx_SOC 15 select SIBYTE_SB1xxx_SOC
@@ -15,6 +17,7 @@ config SIBYTE_BCM1120
15config SIBYTE_BCM1125 17config SIBYTE_BCM1125
16 bool 18 bool
17 select HW_HAS_PCI 19 select HW_HAS_PCI
20 select IRQ_CPU
18 select SIBYTE_BCM112X 21 select SIBYTE_BCM112X
19 select SIBYTE_HAS_ZBUS_PROFILING 22 select SIBYTE_HAS_ZBUS_PROFILING
20 select SIBYTE_SB1xxx_SOC 23 select SIBYTE_SB1xxx_SOC
@@ -22,6 +25,7 @@ config SIBYTE_BCM1125
22config SIBYTE_BCM1125H 25config SIBYTE_BCM1125H
23 bool 26 bool
24 select HW_HAS_PCI 27 select HW_HAS_PCI
28 select IRQ_CPU
25 select SIBYTE_BCM112X 29 select SIBYTE_BCM112X
26 select SIBYTE_ENABLE_LDT_IF_PCI 30 select SIBYTE_ENABLE_LDT_IF_PCI
27 select SIBYTE_HAS_ZBUS_PROFILING 31 select SIBYTE_HAS_ZBUS_PROFILING
@@ -29,12 +33,14 @@ config SIBYTE_BCM1125H
29 33
30config SIBYTE_BCM112X 34config SIBYTE_BCM112X
31 bool 35 bool
36 select IRQ_CPU
32 select SIBYTE_SB1xxx_SOC 37 select SIBYTE_SB1xxx_SOC
33 select SIBYTE_HAS_ZBUS_PROFILING 38 select SIBYTE_HAS_ZBUS_PROFILING
34 39
35config SIBYTE_BCM1x80 40config SIBYTE_BCM1x80
36 bool 41 bool
37 select HW_HAS_PCI 42 select HW_HAS_PCI
43 select IRQ_CPU
38 select SIBYTE_HAS_ZBUS_PROFILING 44 select SIBYTE_HAS_ZBUS_PROFILING
39 select SIBYTE_SB1xxx_SOC 45 select SIBYTE_SB1xxx_SOC
40 select SYS_SUPPORTS_SMP 46 select SYS_SUPPORTS_SMP
@@ -42,6 +48,7 @@ config SIBYTE_BCM1x80
42config SIBYTE_BCM1x55 48config SIBYTE_BCM1x55
43 bool 49 bool
44 select HW_HAS_PCI 50 select HW_HAS_PCI
51 select IRQ_CPU
45 select SIBYTE_SB1xxx_SOC 52 select SIBYTE_SB1xxx_SOC
46 select SIBYTE_HAS_ZBUS_PROFILING 53 select SIBYTE_HAS_ZBUS_PROFILING
47 select SYS_SUPPORTS_SMP 54 select SYS_SUPPORTS_SMP
@@ -49,6 +56,7 @@ config SIBYTE_BCM1x55
49config SIBYTE_SB1xxx_SOC 56config SIBYTE_SB1xxx_SOC
50 bool 57 bool
51 select DMA_COHERENT 58 select DMA_COHERENT
59 select IRQ_CPU
52 select SIBYTE_CFE 60 select SIBYTE_CFE
53 select SWAP_IO_SPACE 61 select SWAP_IO_SPACE
54 select SYS_SUPPORTS_32BIT_KERNEL 62 select SYS_SUPPORTS_32BIT_KERNEL
@@ -166,10 +174,6 @@ config SIBYTE_BW_TRACE
166 buffer activity. Raw buffer data is dumped to console, and 174 buffer activity. Raw buffer data is dumped to console, and
167 must be processed off-line. 175 must be processed off-line.
168 176
169config SIBYTE_SB1250_PROF
170 bool "Support for SB1/SOC profiling - SB1/SCD perf counters"
171 depends on SIBYTE_SB1xxx_SOC
172
173config SIBYTE_TBPROF 177config SIBYTE_TBPROF
174 tristate "Support for ZBbus profiling" 178 tristate "Support for ZBbus profiling"
175 depends on SIBYTE_HAS_ZBUS_PROFILING 179 depends on SIBYTE_HAS_ZBUS_PROFILING
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
index e729b5f30264..cf979dbb282d 100644
--- a/arch/mips/sibyte/bcm1480/irq.c
+++ b/arch/mips/sibyte/bcm1480/irq.c
@@ -450,7 +450,6 @@ static void bcm1480_kgdb_interrupt(void)
450 450
451#endif /* CONFIG_KGDB */ 451#endif /* CONFIG_KGDB */
452 452
453extern void bcm1480_timer_interrupt(void);
454extern void bcm1480_mailbox_interrupt(void); 453extern void bcm1480_mailbox_interrupt(void);
455 454
456asmlinkage void plat_irq_dispatch(void) 455asmlinkage void plat_irq_dispatch(void)
@@ -470,8 +469,16 @@ asmlinkage void plat_irq_dispatch(void)
470 else 469 else
471#endif 470#endif
472 471
473 if (pending & CAUSEF_IP4) 472 if (pending & CAUSEF_IP4) {
474 bcm1480_timer_interrupt(); 473 int cpu = smp_processor_id();
474 int irq = K_BCM1480_INT_TIMER_0 + cpu;
475
476 /* Reset the timer */
477 __raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
478 IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
479
480 do_IRQ(irq);
481 }
475 482
476#ifdef CONFIG_SMP 483#ifdef CONFIG_SMP
477 else if (pending & CAUSEF_IP3) 484 else if (pending & CAUSEF_IP3)
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
index ad593a6c20be..6a4cc84194a9 100644
--- a/arch/mips/sibyte/sb1250/irq.c
+++ b/arch/mips/sibyte/sb1250/irq.c
@@ -28,6 +28,7 @@
28#include <asm/errno.h> 28#include <asm/errno.h>
29#include <asm/signal.h> 29#include <asm/signal.h>
30#include <asm/system.h> 30#include <asm/system.h>
31#include <asm/time.h>
31#include <asm/io.h> 32#include <asm/io.h>
32 33
33#include <asm/sibyte/sb1250_regs.h> 34#include <asm/sibyte/sb1250_regs.h>
@@ -399,18 +400,45 @@ static void sb1250_kgdb_interrupt(void)
399 400
400#endif /* CONFIG_KGDB */ 401#endif /* CONFIG_KGDB */
401 402
402extern void sb1250_timer_interrupt(void); 403static inline void sb1250_timer_interrupt(void)
404{
405 int cpu = smp_processor_id();
406 int irq = K_INT_TIMER_0 + cpu;
407
408 irq_enter();
409 kstat_this_cpu.irqs[irq]++;
410
411 write_seqlock(&xtime_lock);
412
413 /* ACK interrupt */
414 ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
415 IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
416
417 /*
418 * call the generic timer interrupt handling
419 */
420 do_timer(1);
421
422 write_sequnlock(&xtime_lock);
423
424 /*
425 * In UP mode, we call local_timer_interrupt() to do profiling
426 * and process accouting.
427 *
428 * In SMP mode, local_timer_interrupt() is invoked by appropriate
429 * low-level local timer interrupt handler.
430 */
431 local_timer_interrupt(irq);
432
433 irq_exit();
434}
435
403extern void sb1250_mailbox_interrupt(void); 436extern void sb1250_mailbox_interrupt(void);
404 437
405asmlinkage void plat_irq_dispatch(void) 438asmlinkage void plat_irq_dispatch(void)
406{ 439{
407 unsigned int pending; 440 unsigned int pending;
408 441
409#ifdef CONFIG_SIBYTE_SB1250_PROF
410 /* Set compare to count to silence count/compare timer interrupts */
411 write_c0_compare(read_c0_count());
412#endif
413
414 /* 442 /*
415 * What a pain. We have to be really careful saving the upper 32 bits 443 * What a pain. We have to be really careful saving the upper 32 bits
416 * of any * register across function calls if we don't want them 444 * of any * register across function calls if we don't want them
@@ -423,13 +451,9 @@ asmlinkage void plat_irq_dispatch(void)
423 451
424 pending = read_c0_cause() & read_c0_status() & ST0_IM; 452 pending = read_c0_cause() & read_c0_status() & ST0_IM;
425 453
426#ifdef CONFIG_SIBYTE_SB1250_PROF 454 if (pending & CAUSEF_IP7) /* CPU performance counter interrupt */
427 if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */ 455 do_IRQ(MIPS_CPU_IRQ_BASE + 7);
428 sbprof_cpu_intr(); 456 else if (pending & CAUSEF_IP4)
429 else
430#endif
431
432 if (pending & CAUSEF_IP4)
433 sb1250_timer_interrupt(); 457 sb1250_timer_interrupt();
434 458
435#ifdef CONFIG_SMP 459#ifdef CONFIG_SMP
diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c
index 5bb83cd4c113..eb177075e9c0 100644
--- a/arch/mips/sibyte/sb1250/time.c
+++ b/arch/mips/sibyte/sb1250/time.c
@@ -116,18 +116,6 @@ void sb1250_time_init(void)
116 */ 116 */
117} 117}
118 118
119void sb1250_timer_interrupt(void)
120{
121 int cpu = smp_processor_id();
122 int irq = K_INT_TIMER_0 + cpu;
123
124 /* ACK interrupt */
125 ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
126 IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
127
128 ll_timer_interrupt(irq);
129}
130
131/* 119/*
132 * The HPT is free running from SB1250_HPT_VALUE down to 0 then starts over 120 * The HPT is free running from SB1250_HPT_VALUE down to 0 then starts over
133 * again. 121 * again.
diff --git a/include/asm-mips/mach-ip27/irq.h b/include/asm-mips/mach-ip27/irq.h
index 25f0c3f39adf..cf4384bfa846 100644
--- a/include/asm-mips/mach-ip27/irq.h
+++ b/include/asm-mips/mach-ip27/irq.h
@@ -17,4 +17,6 @@
17 */ 17 */
18#define NR_IRQS 256 18#define NR_IRQS 256
19 19
20#include_next <irq.h>
21
20#endif /* __ASM_MACH_IP27_IRQ_H */ 22#endif /* __ASM_MACH_IP27_IRQ_H */
diff --git a/include/asm-mips/qemu.h b/include/asm-mips/qemu.h
index 531caf44560c..487ced4a40de 100644
--- a/include/asm-mips/qemu.h
+++ b/include/asm-mips/qemu.h
@@ -12,7 +12,7 @@
12 * Interrupt numbers 12 * Interrupt numbers
13 */ 13 */
14#define Q_PIC_IRQ_BASE 0 14#define Q_PIC_IRQ_BASE 0
15#define Q_COUNT_COMPARE_IRQ 16 15#define Q_COUNT_COMPARE_IRQ 23
16 16
17/* 17/*
18 * Qemu clock rate. Unlike on real MIPS this has no relation to the 18 * Qemu clock rate. Unlike on real MIPS this has no relation to the
diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h
index 3516b32c9efb..35555bd5c52d 100644
--- a/include/asm-mips/time.h
+++ b/include/asm-mips/time.h
@@ -49,11 +49,6 @@ extern void (*mips_timer_ack)(void);
49extern struct clocksource clocksource_mips; 49extern struct clocksource clocksource_mips;
50 50
51/* 51/*
52 * The low-level timer interrupt routine.
53 */
54extern void ll_timer_interrupt(int irq, void *dev_id);
55
56/*
57 * profiling and process accouting is done separately in local_timer_interrupt 52 * profiling and process accouting is done separately in local_timer_interrupt
58 */ 53 */
59extern void local_timer_interrupt(int irq, void *dev_id); 54extern void local_timer_interrupt(int irq, void *dev_id);
@@ -78,4 +73,9 @@ extern unsigned int mips_hpt_frequency;
78 */ 73 */
79extern int (*perf_irq)(void); 74extern int (*perf_irq)(void);
80 75
76/*
77 * Initialize the calling CPU's compare interrupt as clockevent device
78 */
79extern void mips_clockevent_init(void);
80
81#endif /* _ASM_TIME_H */ 81#endif /* _ASM_TIME_H */