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 defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) 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#else 155#error GCC `-msym32' option required for 64-bit DECstation builds 156#endif 1571: lw t2,(t1) 158 nop 159 and t2,t0 160 beqz t2,1b 161 addu t1,2*PTRSIZE # delay slot 162 163 /* 164 * Do the low-level stuff 165 */ 166 lw a0,(-PTRSIZE)(t1) 167 nop 168 bgez a0,handle_it # irq_nr >= 0? 169 # irq_nr < 0: it is an address 170 nop 171 jr a0 172 # a trick to save a branch: 173 lui t2,(KN03_IOASIC_BASE>>16)&0xffff 174 # upper part of IOASIC Address 175 176/* 177 * Handle "IRQ Controller" Interrupts 178 * Masked Interrupts are still visible and have to be masked "by hand". 179 */ 180 FEXPORT(kn02_io_int) # 3max 181 lui t0,(KN02_CSR_BASE>>16)&0xffff 182 # get interrupt status and mask 183 lw t0,(t0) 184 nop 185 andi t1,t0,KN02_IRQ_ALL 186 b 1f 187 srl t0,16 # shift interrupt mask 188 189 FEXPORT(kn02xa_io_int) # 3min/maxine 190 lui t2,(KN02XA_IOASIC_BASE>>16)&0xffff 191 # upper part of IOASIC Address 192 193 FEXPORT(kn03_io_int) # 3max+ (t2 loaded earlier) 194 lw t0,IO_REG_SIR(t2) # get status: IOASIC sir 195 lw t1,IO_REG_SIMR(t2) # get mask: IOASIC simr 196 nop 197 1981: and t0,t1 # mask out allowed ones 199 200 beqz t0,spurious 201 202 /* 203 * Find irq with highest priority 204 */ 205 # open coded PTR_LA t1,asic_mask_nr_tbl 206#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) 207 # open coded la t1, asic_mask_nr_tbl 208 lui t1, %hi(asic_mask_nr_tbl) 209 addiu t1, %lo(asic_mask_nr_tbl) 210#else 211#error GCC `-msym32' option required for 64-bit DECstation builds 212#endif 2132: lw t2,(t1) 214 nop 215 and t2,t0 216 beq zero,t2,2b 217 addu t1,2*PTRSIZE # delay slot 218 219 /* 220 * Do the low-level stuff 221 */ 222 lw a0,%lo(-PTRSIZE)(t1) 223 nop 224 bgez a0,handle_it # irq_nr >= 0? 225 # irq_nr < 0: it is an address 226 nop 227 jr a0 228 nop # delay slot 229 230/* 231 * Dispatch low-priority interrupts. We reconsider all status 232 * bits again, which looks like a lose, but it makes the code 233 * simple and O(log n), so it gets compensated. 234 */ 235 FEXPORT(cpu_all_int) # HALT, timers, software junk 236 li a0,DEC_CPU_IRQ_BASE 237 srl t0,CAUSEB_IP 238 li t1,CAUSEF_IP>>CAUSEB_IP # mask 239 b 1f 240 li t2,4 # nr of bits / 2 241 242 FEXPORT(kn02_all_int) # impossible ? 243 li a0,KN02_IRQ_BASE 244 li t1,KN02_IRQ_ALL # mask 245 b 1f 246 li t2,4 # nr of bits / 2 247 248 FEXPORT(asic_all_int) # various I/O ASIC junk 249 li a0,IO_IRQ_BASE 250 li t1,IO_IRQ_ALL # mask 251 b 1f 252 li t2,8 # nr of bits / 2 253 254/* 255 * Dispatch DMA interrupts -- O(log n). 256 */ 257 FEXPORT(asic_dma_int) # I/O ASIC DMA events 258 li a0,IO_IRQ_BASE+IO_INR_DMA 259 srl t0,IO_INR_DMA 260 li t1,IO_IRQ_DMA>>IO_INR_DMA # mask 261 li t2,8 # nr of bits / 2 262 263 /* 264 * Find irq with highest priority. 265 * Highest irq number takes precedence. 266 */ 2671: srlv t3,t1,t2 2682: xor t1,t3 269 and t3,t0,t1 270 beqz t3,3f 271 nop 272 move t0,t3 273 addu a0,t2 2743: srl t2,1 275 bnez t2,2b 276 srlv t3,t1,t2 277 278handle_it: 279 j dec_irq_dispatch 280 nop 281 282#ifdef CONFIG_32BIT 283fpu: 284 lw t0,fpu_kstat_irq 285 nop 286 lw t1,(t0) 287 nop 288 addu t1,1 289 j handle_fpe_int 290 sw t1,(t0) 291#endif 292 293spurious: 294 j spurious_interrupt 295 nop 296 END(plat_irq_dispatch) 297 298/* 299 * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl 300 * and asic_mask_nr_tbl are initialized to point all interrupts here. 301 * The tables are then filled in by machine-specific initialisation 302 * in dec_setup(). 303 */ 304 FEXPORT(dec_intr_unimplemented) 305 move a1,t0 # cheats way of printing an arg! 306 PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x"); 307 308 FEXPORT(asic_intr_unimplemented) 309 move a1,t0 # cheats way of printing an arg! 310 PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%08x"); 311