1/* 2 * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen 3 * Copyright (C) 2000, 2001, 2002, 2003, 2005 Maciej W. Rozycki 4 * 5 * Written by Ralf Baechle and Andreas Busse, modified for DECstation 6 * support by Paul Antoine and Harald Koerfgen. 7 * 8 * completely rewritten: 9 * Copyright (C) 1998 Harald Koerfgen 10 * 11 * Rewritten extensively for controller-driven IRQ support 12 * by Maciej W. Rozycki. 13 */ 14 15#include <asm/addrspace.h> 16#include <asm/asm.h> 17#include <asm/mipsregs.h> 18#include <asm/regdef.h> 19#include <asm/stackframe.h> 20 21#include <asm/dec/interrupts.h> 22#include <asm/dec/ioasic_addrs.h> 23#include <asm/dec/ioasic_ints.h> 24#include <asm/dec/kn01.h> 25#include <asm/dec/kn02.h> 26#include <asm/dec/kn02xa.h> 27#include <asm/dec/kn03.h> 28 29#define KN02_CSR_BASE CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR) 30#define KN02XA_IOASIC_BASE CKSEG1ADDR(KN02XA_SLOT_BASE + IOASIC_IOCTL) 31#define KN03_IOASIC_BASE CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_IOCTL) 32 33 .text 34 .set noreorder 35/* 36 * plat_irq_dispatch: Interrupt handler for DECstations 37 * 38 * We follow the model in the Indy interrupt code by David Miller, where he 39 * says: a lot of complication here is taken away because: 40 * 41 * 1) We handle one interrupt and return, sitting in a loop 42 * and moving across all the pending IRQ bits in the cause 43 * register is _NOT_ the answer, the common case is one 44 * pending IRQ so optimize in that direction. 45 * 46 * 2) We need not check against bits in the status register 47 * IRQ mask, that would make this routine slow as hell. 48 * 49 * 3) Linux only thinks in terms of all IRQs on or all IRQs 50 * off, nothing in between like BSD spl() brain-damage. 51 * 52 * Furthermore, the IRQs on the DECstations look basically (barring 53 * software IRQs which we don't use at all) like... 54 * 55 * DS2100/3100's, aka kn01, aka Pmax: 56 * 57 * MIPS IRQ Source 58 * -------- ------ 59 * 0 Software (ignored) 60 * 1 Software (ignored) 61 * 2 SCSI 62 * 3 Lance Ethernet 63 * 4 DZ11 serial 64 * 5 RTC 65 * 6 Memory Controller & Video 66 * 7 FPU 67 * 68 * DS5000/200, aka kn02, aka 3max: 69 * 70 * MIPS IRQ Source 71 * -------- ------ 72 * 0 Software (ignored) 73 * 1 Software (ignored) 74 * 2 TurboChannel 75 * 3 RTC 76 * 4 Reserved 77 * 5 Memory Controller 78 * 6 Reserved 79 * 7 FPU 80 * 81 * DS5000/1xx's, aka kn02ba, aka 3min: 82 * 83 * MIPS IRQ Source 84 * -------- ------ 85 * 0 Software (ignored) 86 * 1 Software (ignored) 87 * 2 TurboChannel Slot 0 88 * 3 TurboChannel Slot 1 89 * 4 TurboChannel Slot 2 90 * 5 TurboChannel Slot 3 (ASIC) 91 * 6 Halt button 92 * 7 FPU/R4k timer 93 * 94 * DS5000/2x's, aka kn02ca, aka maxine: 95 * 96 * MIPS IRQ Source 97 * -------- ------ 98 * 0 Software (ignored) 99 * 1 Software (ignored) 100 * 2 Periodic Interrupt (100usec) 101 * 3 RTC 102 * 4 I/O write timeout 103 * 5 TurboChannel (ASIC) 104 * 6 Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER) 105 * 7 FPU/R4k timer 106 * 107 * DS5000/2xx's, aka kn03, aka 3maxplus: 108 * 109 * MIPS IRQ Source 110 * -------- ------ 111 * 0 Software (ignored) 112 * 1 Software (ignored) 113 * 2 System Board (ASIC) 114 * 3 RTC 115 * 4 Reserved 116 * 5 Memory 117 * 6 Halt Button 118 * 7 FPU/R4k timer 119 * 120 * We handle the IRQ according to _our_ priority (see setup.c), 121 * then we just return. If multiple IRQs are pending then we will 122 * just take another exception, big deal. 123 */ 124 .align 5 125 NESTED(plat_irq_dispatch, PT_SIZE, ra) 126 .set noreorder 127 128 /* 129 * Get pending Interrupts 130 */ 131 mfc0 t0,CP0_CAUSE # get pending interrupts 132 mfc0 t1,CP0_STATUS 133#ifdef CONFIG_32BIT 134 lw t2,cpu_fpu_mask 135#endif 136 andi t0,ST0_IM # CAUSE.CE may be non-zero! 137 and t0,t1 # isolate allowed ones 138 139 beqz t0,spurious 140 141#ifdef CONFIG_32BIT 142 and t2,t0 143 bnez t2,fpu # handle FPU immediately 144#endif 145 146 /* 147 * Find irq with highest priority 148 */ 149 # open coded PTR_LA t1, cpu_mask_nr_tbl 150#if (_MIPS_SZPTR == 32) 151 # open coded la t1, cpu_mask_nr_tbl 152 lui t1, %hi(cpu_mask_nr_tbl) 153 addiu t1, %lo(cpu_mask_nr_tbl) 154 155#endif 156#if (_MIPS_SZPTR == 64) 157 # open coded dla t1, cpu_mask_nr_tbl 158 .set push 159 .set noat 160 lui t1, %highest(cpu_mask_nr_tbl) 161 lui AT, %hi(cpu_mask_nr_tbl) 162 daddiu t1, t1, %higher(cpu_mask_nr_tbl) 163 daddiu AT, AT, %lo(cpu_mask_nr_tbl) 164 dsll t1, 32 165 daddu t1, t1, AT 166 .set pop 167#endif 1681: lw t2,(t1) 169 nop 170 and t2,t0 171 beqz t2,1b 172 addu t1,2*PTRSIZE # delay slot 173 174 /* 175 * Do the low-level stuff 176 */ 177 lw a0,(-PTRSIZE)(t1) 178 nop 179 bgez a0,handle_it # irq_nr >= 0? 180 # irq_nr < 0: it is an address 181 nop 182 jr a0 183 # a trick to save a branch: 184 lui t2,(KN03_IOASIC_BASE>>16)&0xffff 185 # upper part of IOASIC Address 186 187/* 188 * Handle "IRQ Controller" Interrupts 189 * Masked Interrupts are still visible and have to be masked "by hand". 190 */ 191 FEXPORT(kn02_io_int) # 3max 192 lui t0,(KN02_CSR_BASE>>16)&0xffff 193 # get interrupt status and mask 194 lw t0,(t0) 195 nop 196 andi t1,t0,KN02_IRQ_ALL 197 b 1f 198 srl t0,16 # shift interrupt mask 199 200 FEXPORT(kn02xa_io_int) # 3min/maxine 201 lui t2,(KN02XA_IOASIC_BASE>>16)&0xffff 202 # upper part of IOASIC Address 203 204 FEXPORT(kn03_io_int) # 3max+ (t2 loaded earlier) 205 lw t0,IO_REG_SIR(t2) # get status: IOASIC sir 206 lw t1,IO_REG_SIMR(t2) # get mask: IOASIC simr 207 nop 208 2091: and t0,t1 # mask out allowed ones 210 211 beqz t0,spurious 212 213 /* 214 * Find irq with highest priority 215 */ 216 # open coded PTR_LA t1,asic_mask_nr_tbl 217#if (_MIPS_SZPTR == 32) 218 # open coded la t1, asic_mask_nr_tbl 219 lui t1, %hi(asic_mask_nr_tbl) 220 addiu t1, %lo(asic_mask_nr_tbl) 221 222#endif 223#if (_MIPS_SZPTR == 64) 224 # open coded dla t1, asic_mask_nr_tbl 225 .set push 226 .set noat 227 lui t1, %highest(asic_mask_nr_tbl) 228 lui AT, %hi(asic_mask_nr_tbl) 229 daddiu t1, t1, %higher(asic_mask_nr_tbl) 230 daddiu AT, AT, %lo(asic_mask_nr_tbl) 231 dsll t1, 32 232 daddu t1, t1, AT 233 .set pop 234#endif 2352: lw t2,(t1) 236 nop 237 and t2,t0 238 beq zero,t2,2b 239 addu t1,2*PTRSIZE # delay slot 240 241 /* 242 * Do the low-level stuff 243 */ 244 lw a0,%lo(-PTRSIZE)(t1) 245 nop 246 bgez a0,handle_it # irq_nr >= 0? 247 # irq_nr < 0: it is an address 248 nop 249 jr a0 250 nop # delay slot 251 252/* 253 * Dispatch low-priority interrupts. We reconsider all status 254 * bits again, which looks like a lose, but it makes the code 255 * simple and O(log n), so it gets compensated. 256 */ 257 FEXPORT(cpu_all_int) # HALT, timers, software junk 258 li a0,DEC_CPU_IRQ_BASE 259 srl t0,CAUSEB_IP 260 li t1,CAUSEF_IP>>CAUSEB_IP # mask 261 b 1f 262 li t2,4 # nr of bits / 2 263 264 FEXPORT(kn02_all_int) # impossible ? 265 li a0,KN02_IRQ_BASE 266 li t1,KN02_IRQ_ALL # mask 267 b 1f 268 li t2,4 # nr of bits / 2 269 270 FEXPORT(asic_all_int) # various I/O ASIC junk 271 li a0,IO_IRQ_BASE 272 li t1,IO_IRQ_ALL # mask 273 b 1f 274 li t2,8 # nr of bits / 2 275 276/* 277 * Dispatch DMA interrupts -- O(log n). 278 */ 279 FEXPORT(asic_dma_int) # I/O ASIC DMA events 280 li a0,IO_IRQ_BASE+IO_INR_DMA 281 srl t0,IO_INR_DMA 282 li t1,IO_IRQ_DMA>>IO_INR_DMA # mask 283 li t2,8 # nr of bits / 2 284 285 /* 286 * Find irq with highest priority. 287 * Highest irq number takes precedence. 288 */ 2891: srlv t3,t1,t2 2902: xor t1,t3 291 and t3,t0,t1 292 beqz t3,3f 293 nop 294 move t0,t3 295 addu a0,t2 2963: srl t2,1 297 bnez t2,2b 298 srlv t3,t1,t2 299 300handle_it: 301 j dec_irq_dispatch 302 nop 303 304#ifdef CONFIG_32BIT 305fpu: 306 lw t0,fpu_kstat_irq 307 nop 308 lw t1,(t0) 309 nop 310 addu t1,1 311 j handle_fpe_int 312 sw t1,(t0) 313#endif 314 315spurious: 316 j spurious_interrupt 317 nop 318 END(plat_irq_dispatch) 319 320/* 321 * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl 322 * and asic_mask_nr_tbl are initialized to point all interrupts here. 323 * The tables are then filled in by machine-specific initialisation 324 * in dec_setup(). 325 */ 326 FEXPORT(dec_intr_unimplemented) 327 move a1,t0 # cheats way of printing an arg! 328 PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x"); 329 330 FEXPORT(asic_intr_unimplemented) 331 move a1,t0 # cheats way of printing an arg! 332 PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%08x"); 333