ip22-int.c revision 97dcb82de6cc99a5669eb8e342efc24cceb1e77e
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 33struct sgint_regs *sgint; 34 35static char lc0msk_to_irqnr[256]; 36static char lc1msk_to_irqnr[256]; 37static char lc2msk_to_irqnr[256]; 38static char lc3msk_to_irqnr[256]; 39 40extern int ip22_eisa_init(void); 41 42static 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 50static void disable_local0_irq(unsigned int irq) 51{ 52 sgint->imask0 &= ~(1 << (irq - SGINT_LOCAL0)); 53} 54 55static struct irq_chip ip22_local0_irq_type = { 56 .typename = "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 63static 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 71void disable_local1_irq(unsigned int irq) 72{ 73 sgint->imask1 &= ~(1 << (irq - SGINT_LOCAL1)); 74} 75 76static struct irq_chip ip22_local1_irq_type = { 77 .typename = "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 84static 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 90void 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 97static struct irq_chip ip22_local2_irq_type = { 98 .typename = "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 105static 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 111void 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 118static struct irq_chip ip22_local3_irq_type = { 119 .typename = "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 126static 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 143static 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 160extern void ip22_be_interrupt(int irq); 161 162static 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 172static struct irqaction local0_cascade = { 173 .handler = no_action, 174 .flags = IRQF_DISABLED, 175 .name = "local0 cascade", 176}; 177 178static struct irqaction local1_cascade = { 179 .handler = no_action, 180 .flags = IRQF_DISABLED, 181 .name = "local1 cascade", 182}; 183 184static struct irqaction buserr = { 185 .handler = no_action, 186 .flags = IRQF_DISABLED, 187 .name = "Bus Error", 188}; 189 190static struct irqaction map0_cascade = { 191 .handler = no_action, 192 .flags = IRQF_DISABLED, 193 .name = "mapable0 cascade", 194}; 195 196#ifdef USE_LIO3_IRQ 197static 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 207extern void indy_r4k_timer_interrupt(void); 208extern 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 238asmlinkage void plat_irq_dispatch(void) 239{ 240 unsigned int pending = 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 257void __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