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/types.h> 13 #include <linux/init.h> 14 #include <linux/kernel_stat.h> 15 #include <linux/signal.h> 16 #include <linux/sched.h> 17 #include <linux/interrupt.h> 18 #include <linux/irq.h> 19 20 #include <asm/mipsregs.h> 21 #include <asm/addrspace.h> 22 #include <asm/irq_cpu.h> 23 #include <asm/sgi/ioc.h> 24 #include <asm/sgi/hpc3.h> 25 #include <asm/sgi/ip22.h> 26 #include <asm/time.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 /* don't allow mappable interrupt to be enabled from setup_irq, 45 * we have our own way to do so */ 46 if (irq != SGI_MAP_0_IRQ) 47 sgint->imask0 |= (1 << (irq - SGINT_LOCAL0)); 48 } 49 50 static void disable_local0_irq(unsigned int irq) 51 { 52 sgint->imask0 &= ~(1 << (irq - SGINT_LOCAL0)); 53 } 54 55 static struct irq_chip ip22_local0_irq_type = { 56 .name = "IP22 local 0", 57 .ack = disable_local0_irq, 58 .mask = disable_local0_irq, 59 .mask_ack = disable_local0_irq, 60 .unmask = enable_local0_irq, 61 }; 62 63 static void enable_local1_irq(unsigned int irq) 64 { 65 /* don't allow mappable interrupt to be enabled from setup_irq, 66 * we have our own way to do so */ 67 if (irq != SGI_MAP_1_IRQ) 68 sgint->imask1 |= (1 << (irq - SGINT_LOCAL1)); 69 } 70 71 void disable_local1_irq(unsigned int irq) 72 { 73 sgint->imask1 &= ~(1 << (irq - SGINT_LOCAL1)); 74 } 75 76 static struct irq_chip ip22_local1_irq_type = { 77 .name = "IP22 local 1", 78 .ack = disable_local1_irq, 79 .mask = disable_local1_irq, 80 .mask_ack = disable_local1_irq, 81 .unmask = enable_local1_irq, 82 }; 83 84 static void enable_local2_irq(unsigned int irq) 85 { 86 sgint->imask0 |= (1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); 87 sgint->cmeimask0 |= (1 << (irq - SGINT_LOCAL2)); 88 } 89 90 void disable_local2_irq(unsigned int irq) 91 { 92 sgint->cmeimask0 &= ~(1 << (irq - SGINT_LOCAL2)); 93 if (!sgint->cmeimask0) 94 sgint->imask0 &= ~(1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); 95 } 96 97 static struct irq_chip ip22_local2_irq_type = { 98 .name = "IP22 local 2", 99 .ack = disable_local2_irq, 100 .mask = disable_local2_irq, 101 .mask_ack = disable_local2_irq, 102 .unmask = enable_local2_irq, 103 }; 104 105 static void enable_local3_irq(unsigned int irq) 106 { 107 sgint->imask1 |= (1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); 108 sgint->cmeimask1 |= (1 << (irq - SGINT_LOCAL3)); 109 } 110 111 void disable_local3_irq(unsigned int irq) 112 { 113 sgint->cmeimask1 &= ~(1 << (irq - SGINT_LOCAL3)); 114 if (!sgint->cmeimask1) 115 sgint->imask1 &= ~(1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); 116 } 117 118 static struct irq_chip ip22_local3_irq_type = { 119 .name = "IP22 local 3", 120 .ack = disable_local3_irq, 121 .mask = disable_local3_irq, 122 .mask_ack = disable_local3_irq, 123 .unmask = enable_local3_irq, 124 }; 125 126 static void indy_local0_irqdispatch(void) 127 { 128 u8 mask = sgint->istat0 & sgint->imask0; 129 u8 mask2; 130 int irq; 131 132 if (mask & SGINT_ISTAT0_LIO2) { 133 mask2 = sgint->vmeistat & sgint->cmeimask0; 134 irq = lc2msk_to_irqnr[mask2]; 135 } else 136 irq = lc0msk_to_irqnr[mask]; 137 138 /* if irq == 0, then the interrupt has already been cleared */ 139 if (irq) 140 do_IRQ(irq); 141 } 142 143 static void indy_local1_irqdispatch(void) 144 { 145 u8 mask = sgint->istat1 & sgint->imask1; 146 u8 mask2; 147 int irq; 148 149 if (mask & SGINT_ISTAT1_LIO3) { 150 mask2 = sgint->vmeistat & sgint->cmeimask1; 151 irq = lc3msk_to_irqnr[mask2]; 152 } else 153 irq = lc1msk_to_irqnr[mask]; 154 155 /* if irq == 0, then the interrupt has already been cleared */ 156 if (irq) 157 do_IRQ(irq); 158 } 159 160 extern void ip22_be_interrupt(int irq); 161 162 static void indy_buserror_irq(void) 163 { 164 int irq = SGI_BUSERR_IRQ; 165 166 irq_enter(); 167 kstat_this_cpu.irqs[irq]++; 168 ip22_be_interrupt(irq); 169 irq_exit(); 170 } 171 172 static struct irqaction local0_cascade = { 173 .handler = no_action, 174 .flags = IRQF_DISABLED, 175 .name = "local0 cascade", 176 }; 177 178 static struct irqaction local1_cascade = { 179 .handler = no_action, 180 .flags = IRQF_DISABLED, 181 .name = "local1 cascade", 182 }; 183 184 static struct irqaction buserr = { 185 .handler = no_action, 186 .flags = IRQF_DISABLED, 187 .name = "Bus Error", 188 }; 189 190 static struct irqaction map0_cascade = { 191 .handler = no_action, 192 .flags = IRQF_DISABLED, 193 .name = "mapable0 cascade", 194 }; 195 196 #ifdef USE_LIO3_IRQ 197 static struct irqaction map1_cascade = { 198 .handler = no_action, 199 .flags = IRQF_DISABLED, 200 .name = "mapable1 cascade", 201 }; 202 #define SGI_INTERRUPTS SGINT_END 203 #else 204 #define SGI_INTERRUPTS SGINT_LOCAL3 205 #endif 206 207 extern void indy_8254timer_irq(void); 208 209 /* 210 * IRQs on the INDY look basically (barring software IRQs which we don't use 211 * at all) like: 212 * 213 * MIPS IRQ Source 214 * -------- ------ 215 * 0 Software (ignored) 216 * 1 Software (ignored) 217 * 2 Local IRQ level zero 218 * 3 Local IRQ level one 219 * 4 8254 Timer zero 220 * 5 8254 Timer one 221 * 6 Bus Error 222 * 7 R4k timer (what we use) 223 * 224 * We handle the IRQ according to _our_ priority which is: 225 * 226 * Highest ---- R4k Timer 227 * Local IRQ zero 228 * Local IRQ one 229 * Bus Error 230 * 8254 Timer zero 231 * Lowest ---- 8254 Timer one 232 * 233 * then we just return, if multiple IRQs are pending then we will just take 234 * another exception, big deal. 235 */ 236 237 asmlinkage void plat_irq_dispatch(void) 238 { 239 unsigned int pending = read_c0_status() & read_c0_cause(); 240 241 /* 242 * First we check for r4k counter/timer IRQ. 243 */ 244 if (pending & CAUSEF_IP7) 245 do_IRQ(SGI_TIMER_IRQ); 246 else if (pending & CAUSEF_IP2) 247 indy_local0_irqdispatch(); 248 else if (pending & CAUSEF_IP3) 249 indy_local1_irqdispatch(); 250 else if (pending & CAUSEF_IP6) 251 indy_buserror_irq(); 252 else if (pending & (CAUSEF_IP4 | CAUSEF_IP5)) 253 indy_8254timer_irq(); 254 } 255 256 void __init arch_init_irq(void) 257 { 258 int i; 259 260 /* Init local mask --> irq tables. */ 261 for (i = 0; i < 256; i++) { 262 if (i & 0x80) { 263 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 7; 264 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 7; 265 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 7; 266 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 7; 267 } else if (i & 0x40) { 268 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 6; 269 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 6; 270 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 6; 271 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 6; 272 } else if (i & 0x20) { 273 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 5; 274 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 5; 275 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 5; 276 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 5; 277 } else if (i & 0x10) { 278 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 4; 279 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 4; 280 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 4; 281 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 4; 282 } else if (i & 0x08) { 283 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 3; 284 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 3; 285 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 3; 286 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 3; 287 } else if (i & 0x04) { 288 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 2; 289 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 2; 290 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 2; 291 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 2; 292 } else if (i & 0x02) { 293 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 1; 294 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 1; 295 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 1; 296 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 1; 297 } else if (i & 0x01) { 298 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 0; 299 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 0; 300 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 0; 301 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 0; 302 } else { 303 lc0msk_to_irqnr[i] = 0; 304 lc1msk_to_irqnr[i] = 0; 305 lc2msk_to_irqnr[i] = 0; 306 lc3msk_to_irqnr[i] = 0; 307 } 308 } 309 310 /* Mask out all interrupts. */ 311 sgint->imask0 = 0; 312 sgint->imask1 = 0; 313 sgint->cmeimask0 = 0; 314 sgint->cmeimask1 = 0; 315 316 /* init CPU irqs */ 317 mips_cpu_irq_init(); 318 319 for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) { 320 struct irq_chip *handler; 321 322 if (i < SGINT_LOCAL1) 323 handler = &ip22_local0_irq_type; 324 else if (i < SGINT_LOCAL2) 325 handler = &ip22_local1_irq_type; 326 else if (i < SGINT_LOCAL3) 327 handler = &ip22_local2_irq_type; 328 else 329 handler = &ip22_local3_irq_type; 330 331 set_irq_chip_and_handler(i, handler, handle_level_irq); 332 } 333 334 /* vector handler. this register the IRQ as non-sharable */ 335 setup_irq(SGI_LOCAL_0_IRQ, &local0_cascade); 336 setup_irq(SGI_LOCAL_1_IRQ, &local1_cascade); 337 setup_irq(SGI_BUSERR_IRQ, &buserr); 338 339 /* cascade in cascade. i love Indy ;-) */ 340 setup_irq(SGI_MAP_0_IRQ, &map0_cascade); 341 #ifdef USE_LIO3_IRQ 342 setup_irq(SGI_MAP_1_IRQ, &map1_cascade); 343 #endif 344 345 #ifdef CONFIG_EISA 346 if (ip22_is_fullhouse()) /* Only Indigo-2 has EISA stuff */ 347 ip22_eisa_init(); 348 #endif 349 } 350