11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Code to handle IP32 IRQs 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 51da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 61da177e4SLinus Torvalds * for more details. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Copyright (C) 2000 Harald Koerfgen 91da177e4SLinus Torvalds * Copyright (C) 2001 Keith M Wesolowski 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds #include <linux/init.h> 121da177e4SLinus Torvalds #include <linux/kernel_stat.h> 131da177e4SLinus Torvalds #include <linux/types.h> 141da177e4SLinus Torvalds #include <linux/interrupt.h> 151da177e4SLinus Torvalds #include <linux/irq.h> 161da177e4SLinus Torvalds #include <linux/bitops.h> 171da177e4SLinus Torvalds #include <linux/kernel.h> 181da177e4SLinus Torvalds #include <linux/slab.h> 191da177e4SLinus Torvalds #include <linux/mm.h> 201da177e4SLinus Torvalds #include <linux/random.h> 211da177e4SLinus Torvalds #include <linux/sched.h> 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include <asm/mipsregs.h> 241da177e4SLinus Torvalds #include <asm/signal.h> 251da177e4SLinus Torvalds #include <asm/system.h> 261da177e4SLinus Torvalds #include <asm/time.h> 271da177e4SLinus Torvalds #include <asm/ip32/crime.h> 281da177e4SLinus Torvalds #include <asm/ip32/mace.h> 291da177e4SLinus Torvalds #include <asm/ip32/ip32_ints.h> 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds /* issue a PIO read to make sure no PIO writes are pending */ 321da177e4SLinus Torvalds static void inline flush_crime_bus(void) 331da177e4SLinus Torvalds { 34b6d7c7a9SRalf Baechle crime->control; 351da177e4SLinus Torvalds } 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds static void inline flush_mace_bus(void) 381da177e4SLinus Torvalds { 39b6d7c7a9SRalf Baechle mace->perif.ctrl.misc; 401da177e4SLinus Torvalds } 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds #undef DEBUG_IRQ 431da177e4SLinus Torvalds #ifdef DEBUG_IRQ 441da177e4SLinus Torvalds #define DBG(x...) printk(x) 451da177e4SLinus Torvalds #else 461da177e4SLinus Torvalds #define DBG(x...) 471da177e4SLinus Torvalds #endif 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds /* O2 irq map 501da177e4SLinus Torvalds * 511da177e4SLinus Torvalds * IP0 -> software (ignored) 521da177e4SLinus Torvalds * IP1 -> software (ignored) 531da177e4SLinus Torvalds * IP2 -> (irq0) C crime 1.1 all interrupts; crime 1.5 ??? 541da177e4SLinus Torvalds * IP3 -> (irq1) X unknown 551da177e4SLinus Torvalds * IP4 -> (irq2) X unknown 561da177e4SLinus Torvalds * IP5 -> (irq3) X unknown 571da177e4SLinus Torvalds * IP6 -> (irq4) X unknown 581da177e4SLinus Torvalds * IP7 -> (irq5) 0 CPU count/compare timer (system timer) 591da177e4SLinus Torvalds * 601da177e4SLinus Torvalds * crime: (C) 611da177e4SLinus Torvalds * 621da177e4SLinus Torvalds * CRIME_INT_STAT 31:0: 631da177e4SLinus Torvalds * 641da177e4SLinus Torvalds * 0 -> 1 Video in 1 651da177e4SLinus Torvalds * 1 -> 2 Video in 2 661da177e4SLinus Torvalds * 2 -> 3 Video out 671da177e4SLinus Torvalds * 3 -> 4 Mace ethernet 681da177e4SLinus Torvalds * 4 -> S SuperIO sub-interrupt 691da177e4SLinus Torvalds * 5 -> M Miscellaneous sub-interrupt 701da177e4SLinus Torvalds * 6 -> A Audio sub-interrupt 711da177e4SLinus Torvalds * 7 -> 8 PCI bridge errors 721da177e4SLinus Torvalds * 8 -> 9 PCI SCSI aic7xxx 0 731da177e4SLinus Torvalds * 9 -> 10 PCI SCSI aic7xxx 1 741da177e4SLinus Torvalds * 10 -> 11 PCI slot 0 751da177e4SLinus Torvalds * 11 -> 12 unused (PCI slot 1) 761da177e4SLinus Torvalds * 12 -> 13 unused (PCI slot 2) 771da177e4SLinus Torvalds * 13 -> 14 unused (PCI shared 0) 781da177e4SLinus Torvalds * 14 -> 15 unused (PCI shared 1) 791da177e4SLinus Torvalds * 15 -> 16 unused (PCI shared 2) 801da177e4SLinus Torvalds * 16 -> 17 GBE0 (E) 811da177e4SLinus Torvalds * 17 -> 18 GBE1 (E) 821da177e4SLinus Torvalds * 18 -> 19 GBE2 (E) 831da177e4SLinus Torvalds * 19 -> 20 GBE3 (E) 841da177e4SLinus Torvalds * 20 -> 21 CPU errors 851da177e4SLinus Torvalds * 21 -> 22 Memory errors 861da177e4SLinus Torvalds * 22 -> 23 RE empty edge (E) 871da177e4SLinus Torvalds * 23 -> 24 RE full edge (E) 881da177e4SLinus Torvalds * 24 -> 25 RE idle edge (E) 891da177e4SLinus Torvalds * 25 -> 26 RE empty level 901da177e4SLinus Torvalds * 26 -> 27 RE full level 911da177e4SLinus Torvalds * 27 -> 28 RE idle level 921da177e4SLinus Torvalds * 28 -> 29 unused (software 0) (E) 931da177e4SLinus Torvalds * 29 -> 30 unused (software 1) (E) 941da177e4SLinus Torvalds * 30 -> 31 unused (software 2) - crime 1.5 CPU SysCorError (E) 951da177e4SLinus Torvalds * 31 -> 32 VICE 961da177e4SLinus Torvalds * 971da177e4SLinus Torvalds * S, M, A: Use the MACE ISA interrupt register 981da177e4SLinus Torvalds * MACE_ISA_INT_STAT 31:0 991da177e4SLinus Torvalds * 1001da177e4SLinus Torvalds * 0-7 -> 33-40 Audio 1011da177e4SLinus Torvalds * 8 -> 41 RTC 1021da177e4SLinus Torvalds * 9 -> 42 Keyboard 1031da177e4SLinus Torvalds * 10 -> X Keyboard polled 1041da177e4SLinus Torvalds * 11 -> 44 Mouse 1051da177e4SLinus Torvalds * 12 -> X Mouse polled 1061da177e4SLinus Torvalds * 13-15 -> 46-48 Count/compare timers 1071da177e4SLinus Torvalds * 16-19 -> 49-52 Parallel (16 E) 1081da177e4SLinus Torvalds * 20-25 -> 53-58 Serial 1 (22 E) 1091da177e4SLinus Torvalds * 26-31 -> 59-64 Serial 2 (28 E) 1101da177e4SLinus Torvalds * 1111da177e4SLinus Torvalds * Note that this means IRQs 5-7, 43, and 45 do not exist. This is a 1121da177e4SLinus Torvalds * different IRQ map than IRIX uses, but that's OK as Linux irq handling 1131da177e4SLinus Torvalds * is quite different anyway. 1141da177e4SLinus Torvalds */ 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds /* Some initial interrupts to set up */ 117937a8015SRalf Baechle extern irqreturn_t crime_memerr_intr(int irq, void *dev_id); 118937a8015SRalf Baechle extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id); 1191da177e4SLinus Torvalds 120f40298fdSThomas Gleixner struct irqaction memerr_irq = { crime_memerr_intr, IRQF_DISABLED, 1211da177e4SLinus Torvalds CPU_MASK_NONE, "CRIME memory error", NULL, NULL }; 122f40298fdSThomas Gleixner struct irqaction cpuerr_irq = { crime_cpuerr_intr, IRQF_DISABLED, 1231da177e4SLinus Torvalds CPU_MASK_NONE, "CRIME CPU error", NULL, NULL }; 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds /* 1261da177e4SLinus Torvalds * For interrupts wired from a single device to the CPU. Only the clock 1271da177e4SLinus Torvalds * uses this it seems, which is IRQ 0 and IP7. 1281da177e4SLinus Torvalds */ 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds static void enable_cpu_irq(unsigned int irq) 1311da177e4SLinus Torvalds { 1321da177e4SLinus Torvalds set_c0_status(STATUSF_IP7); 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds static void disable_cpu_irq(unsigned int irq) 1361da177e4SLinus Torvalds { 1371da177e4SLinus Torvalds clear_c0_status(STATUSF_IP7); 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds static void end_cpu_irq(unsigned int irq) 1411da177e4SLinus Torvalds { 1421da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 1431da177e4SLinus Torvalds enable_cpu_irq (irq); 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds 14694dee171SRalf Baechle static struct irq_chip ip32_cpu_interrupt = { 14770d21cdeSAtsushi Nemoto .name = "IP32 CPU", 1481603b5acSAtsushi Nemoto .ack = disable_cpu_irq, 1491603b5acSAtsushi Nemoto .mask = disable_cpu_irq, 1501603b5acSAtsushi Nemoto .mask_ack = disable_cpu_irq, 1511603b5acSAtsushi Nemoto .unmask = enable_cpu_irq, 1528ab00b9aSRalf Baechle .end = end_cpu_irq, 1531da177e4SLinus Torvalds }; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds /* 1561da177e4SLinus Torvalds * This is for pure CRIME interrupts - ie not MACE. The advantage? 1571da177e4SLinus Torvalds * We get to split the register in half and do faster lookups. 1581da177e4SLinus Torvalds */ 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds static uint64_t crime_mask; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds static void enable_crime_irq(unsigned int irq) 1631da177e4SLinus Torvalds { 1641da177e4SLinus Torvalds crime_mask |= 1 << (irq - 1); 1651da177e4SLinus Torvalds crime->imask = crime_mask; 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds static void disable_crime_irq(unsigned int irq) 1691da177e4SLinus Torvalds { 1701da177e4SLinus Torvalds crime_mask &= ~(1 << (irq - 1)); 1711da177e4SLinus Torvalds crime->imask = crime_mask; 1721da177e4SLinus Torvalds flush_crime_bus(); 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds static void mask_and_ack_crime_irq(unsigned int irq) 1761da177e4SLinus Torvalds { 1771da177e4SLinus Torvalds /* Edge triggered interrupts must be cleared. */ 1781da177e4SLinus Torvalds if ((irq >= CRIME_GBE0_IRQ && irq <= CRIME_GBE3_IRQ) 1791da177e4SLinus Torvalds || (irq >= CRIME_RE_EMPTY_E_IRQ && irq <= CRIME_RE_IDLE_E_IRQ) 1801da177e4SLinus Torvalds || (irq >= CRIME_SOFT0_IRQ && irq <= CRIME_SOFT2_IRQ)) { 1811da177e4SLinus Torvalds uint64_t crime_int; 1821da177e4SLinus Torvalds crime_int = crime->hard_int; 1831da177e4SLinus Torvalds crime_int &= ~(1 << (irq - 1)); 1841da177e4SLinus Torvalds crime->hard_int = crime_int; 1851da177e4SLinus Torvalds } 1861da177e4SLinus Torvalds disable_crime_irq(irq); 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds static void end_crime_irq(unsigned int irq) 1901da177e4SLinus Torvalds { 1911da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 1921da177e4SLinus Torvalds enable_crime_irq(irq); 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 19594dee171SRalf Baechle static struct irq_chip ip32_crime_interrupt = { 19670d21cdeSAtsushi Nemoto .name = "IP32 CRIME", 1978ab00b9aSRalf Baechle .ack = mask_and_ack_crime_irq, 1981603b5acSAtsushi Nemoto .mask = disable_crime_irq, 1991603b5acSAtsushi Nemoto .mask_ack = mask_and_ack_crime_irq, 2001603b5acSAtsushi Nemoto .unmask = enable_crime_irq, 2018ab00b9aSRalf Baechle .end = end_crime_irq, 2021da177e4SLinus Torvalds }; 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds /* 2051da177e4SLinus Torvalds * This is for MACE PCI interrupts. We can decrease bus traffic by masking 2061da177e4SLinus Torvalds * as close to the source as possible. This also means we can take the 2071da177e4SLinus Torvalds * next chunk of the CRIME register in one piece. 2081da177e4SLinus Torvalds */ 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds static unsigned long macepci_mask; 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds static void enable_macepci_irq(unsigned int irq) 2131da177e4SLinus Torvalds { 2141da177e4SLinus Torvalds macepci_mask |= MACEPCI_CONTROL_INT(irq - 9); 2151da177e4SLinus Torvalds mace->pci.control = macepci_mask; 2161da177e4SLinus Torvalds crime_mask |= 1 << (irq - 1); 2171da177e4SLinus Torvalds crime->imask = crime_mask; 2181da177e4SLinus Torvalds } 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds static void disable_macepci_irq(unsigned int irq) 2211da177e4SLinus Torvalds { 2221da177e4SLinus Torvalds crime_mask &= ~(1 << (irq - 1)); 2231da177e4SLinus Torvalds crime->imask = crime_mask; 2241da177e4SLinus Torvalds flush_crime_bus(); 2251da177e4SLinus Torvalds macepci_mask &= ~MACEPCI_CONTROL_INT(irq - 9); 2261da177e4SLinus Torvalds mace->pci.control = macepci_mask; 2271da177e4SLinus Torvalds flush_mace_bus(); 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds static void end_macepci_irq(unsigned int irq) 2311da177e4SLinus Torvalds { 2321da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 2331da177e4SLinus Torvalds enable_macepci_irq(irq); 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 23694dee171SRalf Baechle static struct irq_chip ip32_macepci_interrupt = { 23770d21cdeSAtsushi Nemoto .name = "IP32 MACE PCI", 2381603b5acSAtsushi Nemoto .ack = disable_macepci_irq, 2391603b5acSAtsushi Nemoto .mask = disable_macepci_irq, 2401603b5acSAtsushi Nemoto .mask_ack = disable_macepci_irq, 2411603b5acSAtsushi Nemoto .unmask = enable_macepci_irq, 2428ab00b9aSRalf Baechle .end = end_macepci_irq, 2431da177e4SLinus Torvalds }; 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds /* This is used for MACE ISA interrupts. That means bits 4-6 in the 2461da177e4SLinus Torvalds * CRIME register. 2471da177e4SLinus Torvalds */ 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds #define MACEISA_AUDIO_INT (MACEISA_AUDIO_SW_INT | \ 2501da177e4SLinus Torvalds MACEISA_AUDIO_SC_INT | \ 2511da177e4SLinus Torvalds MACEISA_AUDIO1_DMAT_INT | \ 2521da177e4SLinus Torvalds MACEISA_AUDIO1_OF_INT | \ 2531da177e4SLinus Torvalds MACEISA_AUDIO2_DMAT_INT | \ 2541da177e4SLinus Torvalds MACEISA_AUDIO2_MERR_INT | \ 2551da177e4SLinus Torvalds MACEISA_AUDIO3_DMAT_INT | \ 2561da177e4SLinus Torvalds MACEISA_AUDIO3_MERR_INT) 2571da177e4SLinus Torvalds #define MACEISA_MISC_INT (MACEISA_RTC_INT | \ 2581da177e4SLinus Torvalds MACEISA_KEYB_INT | \ 2591da177e4SLinus Torvalds MACEISA_KEYB_POLL_INT | \ 2601da177e4SLinus Torvalds MACEISA_MOUSE_INT | \ 2611da177e4SLinus Torvalds MACEISA_MOUSE_POLL_INT | \ 262cfbae5d3SThiemo Seufer MACEISA_TIMER0_INT | \ 263cfbae5d3SThiemo Seufer MACEISA_TIMER1_INT | \ 264cfbae5d3SThiemo Seufer MACEISA_TIMER2_INT) 2651da177e4SLinus Torvalds #define MACEISA_SUPERIO_INT (MACEISA_PARALLEL_INT | \ 2661da177e4SLinus Torvalds MACEISA_PAR_CTXA_INT | \ 2671da177e4SLinus Torvalds MACEISA_PAR_CTXB_INT | \ 2681da177e4SLinus Torvalds MACEISA_PAR_MERR_INT | \ 2691da177e4SLinus Torvalds MACEISA_SERIAL1_INT | \ 2701da177e4SLinus Torvalds MACEISA_SERIAL1_TDMAT_INT | \ 2711da177e4SLinus Torvalds MACEISA_SERIAL1_TDMAPR_INT | \ 2721da177e4SLinus Torvalds MACEISA_SERIAL1_TDMAME_INT | \ 2731da177e4SLinus Torvalds MACEISA_SERIAL1_RDMAT_INT | \ 2741da177e4SLinus Torvalds MACEISA_SERIAL1_RDMAOR_INT | \ 2751da177e4SLinus Torvalds MACEISA_SERIAL2_INT | \ 2761da177e4SLinus Torvalds MACEISA_SERIAL2_TDMAT_INT | \ 2771da177e4SLinus Torvalds MACEISA_SERIAL2_TDMAPR_INT | \ 2781da177e4SLinus Torvalds MACEISA_SERIAL2_TDMAME_INT | \ 2791da177e4SLinus Torvalds MACEISA_SERIAL2_RDMAT_INT | \ 2801da177e4SLinus Torvalds MACEISA_SERIAL2_RDMAOR_INT) 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds static unsigned long maceisa_mask; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds static void enable_maceisa_irq (unsigned int irq) 2851da177e4SLinus Torvalds { 2861da177e4SLinus Torvalds unsigned int crime_int = 0; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds DBG ("maceisa enable: %u\n", irq); 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds switch (irq) { 2911da177e4SLinus Torvalds case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ: 2921da177e4SLinus Torvalds crime_int = MACE_AUDIO_INT; 2931da177e4SLinus Torvalds break; 294cfbae5d3SThiemo Seufer case MACEISA_RTC_IRQ ... MACEISA_TIMER2_IRQ: 2951da177e4SLinus Torvalds crime_int = MACE_MISC_INT; 2961da177e4SLinus Torvalds break; 2971da177e4SLinus Torvalds case MACEISA_PARALLEL_IRQ ... MACEISA_SERIAL2_RDMAOR_IRQ: 2981da177e4SLinus Torvalds crime_int = MACE_SUPERIO_INT; 2991da177e4SLinus Torvalds break; 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds DBG ("crime_int %08x enabled\n", crime_int); 3021da177e4SLinus Torvalds crime_mask |= crime_int; 3031da177e4SLinus Torvalds crime->imask = crime_mask; 3041da177e4SLinus Torvalds maceisa_mask |= 1 << (irq - 33); 3051da177e4SLinus Torvalds mace->perif.ctrl.imask = maceisa_mask; 3061da177e4SLinus Torvalds } 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds static void disable_maceisa_irq(unsigned int irq) 3091da177e4SLinus Torvalds { 3101da177e4SLinus Torvalds unsigned int crime_int = 0; 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds maceisa_mask &= ~(1 << (irq - 33)); 3131da177e4SLinus Torvalds if(!(maceisa_mask & MACEISA_AUDIO_INT)) 3141da177e4SLinus Torvalds crime_int |= MACE_AUDIO_INT; 3151da177e4SLinus Torvalds if(!(maceisa_mask & MACEISA_MISC_INT)) 3161da177e4SLinus Torvalds crime_int |= MACE_MISC_INT; 3171da177e4SLinus Torvalds if(!(maceisa_mask & MACEISA_SUPERIO_INT)) 3181da177e4SLinus Torvalds crime_int |= MACE_SUPERIO_INT; 3191da177e4SLinus Torvalds crime_mask &= ~crime_int; 3201da177e4SLinus Torvalds crime->imask = crime_mask; 3211da177e4SLinus Torvalds flush_crime_bus(); 3221da177e4SLinus Torvalds mace->perif.ctrl.imask = maceisa_mask; 3231da177e4SLinus Torvalds flush_mace_bus(); 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds static void mask_and_ack_maceisa_irq(unsigned int irq) 3271da177e4SLinus Torvalds { 3281603b5acSAtsushi Nemoto unsigned long mace_int; 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds switch (irq) { 3311da177e4SLinus Torvalds case MACEISA_PARALLEL_IRQ: 3321da177e4SLinus Torvalds case MACEISA_SERIAL1_TDMAPR_IRQ: 3331da177e4SLinus Torvalds case MACEISA_SERIAL2_TDMAPR_IRQ: 3341da177e4SLinus Torvalds /* edge triggered */ 3351da177e4SLinus Torvalds mace_int = mace->perif.ctrl.istat; 3361da177e4SLinus Torvalds mace_int &= ~(1 << (irq - 33)); 3371da177e4SLinus Torvalds mace->perif.ctrl.istat = mace_int; 3381da177e4SLinus Torvalds break; 3391da177e4SLinus Torvalds } 3401da177e4SLinus Torvalds disable_maceisa_irq(irq); 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds static void end_maceisa_irq(unsigned irq) 3441da177e4SLinus Torvalds { 3451da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 3461da177e4SLinus Torvalds enable_maceisa_irq(irq); 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds 34994dee171SRalf Baechle static struct irq_chip ip32_maceisa_interrupt = { 35070d21cdeSAtsushi Nemoto .name = "IP32 MACE ISA", 3518ab00b9aSRalf Baechle .ack = mask_and_ack_maceisa_irq, 3521603b5acSAtsushi Nemoto .mask = disable_maceisa_irq, 3531603b5acSAtsushi Nemoto .mask_ack = mask_and_ack_maceisa_irq, 3541603b5acSAtsushi Nemoto .unmask = enable_maceisa_irq, 3558ab00b9aSRalf Baechle .end = end_maceisa_irq, 3561da177e4SLinus Torvalds }; 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds /* This is used for regular non-ISA, non-PCI MACE interrupts. That means 3591da177e4SLinus Torvalds * bits 0-3 and 7 in the CRIME register. 3601da177e4SLinus Torvalds */ 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds static void enable_mace_irq(unsigned int irq) 3631da177e4SLinus Torvalds { 3641da177e4SLinus Torvalds crime_mask |= 1 << (irq - 1); 3651da177e4SLinus Torvalds crime->imask = crime_mask; 3661da177e4SLinus Torvalds } 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds static void disable_mace_irq(unsigned int irq) 3691da177e4SLinus Torvalds { 3701da177e4SLinus Torvalds crime_mask &= ~(1 << (irq - 1)); 3711da177e4SLinus Torvalds crime->imask = crime_mask; 3721da177e4SLinus Torvalds flush_crime_bus(); 3731da177e4SLinus Torvalds } 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds static void end_mace_irq(unsigned int irq) 3761da177e4SLinus Torvalds { 3771da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 3781da177e4SLinus Torvalds enable_mace_irq(irq); 3791da177e4SLinus Torvalds } 3801da177e4SLinus Torvalds 38194dee171SRalf Baechle static struct irq_chip ip32_mace_interrupt = { 38270d21cdeSAtsushi Nemoto .name = "IP32 MACE", 3831603b5acSAtsushi Nemoto .ack = disable_mace_irq, 3841603b5acSAtsushi Nemoto .mask = disable_mace_irq, 3851603b5acSAtsushi Nemoto .mask_ack = disable_mace_irq, 3861603b5acSAtsushi Nemoto .unmask = enable_mace_irq, 3878ab00b9aSRalf Baechle .end = end_mace_irq, 3881da177e4SLinus Torvalds }; 3891da177e4SLinus Torvalds 390937a8015SRalf Baechle static void ip32_unknown_interrupt(void) 3911da177e4SLinus Torvalds { 3921da177e4SLinus Torvalds printk ("Unknown interrupt occurred!\n"); 3931da177e4SLinus Torvalds printk ("cp0_status: %08x\n", read_c0_status()); 3941da177e4SLinus Torvalds printk ("cp0_cause: %08x\n", read_c0_cause()); 3951da177e4SLinus Torvalds printk ("CRIME intr mask: %016lx\n", crime->imask); 3961da177e4SLinus Torvalds printk ("CRIME intr status: %016lx\n", crime->istat); 3971da177e4SLinus Torvalds printk ("CRIME hardware intr register: %016lx\n", crime->hard_int); 3981da177e4SLinus Torvalds printk ("MACE ISA intr mask: %08lx\n", mace->perif.ctrl.imask); 3991da177e4SLinus Torvalds printk ("MACE ISA intr status: %08lx\n", mace->perif.ctrl.istat); 4001da177e4SLinus Torvalds printk ("MACE PCI control register: %08x\n", mace->pci.control); 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds printk("Register dump:\n"); 403937a8015SRalf Baechle show_regs(get_irq_regs()); 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds printk("Please mail this report to linux-mips@linux-mips.org\n"); 4061da177e4SLinus Torvalds printk("Spinning..."); 4071da177e4SLinus Torvalds while(1) ; 4081da177e4SLinus Torvalds } 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds /* CRIME 1.1 appears to deliver all interrupts to this one pin. */ 4111da177e4SLinus Torvalds /* change this to loop over all edge-triggered irqs, exception masked out ones */ 412937a8015SRalf Baechle static void ip32_irq0(void) 4131da177e4SLinus Torvalds { 4141da177e4SLinus Torvalds uint64_t crime_int; 4151da177e4SLinus Torvalds int irq = 0; 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds crime_int = crime->istat & crime_mask; 4186f8782c4SAtsushi Nemoto irq = __ffs(crime_int); 4196f8782c4SAtsushi Nemoto crime_int = 1 << irq; 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds if (crime_int & CRIME_MACEISA_INT_MASK) { 4221da177e4SLinus Torvalds unsigned long mace_int = mace->perif.ctrl.istat; 4236f8782c4SAtsushi Nemoto irq = __ffs(mace_int & maceisa_mask) + 32; 4241da177e4SLinus Torvalds } 4256f8782c4SAtsushi Nemoto irq++; 4261da177e4SLinus Torvalds DBG("*irq %u*\n", irq); 427937a8015SRalf Baechle do_IRQ(irq); 4281da177e4SLinus Torvalds } 4291da177e4SLinus Torvalds 430937a8015SRalf Baechle static void ip32_irq1(void) 4311da177e4SLinus Torvalds { 432937a8015SRalf Baechle ip32_unknown_interrupt(); 4331da177e4SLinus Torvalds } 4341da177e4SLinus Torvalds 435937a8015SRalf Baechle static void ip32_irq2(void) 4361da177e4SLinus Torvalds { 437937a8015SRalf Baechle ip32_unknown_interrupt(); 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds 440937a8015SRalf Baechle static void ip32_irq3(void) 4411da177e4SLinus Torvalds { 442937a8015SRalf Baechle ip32_unknown_interrupt(); 4431da177e4SLinus Torvalds } 4441da177e4SLinus Torvalds 445937a8015SRalf Baechle static void ip32_irq4(void) 4461da177e4SLinus Torvalds { 447937a8015SRalf Baechle ip32_unknown_interrupt(); 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds 450937a8015SRalf Baechle static void ip32_irq5(void) 4511da177e4SLinus Torvalds { 452937a8015SRalf Baechle ll_timer_interrupt(IP32_R4K_TIMER_IRQ); 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds 455937a8015SRalf Baechle asmlinkage void plat_irq_dispatch(void) 456e4ac58afSRalf Baechle { 457*119537c0SThiemo Seufer unsigned int pending = read_c0_status() & read_c0_cause(); 458e4ac58afSRalf Baechle 459e4ac58afSRalf Baechle if (likely(pending & IE_IRQ0)) 460937a8015SRalf Baechle ip32_irq0(); 461e4ac58afSRalf Baechle else if (unlikely(pending & IE_IRQ1)) 462937a8015SRalf Baechle ip32_irq1(); 463e4ac58afSRalf Baechle else if (unlikely(pending & IE_IRQ2)) 464937a8015SRalf Baechle ip32_irq2(); 465e4ac58afSRalf Baechle else if (unlikely(pending & IE_IRQ3)) 466937a8015SRalf Baechle ip32_irq3(); 467e4ac58afSRalf Baechle else if (unlikely(pending & IE_IRQ4)) 468937a8015SRalf Baechle ip32_irq4(); 469e4ac58afSRalf Baechle else if (likely(pending & IE_IRQ5)) 470937a8015SRalf Baechle ip32_irq5(); 471e4ac58afSRalf Baechle } 472e4ac58afSRalf Baechle 4731da177e4SLinus Torvalds void __init arch_init_irq(void) 4741da177e4SLinus Torvalds { 4751da177e4SLinus Torvalds unsigned int irq; 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds /* Install our interrupt handler, then clear and disable all 4781da177e4SLinus Torvalds * CRIME and MACE interrupts. */ 4791da177e4SLinus Torvalds crime->imask = 0; 4801da177e4SLinus Torvalds crime->hard_int = 0; 4811da177e4SLinus Torvalds crime->soft_int = 0; 4821da177e4SLinus Torvalds mace->perif.ctrl.istat = 0; 4831da177e4SLinus Torvalds mace->perif.ctrl.imask = 0; 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds for (irq = 0; irq <= IP32_IRQ_MAX; irq++) { 48694dee171SRalf Baechle struct irq_chip *controller; 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds if (irq == IP32_R4K_TIMER_IRQ) 4891da177e4SLinus Torvalds controller = &ip32_cpu_interrupt; 4901da177e4SLinus Torvalds else if (irq <= MACE_PCI_BRIDGE_IRQ && irq >= MACE_VID_IN1_IRQ) 4911da177e4SLinus Torvalds controller = &ip32_mace_interrupt; 4921da177e4SLinus Torvalds else if (irq <= MACEPCI_SHARED2_IRQ && irq >= MACEPCI_SCSI0_IRQ) 4931da177e4SLinus Torvalds controller = &ip32_macepci_interrupt; 4941da177e4SLinus Torvalds else if (irq <= CRIME_VICE_IRQ && irq >= CRIME_GBE0_IRQ) 4951da177e4SLinus Torvalds controller = &ip32_crime_interrupt; 4961da177e4SLinus Torvalds else 4971da177e4SLinus Torvalds controller = &ip32_maceisa_interrupt; 4981da177e4SLinus Torvalds 4991603b5acSAtsushi Nemoto set_irq_chip(irq, controller); 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds setup_irq(CRIME_MEMERR_IRQ, &memerr_irq); 5021da177e4SLinus Torvalds setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq); 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) 5051da177e4SLinus Torvalds change_c0_status(ST0_IM, ALLINTS); 5061da177e4SLinus Torvalds } 507