aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorYi Li <yi.li@analog.com>2009-12-28 05:21:49 -0500
committerMike Frysinger <vapier@gentoo.org>2010-03-09 00:30:48 -0500
commit0d152c27e336b5fd777da7dd3e814617e7305afd (patch)
tree2863b1b2f0fe0676a5928b197c8d1d289ab71777 /arch
parent682f5dc4ed7cdef1f55e40ee505c4346dfa6fa91 (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')
-rw-r--r--arch/blackfin/Kconfig26
-rw-r--r--arch/blackfin/include/asm/time.h6
-rw-r--r--arch/blackfin/kernel/time-ts.c197
-rw-r--r--arch/blackfin/mach-bf561/include/mach/smp.h2
-rw-r--r--arch/blackfin/mach-bf561/smp.c18
-rw-r--r--arch/blackfin/mach-common/ints-priority.c3
-rw-r--r--arch/blackfin/mach-common/smp.c17
7 files changed, 146 insertions, 123 deletions
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index b483639c80b3..0bd26dbca09f 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -236,7 +236,7 @@ endchoice
236 236
237config SMP 237config SMP
238 depends on BF561 238 depends on BF561
239 select GENERIC_CLOCKEVENTS 239 select TICKSOURCE_CORETMR
240 bool "Symmetric multi-processing support" 240 bool "Symmetric multi-processing support"
241 ---help--- 241 ---help---
242 This enables support for systems with more than one CPU, 242 This enables support for systems with more than one CPU,
@@ -610,23 +610,23 @@ config GENERIC_CLOCKEVENTS
610 bool "Generic clock events" 610 bool "Generic clock events"
611 default y 611 default y
612 612
613choice 613menu "Clock event device"
614 prompt "Kernel Tick Source"
615 depends on GENERIC_CLOCKEVENTS 614 depends on GENERIC_CLOCKEVENTS
616 default TICKSOURCE_CORETMR
617
618config TICKSOURCE_GPTMR0 615config TICKSOURCE_GPTMR0
619 bool "Gptimer0 (SCLK domain)" 616 bool "GPTimer0"
617 depends on !SMP
620 select BFIN_GPTIMERS 618 select BFIN_GPTIMERS
621 619
622config TICKSOURCE_CORETMR 620config TICKSOURCE_CORETMR
623 bool "Core timer (CCLK domain)" 621 bool "Core timer"
624 622 default y
625endchoice 623endmenu
626 624
627config CYCLES_CLOCKSOURCE 625menu "Clock souce"
628 bool "Use 'CYCLES' as a clocksource"
629 depends on GENERIC_CLOCKEVENTS 626 depends on GENERIC_CLOCKEVENTS
627config CYCLES_CLOCKSOURCE
628 bool "CYCLES"
629 default y
630 depends on !BFIN_SCRATCH_REG_CYCLES 630 depends on !BFIN_SCRATCH_REG_CYCLES
631 depends on !SMP 631 depends on !SMP
632 help 632 help
@@ -637,10 +637,10 @@ config CYCLES_CLOCKSOURCE
637 writing the registers will most likely crash the kernel. 637 writing the registers will most likely crash the kernel.
638 638
639config GPTMR0_CLOCKSOURCE 639config GPTMR0_CLOCKSOURCE
640 bool "Use GPTimer0 as a clocksource" 640 bool "GPTimer0"
641 select BFIN_GPTIMERS 641 select BFIN_GPTIMERS
642 depends on GENERIC_CLOCKEVENTS
643 depends on !TICKSOURCE_GPTMR0 642 depends on !TICKSOURCE_GPTMR0
643endmenu
644 644
645config ARCH_USES_GETTIMEOFFSET 645config ARCH_USES_GETTIMEOFFSET
646 depends on !GENERIC_CLOCKEVENTS 646 depends on !GENERIC_CLOCKEVENTS
diff --git a/arch/blackfin/include/asm/time.h b/arch/blackfin/include/asm/time.h
index 589e937ed1eb..767b938ccf8c 100644
--- a/arch/blackfin/include/asm/time.h
+++ b/arch/blackfin/include/asm/time.h
@@ -37,5 +37,9 @@ extern unsigned long long __bfin_cycles_off;
37extern unsigned int __bfin_cycles_mod; 37extern unsigned int __bfin_cycles_mod;
38#endif 38#endif
39 39
40extern void __init setup_core_timer(void); 40#if defined(CONFIG_TICKSOURCE_CORETMR)
41extern void bfin_coretmr_init(void);
42extern void bfin_coretmr_clockevent_init(void);
43#endif
44
41#endif 45#endif
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 */
138notrace unsigned long long sched_clock(void) 137notrace 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
151irqreturn_t timer_interrupt(int irq, void *dev_id);
152
153static int bfin_timer_set_next_event(unsigned long, \
154 struct clock_event_device *);
155
156static void bfin_timer_set_mode(enum clock_event_mode, \
157 struct clock_event_device *);
158
159static 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
175static 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)
188static int bfin_timer_set_next_event(unsigned long cycles, 148static 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
199static void bfin_timer_set_mode(enum clock_event_mode mode, 159static 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
227static void bfin_timer_ack(void) 187static 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
232static void __init bfin_timer_init(void) 192static void __init bfin_gptmr0_init(void)
233{ 193{
234 disable_gptimers(TIMER0bit); 194 disable_gptimers(TIMER0bit);
235} 195}
236 196
237static unsigned long __init bfin_clockevent_check(void) 197#ifdef CONFIG_CORE_TIMER_IRQ_L1
198__attribute__((l1_text))
199#endif
200irqreturn_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 */ 209static 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
245static int bfin_timer_set_next_event(unsigned long cycles, 216static 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
226static 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 */
243static DEFINE_PER_CPU(struct clock_event_device, coretmr_events);
244
245static 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
256static void bfin_timer_set_mode(enum clock_event_mode mode, 256static 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
288static void bfin_timer_ack(void) 288void bfin_coretmr_init(void)
289{
290}
291
292static 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
308static 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; 305irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id)
312}
313
314void __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 */
325irqreturn_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
334static int __init bfin_clockevent_init(void) 315static 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; 322void 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
351void __init time_init(void) 348void __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}
diff --git a/arch/blackfin/mach-bf561/include/mach/smp.h b/arch/blackfin/mach-bf561/include/mach/smp.h
index 390c7f4ae7b3..2c8c514dd386 100644
--- a/arch/blackfin/mach-bf561/include/mach/smp.h
+++ b/arch/blackfin/mach-bf561/include/mach/smp.h
@@ -25,4 +25,6 @@ void platform_send_ipi_cpu(unsigned int cpu);
25 25
26void platform_clear_ipi(unsigned int cpu); 26void platform_clear_ipi(unsigned int cpu);
27 27
28void bfin_local_timer_setup(void);
29
28#endif /* !_MACH_BF561_SMP */ 30#endif /* !_MACH_BF561_SMP */
diff --git a/arch/blackfin/mach-bf561/smp.c b/arch/blackfin/mach-bf561/smp.c
index ec93f3ef8fa3..90369429ee66 100644
--- a/arch/blackfin/mach-bf561/smp.c
+++ b/arch/blackfin/mach-bf561/smp.c
@@ -11,6 +11,7 @@
11#include <linux/delay.h> 11#include <linux/delay.h>
12#include <asm/smp.h> 12#include <asm/smp.h>
13#include <asm/dma.h> 13#include <asm/dma.h>
14#include <asm/time.h>
14 15
15static DEFINE_SPINLOCK(boot_lock); 16static DEFINE_SPINLOCK(boot_lock);
16 17
@@ -144,3 +145,20 @@ void platform_clear_ipi(unsigned int cpu)
144 bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + cpu))); 145 bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + cpu)));
145 SSYNC(); 146 SSYNC();
146} 147}
148
149/*
150 * Setup core B's local core timer.
151 * In SMP, core timer is used for clock event device.
152 */
153void __cpuinit bfin_local_timer_setup(void)
154{
155#if defined(CONFIG_TICKSOURCE_CORETMR)
156 bfin_coretmr_init();
157 bfin_coretmr_clockevent_init();
158 get_irq_chip(IRQ_CORETMR)->unmask(IRQ_CORETMR);
159#else
160 /* Power down the core timer, just to play safe. */
161 bfin_write_TCNTL(0);
162#endif
163
164}
diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c
index a5d243409d23..efbdb6a19418 100644
--- a/arch/blackfin/mach-common/ints-priority.c
+++ b/arch/blackfin/mach-common/ints-priority.c
@@ -1073,9 +1073,6 @@ int __init init_arch_irq(void)
1073#endif 1073#endif
1074 1074
1075#ifdef CONFIG_SMP 1075#ifdef CONFIG_SMP
1076#ifdef CONFIG_TICKSOURCE_GPTMR0
1077 case IRQ_TIMER0:
1078#endif
1079#ifdef CONFIG_TICKSOURCE_CORETMR 1076#ifdef CONFIG_TICKSOURCE_CORETMR
1080 case IRQ_CORETMR: 1077 case IRQ_CORETMR:
1081#endif 1078#endif
diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c
index eddb720c718e..b343ab3764a1 100644
--- a/arch/blackfin/mach-common/smp.c
+++ b/arch/blackfin/mach-common/smp.c
@@ -365,9 +365,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
365 365
366static void __cpuinit setup_secondary(unsigned int cpu) 366static void __cpuinit setup_secondary(unsigned int cpu)
367{ 367{
368#if !defined(CONFIG_TICKSOURCE_GPTMR0)
369 struct irq_desc *timer_desc;
370#endif
371 unsigned long ilat; 368 unsigned long ilat;
372 369
373 bfin_write_IMASK(0); 370 bfin_write_IMASK(0);
@@ -382,17 +379,6 @@ static void __cpuinit setup_secondary(unsigned int cpu)
382 bfin_irq_flags |= IMASK_IVG15 | 379 bfin_irq_flags |= IMASK_IVG15 |
383 IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | 380 IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
384 IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; 381 IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
385
386#if defined(CONFIG_TICKSOURCE_GPTMR0)
387 /* Power down the core timer, just to play safe. */
388 bfin_write_TCNTL(0);
389
390 /* system timer0 has been setup by CoreA. */
391#else
392 timer_desc = irq_desc + IRQ_CORETMR;
393 setup_core_timer();
394 timer_desc->chip->enable(IRQ_CORETMR);
395#endif
396} 382}
397 383
398void __cpuinit secondary_start_kernel(void) 384void __cpuinit secondary_start_kernel(void)
@@ -435,6 +421,9 @@ void __cpuinit secondary_start_kernel(void)
435 421
436 platform_secondary_init(cpu); 422 platform_secondary_init(cpu);
437 423
424 /* setup local core timer */
425 bfin_local_timer_setup();
426
438 local_irq_enable(); 427 local_irq_enable();
439 428
440 /* 429 /*