Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sparc32, leon: Remove separate "ticker" timer for SMP

This reduces the need from two timers to one timer.

Moreover, without this patch, when the "ticker" timer triggers timer_cs_read via
tick_periodic it reads the value of the usual timer it can get an wrapped timer
value without timer_cs_internal_counter having been updated leading to the clock
going backwards. This effectively hangs one cpu that gets stuck in
update_wall_time with an offset slightly smaller than 0xffffffffffffffff.

Signed-off-by: Andreas Larsson <andreas@gaisler.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Andreas Larsson and committed by
David S. Miller
1ffbc51a 117a0c5f

+26 -45
+1 -1
arch/sparc/include/asm/leon.h
··· 135 135 136 136 #ifdef CONFIG_SMP 137 137 # define LEON3_IRQ_IPI_DEFAULT 13 138 - # define LEON3_IRQ_TICKER (leon3_ticker_irq) 138 + # define LEON3_IRQ_TICKER (leon3_gptimer_irq) 139 139 # define LEON3_IRQ_CROSS_CALL 15 140 140 #endif 141 141
+1
arch/sparc/include/asm/leon_amba.h
··· 47 47 #define LEON3_GPTIMER_LD 4 48 48 #define LEON3_GPTIMER_IRQEN 8 49 49 #define LEON3_GPTIMER_SEPIRQ 8 50 + #define LEON3_GPTIMER_TIMERS 0x7 50 51 51 52 #define LEON23_REG_TIMER_CONTROL_EN 0x00000001 /* 1 = enable counting */ 52 53 /* 0 = hold scalar and counter */
+24 -44
arch/sparc/kernel/leon_kernel.c
··· 38 38 39 39 unsigned long leon3_gptimer_irq; /* interrupt controller irq number */ 40 40 unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ 41 - int leon3_ticker_irq; /* Timer ticker IRQ */ 42 41 unsigned int sparc_leon_eirq; 43 42 #define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu]) 44 43 #define LEON_IACK (&leon3_irqctrl_regs->iclear) ··· 277 278 278 279 leon_clear_profile_irq(cpu); 279 280 281 + if (cpu == boot_cpu_id) 282 + timer_interrupt(irq, NULL); 283 + 280 284 ce = &per_cpu(sparc32_clockevent, cpu); 281 285 282 286 irq_enter(); ··· 301 299 int icsel; 302 300 int ampopts; 303 301 int err; 302 + u32 config; 304 303 305 304 sparc_config.get_cycles_offset = leon_cycles_offset; 306 305 sparc_config.cs_period = 1000000 / HZ; ··· 380 377 LEON3_BYPASS_STORE_PA( 381 378 &leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0); 382 379 383 - #ifdef CONFIG_SMP 384 - leon3_ticker_irq = leon3_gptimer_irq + 1 + leon3_gptimer_idx; 385 - 386 - if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) & 387 - (1<<LEON3_GPTIMER_SEPIRQ))) { 388 - printk(KERN_ERR "timer not configured with separate irqs\n"); 389 - BUG(); 390 - } 391 - 392 - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].val, 393 - 0); 394 - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld, 395 - (((1000000/HZ) - 1))); 396 - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, 397 - 0); 398 - #endif 399 - 400 380 /* 401 381 * The IRQ controller may (if implemented) consist of multiple 402 382 * IRQ controllers, each mapped on a 4Kb boundary. ··· 402 416 if (eirq != 0) 403 417 leon_eirq_setup(eirq); 404 418 405 - irq = _leon_build_device_irq(NULL, leon3_gptimer_irq+leon3_gptimer_idx); 406 - err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL); 407 - if (err) { 408 - printk(KERN_ERR "unable to attach timer IRQ%d\n", irq); 409 - prom_halt(); 410 - } 411 - 412 419 #ifdef CONFIG_SMP 413 420 { 414 421 unsigned long flags; ··· 418 439 } 419 440 #endif 420 441 442 + config = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config); 443 + if (config & (1 << LEON3_GPTIMER_SEPIRQ)) 444 + leon3_gptimer_irq += leon3_gptimer_idx; 445 + else if ((config & LEON3_GPTIMER_TIMERS) > 1) 446 + pr_warn("GPTIMER uses shared irqs, using other timers of the same core will fail.\n"); 447 + 448 + #ifdef CONFIG_SMP 449 + /* Install per-cpu IRQ handler for broadcasted ticker */ 450 + irq = leon_build_device_irq(leon3_gptimer_irq, handle_percpu_irq, 451 + "per-cpu", 0); 452 + err = request_irq(irq, leon_percpu_timer_ce_interrupt, 453 + IRQF_PERCPU | IRQF_TIMER, "timer", NULL); 454 + #else 455 + irq = _leon_build_device_irq(NULL, leon3_gptimer_irq); 456 + err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL); 457 + #endif 458 + if (err) { 459 + pr_err("Unable to attach timer IRQ%d\n", irq); 460 + prom_halt(); 461 + } 421 462 LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 422 463 LEON3_GPTIMER_EN | 423 464 LEON3_GPTIMER_RL | 424 465 LEON3_GPTIMER_LD | 425 466 LEON3_GPTIMER_IRQEN); 426 - 427 - #ifdef CONFIG_SMP 428 - /* Install per-cpu IRQ handler for broadcasted ticker */ 429 - irq = leon_build_device_irq(leon3_ticker_irq, handle_percpu_irq, 430 - "per-cpu", 0); 431 - err = request_irq(irq, leon_percpu_timer_ce_interrupt, 432 - IRQF_PERCPU | IRQF_TIMER, "ticker", 433 - NULL); 434 - if (err) { 435 - printk(KERN_ERR "unable to attach ticker IRQ%d\n", irq); 436 - prom_halt(); 437 - } 438 - 439 - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, 440 - LEON3_GPTIMER_EN | 441 - LEON3_GPTIMER_RL | 442 - LEON3_GPTIMER_LD | 443 - LEON3_GPTIMER_IRQEN); 444 - #endif 445 467 return; 446 468 bad: 447 469 printk(KERN_ERR "No Timer/irqctrl found\n");