1 /* 2 * ip22-int.c: Routines for generic manipulation of the INT[23] ASIC 3 * found on INDY and Indigo2 workstations. 4 * 5 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) 6 * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) 7 * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) 8 * - Indigo2 changes 9 * - Interrupt handling fixes 10 * Copyright (C) 2001, 2003 Ladislav Michl (ladis@linux-mips.org) 11 */ 12 #include <linux/config.h> 13 #include <linux/types.h> 14 #include <linux/init.h> 15 #include <linux/kernel_stat.h> 16 #include <linux/signal.h> 17 #include <linux/sched.h> 18 #include <linux/interrupt.h> 19 #include <linux/irq.h> 20 21 #include <asm/mipsregs.h> 22 #include <asm/addrspace.h> 23 24 #include <asm/sgi/ioc.h> 25 #include <asm/sgi/hpc3.h> 26 #include <asm/sgi/ip22.h> 27 28 /* #define DEBUG_SGINT */ 29 30 /* So far nothing hangs here */ 31 #undef USE_LIO3_IRQ 32 33 struct sgint_regs *sgint; 34 35 static char lc0msk_to_irqnr[256]; 36 static char lc1msk_to_irqnr[256]; 37 static char lc2msk_to_irqnr[256]; 38 static char lc3msk_to_irqnr[256]; 39 40 extern int ip22_eisa_init(void); 41 42 static void enable_local0_irq(unsigned int irq) 43 { 44 unsigned long flags; 45 46 local_irq_save(flags); 47 /* don't allow mappable interrupt to be enabled from setup_irq, 48 * we have our own way to do so */ 49 if (irq != SGI_MAP_0_IRQ) 50 sgint->imask0 |= (1 << (irq - SGINT_LOCAL0)); 51 local_irq_restore(flags); 52 } 53 54 static unsigned int startup_local0_irq(unsigned int irq) 55 { 56 enable_local0_irq(irq); 57 return 0; /* Never anything pending */ 58 } 59 60 static void disable_local0_irq(unsigned int irq) 61 { 62 unsigned long flags; 63 64 local_irq_save(flags); 65 sgint->imask0 &= ~(1 << (irq - SGINT_LOCAL0)); 66 local_irq_restore(flags); 67 } 68 69 #define shutdown_local0_irq disable_local0_irq 70 #define mask_and_ack_local0_irq disable_local0_irq 71 72 static void end_local0_irq (unsigned int irq) 73 { 74 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 75 enable_local0_irq(irq); 76 } 77 78 static struct hw_interrupt_type ip22_local0_irq_type = { 79 .typename = "IP22 local 0", 80 .startup = startup_local0_irq, 81 .shutdown = shutdown_local0_irq, 82 .enable = enable_local0_irq, 83 .disable = disable_local0_irq, 84 .ack = mask_and_ack_local0_irq, 85 .end = end_local0_irq, 86 }; 87 88 static void enable_local1_irq(unsigned int irq) 89 { 90 unsigned long flags; 91 92 local_irq_save(flags); 93 /* don't allow mappable interrupt to be enabled from setup_irq, 94 * we have our own way to do so */ 95 if (irq != SGI_MAP_1_IRQ) 96 sgint->imask1 |= (1 << (irq - SGINT_LOCAL1)); 97 local_irq_restore(flags); 98 } 99 100 static unsigned int startup_local1_irq(unsigned int irq) 101 { 102 enable_local1_irq(irq); 103 return 0; /* Never anything pending */ 104 } 105 106 void disable_local1_irq(unsigned int irq) 107 { 108 unsigned long flags; 109 110 local_irq_save(flags); 111 sgint->imask1 &= ~(1 << (irq - SGINT_LOCAL1)); 112 local_irq_restore(flags); 113 } 114 115 #define shutdown_local1_irq disable_local1_irq 116 #define mask_and_ack_local1_irq disable_local1_irq 117 118 static void end_local1_irq (unsigned int irq) 119 { 120 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 121 enable_local1_irq(irq); 122 } 123 124 static struct hw_interrupt_type ip22_local1_irq_type = { 125 .typename = "IP22 local 1", 126 .startup = startup_local1_irq, 127 .shutdown = shutdown_local1_irq, 128 .enable = enable_local1_irq, 129 .disable = disable_local1_irq, 130 .ack = mask_and_ack_local1_irq, 131 .end = end_local1_irq, 132 }; 133 134 static void enable_local2_irq(unsigned int irq) 135 { 136 unsigned long flags; 137 138 local_irq_save(flags); 139 sgint->imask0 |= (1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); 140 sgint->cmeimask0 |= (1 << (irq - SGINT_LOCAL2)); 141 local_irq_restore(flags); 142 } 143 144 static unsigned int startup_local2_irq(unsigned int irq) 145 { 146 enable_local2_irq(irq); 147 return 0; /* Never anything pending */ 148 } 149 150 void disable_local2_irq(unsigned int irq) 151 { 152 unsigned long flags; 153 154 local_irq_save(flags); 155 sgint->cmeimask0 &= ~(1 << (irq - SGINT_LOCAL2)); 156 if (!sgint->cmeimask0) 157 sgint->imask0 &= ~(1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); 158 local_irq_restore(flags); 159 } 160 161 #define shutdown_local2_irq disable_local2_irq 162 #define mask_and_ack_local2_irq disable_local2_irq 163 164 static void end_local2_irq (unsigned int irq) 165 { 166 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 167 enable_local2_irq(irq); 168 } 169 170 static struct hw_interrupt_type ip22_local2_irq_type = { 171 .typename = "IP22 local 2", 172 .startup = startup_local2_irq, 173 .shutdown = shutdown_local2_irq, 174 .enable = enable_local2_irq, 175 .disable = disable_local2_irq, 176 .ack = mask_and_ack_local2_irq, 177 .end = end_local2_irq, 178 }; 179 180 static void enable_local3_irq(unsigned int irq) 181 { 182 unsigned long flags; 183 184 local_irq_save(flags); 185 sgint->imask1 |= (1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); 186 sgint->cmeimask1 |= (1 << (irq - SGINT_LOCAL3)); 187 local_irq_restore(flags); 188 } 189 190 static unsigned int startup_local3_irq(unsigned int irq) 191 { 192 enable_local3_irq(irq); 193 return 0; /* Never anything pending */ 194 } 195 196 void disable_local3_irq(unsigned int irq) 197 { 198 unsigned long flags; 199 200 local_irq_save(flags); 201 sgint->cmeimask1 &= ~(1 << (irq - SGINT_LOCAL3)); 202 if (!sgint->cmeimask1) 203 sgint->imask1 &= ~(1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); 204 local_irq_restore(flags); 205 } 206 207 #define shutdown_local3_irq disable_local3_irq 208 #define mask_and_ack_local3_irq disable_local3_irq 209 210 static void end_local3_irq (unsigned int irq) 211 { 212 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 213 enable_local3_irq(irq); 214 } 215 216 static struct hw_interrupt_type ip22_local3_irq_type = { 217 .typename = "IP22 local 3", 218 .startup = startup_local3_irq, 219 .shutdown = shutdown_local3_irq, 220 .enable = enable_local3_irq, 221 .disable = disable_local3_irq, 222 .ack = mask_and_ack_local3_irq, 223 .end = end_local3_irq, 224 }; 225 226 static void indy_local0_irqdispatch(struct pt_regs *regs) 227 { 228 u8 mask = sgint->istat0 & sgint->imask0; 229 u8 mask2; 230 int irq; 231 232 if (mask & SGINT_ISTAT0_LIO2) { 233 mask2 = sgint->vmeistat & sgint->cmeimask0; 234 irq = lc2msk_to_irqnr[mask2]; 235 } else 236 irq = lc0msk_to_irqnr[mask]; 237 238 /* if irq == 0, then the interrupt has already been cleared */ 239 if (irq) 240 do_IRQ(irq, regs); 241 return; 242 } 243 244 static void indy_local1_irqdispatch(struct pt_regs *regs) 245 { 246 u8 mask = sgint->istat1 & sgint->imask1; 247 u8 mask2; 248 int irq; 249 250 if (mask & SGINT_ISTAT1_LIO3) { 251 mask2 = sgint->vmeistat & sgint->cmeimask1; 252 irq = lc3msk_to_irqnr[mask2]; 253 } else 254 irq = lc1msk_to_irqnr[mask]; 255 256 /* if irq == 0, then the interrupt has already been cleared */ 257 if (irq) 258 do_IRQ(irq, regs); 259 return; 260 } 261 262 extern void ip22_be_interrupt(int irq, struct pt_regs *regs); 263 264 static void indy_buserror_irq(struct pt_regs *regs) 265 { 266 int irq = SGI_BUSERR_IRQ; 267 268 irq_enter(); 269 kstat_this_cpu.irqs[irq]++; 270 ip22_be_interrupt(irq, regs); 271 irq_exit(); 272 } 273 274 static struct irqaction local0_cascade = { 275 .handler = no_action, 276 .flags = SA_INTERRUPT, 277 .name = "local0 cascade", 278 }; 279 280 static struct irqaction local1_cascade = { 281 .handler = no_action, 282 .flags = SA_INTERRUPT, 283 .name = "local1 cascade", 284 }; 285 286 static struct irqaction buserr = { 287 .handler = no_action, 288 .flags = SA_INTERRUPT, 289 .name = "Bus Error", 290 }; 291 292 static struct irqaction map0_cascade = { 293 .handler = no_action, 294 .flags = SA_INTERRUPT, 295 .name = "mapable0 cascade", 296 }; 297 298 #ifdef USE_LIO3_IRQ 299 static struct irqaction map1_cascade = { 300 .handler = no_action, 301 .flags = SA_INTERRUPT, 302 .name = "mapable1 cascade", 303 }; 304 #define SGI_INTERRUPTS SGINT_END 305 #else 306 #define SGI_INTERRUPTS SGINT_LOCAL3 307 #endif 308 309 extern void indy_r4k_timer_interrupt(struct pt_regs *regs); 310 extern void indy_8254timer_irq(struct pt_regs *regs); 311 312 /* 313 * IRQs on the INDY look basically (barring software IRQs which we don't use 314 * at all) like: 315 * 316 * MIPS IRQ Source 317 * -------- ------ 318 * 0 Software (ignored) 319 * 1 Software (ignored) 320 * 2 Local IRQ level zero 321 * 3 Local IRQ level one 322 * 4 8254 Timer zero 323 * 5 8254 Timer one 324 * 6 Bus Error 325 * 7 R4k timer (what we use) 326 * 327 * We handle the IRQ according to _our_ priority which is: 328 * 329 * Highest ---- R4k Timer 330 * Local IRQ zero 331 * Local IRQ one 332 * Bus Error 333 * 8254 Timer zero 334 * Lowest ---- 8254 Timer one 335 * 336 * then we just return, if multiple IRQs are pending then we will just take 337 * another exception, big deal. 338 */ 339 340 asmlinkage void plat_irq_dispatch(struct pt_regs *regs) 341 { 342 unsigned int pending = read_c0_cause(); 343 344 /* 345 * First we check for r4k counter/timer IRQ. 346 */ 347 if (pending & CAUSEF_IP7) 348 indy_r4k_timer_interrupt(regs); 349 else if (pending & CAUSEF_IP2) 350 indy_local0_irqdispatch(regs); 351 else if (pending & CAUSEF_IP3) 352 indy_local1_irqdispatch(regs); 353 else if (pending & CAUSEF_IP6) 354 indy_buserror_irq(regs); 355 else if (pending & (CAUSEF_IP4 | CAUSEF_IP5)) 356 indy_8254timer_irq(regs); 357 } 358 359 extern void mips_cpu_irq_init(unsigned int irq_base); 360 361 void __init arch_init_irq(void) 362 { 363 int i; 364 365 /* Init local mask --> irq tables. */ 366 for (i = 0; i < 256; i++) { 367 if (i & 0x80) { 368 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 7; 369 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 7; 370 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 7; 371 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 7; 372 } else if (i & 0x40) { 373 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 6; 374 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 6; 375 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 6; 376 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 6; 377 } else if (i & 0x20) { 378 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 5; 379 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 5; 380 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 5; 381 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 5; 382 } else if (i & 0x10) { 383 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 4; 384 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 4; 385 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 4; 386 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 4; 387 } else if (i & 0x08) { 388 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 3; 389 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 3; 390 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 3; 391 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 3; 392 } else if (i & 0x04) { 393 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 2; 394 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 2; 395 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 2; 396 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 2; 397 } else if (i & 0x02) { 398 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 1; 399 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 1; 400 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 1; 401 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 1; 402 } else if (i & 0x01) { 403 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 0; 404 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 0; 405 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 0; 406 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 0; 407 } else { 408 lc0msk_to_irqnr[i] = 0; 409 lc1msk_to_irqnr[i] = 0; 410 lc2msk_to_irqnr[i] = 0; 411 lc3msk_to_irqnr[i] = 0; 412 } 413 } 414 415 /* Mask out all interrupts. */ 416 sgint->imask0 = 0; 417 sgint->imask1 = 0; 418 sgint->cmeimask0 = 0; 419 sgint->cmeimask1 = 0; 420 421 /* init CPU irqs */ 422 mips_cpu_irq_init(SGINT_CPU); 423 424 for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) { 425 hw_irq_controller *handler; 426 427 if (i < SGINT_LOCAL1) 428 handler = &ip22_local0_irq_type; 429 else if (i < SGINT_LOCAL2) 430 handler = &ip22_local1_irq_type; 431 else if (i < SGINT_LOCAL3) 432 handler = &ip22_local2_irq_type; 433 else 434 handler = &ip22_local3_irq_type; 435 436 irq_desc[i].status = IRQ_DISABLED; 437 irq_desc[i].action = 0; 438 irq_desc[i].depth = 1; 439 irq_desc[i].chip = handler; 440 } 441 442 /* vector handler. this register the IRQ as non-sharable */ 443 setup_irq(SGI_LOCAL_0_IRQ, &local0_cascade); 444 setup_irq(SGI_LOCAL_1_IRQ, &local1_cascade); 445 setup_irq(SGI_BUSERR_IRQ, &buserr); 446 447 /* cascade in cascade. i love Indy ;-) */ 448 setup_irq(SGI_MAP_0_IRQ, &map0_cascade); 449 #ifdef USE_LIO3_IRQ 450 setup_irq(SGI_MAP_1_IRQ, &map1_cascade); 451 #endif 452 453 #ifdef CONFIG_EISA 454 if (ip22_is_fullhouse()) /* Only Indigo-2 has EISA stuff */ 455 ip22_eisa_init (); 456 #endif 457 } 458