irq_handler.S 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. /*
  19. * bcm1480_irq_handler() is the routine that is actually called when an
  20. * interrupt occurs. It is installed as the exception vector handler in
  21. * init_IRQ() in arch/mips/sibyte/bcm1480/irq.c
  22. *
  23. * In the handle we figure out which interrupts need handling, and use that
  24. * to call the dispatcher, which will take care of actually calling
  25. * registered handlers
  26. *
  27. * Note that we take care of all raised interrupts in one go at the handler.
  28. * This is more BSDish than the Indy code, and also, IMHO, more sane.
  29. */
  30. #include <linux/config.h>
  31. #include <asm/addrspace.h>
  32. #include <asm/asm.h>
  33. #include <asm/mipsregs.h>
  34. #include <asm/regdef.h>
  35. #include <asm/stackframe.h>
  36. #include <asm/sibyte/sb1250_defs.h>
  37. #include <asm/sibyte/bcm1480_regs.h>
  38. #include <asm/sibyte/bcm1480_int.h>
  39. /*
  40. * What a pain. We have to be really careful saving the upper 32 bits of any
  41. * register across function calls if we don't want them trashed--since were
  42. * running in -o32, the calling routing never saves the full 64 bits of a
  43. * register across a function call. Being the interrupt handler, we're
  44. * guaranteed that interrupts are disabled during this code so we don't have
  45. * to worry about random interrupts blasting the high 32 bits.
  46. */
  47. .text
  48. .set push
  49. .set noreorder
  50. .set noat
  51. .set mips64
  52. #.set mips4
  53. .align 5
  54. NESTED(bcm1480_irq_handler, PT_SIZE, sp)
  55. SAVE_ALL
  56. CLI
  57. #ifdef CONFIG_SIBYTE_BCM1480_PROF
  58. /* Set compare to count to silence count/compare timer interrupts */
  59. mfc0 t1, CP0_COUNT
  60. mtc0 t1, CP0_COMPARE /* pause to clear IP[7] bit of cause ? */
  61. #endif
  62. /* Read cause */
  63. mfc0 s0, CP0_CAUSE
  64. #ifdef CONFIG_SIBYTE_BCM1480_PROF
  65. /* Cpu performance counter interrupt is routed to IP[7] */
  66. andi t1, s0, CAUSEF_IP7
  67. beqz t1, 0f
  68. srl t1, s0, (CAUSEB_BD-2) /* Shift BD bit to bit 2 */
  69. and t1, t1, 0x4 /* mask to get just BD bit */
  70. #ifdef CONFIG_MIPS64
  71. dmfc0 a0, CP0_EPC
  72. daddu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */
  73. #else
  74. mfc0 a0, CP0_EPC
  75. addu a0, a0, t1 /* a0 = EPC + (BD ? 4 : 0) */
  76. #endif
  77. jal sbprof_cpu_intr
  78. nop
  79. j ret_from_irq
  80. nop
  81. 0:
  82. #endif
  83. /* Timer interrupt is routed to IP[4] */
  84. andi t1, s0, CAUSEF_IP4
  85. beqz t1, 1f
  86. nop
  87. jal bcm1480_timer_interrupt
  88. move a0, sp /* Pass the registers along */
  89. j ret_from_irq
  90. nop /* delay slot */
  91. 1:
  92. #ifdef CONFIG_SMP
  93. /* Mailbox interrupt is routed to IP[3] */
  94. andi t1, s0, CAUSEF_IP3
  95. beqz t1, 2f
  96. nop
  97. jal bcm1480_mailbox_interrupt
  98. move a0, sp
  99. j ret_from_irq
  100. nop /* delay slot */
  101. 2:
  102. #endif
  103. #ifdef CONFIG_KGDB
  104. /* KGDB (uart 1) interrupt is routed to IP[6] */
  105. andi t1, s0, CAUSEF_IP6
  106. beqz t1, 3f
  107. nop /* delay slot */
  108. jal bcm1480_kgdb_interrupt
  109. move a0, sp
  110. j ret_from_irq
  111. nop /* delay slot */
  112. 3:
  113. #endif
  114. and t1, s0, CAUSEF_IP2
  115. beqz t1, 9f
  116. nop
  117. /*
  118. * Default...we've hit an IP[2] interrupt, which means we've got
  119. * to check the 1480 interrupt registers to figure out what to do
  120. * Need to detect which CPU we're on, now that smp_affinity is
  121. * supported.
  122. */
  123. PTR_LA v0, CKSEG1 + A_BCM1480_IMR_CPU0_BASE
  124. #ifdef CONFIG_SMP
  125. lw t1, TI_CPU($28)
  126. sll t1, t1, BCM1480_IMR_REGISTER_SPACING_SHIFT
  127. addu v0, v0, t1
  128. #endif
  129. /* Read IP[2] status (get both high and low halves of status) */
  130. ld s0, R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H(v0)
  131. ld s1, R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L(v0)
  132. move s2, zero /* intr number */
  133. li s3, 64
  134. beqz s0, 9f /* No interrupts. Return. */
  135. move a1, sp
  136. xori s4, s0, 1 /* if s0 (_H) == 1, it's a low intr, so... */
  137. movz s2, s3, s4 /* start the intr number at 64, and */
  138. movz s0, s1, s4 /* look at the low status value. */
  139. dclz s1, s0 /* Find the next interrupt. */
  140. dsubu a0, zero, s1
  141. daddiu a0, a0, 63
  142. jal do_IRQ
  143. daddu a0, a0, s2
  144. 9: j ret_from_irq
  145. nop
  146. .set pop
  147. END(bcm1480_irq_handler)