diff options
author | David S. Miller <davem@davemloft.net> | 2008-09-14 01:04:55 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-09-20 00:17:56 -0400 |
commit | f5f1085720c4799dd1437f78e28e40c8dd557bba (patch) | |
tree | 8ff072a3fa2d8b293e39fdf9610ddd56093bf972 /arch/sparc/kernel/sun4d_irq.c | |
parent | 69c010b24560be5ca7667e94a352183e60ed205e (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/sun4d_irq.c')
-rw-r--r-- | arch/sparc/kernel/sun4d_irq.c | 139 |
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 | ||
48 | struct sun4d_timer_regs *sun4d_timers; | 48 | struct 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 | |||
56 | static 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 | ||
447 | static void sun4d_clear_clock_irq(void) | 456 | static 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 | ||
453 | static void sun4d_clear_profile_irq(int cpu) | 461 | static 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 | ||
463 | static void __init sun4d_init_timers(irq_handler_t counter_fn) | 471 | static 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 | |||
481 | static 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"); | 508 | static 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 | ||
530 | void __init sun4d_init_sbi_irq(void) | 557 | void __init sun4d_init_sbi_irq(void) |