aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-09-14 01:04:55 -0400
committerDavid S. Miller <davem@davemloft.net>2008-09-20 00:17:56 -0400
commitf5f1085720c4799dd1437f78e28e40c8dd557bba (patch)
tree8ff072a3fa2d8b293e39fdf9610ddd56093bf972 /arch/sparc/kernel
parent69c010b24560be5ca7667e94a352183e60ed205e (diff)
sparc32: Use PROM infrastructure for probing and mapping sun4d timers.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r--arch/sparc/kernel/sun4d_irq.c139
1 files changed, 83 insertions, 56 deletions
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 12541f51fcfc..4156bf6657fb 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -45,7 +45,16 @@
45/* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */ 45/* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
46/* #define DISTRIBUTE_IRQS */ 46/* #define DISTRIBUTE_IRQS */
47 47
48struct sun4d_timer_regs *sun4d_timers; 48struct sun4d_timer_regs {
49 u32 l10_timer_limit;
50 u32 l10_cur_countx;
51 u32 l10_limit_noclear;
52 u32 ctrl;
53 u32 l10_cur_count;
54};
55
56static struct sun4d_timer_regs __iomem *sun4d_timers;
57
49#define TIMER_IRQ 10 58#define TIMER_IRQ 10
50 59
51#define MAX_STATIC_ALLOC 4 60#define MAX_STATIC_ALLOC 4
@@ -446,8 +455,7 @@ void __init sun4d_distribute_irqs(void)
446 455
447static void sun4d_clear_clock_irq(void) 456static void sun4d_clear_clock_irq(void)
448{ 457{
449 volatile unsigned int clear_intr; 458 sbus_readl(&sun4d_timers->l10_timer_limit);
450 clear_intr = sun4d_timers->l10_timer_limit;
451} 459}
452 460
453static void sun4d_clear_profile_irq(int cpu) 461static void sun4d_clear_profile_irq(int cpu)
@@ -460,71 +468,90 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit)
460 bw_set_prof_limit(cpu, limit); 468 bw_set_prof_limit(cpu, limit);
461} 469}
462 470
463static void __init sun4d_init_timers(irq_handler_t counter_fn) 471static void __init sun4d_load_profile_irqs(void)
464{ 472{
465 int irq; 473 int cpu = 0, mid;
466 int cpu;
467 struct resource r;
468 int mid;
469 474
470 /* Map the User Timer registers. */ 475 while (!cpu_find_by_instance(cpu, NULL, &mid)) {
471 memset(&r, 0, sizeof(r)); 476 sun4d_load_profile_irq(mid >> 3, 0);
477 cpu++;
478 }
479}
480
481static void __init sun4d_fixup_trap_table(void)
482{
472#ifdef CONFIG_SMP 483#ifdef CONFIG_SMP
473 r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT; 484 unsigned long flags;
474#else 485 extern unsigned long lvl14_save[4];
475 r.start = CSR_BASE(0)+BW_TIMER_LIMIT; 486 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
487 extern unsigned int real_irq_entry[], smp4d_ticker[];
488 extern unsigned int patchme_maybe_smp_msg[];
489
490 /* Adjust so that we jump directly to smp4d_ticker */
491 lvl14_save[2] += smp4d_ticker - real_irq_entry;
492
493 /* For SMP we use the level 14 ticker, however the bootup code
494 * has copied the firmware's level 14 vector into the boot cpu's
495 * trap table, we must fix this now or we get squashed.
496 */
497 local_irq_save(flags);
498 patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
499 trap_table->inst_one = lvl14_save[0];
500 trap_table->inst_two = lvl14_save[1];
501 trap_table->inst_three = lvl14_save[2];
502 trap_table->inst_four = lvl14_save[3];
503 local_flush_cache_all();
504 local_irq_restore(flags);
476#endif 505#endif
477 r.flags = 0xf; 506}
478 sun4d_timers = (struct sun4d_timer_regs *) of_ioremap(&r, 0, 507
479 PAGE_SIZE, "user timer"); 508static void __init sun4d_init_timers(irq_handler_t counter_fn)
509{
510 struct device_node *dp;
511 struct resource res;
512 const u32 *reg;
513 int err;
514
515 dp = of_find_node_by_name(NULL, "cpu-unit");
516 if (!dp) {
517 prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
518 prom_halt();
519 }
520
521 /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
522 * registers via any cpu's mapping. The first 'reg' property is the
523 * bootbus.
524 */
525 reg = of_get_property(dp, "reg", NULL);
526 if (!reg) {
527 prom_printf("sun4d_init_timers: No reg property\n");
528 prom_halt();
529 }
530
531 res.start = reg[1];
532 res.end = reg[2] - 1;
533 res.flags = reg[0] & 0xff;
534 sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
535 sizeof(struct sun4d_timer_regs), "user timer");
536 if (!sun4d_timers) {
537 prom_printf("sun4d_init_timers: Can't map timer regs\n");
538 prom_halt();
539 }
540
541 sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
480 542
481 sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
482 master_l10_counter = &sun4d_timers->l10_cur_count; 543 master_l10_counter = &sun4d_timers->l10_cur_count;
483 master_l10_limit = &sun4d_timers->l10_timer_limit; 544 master_l10_limit = &sun4d_timers->l10_timer_limit;
484 545
485 irq = request_irq(TIMER_IRQ, 546 err = request_irq(TIMER_IRQ, counter_fn,
486 counter_fn,
487 (IRQF_DISABLED | SA_STATIC_ALLOC), 547 (IRQF_DISABLED | SA_STATIC_ALLOC),
488 "timer", NULL); 548 "timer", NULL);
489 if (irq) { 549 if (err) {
490 prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); 550 prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err);
491 prom_halt(); 551 prom_halt();
492 } 552 }
493 553 sun4d_load_profile_irqs();
494 /* Enable user timer free run for CPU 0 in BW */ 554 sun4d_fixup_trap_table();
495 /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
496
497 cpu = 0;
498 while (!cpu_find_by_instance(cpu, NULL, &mid)) {
499 sun4d_load_profile_irq(mid >> 3, 0);
500 cpu++;
501 }
502
503#ifdef CONFIG_SMP
504 {
505 unsigned long flags;
506 extern unsigned long lvl14_save[4];
507 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
508 extern unsigned int real_irq_entry[], smp4d_ticker[];
509 extern unsigned int patchme_maybe_smp_msg[];
510
511 /* Adjust so that we jump directly to smp4d_ticker */
512 lvl14_save[2] += smp4d_ticker - real_irq_entry;
513
514 /* For SMP we use the level 14 ticker, however the bootup code
515 * has copied the firmware's level 14 vector into the boot cpu's
516 * trap table, we must fix this now or we get squashed.
517 */
518 local_irq_save(flags);
519 patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
520 trap_table->inst_one = lvl14_save[0];
521 trap_table->inst_two = lvl14_save[1];
522 trap_table->inst_three = lvl14_save[2];
523 trap_table->inst_four = lvl14_save[3];
524 local_flush_cache_all();
525 local_irq_restore(flags);
526 }
527#endif
528} 555}
529 556
530void __init sun4d_init_sbi_irq(void) 557void __init sun4d_init_sbi_irq(void)