diff options
Diffstat (limited to 'arch/mips/sibyte/sb1250/irq.c')
-rw-r--r-- | arch/mips/sibyte/sb1250/irq.c | 78 |
1 files changed, 72 insertions, 6 deletions
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c index 589537bfcc3d..0f6e54db4888 100644 --- a/arch/mips/sibyte/sb1250/irq.c +++ b/arch/mips/sibyte/sb1250/irq.c | |||
@@ -163,10 +163,6 @@ static void sb1250_set_affinity(unsigned int irq, cpumask_t mask) | |||
163 | } | 163 | } |
164 | #endif | 164 | #endif |
165 | 165 | ||
166 | |||
167 | /* Defined in arch/mips/sibyte/sb1250/irq_handler.S */ | ||
168 | extern void sb1250_irq_handler(void); | ||
169 | |||
170 | /*****************************************************************************/ | 166 | /*****************************************************************************/ |
171 | 167 | ||
172 | static unsigned int startup_sb1250_irq(unsigned int irq) | 168 | static unsigned int startup_sb1250_irq(unsigned int irq) |
@@ -379,7 +375,6 @@ void __init arch_init_irq(void) | |||
379 | #endif | 375 | #endif |
380 | /* Enable necessary IPs, disable the rest */ | 376 | /* Enable necessary IPs, disable the rest */ |
381 | change_c0_status(ST0_IM, imask); | 377 | change_c0_status(ST0_IM, imask); |
382 | set_except_vector(0, sb1250_irq_handler); | ||
383 | 378 | ||
384 | #ifdef CONFIG_KGDB | 379 | #ifdef CONFIG_KGDB |
385 | if (kgdb_flag) { | 380 | if (kgdb_flag) { |
@@ -409,7 +404,7 @@ void __init arch_init_irq(void) | |||
409 | #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) | 404 | #define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg))) |
410 | #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) | 405 | #define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg))) |
411 | 406 | ||
412 | void sb1250_kgdb_interrupt(struct pt_regs *regs) | 407 | static void sb1250_kgdb_interrupt(struct pt_regs *regs) |
413 | { | 408 | { |
414 | /* | 409 | /* |
415 | * Clear break-change status (allow some time for the remote | 410 | * Clear break-change status (allow some time for the remote |
@@ -424,3 +419,74 @@ void sb1250_kgdb_interrupt(struct pt_regs *regs) | |||
424 | } | 419 | } |
425 | 420 | ||
426 | #endif /* CONFIG_KGDB */ | 421 | #endif /* CONFIG_KGDB */ |
422 | |||
423 | static inline int dclz(unsigned long long x) | ||
424 | { | ||
425 | int lz; | ||
426 | |||
427 | __asm__ ( | ||
428 | " .set push \n" | ||
429 | " .set mips64 \n" | ||
430 | " dclz %0, %1 \n" | ||
431 | " .set pop \n" | ||
432 | : "=r" (lz) | ||
433 | : "r" (x)); | ||
434 | |||
435 | return lz; | ||
436 | } | ||
437 | |||
438 | asmlinkage void plat_irq_dispatch(struct pt_regs *regs) | ||
439 | { | ||
440 | unsigned int pending; | ||
441 | |||
442 | #ifdef CONFIG_SIBYTE_SB1250_PROF | ||
443 | /* Set compare to count to silence count/compare timer interrupts */ | ||
444 | write_c0_count(read_c0_count()); | ||
445 | #endif | ||
446 | |||
447 | /* | ||
448 | * What a pain. We have to be really careful saving the upper 32 bits | ||
449 | * of any * register across function calls if we don't want them | ||
450 | * trashed--since were running in -o32, the calling routing never saves | ||
451 | * the full 64 bits of a register across a function call. Being the | ||
452 | * interrupt handler, we're guaranteed that interrupts are disabled | ||
453 | * during this code so we don't have to worry about random interrupts | ||
454 | * blasting the high 32 bits. | ||
455 | */ | ||
456 | |||
457 | pending = read_c0_cause(); | ||
458 | |||
459 | #ifdef CONFIG_SIBYTE_SB1250_PROF | ||
460 | if (pending & CAUSEF_IP7) { /* Cpu performance counter interrupt */ | ||
461 | sbprof_cpu_intr(exception_epc(regs)); | ||
462 | } | ||
463 | #endif | ||
464 | |||
465 | if (pending & CAUSEF_IP4) | ||
466 | sb1250_timer_interrupt(regs); | ||
467 | |||
468 | #ifdef CONFIG_SMP | ||
469 | if (pending & CAUSEF_IP3) | ||
470 | sb1250_mailbox_interrupt(regs); | ||
471 | #endif | ||
472 | |||
473 | #ifdef CONFIG_KGDB | ||
474 | if (pending & CAUSEF_IP6) /* KGDB (uart 1) */ | ||
475 | sb1250_kgdb_interrupt(regs); | ||
476 | #endif | ||
477 | |||
478 | if (pending & CAUSEF_IP2) { | ||
479 | unsigned long long mask; | ||
480 | |||
481 | /* | ||
482 | * Default...we've hit an IP[2] interrupt, which means we've | ||
483 | * got to check the 1250 interrupt registers to figure out what | ||
484 | * to do. Need to detect which CPU we're on, now that | ||
485 | ~ smp_affinity is supported. | ||
486 | */ | ||
487 | mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(), | ||
488 | R_IMR_INTERRUPT_STATUS_BASE))); | ||
489 | if (mask) | ||
490 | do_IRQ(63 - dclz(mask), regs); | ||
491 | } | ||
492 | } | ||