aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/sun4d_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/sun4d_irq.c')
-rw-r--r--arch/sparc/kernel/sun4d_irq.c286
1 files changed, 144 insertions, 142 deletions
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 1290b5998f83..d3cb76ce418b 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -19,6 +19,8 @@
19#include <linux/smp.h> 19#include <linux/smp.h>
20#include <linux/spinlock.h> 20#include <linux/spinlock.h>
21#include <linux/seq_file.h> 21#include <linux/seq_file.h>
22#include <linux/of.h>
23#include <linux/of_device.h>
22 24
23#include <asm/ptrace.h> 25#include <asm/ptrace.h>
24#include <asm/processor.h> 26#include <asm/processor.h>
@@ -34,7 +36,6 @@
34#include <asm/io.h> 36#include <asm/io.h>
35#include <asm/pgalloc.h> 37#include <asm/pgalloc.h>
36#include <asm/pgtable.h> 38#include <asm/pgtable.h>
37#include <asm/sbus.h>
38#include <asm/sbi.h> 39#include <asm/sbi.h>
39#include <asm/cacheflush.h> 40#include <asm/cacheflush.h>
40#include <asm/irq_regs.h> 41#include <asm/irq_regs.h>
@@ -44,16 +45,22 @@
44/* 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 */
45/* #define DISTRIBUTE_IRQS */ 46/* #define DISTRIBUTE_IRQS */
46 47
47struct 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
48#define TIMER_IRQ 10 58#define TIMER_IRQ 10
49 59
50#define MAX_STATIC_ALLOC 4 60#define MAX_STATIC_ALLOC 4
51extern struct irqaction static_irqaction[MAX_STATIC_ALLOC]; 61extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
52extern int static_irq_count; 62extern int static_irq_count;
53unsigned char cpu_leds[32];
54#ifdef CONFIG_SMP
55static unsigned char sbus_tid[32]; 63static unsigned char sbus_tid[32];
56#endif
57 64
58static struct irqaction *irq_action[NR_IRQS]; 65static struct irqaction *irq_action[NR_IRQS];
59extern spinlock_t irq_action_lock; 66extern spinlock_t irq_action_lock;
@@ -72,9 +79,9 @@ static int sbus_to_pil[] = {
72}; 79};
73 80
74static int nsbi; 81static int nsbi;
75#ifdef CONFIG_SMP 82
83/* Exported for sun4d_smp.c */
76DEFINE_SPINLOCK(sun4d_imsk_lock); 84DEFINE_SPINLOCK(sun4d_imsk_lock);
77#endif
78 85
79int show_sun4d_interrupts(struct seq_file *p, void *v) 86int show_sun4d_interrupts(struct seq_file *p, void *v)
80{ 87{
@@ -257,26 +264,6 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
257 set_irq_regs(old_regs); 264 set_irq_regs(old_regs);
258} 265}
259 266
260unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq)
261{
262 int sbusl = pil_to_sbus[irq];
263
264 if (sbusl)
265 return ((sdev->bus->board + 1) << 5) + (sbusl << 2) + sdev->slot;
266 else
267 return irq;
268}
269
270static unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev,
271 unsigned int sbint)
272{
273 if (sbint >= sizeof(sbus_to_pil)) {
274 printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
275 BUG();
276 }
277 return sun4d_build_irq(sdev, sbus_to_pil[sbint]);
278}
279
280int sun4d_request_irq(unsigned int irq, 267int sun4d_request_irq(unsigned int irq,
281 irq_handler_t handler, 268 irq_handler_t handler,
282 unsigned long irqflags, const char * devname, void *dev_id) 269 unsigned long irqflags, const char * devname, void *dev_id)
@@ -360,36 +347,28 @@ out:
360 347
361static void sun4d_disable_irq(unsigned int irq) 348static void sun4d_disable_irq(unsigned int irq)
362{ 349{
363#ifdef CONFIG_SMP
364 int tid = sbus_tid[(irq >> 5) - 1]; 350 int tid = sbus_tid[(irq >> 5) - 1];
365 unsigned long flags; 351 unsigned long flags;
366#endif
367 352
368 if (irq < NR_IRQS) return; 353 if (irq < NR_IRQS)
369#ifdef CONFIG_SMP 354 return;
355
370 spin_lock_irqsave(&sun4d_imsk_lock, flags); 356 spin_lock_irqsave(&sun4d_imsk_lock, flags);
371 cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7])); 357 cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
372 spin_unlock_irqrestore(&sun4d_imsk_lock, flags); 358 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
373#else
374 cc_set_imsk(cc_get_imsk() | (1 << sbus_to_pil[(irq >> 2) & 7]));
375#endif
376} 359}
377 360
378static void sun4d_enable_irq(unsigned int irq) 361static void sun4d_enable_irq(unsigned int irq)
379{ 362{
380#ifdef CONFIG_SMP
381 int tid = sbus_tid[(irq >> 5) - 1]; 363 int tid = sbus_tid[(irq >> 5) - 1];
382 unsigned long flags; 364 unsigned long flags;
383#endif
384 365
385 if (irq < NR_IRQS) return; 366 if (irq < NR_IRQS)
386#ifdef CONFIG_SMP 367 return;
368
387 spin_lock_irqsave(&sun4d_imsk_lock, flags); 369 spin_lock_irqsave(&sun4d_imsk_lock, flags);
388 cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7])); 370 cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
389 spin_unlock_irqrestore(&sun4d_imsk_lock, flags); 371 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
390#else
391 cc_set_imsk(cc_get_imsk() & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
392#endif
393} 372}
394 373
395#ifdef CONFIG_SMP 374#ifdef CONFIG_SMP
@@ -409,47 +388,55 @@ static void sun4d_set_udt(int cpu)
409/* Setup IRQ distribution scheme. */ 388/* Setup IRQ distribution scheme. */
410void __init sun4d_distribute_irqs(void) 389void __init sun4d_distribute_irqs(void)
411{ 390{
391 struct device_node *dp;
392
412#ifdef DISTRIBUTE_IRQS 393#ifdef DISTRIBUTE_IRQS
413 struct sbus_bus *sbus; 394 cpumask_t sbus_serving_map;
414 unsigned long sbus_serving_map;
415 395
416 sbus_serving_map = cpu_present_map; 396 sbus_serving_map = cpu_present_map;
417 for_each_sbus(sbus) { 397 for_each_node_by_name(dp, "sbi") {
418 if ((sbus->board * 2) == boot_cpu_id && (cpu_present_map & (1 << (sbus->board * 2 + 1)))) 398 int board = of_getintprop_default(dp, "board#", 0);
419 sbus_tid[sbus->board] = (sbus->board * 2 + 1); 399
420 else if (cpu_present_map & (1 << (sbus->board * 2))) 400 if ((board * 2) == boot_cpu_id && cpu_isset(board * 2 + 1, cpu_present_map))
421 sbus_tid[sbus->board] = (sbus->board * 2); 401 sbus_tid[board] = (board * 2 + 1);
422 else if (cpu_present_map & (1 << (sbus->board * 2 + 1))) 402 else if (cpu_isset(board * 2, cpu_present_map))
423 sbus_tid[sbus->board] = (sbus->board * 2 + 1); 403 sbus_tid[board] = (board * 2);
404 else if (cpu_isset(board * 2 + 1, cpu_present_map))
405 sbus_tid[board] = (board * 2 + 1);
424 else 406 else
425 sbus_tid[sbus->board] = 0xff; 407 sbus_tid[board] = 0xff;
426 if (sbus_tid[sbus->board] != 0xff) 408 if (sbus_tid[board] != 0xff)
427 sbus_serving_map &= ~(1 << sbus_tid[sbus->board]); 409 cpu_clear(sbus_tid[board], sbus_serving_map);
428 } 410 }
429 for_each_sbus(sbus) 411 for_each_node_by_name(dp, "sbi") {
430 if (sbus_tid[sbus->board] == 0xff) { 412 int board = of_getintprop_default(dp, "board#", 0);
413 if (sbus_tid[board] == 0xff) {
431 int i = 31; 414 int i = 31;
432 415
433 if (!sbus_serving_map) 416 if (cpus_empty(sbus_serving_map))
434 sbus_serving_map = cpu_present_map; 417 sbus_serving_map = cpu_present_map;
435 while (!(sbus_serving_map & (1 << i))) 418 while (cpu_isset(i, sbus_serving_map))
436 i--; 419 i--;
437 sbus_tid[sbus->board] = i; 420 sbus_tid[board] = i;
438 sbus_serving_map &= ~(1 << i); 421 cpu_clear(i, sbus_serving_map);
439 } 422 }
440 for_each_sbus(sbus) { 423 }
441 printk("sbus%d IRQs directed to CPU%d\n", sbus->board, sbus_tid[sbus->board]); 424 for_each_node_by_name(dp, "sbi") {
442 set_sbi_tid(sbus->devid, sbus_tid[sbus->board] << 3); 425 int devid = of_getintprop_default(dp, "device-id", 0);
426 int board = of_getintprop_default(dp, "board#", 0);
427 printk("sbus%d IRQs directed to CPU%d\n", board, sbus_tid[board]);
428 set_sbi_tid(devid, sbus_tid[board] << 3);
443 } 429 }
444#else 430#else
445 struct sbus_bus *sbus;
446 int cpuid = cpu_logical_map(1); 431 int cpuid = cpu_logical_map(1);
447 432
448 if (cpuid == -1) 433 if (cpuid == -1)
449 cpuid = cpu_logical_map(0); 434 cpuid = cpu_logical_map(0);
450 for_each_sbus(sbus) { 435 for_each_node_by_name(dp, "sbi") {
451 sbus_tid[sbus->board] = cpuid; 436 int devid = of_getintprop_default(dp, "device-id", 0);
452 set_sbi_tid(sbus->devid, cpuid << 3); 437 int board = of_getintprop_default(dp, "board#", 0);
438 sbus_tid[board] = cpuid;
439 set_sbi_tid(devid, cpuid << 3);
453 } 440 }
454 printk("All sbus IRQs directed to CPU%d\n", cpuid); 441 printk("All sbus IRQs directed to CPU%d\n", cpuid);
455#endif 442#endif
@@ -458,13 +445,7 @@ void __init sun4d_distribute_irqs(void)
458 445
459static void sun4d_clear_clock_irq(void) 446static void sun4d_clear_clock_irq(void)
460{ 447{
461 volatile unsigned int clear_intr; 448 sbus_readl(&sun4d_timers->l10_timer_limit);
462 clear_intr = sun4d_timers->l10_timer_limit;
463}
464
465static void sun4d_clear_profile_irq(int cpu)
466{
467 bw_get_prof_limit(cpu);
468} 449}
469 450
470static void sun4d_load_profile_irq(int cpu, unsigned int limit) 451static void sun4d_load_profile_irq(int cpu, unsigned int limit)
@@ -472,98 +453,121 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit)
472 bw_set_prof_limit(cpu, limit); 453 bw_set_prof_limit(cpu, limit);
473} 454}
474 455
475static void __init sun4d_init_timers(irq_handler_t counter_fn) 456static void __init sun4d_load_profile_irqs(void)
476{ 457{
477 int irq; 458 int cpu = 0, mid;
478 int cpu;
479 struct resource r;
480 int mid;
481 459
482 /* Map the User Timer registers. */ 460 while (!cpu_find_by_instance(cpu, NULL, &mid)) {
483 memset(&r, 0, sizeof(r)); 461 sun4d_load_profile_irq(mid >> 3, 0);
462 cpu++;
463 }
464}
465
466static void __init sun4d_fixup_trap_table(void)
467{
484#ifdef CONFIG_SMP 468#ifdef CONFIG_SMP
485 r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT; 469 unsigned long flags;
486#else 470 extern unsigned long lvl14_save[4];
487 r.start = CSR_BASE(0)+BW_TIMER_LIMIT; 471 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
472 extern unsigned int real_irq_entry[], smp4d_ticker[];
473 extern unsigned int patchme_maybe_smp_msg[];
474
475 /* Adjust so that we jump directly to smp4d_ticker */
476 lvl14_save[2] += smp4d_ticker - real_irq_entry;
477
478 /* For SMP we use the level 14 ticker, however the bootup code
479 * has copied the firmware's level 14 vector into the boot cpu's
480 * trap table, we must fix this now or we get squashed.
481 */
482 local_irq_save(flags);
483 patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
484 trap_table->inst_one = lvl14_save[0];
485 trap_table->inst_two = lvl14_save[1];
486 trap_table->inst_three = lvl14_save[2];
487 trap_table->inst_four = lvl14_save[3];
488 local_flush_cache_all();
489 local_irq_restore(flags);
488#endif 490#endif
489 r.flags = 0xf; 491}
490 sun4d_timers = (struct sun4d_timer_regs *) sbus_ioremap(&r, 0,
491 PAGE_SIZE, "user timer");
492 492
493 sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); 493static void __init sun4d_init_timers(irq_handler_t counter_fn)
494 master_l10_counter = &sun4d_timers->l10_cur_count; 494{
495 master_l10_limit = &sun4d_timers->l10_timer_limit; 495 struct device_node *dp;
496 struct resource res;
497 const u32 *reg;
498 int err;
499
500 dp = of_find_node_by_name(NULL, "cpu-unit");
501 if (!dp) {
502 prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
503 prom_halt();
504 }
496 505
497 irq = request_irq(TIMER_IRQ, 506 /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
498 counter_fn, 507 * registers via any cpu's mapping. The first 'reg' property is the
499 (IRQF_DISABLED | SA_STATIC_ALLOC), 508 * bootbus.
500 "timer", NULL); 509 */
501 if (irq) { 510 reg = of_get_property(dp, "reg", NULL);
502 prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); 511 if (!reg) {
512 prom_printf("sun4d_init_timers: No reg property\n");
503 prom_halt(); 513 prom_halt();
504 } 514 }
505
506 /* Enable user timer free run for CPU 0 in BW */
507 /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
508 515
509 cpu = 0; 516 res.start = reg[1];
510 while (!cpu_find_by_instance(cpu, NULL, &mid)) { 517 res.end = reg[2] - 1;
511 sun4d_load_profile_irq(mid >> 3, 0); 518 res.flags = reg[0] & 0xff;
512 cpu++; 519 sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
520 sizeof(struct sun4d_timer_regs), "user timer");
521 if (!sun4d_timers) {
522 prom_printf("sun4d_init_timers: Can't map timer regs\n");
523 prom_halt();
513 } 524 }
514 525
515#ifdef CONFIG_SMP 526 sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
516 { 527
517 unsigned long flags; 528 master_l10_counter = &sun4d_timers->l10_cur_count;
518 extern unsigned long lvl14_save[4]; 529
519 struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)]; 530 err = request_irq(TIMER_IRQ, counter_fn,
520 extern unsigned int real_irq_entry[], smp4d_ticker[]; 531 (IRQF_DISABLED | SA_STATIC_ALLOC),
521 extern unsigned int patchme_maybe_smp_msg[]; 532 "timer", NULL);
522 533 if (err) {
523 /* Adjust so that we jump directly to smp4d_ticker */ 534 prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err);
524 lvl14_save[2] += smp4d_ticker - real_irq_entry; 535 prom_halt();
525
526 /* For SMP we use the level 14 ticker, however the bootup code
527 * has copied the firmware's level 14 vector into the boot cpu's
528 * trap table, we must fix this now or we get squashed.
529 */
530 local_irq_save(flags);
531 patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
532 trap_table->inst_one = lvl14_save[0];
533 trap_table->inst_two = lvl14_save[1];
534 trap_table->inst_three = lvl14_save[2];
535 trap_table->inst_four = lvl14_save[3];
536 local_flush_cache_all();
537 local_irq_restore(flags);
538 } 536 }
539#endif 537 sun4d_load_profile_irqs();
538 sun4d_fixup_trap_table();
540} 539}
541 540
542void __init sun4d_init_sbi_irq(void) 541void __init sun4d_init_sbi_irq(void)
543{ 542{
544 struct sbus_bus *sbus; 543 struct device_node *dp;
545 unsigned mask; 544 int target_cpu = 0;
545
546#ifdef CONFIG_SMP
547 target_cpu = boot_cpu_id;
548#endif
546 549
547 nsbi = 0; 550 nsbi = 0;
548 for_each_sbus(sbus) 551 for_each_node_by_name(dp, "sbi")
549 nsbi++; 552 nsbi++;
550 sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC); 553 sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
551 if (!sbus_actions) { 554 if (!sbus_actions) {
552 prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n"); 555 prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n");
553 prom_halt(); 556 prom_halt();
554 } 557 }
555 for_each_sbus(sbus) { 558 for_each_node_by_name(dp, "sbi") {
556#ifdef CONFIG_SMP 559 int devid = of_getintprop_default(dp, "device-id", 0);
557 extern unsigned char boot_cpu_id; 560 int board = of_getintprop_default(dp, "board#", 0);
558 561 unsigned int mask;
559 set_sbi_tid(sbus->devid, boot_cpu_id << 3); 562
560 sbus_tid[sbus->board] = boot_cpu_id; 563 set_sbi_tid(devid, target_cpu << 3);
561#endif 564 sbus_tid[board] = target_cpu;
565
562 /* Get rid of pending irqs from PROM */ 566 /* Get rid of pending irqs from PROM */
563 mask = acquire_sbi(sbus->devid, 0xffffffff); 567 mask = acquire_sbi(devid, 0xffffffff);
564 if (mask) { 568 if (mask) {
565 printk ("Clearing pending IRQs %08x on SBI %d\n", mask, sbus->board); 569 printk ("Clearing pending IRQs %08x on SBI %d\n", mask, board);
566 release_sbi(sbus->devid, mask); 570 release_sbi(devid, mask);
567 } 571 }
568 } 572 }
569} 573}
@@ -572,11 +576,9 @@ void __init sun4d_init_IRQ(void)
572{ 576{
573 local_irq_disable(); 577 local_irq_disable();
574 578
575 BTFIXUPSET_CALL(sbint_to_irq, sun4d_sbint_to_irq, BTFIXUPCALL_NORM);
576 BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM); 579 BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
577 BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM); 580 BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
578 BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM); 581 BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
579 BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM);
580 BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM); 582 BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
581 sparc_init_timers = sun4d_init_timers; 583 sparc_init_timers = sun4d_init_timers;
582#ifdef CONFIG_SMP 584#ifdef CONFIG_SMP