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