diff options
Diffstat (limited to 'arch/mips/mips-boards/generic/time.c')
-rw-r--r-- | arch/mips/mips-boards/generic/time.c | 149 |
1 files changed, 22 insertions, 127 deletions
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index d7bff9ca5356..1d00b778ff1e 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <asm/mipsregs.h> | 31 | #include <asm/mipsregs.h> |
32 | #include <asm/mipsmtregs.h> | 32 | #include <asm/mipsmtregs.h> |
33 | #include <asm/hardirq.h> | 33 | #include <asm/hardirq.h> |
34 | #include <asm/i8253.h> | ||
34 | #include <asm/irq.h> | 35 | #include <asm/irq.h> |
35 | #include <asm/div64.h> | 36 | #include <asm/div64.h> |
36 | #include <asm/cpu.h> | 37 | #include <asm/cpu.h> |
@@ -55,7 +56,6 @@ unsigned long cpu_khz; | |||
55 | 56 | ||
56 | static int mips_cpu_timer_irq; | 57 | static int mips_cpu_timer_irq; |
57 | extern int cp0_perfcount_irq; | 58 | extern int cp0_perfcount_irq; |
58 | extern void smtc_timer_broadcast(void); | ||
59 | 59 | ||
60 | static void mips_timer_dispatch(void) | 60 | static void mips_timer_dispatch(void) |
61 | { | 61 | { |
@@ -68,108 +68,6 @@ static void mips_perf_dispatch(void) | |||
68 | } | 68 | } |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * Redeclare until I get around mopping the timer code insanity on MIPS. | ||
72 | */ | ||
73 | extern int null_perf_irq(void); | ||
74 | |||
75 | extern int (*perf_irq)(void); | ||
76 | |||
77 | /* | ||
78 | * Possibly handle a performance counter interrupt. | ||
79 | * Return true if the timer interrupt should not be checked | ||
80 | */ | ||
81 | static inline int handle_perf_irq (int r2) | ||
82 | { | ||
83 | /* | ||
84 | * The performance counter overflow interrupt may be shared with the | ||
85 | * timer interrupt (cp0_perfcount_irq < 0). If it is and a | ||
86 | * performance counter has overflowed (perf_irq() == IRQ_HANDLED) | ||
87 | * and we can't reliably determine if a counter interrupt has also | ||
88 | * happened (!r2) then don't check for a timer interrupt. | ||
89 | */ | ||
90 | return (cp0_perfcount_irq < 0) && | ||
91 | perf_irq() == IRQ_HANDLED && | ||
92 | !r2; | ||
93 | } | ||
94 | |||
95 | irqreturn_t mips_timer_interrupt(int irq, void *dev_id) | ||
96 | { | ||
97 | int cpu = smp_processor_id(); | ||
98 | |||
99 | #ifdef CONFIG_MIPS_MT_SMTC | ||
100 | /* | ||
101 | * In an SMTC system, one Count/Compare set exists per VPE. | ||
102 | * Which TC within a VPE gets the interrupt is essentially | ||
103 | * random - we only know that it shouldn't be one with | ||
104 | * IXMT set. Whichever TC gets the interrupt needs to | ||
105 | * send special interprocessor interrupts to the other | ||
106 | * TCs to make sure that they schedule, etc. | ||
107 | * | ||
108 | * That code is specific to the SMTC kernel, not to | ||
109 | * the a particular platform, so it's invoked from | ||
110 | * the general MIPS timer_interrupt routine. | ||
111 | */ | ||
112 | |||
113 | /* | ||
114 | * We could be here due to timer interrupt, | ||
115 | * perf counter overflow, or both. | ||
116 | */ | ||
117 | (void) handle_perf_irq(1); | ||
118 | |||
119 | if (read_c0_cause() & (1 << 30)) { | ||
120 | /* | ||
121 | * There are things we only want to do once per tick | ||
122 | * in an "MP" system. One TC of each VPE will take | ||
123 | * the actual timer interrupt. The others will get | ||
124 | * timer broadcast IPIs. We use whoever it is that takes | ||
125 | * the tick on VPE 0 to run the full timer_interrupt(). | ||
126 | */ | ||
127 | if (cpu_data[cpu].vpe_id == 0) { | ||
128 | timer_interrupt(irq, NULL); | ||
129 | } else { | ||
130 | write_c0_compare(read_c0_count() + | ||
131 | (mips_hpt_frequency/HZ)); | ||
132 | local_timer_interrupt(irq, dev_id); | ||
133 | } | ||
134 | smtc_timer_broadcast(); | ||
135 | } | ||
136 | #else /* CONFIG_MIPS_MT_SMTC */ | ||
137 | int r2 = cpu_has_mips_r2; | ||
138 | |||
139 | if (handle_perf_irq(r2)) | ||
140 | goto out; | ||
141 | |||
142 | if (r2 && ((read_c0_cause() & (1 << 30)) == 0)) | ||
143 | goto out; | ||
144 | |||
145 | if (cpu == 0) { | ||
146 | /* | ||
147 | * CPU 0 handles the global timer interrupt job and process | ||
148 | * accounting resets count/compare registers to trigger next | ||
149 | * timer int. | ||
150 | */ | ||
151 | timer_interrupt(irq, NULL); | ||
152 | } else { | ||
153 | /* Everyone else needs to reset the timer int here as | ||
154 | ll_local_timer_interrupt doesn't */ | ||
155 | /* | ||
156 | * FIXME: need to cope with counter underflow. | ||
157 | * More support needs to be added to kernel/time for | ||
158 | * counter/timer interrupts on multiple CPU's | ||
159 | */ | ||
160 | write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ)); | ||
161 | |||
162 | /* | ||
163 | * Other CPUs should do profiling and process accounting | ||
164 | */ | ||
165 | local_timer_interrupt(irq, dev_id); | ||
166 | } | ||
167 | out: | ||
168 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
169 | return IRQ_HANDLED; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect | 71 | * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect |
174 | */ | 72 | */ |
175 | static unsigned int __init estimate_cpu_frequency(void) | 73 | static unsigned int __init estimate_cpu_frequency(void) |
@@ -224,19 +122,19 @@ static unsigned int __init estimate_cpu_frequency(void) | |||
224 | return count; | 122 | return count; |
225 | } | 123 | } |
226 | 124 | ||
227 | unsigned long __init mips_rtc_get_time(void) | 125 | unsigned long read_persistent_clock(void) |
228 | { | 126 | { |
229 | return mc146818_get_cmos_time(); | 127 | return mc146818_get_cmos_time(); |
230 | } | 128 | } |
231 | 129 | ||
232 | void __init mips_time_init(void) | 130 | void __init plat_time_init(void) |
233 | { | 131 | { |
234 | unsigned int est_freq; | 132 | unsigned int est_freq; |
235 | 133 | ||
236 | /* Set Data mode - binary. */ | 134 | /* Set Data mode - binary. */ |
237 | CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); | 135 | CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); |
238 | 136 | ||
239 | est_freq = estimate_cpu_frequency (); | 137 | est_freq = estimate_cpu_frequency(); |
240 | 138 | ||
241 | printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, | 139 | printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, |
242 | (est_freq%1000000)*100/1000000); | 140 | (est_freq%1000000)*100/1000000); |
@@ -244,38 +142,37 @@ void __init mips_time_init(void) | |||
244 | cpu_khz = est_freq / 1000; | 142 | cpu_khz = est_freq / 1000; |
245 | 143 | ||
246 | mips_scroll_message(); | 144 | mips_scroll_message(); |
145 | #ifdef CONFIG_I8253 /* Only Malta has a PIT */ | ||
146 | setup_pit_timer(); | ||
147 | #endif | ||
247 | } | 148 | } |
248 | 149 | ||
249 | irqreturn_t mips_perf_interrupt(int irq, void *dev_id) | 150 | //static irqreturn_t mips_perf_interrupt(int irq, void *dev_id) |
250 | { | 151 | //{ |
251 | return perf_irq(); | 152 | // return perf_irq(); |
252 | } | 153 | //} |
253 | 154 | ||
254 | static struct irqaction perf_irqaction = { | 155 | //static struct irqaction perf_irqaction = { |
255 | .handler = mips_perf_interrupt, | 156 | // .handler = mips_perf_interrupt, |
256 | .flags = IRQF_DISABLED | IRQF_PERCPU, | 157 | // .flags = IRQF_DISABLED | IRQF_PERCPU, |
257 | .name = "performance", | 158 | // .name = "performance", |
258 | }; | 159 | //}; |
259 | 160 | ||
260 | void __init plat_perf_setup(struct irqaction *irq) | 161 | void __init plat_perf_setup(void) |
261 | { | 162 | { |
163 | // struct irqaction *irq = &perf_irqaction; | ||
164 | |||
262 | cp0_perfcount_irq = -1; | 165 | cp0_perfcount_irq = -1; |
263 | 166 | ||
264 | #ifdef MSC01E_INT_BASE | 167 | #ifdef MSC01E_INT_BASE |
265 | if (cpu_has_veic) { | 168 | if (cpu_has_veic) { |
266 | set_vi_handler (MSC01E_INT_PERFCTR, mips_perf_dispatch); | 169 | set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch); |
267 | cp0_perfcount_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; | 170 | cp0_perfcount_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; |
268 | } else | 171 | } else |
269 | #endif | 172 | #endif |
270 | if (cp0_perfcount_irq >= 0) { | 173 | if (cp0_perfcount_irq >= 0) { |
271 | if (cpu_has_vint) | 174 | if (cpu_has_vint) |
272 | set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); | 175 | set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); |
273 | #ifdef CONFIG_MIPS_MT_SMTC | ||
274 | setup_irq_smtc(cp0_perfcount_irq, irq, | ||
275 | 0x100 << cp0_perfcount_irq); | ||
276 | #else | ||
277 | setup_irq(cp0_perfcount_irq, irq); | ||
278 | #endif /* CONFIG_MIPS_MT_SMTC */ | ||
279 | #ifdef CONFIG_SMP | 176 | #ifdef CONFIG_SMP |
280 | set_irq_handler(cp0_perfcount_irq, handle_percpu_irq); | 177 | set_irq_handler(cp0_perfcount_irq, handle_percpu_irq); |
281 | #endif | 178 | #endif |
@@ -286,7 +183,7 @@ void __init plat_timer_setup(struct irqaction *irq) | |||
286 | { | 183 | { |
287 | #ifdef MSC01E_INT_BASE | 184 | #ifdef MSC01E_INT_BASE |
288 | if (cpu_has_veic) { | 185 | if (cpu_has_veic) { |
289 | set_vi_handler (MSC01E_INT_CPUCTR, mips_timer_dispatch); | 186 | set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch); |
290 | mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR; | 187 | mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR; |
291 | } | 188 | } |
292 | else | 189 | else |
@@ -297,8 +194,6 @@ void __init plat_timer_setup(struct irqaction *irq) | |||
297 | mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; | 194 | mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; |
298 | } | 195 | } |
299 | 196 | ||
300 | /* we are using the cpu counter for timer interrupts */ | ||
301 | irq->handler = mips_timer_interrupt; /* we use our own handler */ | ||
302 | #ifdef CONFIG_MIPS_MT_SMTC | 197 | #ifdef CONFIG_MIPS_MT_SMTC |
303 | setup_irq_smtc(mips_cpu_timer_irq, irq, 0x100 << cp0_compare_irq); | 198 | setup_irq_smtc(mips_cpu_timer_irq, irq, 0x100 << cp0_compare_irq); |
304 | #else | 199 | #else |
@@ -308,5 +203,5 @@ void __init plat_timer_setup(struct irqaction *irq) | |||
308 | set_irq_handler(mips_cpu_timer_irq, handle_percpu_irq); | 203 | set_irq_handler(mips_cpu_timer_irq, handle_percpu_irq); |
309 | #endif | 204 | #endif |
310 | 205 | ||
311 | plat_perf_setup(&perf_irqaction); | 206 | plat_perf_setup(); |
312 | } | 207 | } |