aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/mips-boards/generic/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/mips-boards/generic/time.c')
-rw-r--r--arch/mips/mips-boards/generic/time.c51
1 files changed, 46 insertions, 5 deletions
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index 3a6f1428b2cb..72a12d931cba 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -61,6 +61,15 @@ static unsigned int display_count = 0;
61static unsigned int timer_tick_count=0; 61static unsigned int timer_tick_count=0;
62static int mips_cpu_timer_irq; 62static int mips_cpu_timer_irq;
63 63
64static inline void scroll_display_message(void)
65{
66 if ((timer_tick_count++ % HZ) == 0) {
67 mips_display_message(&display_string[display_count++]);
68 if (display_count == MAX_DISPLAY_COUNT)
69 display_count = 0;
70 }
71}
72
64static void mips_timer_dispatch (struct pt_regs *regs) 73static void mips_timer_dispatch (struct pt_regs *regs)
65{ 74{
66 do_IRQ (mips_cpu_timer_irq, regs); 75 do_IRQ (mips_cpu_timer_irq, regs);
@@ -68,17 +77,42 @@ static void mips_timer_dispatch (struct pt_regs *regs)
68 77
69irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 78irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
70{ 79{
80#ifdef CONFIG_SMP
81 int cpu = smp_processor_id();
82
83 if (cpu == 0) {
84 /*
85 * CPU 0 handles the global timer interrupt job and process accounting
86 * resets count/compare registers to trigger next timer int.
87 */
88 (void) timer_interrupt(irq, dev_id, regs);
89 scroll_display_message();
90 }
91 else {
92 /* Everyone else needs to reset the timer int here as
93 ll_local_timer_interrupt doesn't */
94 /*
95 * FIXME: need to cope with counter underflow.
96 * More support needs to be added to kernel/time for
97 * counter/timer interrupts on multiple CPU's
98 */
99 write_c0_compare (read_c0_count() + (mips_hpt_frequency/HZ));
100 /*
101 * other CPUs should do profiling and process accounting
102 */
103 local_timer_interrupt (irq, dev_id, regs);
104 }
105
106 return IRQ_HANDLED;
107#else
71 irqreturn_t r; 108 irqreturn_t r;
72 109
73 r = timer_interrupt(irq, dev_id, regs); 110 r = timer_interrupt(irq, dev_id, regs);
74 111
75 if ((timer_tick_count++ % HZ) == 0) { 112 scroll_display_message();
76 mips_display_message(&display_string[display_count++]);
77 if (display_count == MAX_DISPLAY_COUNT)
78 display_count = 0;
79 }
80 113
81 return r; 114 return r;
115#endif
82} 116}
83 117
84/* 118/*
@@ -176,6 +210,13 @@ void __init mips_timer_setup(struct irqaction *irq)
176 irq->handler = mips_timer_interrupt; /* we use our own handler */ 210 irq->handler = mips_timer_interrupt; /* we use our own handler */
177 setup_irq(mips_cpu_timer_irq, irq); 211 setup_irq(mips_cpu_timer_irq, irq);
178 212
213#ifdef CONFIG_SMP
214 /* irq_desc(riptor) is a global resource, when the interrupt overlaps
215 on seperate cpu's the first one tries to handle the second interrupt.
216 The effect is that the int remains disabled on the second cpu.
217 Mark the interrupt with IRQ_PER_CPU to avoid any confusion */
218 irq_desc[mips_cpu_timer_irq].status |= IRQ_PER_CPU;
219#endif
179 220
180 /* to generate the first timer interrupt */ 221 /* to generate the first timer interrupt */
181 write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ); 222 write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ);