aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel
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/blackfin/kernel
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/blackfin/kernel')
-rw-r--r--arch/blackfin/kernel/time-ts.c197
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 */
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}