diff options
Diffstat (limited to 'arch/mips/mips-boards/generic/time.c')
-rw-r--r-- | arch/mips/mips-boards/generic/time.c | 88 |
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 | ||
42 | unsigned long cpu_khz; | 47 | unsigned 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) |
51 | static char display_string[] = " LINUX ON ATLAS "; | 50 | static char display_string[] = " LINUX ON ATLAS "; |
52 | #endif | 51 | #endif |
@@ -59,20 +58,61 @@ static char display_string[] = " LINUX ON SEAD "; | |||
59 | static unsigned int display_count = 0; | 58 | static 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 | |||
64 | static unsigned int timer_tick_count=0; | 61 | static unsigned int timer_tick_count=0; |
62 | static int mips_cpu_timer_irq; | ||
65 | 63 | ||
66 | void mips_timer_interrupt(struct pt_regs *regs) | 64 | static 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 | |||
73 | static void mips_timer_dispatch (struct pt_regs *regs) | ||
74 | { | ||
75 | do_IRQ (mips_cpu_timer_irq, regs); | ||
76 | } | ||
72 | 77 | ||
78 | irqreturn_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 | ||
158 | void __init mips_timer_setup(struct irqaction *irq) | 196 | void __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 | } |