diff options
Diffstat (limited to 'arch/mips/sibyte/bcm1480/irq.c')
-rw-r--r-- | arch/mips/sibyte/bcm1480/irq.c | 77 |
1 files changed, 73 insertions, 4 deletions
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c index 9cf7d713b13c..e61760b14d99 100644 --- a/arch/mips/sibyte/bcm1480/irq.c +++ b/arch/mips/sibyte/bcm1480/irq.c | |||
@@ -187,9 +187,6 @@ static void bcm1480_set_affinity(unsigned int irq, cpumask_t mask) | |||
187 | #endif | 187 | #endif |
188 | 188 | ||
189 | 189 | ||
190 | /* Defined in arch/mips/sibyte/bcm1480/irq_handler.S */ | ||
191 | extern void bcm1480_irq_handler(void); | ||
192 | |||
193 | /*****************************************************************************/ | 190 | /*****************************************************************************/ |
194 | 191 | ||
195 | static unsigned int startup_bcm1480_irq(unsigned int irq) | 192 | static unsigned int startup_bcm1480_irq(unsigned int irq) |
@@ -422,7 +419,6 @@ void __init arch_init_irq(void) | |||
422 | #endif | 419 | #endif |
423 | /* Enable necessary IPs, disable the rest */ | 420 | /* Enable necessary IPs, disable the rest */ |
424 | change_c0_status(ST0_IM, imask); | 421 | change_c0_status(ST0_IM, imask); |
425 | set_except_vector(0, bcm1480_irq_handler); | ||
426 | 422 | ||
427 | #ifdef CONFIG_KGDB | 423 | #ifdef CONFIG_KGDB |
428 | if (kgdb_flag) { | 424 | if (kgdb_flag) { |
@@ -473,3 +469,76 @@ void bcm1480_kgdb_interrupt(struct pt_regs *regs) | |||
473 | } | 469 | } |
474 | 470 | ||
475 | #endif /* CONFIG_KGDB */ | 471 | #endif /* CONFIG_KGDB */ |
472 | |||
473 | static inline int dclz(unsigned long long x) | ||
474 | { | ||
475 | int lz; | ||
476 | |||
477 | __asm__ ( | ||
478 | " .set push \n" | ||
479 | " .set mips64 \n" | ||
480 | " dclz %0, %1 \n" | ||
481 | " .set pop \n" | ||
482 | : "=r" (lz) | ||
483 | : "r" (x)); | ||
484 | |||
485 | return lz; | ||
486 | } | ||
487 | |||
488 | extern void bcm1480_timer_interrupt(struct pt_regs *regs); | ||
489 | extern void bcm1480_mailbox_interrupt(struct pt_regs *regs); | ||
490 | extern void bcm1480_kgdb_interrupt(struct pt_regs *regs); | ||
491 | |||
492 | asmlinkage void plat_irq_dispatch(struct pt_regs *regs) | ||
493 | { | ||
494 | unsigned int pending; | ||
495 | |||
496 | #ifdef CONFIG_SIBYTE_BCM1480_PROF | ||
497 | /* Set compare to count to silence count/compare timer interrupts */ | ||
498 | write_c0_compare(read_c0_count()); | ||
499 | #endif | ||
500 | |||
501 | pending = read_c0_cause(); | ||
502 | |||
503 | #ifdef CONFIG_SIBYTE_BCM1480_PROF | ||
504 | if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */ | ||
505 | sbprof_cpu_intr(exception_epc(regs)); | ||
506 | #endif | ||
507 | |||
508 | if (pending & CAUSEF_IP4) | ||
509 | bcm1480_timer_interrupt(regs); | ||
510 | |||
511 | #ifdef CONFIG_SMP | ||
512 | if (pending & CAUSEF_IP3) | ||
513 | bcm1480_mailbox_interrupt(regs); | ||
514 | #endif | ||
515 | |||
516 | #ifdef CONFIG_KGDB | ||
517 | if (pending & CAUSEF_IP6) | ||
518 | bcm1480_kgdb_interrupt(regs); /* KGDB (uart 1) */ | ||
519 | #endif | ||
520 | |||
521 | if (pending & CAUSEF_IP2) { | ||
522 | unsigned long long mask_h, mask_l; | ||
523 | unsigned long base; | ||
524 | |||
525 | /* | ||
526 | * Default...we've hit an IP[2] interrupt, which means we've | ||
527 | * got to check the 1480 interrupt registers to figure out what | ||
528 | * to do. Need to detect which CPU we're on, now that | ||
529 | * smp_affinity is supported. | ||
530 | */ | ||
531 | base = A_BCM1480_IMR_MAPPER(smp_processor_id()); | ||
532 | mask_h = __raw_readq( | ||
533 | IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H)); | ||
534 | mask_l = __raw_readq( | ||
535 | IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L)); | ||
536 | |||
537 | if (!mask_h) { | ||
538 | if (mask_h ^ 1) | ||
539 | do_IRQ(63 - dclz(mask_h), regs); | ||
540 | else | ||
541 | do_IRQ(127 - dclz(mask_l), regs); | ||
542 | } | ||
543 | } | ||
544 | } | ||