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 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 /* 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_r4k_timer_interrupt(void); 208 extern void indy_8254timer_irq(void); 209 210 /* 211 * IRQs on the INDY look basically (barring software IRQs which we don't use 212 * at all) like: 213 * 214 * MIPS IRQ Source 215 * -------- ------ 216 * 0 Software (ignored) 217 * 1 Software (ignored) 218 * 2 Local IRQ level zero 219 * 3 Local IRQ level one 220 * 4 8254 Timer zero 221 * 5 8254 Timer one 222 * 6 Bus Error 223 * 7 R4k timer (what we use) 224 * 225 * We handle the IRQ according to _our_ priority which is: 226 * 227 * Highest ---- R4k Timer 228 * Local IRQ zero 229 * Local IRQ one 230 * Bus Error 231 * 8254 Timer zero 232 * Lowest ---- 8254 Timer one 233 * 234 * then we just return, if multiple IRQs are pending then we will just take 235 * another exception, big deal. 236 */ 237 238 asmlinkage void plat_irq_dispatch(void) 239 { 240 unsigned int pending = read_c0_status() & read_c0_cause(); 241 242 /* 243 * First we check for r4k counter/timer IRQ. 244 */ 245 if (pending & CAUSEF_IP7) 246 indy_r4k_timer_interrupt(); 247 else if (pending & CAUSEF_IP2) 248 indy_local0_irqdispatch(); 249 else if (pending & CAUSEF_IP3) 250 indy_local1_irqdispatch(); 251 else if (pending & CAUSEF_IP6) 252 indy_buserror_irq(); 253 else if (pending & (CAUSEF_IP4 | CAUSEF_IP5)) 254 indy_8254timer_irq(); 255 } 256 257 void __init arch_init_irq(void) 258 { 259 int i; 260 261 /* Init local mask --> irq tables. */ 262 for (i = 0; i < 256; i++) { 263 if (i & 0x80) { 264 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 7; 265 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 7; 266 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 7; 267 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 7; 268 } else if (i & 0x40) { 269 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 6; 270 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 6; 271 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 6; 272 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 6; 273 } else if (i & 0x20) { 274 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 5; 275 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 5; 276 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 5; 277 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 5; 278 } else if (i & 0x10) { 279 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 4; 280 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 4; 281 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 4; 282 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 4; 283 } else if (i & 0x08) { 284 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 3; 285 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 3; 286 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 3; 287 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 3; 288 } else if (i & 0x04) { 289 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 2; 290 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 2; 291 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 2; 292 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 2; 293 } else if (i & 0x02) { 294 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 1; 295 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 1; 296 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 1; 297 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 1; 298 } else if (i & 0x01) { 299 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 0; 300 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 0; 301 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 0; 302 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 0; 303 } else { 304 lc0msk_to_irqnr[i] = 0; 305 lc1msk_to_irqnr[i] = 0; 306 lc2msk_to_irqnr[i] = 0; 307 lc3msk_to_irqnr[i] = 0; 308 } 309 } 310 311 /* Mask out all interrupts. */ 312 sgint->imask0 = 0; 313 sgint->imask1 = 0; 314 sgint->cmeimask0 = 0; 315 sgint->cmeimask1 = 0; 316 317 /* init CPU irqs */ 318 mips_cpu_irq_init(); 319 320 for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) { 321 struct irq_chip *handler; 322 323 if (i < SGINT_LOCAL1) 324 handler = &ip22_local0_irq_type; 325 else if (i < SGINT_LOCAL2) 326 handler = &ip22_local1_irq_type; 327 else if (i < SGINT_LOCAL3) 328 handler = &ip22_local2_irq_type; 329 else 330 handler = &ip22_local3_irq_type; 331 332 set_irq_chip_and_handler(i, handler, handle_level_irq); 333 } 334 335 /* vector handler. this register the IRQ as non-sharable */ 336 setup_irq(SGI_LOCAL_0_IRQ, &local0_cascade); 337 setup_irq(SGI_LOCAL_1_IRQ, &local1_cascade); 338 setup_irq(SGI_BUSERR_IRQ, &buserr); 339 340 /* cascade in cascade. i love Indy ;-) */ 341 setup_irq(SGI_MAP_0_IRQ, &map0_cascade); 342 #ifdef USE_LIO3_IRQ 343 setup_irq(SGI_MAP_1_IRQ, &map1_cascade); 344 #endif 345 346 #ifdef CONFIG_EISA 347 if (ip22_is_fullhouse()) /* Only Indigo-2 has EISA stuff */ 348 ip22_eisa_init (); 349 #endif 350 } 351