aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/sibyte/sb1250/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/sibyte/sb1250/irq.c')
-rw-r--r--arch/mips/sibyte/sb1250/irq.c78
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 */
168extern void sb1250_irq_handler(void);
169
170/*****************************************************************************/ 166/*****************************************************************************/
171 167
172static unsigned int startup_sb1250_irq(unsigned int irq) 168static 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
412void sb1250_kgdb_interrupt(struct pt_regs *regs) 407static 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
423static 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
438asmlinkage 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}