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.c88
1 files changed, 72 insertions, 16 deletions
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index 16315444dd5a..72a12d931cba 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -31,22 +31,21 @@
31 31
32#include <asm/mipsregs.h> 32#include <asm/mipsregs.h>
33#include <asm/ptrace.h> 33#include <asm/ptrace.h>
34#include <asm/hardirq.h>
35#include <asm/irq.h>
34#include <asm/div64.h> 36#include <asm/div64.h>
35#include <asm/cpu.h> 37#include <asm/cpu.h>
36#include <asm/time.h> 38#include <asm/time.h>
37#include <asm/mc146818-time.h> 39#include <asm/mc146818-time.h>
40#include <asm/msc01_ic.h>
38 41
39#include <asm/mips-boards/generic.h> 42#include <asm/mips-boards/generic.h>
40#include <asm/mips-boards/prom.h> 43#include <asm/mips-boards/prom.h>
44#include <asm/mips-boards/maltaint.h>
45#include <asm/mc146818-time.h>
41 46
42unsigned long cpu_khz; 47unsigned long cpu_khz;
43 48
44#if defined(CONFIG_MIPS_SEAD)
45#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ5)
46#else
47#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
48#endif
49
50#if defined(CONFIG_MIPS_ATLAS) 49#if defined(CONFIG_MIPS_ATLAS)
51static char display_string[] = " LINUX ON ATLAS "; 50static char display_string[] = " LINUX ON ATLAS ";
52#endif 51#endif
@@ -59,20 +58,61 @@ static char display_string[] = " LINUX ON SEAD ";
59static unsigned int display_count = 0; 58static unsigned int display_count = 0;
60#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) 59#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8)
61 60
62#define MIPS_CPU_TIMER_IRQ (NR_IRQS-1)
63
64static unsigned int timer_tick_count=0; 61static unsigned int timer_tick_count=0;
62static int mips_cpu_timer_irq;
65 63
66void mips_timer_interrupt(struct pt_regs *regs) 64static inline void scroll_display_message(void)
67{ 65{
68 if ((timer_tick_count++ % HZ) == 0) { 66 if ((timer_tick_count++ % HZ) == 0) {
69 mips_display_message(&display_string[display_count++]); 67 mips_display_message(&display_string[display_count++]);
70 if (display_count == MAX_DISPLAY_COUNT) 68 if (display_count == MAX_DISPLAY_COUNT)
71 display_count = 0; 69 display_count = 0;
70 }
71}
72
73static void mips_timer_dispatch (struct pt_regs *regs)
74{
75 do_IRQ (mips_cpu_timer_irq, regs);
76}
72 77
78irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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);
73 } 104 }
74 105
75 ll_timer_interrupt(MIPS_CPU_TIMER_IRQ, regs); 106 return IRQ_HANDLED;
107#else
108 irqreturn_t r;
109
110 r = timer_interrupt(irq, dev_id, regs);
111
112 scroll_display_message();
113
114 return r;
115#endif
76} 116}
77 117
78/* 118/*
@@ -140,10 +180,8 @@ void __init mips_time_init(void)
140 180
141 local_irq_save(flags); 181 local_irq_save(flags);
142 182
143#if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_MALTA)
144 /* Set Data mode - binary. */ 183 /* Set Data mode - binary. */
145 CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); 184 CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
146#endif
147 185
148 est_freq = estimate_cpu_frequency (); 186 est_freq = estimate_cpu_frequency ();
149 187
@@ -157,11 +195,29 @@ void __init mips_time_init(void)
157 195
158void __init mips_timer_setup(struct irqaction *irq) 196void __init mips_timer_setup(struct irqaction *irq)
159{ 197{
198 if (cpu_has_veic) {
199 set_vi_handler (MSC01E_INT_CPUCTR, mips_timer_dispatch);
200 mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
201 }
202 else {
203 if (cpu_has_vint)
204 set_vi_handler (MIPSCPU_INT_CPUCTR, mips_timer_dispatch);
205 mips_cpu_timer_irq = MIPSCPU_INT_BASE + MIPSCPU_INT_CPUCTR;
206 }
207
208
160 /* we are using the cpu counter for timer interrupts */ 209 /* we are using the cpu counter for timer interrupts */
161 irq->handler = no_action; /* we use our own handler */ 210 irq->handler = mips_timer_interrupt; /* we use our own handler */
162 setup_irq(MIPS_CPU_TIMER_IRQ, irq); 211 setup_irq(mips_cpu_timer_irq, irq);
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
163 220
164 /* to generate the first timer interrupt */ 221 /* to generate the first timer interrupt */
165 write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ); 222 write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ);
166 set_c0_status(ALLINTS);
167} 223}