11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * ip22-int.c: Routines for generic manipulation of the INT[23] ASIC 31da177e4SLinus Torvalds * found on INDY and Indigo2 workstations. 41da177e4SLinus Torvalds * 579add627SJustin P. Mattock * Copyright (C) 1996 David S. Miller (davem@davemloft.net) 61da177e4SLinus Torvalds * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) 71da177e4SLinus Torvalds * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) 81da177e4SLinus Torvalds * - Indigo2 changes 91da177e4SLinus Torvalds * - Interrupt handling fixes 101da177e4SLinus Torvalds * Copyright (C) 2001, 2003 Ladislav Michl (ladis@linux-mips.org) 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds #include <linux/types.h> 131da177e4SLinus Torvalds #include <linux/init.h> 141da177e4SLinus Torvalds #include <linux/kernel_stat.h> 151da177e4SLinus Torvalds #include <linux/interrupt.h> 168f99a162SWu Zhangjin #include <linux/ftrace.h> 171da177e4SLinus Torvalds 1897dcb82dSAtsushi Nemoto #include <asm/irq_cpu.h> 191da177e4SLinus Torvalds #include <asm/sgi/hpc3.h> 201da177e4SLinus Torvalds #include <asm/sgi/ip22.h> 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds /* So far nothing hangs here */ 231da177e4SLinus Torvalds #undef USE_LIO3_IRQ 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds struct sgint_regs *sgint; 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds static char lc0msk_to_irqnr[256]; 281da177e4SLinus Torvalds static char lc1msk_to_irqnr[256]; 291da177e4SLinus Torvalds static char lc2msk_to_irqnr[256]; 301da177e4SLinus Torvalds static char lc3msk_to_irqnr[256]; 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds extern int ip22_eisa_init(void); 331da177e4SLinus Torvalds 349458ea56SThomas Gleixner static void enable_local0_irq(struct irq_data *d) 351da177e4SLinus Torvalds { 361da177e4SLinus Torvalds /* don't allow mappable interrupt to be enabled from setup_irq, 371da177e4SLinus Torvalds * we have our own way to do so */ 389458ea56SThomas Gleixner if (d->irq != SGI_MAP_0_IRQ) 399458ea56SThomas Gleixner sgint->imask0 |= (1 << (d->irq - SGINT_LOCAL0)); 401da177e4SLinus Torvalds } 411da177e4SLinus Torvalds 429458ea56SThomas Gleixner static void disable_local0_irq(struct irq_data *d) 431da177e4SLinus Torvalds { 449458ea56SThomas Gleixner sgint->imask0 &= ~(1 << (d->irq - SGINT_LOCAL0)); 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 4794dee171SRalf Baechle static struct irq_chip ip22_local0_irq_type = { 4870d21cdeSAtsushi Nemoto .name = "IP22 local 0", 499458ea56SThomas Gleixner .irq_mask = disable_local0_irq, 509458ea56SThomas Gleixner .irq_unmask = enable_local0_irq, 511da177e4SLinus Torvalds }; 521da177e4SLinus Torvalds 539458ea56SThomas Gleixner static void enable_local1_irq(struct irq_data *d) 541da177e4SLinus Torvalds { 551da177e4SLinus Torvalds /* don't allow mappable interrupt to be enabled from setup_irq, 561da177e4SLinus Torvalds * we have our own way to do so */ 579458ea56SThomas Gleixner if (d->irq != SGI_MAP_1_IRQ) 589458ea56SThomas Gleixner sgint->imask1 |= (1 << (d->irq - SGINT_LOCAL1)); 591da177e4SLinus Torvalds } 601da177e4SLinus Torvalds 619458ea56SThomas Gleixner static void disable_local1_irq(struct irq_data *d) 621da177e4SLinus Torvalds { 639458ea56SThomas Gleixner sgint->imask1 &= ~(1 << (d->irq - SGINT_LOCAL1)); 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 6694dee171SRalf Baechle static struct irq_chip ip22_local1_irq_type = { 6770d21cdeSAtsushi Nemoto .name = "IP22 local 1", 689458ea56SThomas Gleixner .irq_mask = disable_local1_irq, 699458ea56SThomas Gleixner .irq_unmask = enable_local1_irq, 701da177e4SLinus Torvalds }; 711da177e4SLinus Torvalds 729458ea56SThomas Gleixner static void enable_local2_irq(struct irq_data *d) 731da177e4SLinus Torvalds { 741da177e4SLinus Torvalds sgint->imask0 |= (1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); 759458ea56SThomas Gleixner sgint->cmeimask0 |= (1 << (d->irq - SGINT_LOCAL2)); 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds 789458ea56SThomas Gleixner static void disable_local2_irq(struct irq_data *d) 791da177e4SLinus Torvalds { 809458ea56SThomas Gleixner sgint->cmeimask0 &= ~(1 << (d->irq - SGINT_LOCAL2)); 811da177e4SLinus Torvalds if (!sgint->cmeimask0) 821da177e4SLinus Torvalds sgint->imask0 &= ~(1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0)); 831da177e4SLinus Torvalds } 841da177e4SLinus Torvalds 8594dee171SRalf Baechle static struct irq_chip ip22_local2_irq_type = { 8670d21cdeSAtsushi Nemoto .name = "IP22 local 2", 879458ea56SThomas Gleixner .irq_mask = disable_local2_irq, 889458ea56SThomas Gleixner .irq_unmask = enable_local2_irq, 891da177e4SLinus Torvalds }; 901da177e4SLinus Torvalds 919458ea56SThomas Gleixner static void enable_local3_irq(struct irq_data *d) 921da177e4SLinus Torvalds { 931da177e4SLinus Torvalds sgint->imask1 |= (1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); 949458ea56SThomas Gleixner sgint->cmeimask1 |= (1 << (d->irq - SGINT_LOCAL3)); 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 979458ea56SThomas Gleixner static void disable_local3_irq(struct irq_data *d) 981da177e4SLinus Torvalds { 999458ea56SThomas Gleixner sgint->cmeimask1 &= ~(1 << (d->irq - SGINT_LOCAL3)); 1001da177e4SLinus Torvalds if (!sgint->cmeimask1) 1011da177e4SLinus Torvalds sgint->imask1 &= ~(1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1)); 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 10494dee171SRalf Baechle static struct irq_chip ip22_local3_irq_type = { 10570d21cdeSAtsushi Nemoto .name = "IP22 local 3", 1069458ea56SThomas Gleixner .irq_mask = disable_local3_irq, 1079458ea56SThomas Gleixner .irq_unmask = enable_local3_irq, 1081da177e4SLinus Torvalds }; 1091da177e4SLinus Torvalds 110937a8015SRalf Baechle static void indy_local0_irqdispatch(void) 1111da177e4SLinus Torvalds { 1121da177e4SLinus Torvalds u8 mask = sgint->istat0 & sgint->imask0; 1131da177e4SLinus Torvalds u8 mask2; 1141da177e4SLinus Torvalds int irq; 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds if (mask & SGINT_ISTAT0_LIO2) { 1171da177e4SLinus Torvalds mask2 = sgint->vmeistat & sgint->cmeimask0; 1181da177e4SLinus Torvalds irq = lc2msk_to_irqnr[mask2]; 1191da177e4SLinus Torvalds } else 1201da177e4SLinus Torvalds irq = lc0msk_to_irqnr[mask]; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds /* if irq == 0, then the interrupt has already been cleared */ 1231da177e4SLinus Torvalds if (irq) 124937a8015SRalf Baechle do_IRQ(irq); 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds 127937a8015SRalf Baechle static void indy_local1_irqdispatch(void) 1281da177e4SLinus Torvalds { 1291da177e4SLinus Torvalds u8 mask = sgint->istat1 & sgint->imask1; 1301da177e4SLinus Torvalds u8 mask2; 1311da177e4SLinus Torvalds int irq; 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds if (mask & SGINT_ISTAT1_LIO3) { 1341da177e4SLinus Torvalds mask2 = sgint->vmeistat & sgint->cmeimask1; 1351da177e4SLinus Torvalds irq = lc3msk_to_irqnr[mask2]; 1361da177e4SLinus Torvalds } else 1371da177e4SLinus Torvalds irq = lc1msk_to_irqnr[mask]; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds /* if irq == 0, then the interrupt has already been cleared */ 1401da177e4SLinus Torvalds if (irq) 141937a8015SRalf Baechle do_IRQ(irq); 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 144937a8015SRalf Baechle extern void ip22_be_interrupt(int irq); 1451da177e4SLinus Torvalds 1468f99a162SWu Zhangjin static void __irq_entry indy_buserror_irq(void) 1471da177e4SLinus Torvalds { 1481da177e4SLinus Torvalds int irq = SGI_BUSERR_IRQ; 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds irq_enter(); 151*310ff2c8SThomas Gleixner kstat_incr_irq_this_cpu(irq); 152937a8015SRalf Baechle ip22_be_interrupt(irq); 1531da177e4SLinus Torvalds irq_exit(); 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds static struct irqaction local0_cascade = { 1571da177e4SLinus Torvalds .handler = no_action, 1588b5690f8SYong Zhang .flags = IRQF_NO_THREAD, 1591da177e4SLinus Torvalds .name = "local0 cascade", 1601da177e4SLinus Torvalds }; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds static struct irqaction local1_cascade = { 1631da177e4SLinus Torvalds .handler = no_action, 1648b5690f8SYong Zhang .flags = IRQF_NO_THREAD, 1651da177e4SLinus Torvalds .name = "local1 cascade", 1661da177e4SLinus Torvalds }; 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds static struct irqaction buserr = { 1691da177e4SLinus Torvalds .handler = no_action, 1708b5690f8SYong Zhang .flags = IRQF_NO_THREAD, 1711da177e4SLinus Torvalds .name = "Bus Error", 1721da177e4SLinus Torvalds }; 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds static struct irqaction map0_cascade = { 1751da177e4SLinus Torvalds .handler = no_action, 1768b5690f8SYong Zhang .flags = IRQF_NO_THREAD, 1771da177e4SLinus Torvalds .name = "mapable0 cascade", 1781da177e4SLinus Torvalds }; 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds #ifdef USE_LIO3_IRQ 1811da177e4SLinus Torvalds static struct irqaction map1_cascade = { 1821da177e4SLinus Torvalds .handler = no_action, 1838b5690f8SYong Zhang .flags = IRQF_NO_THREAD, 1841da177e4SLinus Torvalds .name = "mapable1 cascade", 1851da177e4SLinus Torvalds }; 1861da177e4SLinus Torvalds #define SGI_INTERRUPTS SGINT_END 1871da177e4SLinus Torvalds #else 1881da177e4SLinus Torvalds #define SGI_INTERRUPTS SGINT_LOCAL3 1891da177e4SLinus Torvalds #endif 1901da177e4SLinus Torvalds 191937a8015SRalf Baechle extern void indy_8254timer_irq(void); 192e4ac58afSRalf Baechle 193e4ac58afSRalf Baechle /* 194e4ac58afSRalf Baechle * IRQs on the INDY look basically (barring software IRQs which we don't use 195e4ac58afSRalf Baechle * at all) like: 196e4ac58afSRalf Baechle * 197e4ac58afSRalf Baechle * MIPS IRQ Source 198e4ac58afSRalf Baechle * -------- ------ 199e4ac58afSRalf Baechle * 0 Software (ignored) 200e4ac58afSRalf Baechle * 1 Software (ignored) 201e4ac58afSRalf Baechle * 2 Local IRQ level zero 202e4ac58afSRalf Baechle * 3 Local IRQ level one 203e4ac58afSRalf Baechle * 4 8254 Timer zero 204e4ac58afSRalf Baechle * 5 8254 Timer one 205e4ac58afSRalf Baechle * 6 Bus Error 206e4ac58afSRalf Baechle * 7 R4k timer (what we use) 207e4ac58afSRalf Baechle * 208e4ac58afSRalf Baechle * We handle the IRQ according to _our_ priority which is: 209e4ac58afSRalf Baechle * 210e4ac58afSRalf Baechle * Highest ---- R4k Timer 211e4ac58afSRalf Baechle * Local IRQ zero 212e4ac58afSRalf Baechle * Local IRQ one 213e4ac58afSRalf Baechle * Bus Error 214e4ac58afSRalf Baechle * 8254 Timer zero 215e4ac58afSRalf Baechle * Lowest ---- 8254 Timer one 216e4ac58afSRalf Baechle * 217e4ac58afSRalf Baechle * then we just return, if multiple IRQs are pending then we will just take 218e4ac58afSRalf Baechle * another exception, big deal. 219e4ac58afSRalf Baechle */ 220e4ac58afSRalf Baechle 221937a8015SRalf Baechle asmlinkage void plat_irq_dispatch(void) 222e4ac58afSRalf Baechle { 223119537c0SThiemo Seufer unsigned int pending = read_c0_status() & read_c0_cause(); 224e4ac58afSRalf Baechle 225e4ac58afSRalf Baechle /* 226e4ac58afSRalf Baechle * First we check for r4k counter/timer IRQ. 227e4ac58afSRalf Baechle */ 228e4ac58afSRalf Baechle if (pending & CAUSEF_IP7) 2297bcf7717SRalf Baechle do_IRQ(SGI_TIMER_IRQ); 230e4ac58afSRalf Baechle else if (pending & CAUSEF_IP2) 231937a8015SRalf Baechle indy_local0_irqdispatch(); 232e4ac58afSRalf Baechle else if (pending & CAUSEF_IP3) 233937a8015SRalf Baechle indy_local1_irqdispatch(); 234e4ac58afSRalf Baechle else if (pending & CAUSEF_IP6) 235937a8015SRalf Baechle indy_buserror_irq(); 236e4ac58afSRalf Baechle else if (pending & (CAUSEF_IP4 | CAUSEF_IP5)) 237937a8015SRalf Baechle indy_8254timer_irq(); 238e4ac58afSRalf Baechle } 239e4ac58afSRalf Baechle 2401da177e4SLinus Torvalds void __init arch_init_irq(void) 2411da177e4SLinus Torvalds { 2421da177e4SLinus Torvalds int i; 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds /* Init local mask --> irq tables. */ 2451da177e4SLinus Torvalds for (i = 0; i < 256; i++) { 2461da177e4SLinus Torvalds if (i & 0x80) { 2471da177e4SLinus Torvalds lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 7; 2481da177e4SLinus Torvalds lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 7; 2491da177e4SLinus Torvalds lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 7; 2501da177e4SLinus Torvalds lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 7; 2511da177e4SLinus Torvalds } else if (i & 0x40) { 2521da177e4SLinus Torvalds lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 6; 2531da177e4SLinus Torvalds lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 6; 2541da177e4SLinus Torvalds lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 6; 2551da177e4SLinus Torvalds lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 6; 2561da177e4SLinus Torvalds } else if (i & 0x20) { 2571da177e4SLinus Torvalds lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 5; 2581da177e4SLinus Torvalds lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 5; 2591da177e4SLinus Torvalds lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 5; 2601da177e4SLinus Torvalds lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 5; 2611da177e4SLinus Torvalds } else if (i & 0x10) { 2621da177e4SLinus Torvalds lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 4; 2631da177e4SLinus Torvalds lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 4; 2641da177e4SLinus Torvalds lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 4; 2651da177e4SLinus Torvalds lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 4; 2661da177e4SLinus Torvalds } else if (i & 0x08) { 2671da177e4SLinus Torvalds lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 3; 2681da177e4SLinus Torvalds lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 3; 2691da177e4SLinus Torvalds lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 3; 2701da177e4SLinus Torvalds lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 3; 2711da177e4SLinus Torvalds } else if (i & 0x04) { 2721da177e4SLinus Torvalds lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 2; 2731da177e4SLinus Torvalds lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 2; 2741da177e4SLinus Torvalds lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 2; 2751da177e4SLinus Torvalds lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 2; 2761da177e4SLinus Torvalds } else if (i & 0x02) { 2771da177e4SLinus Torvalds lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 1; 2781da177e4SLinus Torvalds lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 1; 2791da177e4SLinus Torvalds lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 1; 2801da177e4SLinus Torvalds lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 1; 2811da177e4SLinus Torvalds } else if (i & 0x01) { 2821da177e4SLinus Torvalds lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 0; 2831da177e4SLinus Torvalds lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 0; 2841da177e4SLinus Torvalds lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 0; 2851da177e4SLinus Torvalds lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 0; 2861da177e4SLinus Torvalds } else { 2871da177e4SLinus Torvalds lc0msk_to_irqnr[i] = 0; 2881da177e4SLinus Torvalds lc1msk_to_irqnr[i] = 0; 2891da177e4SLinus Torvalds lc2msk_to_irqnr[i] = 0; 2901da177e4SLinus Torvalds lc3msk_to_irqnr[i] = 0; 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds /* Mask out all interrupts. */ 2951da177e4SLinus Torvalds sgint->imask0 = 0; 2961da177e4SLinus Torvalds sgint->imask1 = 0; 2971da177e4SLinus Torvalds sgint->cmeimask0 = 0; 2981da177e4SLinus Torvalds sgint->cmeimask1 = 0; 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds /* init CPU irqs */ 30197dcb82dSAtsushi Nemoto mips_cpu_irq_init(); 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) { 30494dee171SRalf Baechle struct irq_chip *handler; 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds if (i < SGINT_LOCAL1) 3071da177e4SLinus Torvalds handler = &ip22_local0_irq_type; 3081da177e4SLinus Torvalds else if (i < SGINT_LOCAL2) 3091da177e4SLinus Torvalds handler = &ip22_local1_irq_type; 3101da177e4SLinus Torvalds else if (i < SGINT_LOCAL3) 3111da177e4SLinus Torvalds handler = &ip22_local2_irq_type; 3121da177e4SLinus Torvalds else 3131da177e4SLinus Torvalds handler = &ip22_local3_irq_type; 3141da177e4SLinus Torvalds 315e4ec7989SThomas Gleixner irq_set_chip_and_handler(i, handler, handle_level_irq); 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds /* vector handler. this register the IRQ as non-sharable */ 3191da177e4SLinus Torvalds setup_irq(SGI_LOCAL_0_IRQ, &local0_cascade); 3201da177e4SLinus Torvalds setup_irq(SGI_LOCAL_1_IRQ, &local1_cascade); 3211da177e4SLinus Torvalds setup_irq(SGI_BUSERR_IRQ, &buserr); 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds /* cascade in cascade. i love Indy ;-) */ 3241da177e4SLinus Torvalds setup_irq(SGI_MAP_0_IRQ, &map0_cascade); 3251da177e4SLinus Torvalds #ifdef USE_LIO3_IRQ 3261da177e4SLinus Torvalds setup_irq(SGI_MAP_1_IRQ, &map1_cascade); 3271da177e4SLinus Torvalds #endif 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds #ifdef CONFIG_EISA 3301da177e4SLinus Torvalds if (ip22_is_fullhouse()) /* Only Indigo-2 has EISA stuff */ 3311da177e4SLinus Torvalds ip22_eisa_init(); 3321da177e4SLinus Torvalds #endif 3331da177e4SLinus Torvalds } 334