diff options
author | Yi Li <yi.li@analog.com> | 2009-12-28 05:21:49 -0500 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2010-03-09 00:30:48 -0500 |
commit | 0d152c27e336b5fd777da7dd3e814617e7305afd (patch) | |
tree | 2863b1b2f0fe0676a5928b197c8d1d289ab71777 /arch/blackfin/kernel/time-ts.c | |
parent | 682f5dc4ed7cdef1f55e40ee505c4346dfa6fa91 (diff) |
Blackfin: SMP: make core timers per-cpu clock events for HRT
SMP systems require per-cpu local clock event devices in order to enable
HRT support. One a BF561, we can use local core timer for this purpose.
Originally, there was one global core-timer clock event device set up for
core A.
To accomplish this feat, we need to split the gptimer0/core timer logic
so that each is a standalone clock event. There is no requirement that
we only have one clock event source anyways. Once we have this, we just
define per-cpu clock event devices for each local core timer.
Signed-off-by: Yi Li <yi.li@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch/blackfin/kernel/time-ts.c')
-rw-r--r-- | arch/blackfin/kernel/time-ts.c | 197 |
1 files changed, 105 insertions, 92 deletions
diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c index 17c38c5b5b22..a351f97c87a3 100644 --- a/arch/blackfin/kernel/time-ts.c +++ b/arch/blackfin/kernel/time-ts.c | |||
@@ -132,7 +132,6 @@ static int __init bfin_cs_gptimer0_init(void) | |||
132 | # define bfin_cs_gptimer0_init() | 132 | # define bfin_cs_gptimer0_init() |
133 | #endif | 133 | #endif |
134 | 134 | ||
135 | |||
136 | #if defined(CONFIG_GPTMR0_CLOCKSOURCE) || defined(CONFIG_CYCLES_CLOCKSOURCE) | 135 | #if defined(CONFIG_GPTMR0_CLOCKSOURCE) || defined(CONFIG_CYCLES_CLOCKSOURCE) |
137 | /* prefer to use cycles since it has higher rating */ | 136 | /* prefer to use cycles since it has higher rating */ |
138 | notrace unsigned long long sched_clock(void) | 137 | notrace unsigned long long sched_clock(void) |
@@ -145,47 +144,8 @@ notrace unsigned long long sched_clock(void) | |||
145 | } | 144 | } |
146 | #endif | 145 | #endif |
147 | 146 | ||
148 | #ifdef CONFIG_CORE_TIMER_IRQ_L1 | ||
149 | __attribute__((l1_text)) | ||
150 | #endif | ||
151 | irqreturn_t timer_interrupt(int irq, void *dev_id); | ||
152 | |||
153 | static int bfin_timer_set_next_event(unsigned long, \ | ||
154 | struct clock_event_device *); | ||
155 | |||
156 | static void bfin_timer_set_mode(enum clock_event_mode, \ | ||
157 | struct clock_event_device *); | ||
158 | |||
159 | static struct clock_event_device clockevent_bfin = { | ||
160 | #if defined(CONFIG_TICKSOURCE_GPTMR0) | ||
161 | .name = "bfin_gptimer0", | ||
162 | .rating = 300, | ||
163 | .irq = IRQ_TIMER0, | ||
164 | #else | ||
165 | .name = "bfin_core_timer", | ||
166 | .rating = 350, | ||
167 | .irq = IRQ_CORETMR, | ||
168 | #endif | ||
169 | .shift = 32, | ||
170 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
171 | .set_next_event = bfin_timer_set_next_event, | ||
172 | .set_mode = bfin_timer_set_mode, | ||
173 | }; | ||
174 | |||
175 | static struct irqaction bfin_timer_irq = { | ||
176 | #if defined(CONFIG_TICKSOURCE_GPTMR0) | ||
177 | .name = "Blackfin GPTimer0", | ||
178 | #else | ||
179 | .name = "Blackfin CoreTimer", | ||
180 | #endif | ||
181 | .flags = IRQF_DISABLED | IRQF_TIMER | \ | ||
182 | IRQF_IRQPOLL | IRQF_PERCPU, | ||
183 | .handler = timer_interrupt, | ||
184 | .dev_id = &clockevent_bfin, | ||
185 | }; | ||
186 | |||
187 | #if defined(CONFIG_TICKSOURCE_GPTMR0) | 147 | #if defined(CONFIG_TICKSOURCE_GPTMR0) |
188 | static int bfin_timer_set_next_event(unsigned long cycles, | 148 | static int bfin_gptmr0_set_next_event(unsigned long cycles, |
189 | struct clock_event_device *evt) | 149 | struct clock_event_device *evt) |
190 | { | 150 | { |
191 | disable_gptimers(TIMER0bit); | 151 | disable_gptimers(TIMER0bit); |
@@ -196,7 +156,7 @@ static int bfin_timer_set_next_event(unsigned long cycles, | |||
196 | return 0; | 156 | return 0; |
197 | } | 157 | } |
198 | 158 | ||
199 | static void bfin_timer_set_mode(enum clock_event_mode mode, | 159 | static void bfin_gptmr0_set_mode(enum clock_event_mode mode, |
200 | struct clock_event_device *evt) | 160 | struct clock_event_device *evt) |
201 | { | 161 | { |
202 | switch (mode) { | 162 | switch (mode) { |
@@ -224,25 +184,65 @@ static void bfin_timer_set_mode(enum clock_event_mode mode, | |||
224 | } | 184 | } |
225 | } | 185 | } |
226 | 186 | ||
227 | static void bfin_timer_ack(void) | 187 | static void bfin_gptmr0_ack(void) |
228 | { | 188 | { |
229 | set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0); | 189 | set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0); |
230 | } | 190 | } |
231 | 191 | ||
232 | static void __init bfin_timer_init(void) | 192 | static void __init bfin_gptmr0_init(void) |
233 | { | 193 | { |
234 | disable_gptimers(TIMER0bit); | 194 | disable_gptimers(TIMER0bit); |
235 | } | 195 | } |
236 | 196 | ||
237 | static unsigned long __init bfin_clockevent_check(void) | 197 | #ifdef CONFIG_CORE_TIMER_IRQ_L1 |
198 | __attribute__((l1_text)) | ||
199 | #endif | ||
200 | irqreturn_t bfin_gptmr0_interrupt(int irq, void *dev_id) | ||
238 | { | 201 | { |
239 | setup_irq(IRQ_TIMER0, &bfin_timer_irq); | 202 | struct clock_event_device *evt = dev_id; |
240 | return get_sclk(); | 203 | smp_mb(); |
204 | evt->event_handler(evt); | ||
205 | bfin_gptmr0_ack(); | ||
206 | return IRQ_HANDLED; | ||
241 | } | 207 | } |
242 | 208 | ||
243 | #else /* CONFIG_TICKSOURCE_CORETMR */ | 209 | static struct irqaction gptmr0_irq = { |
210 | .name = "Blackfin GPTimer0", | ||
211 | .flags = IRQF_DISABLED | IRQF_TIMER | \ | ||
212 | IRQF_IRQPOLL | IRQF_PERCPU, | ||
213 | .handler = bfin_gptmr0_interrupt, | ||
214 | }; | ||
244 | 215 | ||
245 | static int bfin_timer_set_next_event(unsigned long cycles, | 216 | static struct clock_event_device clockevent_gptmr0 = { |
217 | .name = "bfin_gptimer0", | ||
218 | .rating = 300, | ||
219 | .irq = IRQ_TIMER0, | ||
220 | .shift = 32, | ||
221 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
222 | .set_next_event = bfin_gptmr0_set_next_event, | ||
223 | .set_mode = bfin_gptmr0_set_mode, | ||
224 | }; | ||
225 | |||
226 | static void __init bfin_gptmr0_clockevent_init(struct clock_event_device *evt) | ||
227 | { | ||
228 | unsigned long clock_tick; | ||
229 | |||
230 | clock_tick = get_sclk(); | ||
231 | evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift); | ||
232 | evt->max_delta_ns = clockevent_delta2ns(-1, evt); | ||
233 | evt->min_delta_ns = clockevent_delta2ns(100, evt); | ||
234 | |||
235 | evt->cpumask = cpumask_of(0); | ||
236 | |||
237 | clockevents_register_device(evt); | ||
238 | } | ||
239 | #endif /* CONFIG_TICKSOURCE_GPTMR0 */ | ||
240 | |||
241 | #if defined(CONFIG_TICKSOURCE_CORETMR) | ||
242 | /* per-cpu local core timer */ | ||
243 | static DEFINE_PER_CPU(struct clock_event_device, coretmr_events); | ||
244 | |||
245 | static int bfin_coretmr_set_next_event(unsigned long cycles, | ||
246 | struct clock_event_device *evt) | 246 | struct clock_event_device *evt) |
247 | { | 247 | { |
248 | bfin_write_TCNTL(TMPWR); | 248 | bfin_write_TCNTL(TMPWR); |
@@ -253,7 +253,7 @@ static int bfin_timer_set_next_event(unsigned long cycles, | |||
253 | return 0; | 253 | return 0; |
254 | } | 254 | } |
255 | 255 | ||
256 | static void bfin_timer_set_mode(enum clock_event_mode mode, | 256 | static void bfin_coretmr_set_mode(enum clock_event_mode mode, |
257 | struct clock_event_device *evt) | 257 | struct clock_event_device *evt) |
258 | { | 258 | { |
259 | switch (mode) { | 259 | switch (mode) { |
@@ -285,19 +285,13 @@ static void bfin_timer_set_mode(enum clock_event_mode mode, | |||
285 | } | 285 | } |
286 | } | 286 | } |
287 | 287 | ||
288 | static void bfin_timer_ack(void) | 288 | void bfin_coretmr_init(void) |
289 | { | ||
290 | } | ||
291 | |||
292 | static void __init bfin_timer_init(void) | ||
293 | { | 289 | { |
294 | /* power up the timer, but don't enable it just yet */ | 290 | /* power up the timer, but don't enable it just yet */ |
295 | bfin_write_TCNTL(TMPWR); | 291 | bfin_write_TCNTL(TMPWR); |
296 | CSYNC(); | 292 | CSYNC(); |
297 | 293 | ||
298 | /* | 294 | /* the TSCALE prescaler counter. */ |
299 | * the TSCALE prescaler counter. | ||
300 | */ | ||
301 | bfin_write_TSCALE(TIME_SCALE - 1); | 295 | bfin_write_TSCALE(TIME_SCALE - 1); |
302 | bfin_write_TPERIOD(0); | 296 | bfin_write_TPERIOD(0); |
303 | bfin_write_TCOUNT(0); | 297 | bfin_write_TCOUNT(0); |
@@ -305,48 +299,51 @@ static void __init bfin_timer_init(void) | |||
305 | CSYNC(); | 299 | CSYNC(); |
306 | } | 300 | } |
307 | 301 | ||
308 | static unsigned long __init bfin_clockevent_check(void) | 302 | #ifdef CONFIG_CORE_TIMER_IRQ_L1 |
309 | { | 303 | __attribute__((l1_text)) |
310 | setup_irq(IRQ_CORETMR, &bfin_timer_irq); | 304 | #endif |
311 | return get_cclk() / TIME_SCALE; | 305 | irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id) |
312 | } | ||
313 | |||
314 | void __init setup_core_timer(void) | ||
315 | { | 306 | { |
316 | bfin_timer_init(); | 307 | int cpu = smp_processor_id(); |
317 | bfin_timer_set_mode(CLOCK_EVT_MODE_PERIODIC, NULL); | 308 | struct clock_event_device *evt = &per_cpu(coretmr_events, cpu); |
318 | } | ||
319 | #endif /* CONFIG_TICKSOURCE_GPTMR0 */ | ||
320 | 309 | ||
321 | /* | ||
322 | * timer_interrupt() needs to keep up the real-time clock, | ||
323 | * as well as call the "do_timer()" routine every clocktick | ||
324 | */ | ||
325 | irqreturn_t timer_interrupt(int irq, void *dev_id) | ||
326 | { | ||
327 | struct clock_event_device *evt = dev_id; | ||
328 | smp_mb(); | 310 | smp_mb(); |
329 | evt->event_handler(evt); | 311 | evt->event_handler(evt); |
330 | bfin_timer_ack(); | ||
331 | return IRQ_HANDLED; | 312 | return IRQ_HANDLED; |
332 | } | 313 | } |
333 | 314 | ||
334 | static int __init bfin_clockevent_init(void) | 315 | static struct irqaction coretmr_irq = { |
335 | { | 316 | .name = "Blackfin CoreTimer", |
336 | unsigned long timer_clk; | 317 | .flags = IRQF_DISABLED | IRQF_TIMER | \ |
337 | 318 | IRQF_IRQPOLL | IRQF_PERCPU, | |
338 | timer_clk = bfin_clockevent_check(); | 319 | .handler = bfin_coretmr_interrupt, |
339 | 320 | }; | |
340 | bfin_timer_init(); | ||
341 | |||
342 | clockevent_bfin.mult = div_sc(timer_clk, NSEC_PER_SEC, clockevent_bfin.shift); | ||
343 | clockevent_bfin.max_delta_ns = clockevent_delta2ns(-1, &clockevent_bfin); | ||
344 | clockevent_bfin.min_delta_ns = clockevent_delta2ns(100, &clockevent_bfin); | ||
345 | clockevent_bfin.cpumask = cpumask_of(0); | ||
346 | clockevents_register_device(&clockevent_bfin); | ||
347 | 321 | ||
348 | return 0; | 322 | void bfin_coretmr_clockevent_init(void) |
323 | { | ||
324 | unsigned long clock_tick; | ||
325 | unsigned int cpu = smp_processor_id(); | ||
326 | struct clock_event_device *evt = &per_cpu(coretmr_events, cpu); | ||
327 | |||
328 | evt->name = "bfin_core_timer"; | ||
329 | evt->rating = 350; | ||
330 | evt->irq = -1; | ||
331 | evt->shift = 32; | ||
332 | evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; | ||
333 | evt->set_next_event = bfin_coretmr_set_next_event; | ||
334 | evt->set_mode = bfin_coretmr_set_mode; | ||
335 | |||
336 | clock_tick = get_cclk() / TIME_SCALE; | ||
337 | evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift); | ||
338 | evt->max_delta_ns = clockevent_delta2ns(-1, evt); | ||
339 | evt->min_delta_ns = clockevent_delta2ns(100, evt); | ||
340 | |||
341 | evt->cpumask = cpumask_of(cpu); | ||
342 | |||
343 | clockevents_register_device(evt); | ||
349 | } | 344 | } |
345 | #endif /* CONFIG_TICKSOURCE_CORETMR */ | ||
346 | |||
350 | 347 | ||
351 | void __init time_init(void) | 348 | void __init time_init(void) |
352 | { | 349 | { |
@@ -370,5 +367,21 @@ void __init time_init(void) | |||
370 | 367 | ||
371 | bfin_cs_cycles_init(); | 368 | bfin_cs_cycles_init(); |
372 | bfin_cs_gptimer0_init(); | 369 | bfin_cs_gptimer0_init(); |
373 | bfin_clockevent_init(); | 370 | |
371 | #if defined(CONFIG_TICKSOURCE_CORETMR) | ||
372 | bfin_coretmr_init(); | ||
373 | setup_irq(IRQ_CORETMR, &coretmr_irq); | ||
374 | bfin_coretmr_clockevent_init(); | ||
375 | #endif | ||
376 | |||
377 | #if defined(CONFIG_TICKSOURCE_GPTMR0) | ||
378 | bfin_gptmr0_init(); | ||
379 | setup_irq(IRQ_TIMER0, &gptmr0_irq); | ||
380 | gptmr0_irq.dev_id = &clockevent_gptmr0; | ||
381 | bfin_gptmr0_clockevent_init(&clockevent_gptmr0); | ||
382 | #endif | ||
383 | |||
384 | #if !defined(CONFIG_TICKSOURCE_CORETMR) && !defined(CONFIG_TICKSOURCE_GPTMR0) | ||
385 | # error at least one clock event device is required | ||
386 | #endif | ||
374 | } | 387 | } |