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 120*4e45171cSThomas Gleixner struct irqaction memerr_irq = { 121*4e45171cSThomas Gleixner .handler = crime_memerr_intr, 122*4e45171cSThomas Gleixner .flags = IRQF_DISABLED, 123*4e45171cSThomas Gleixner .mask = CPU_MASK_NONE, 124*4e45171cSThomas Gleixner .name = "CRIME memory error", 125*4e45171cSThomas Gleixner }; 126*4e45171cSThomas Gleixner struct irqaction cpuerr_irq = { 127*4e45171cSThomas Gleixner .handler = crime_cpuerr_intr, 128*4e45171cSThomas Gleixner .flags = IRQF_DISABLED, 129*4e45171cSThomas Gleixner .mask = CPU_MASK_NONE, 130*4e45171cSThomas Gleixner .name = "CRIME CPU error", 131*4e45171cSThomas Gleixner }; 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds /* 1341da177e4SLinus Torvalds * For interrupts wired from a single device to the CPU. Only the clock 1351da177e4SLinus Torvalds * uses this it seems, which is IRQ 0 and IP7. 1361da177e4SLinus Torvalds */ 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds static void enable_cpu_irq(unsigned int irq) 1391da177e4SLinus Torvalds { 1401da177e4SLinus Torvalds set_c0_status(STATUSF_IP7); 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds static void disable_cpu_irq(unsigned int irq) 1441da177e4SLinus Torvalds { 1451da177e4SLinus Torvalds clear_c0_status(STATUSF_IP7); 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds static void end_cpu_irq(unsigned int irq) 1491da177e4SLinus Torvalds { 1501da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 1511da177e4SLinus Torvalds enable_cpu_irq (irq); 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 15494dee171SRalf Baechle static struct irq_chip ip32_cpu_interrupt = { 15570d21cdeSAtsushi Nemoto .name = "IP32 CPU", 1561603b5acSAtsushi Nemoto .ack = disable_cpu_irq, 1571603b5acSAtsushi Nemoto .mask = disable_cpu_irq, 1581603b5acSAtsushi Nemoto .mask_ack = disable_cpu_irq, 1591603b5acSAtsushi Nemoto .unmask = enable_cpu_irq, 1608ab00b9aSRalf Baechle .end = end_cpu_irq, 1611da177e4SLinus Torvalds }; 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds /* 1641da177e4SLinus Torvalds * This is for pure CRIME interrupts - ie not MACE. The advantage? 1651da177e4SLinus Torvalds * We get to split the register in half and do faster lookups. 1661da177e4SLinus Torvalds */ 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds static uint64_t crime_mask; 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds static void enable_crime_irq(unsigned int irq) 1711da177e4SLinus Torvalds { 1721da177e4SLinus Torvalds crime_mask |= 1 << (irq - 1); 1731da177e4SLinus Torvalds crime->imask = crime_mask; 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds static void disable_crime_irq(unsigned int irq) 1771da177e4SLinus Torvalds { 1781da177e4SLinus Torvalds crime_mask &= ~(1 << (irq - 1)); 1791da177e4SLinus Torvalds crime->imask = crime_mask; 1801da177e4SLinus Torvalds flush_crime_bus(); 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds static void mask_and_ack_crime_irq(unsigned int irq) 1841da177e4SLinus Torvalds { 1851da177e4SLinus Torvalds /* Edge triggered interrupts must be cleared. */ 1861da177e4SLinus Torvalds if ((irq >= CRIME_GBE0_IRQ && irq <= CRIME_GBE3_IRQ) 1871da177e4SLinus Torvalds || (irq >= CRIME_RE_EMPTY_E_IRQ && irq <= CRIME_RE_IDLE_E_IRQ) 1881da177e4SLinus Torvalds || (irq >= CRIME_SOFT0_IRQ && irq <= CRIME_SOFT2_IRQ)) { 1891da177e4SLinus Torvalds uint64_t crime_int; 1901da177e4SLinus Torvalds crime_int = crime->hard_int; 1911da177e4SLinus Torvalds crime_int &= ~(1 << (irq - 1)); 1921da177e4SLinus Torvalds crime->hard_int = crime_int; 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds disable_crime_irq(irq); 1951da177e4SLinus Torvalds } 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds static void end_crime_irq(unsigned int irq) 1981da177e4SLinus Torvalds { 1991da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 2001da177e4SLinus Torvalds enable_crime_irq(irq); 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 20394dee171SRalf Baechle static struct irq_chip ip32_crime_interrupt = { 20470d21cdeSAtsushi Nemoto .name = "IP32 CRIME", 2058ab00b9aSRalf Baechle .ack = mask_and_ack_crime_irq, 2061603b5acSAtsushi Nemoto .mask = disable_crime_irq, 2071603b5acSAtsushi Nemoto .mask_ack = mask_and_ack_crime_irq, 2081603b5acSAtsushi Nemoto .unmask = enable_crime_irq, 2098ab00b9aSRalf Baechle .end = end_crime_irq, 2101da177e4SLinus Torvalds }; 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds /* 2131da177e4SLinus Torvalds * This is for MACE PCI interrupts. We can decrease bus traffic by masking 2141da177e4SLinus Torvalds * as close to the source as possible. This also means we can take the 2151da177e4SLinus Torvalds * next chunk of the CRIME register in one piece. 2161da177e4SLinus Torvalds */ 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds static unsigned long macepci_mask; 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds static void enable_macepci_irq(unsigned int irq) 2211da177e4SLinus Torvalds { 2221da177e4SLinus Torvalds macepci_mask |= MACEPCI_CONTROL_INT(irq - 9); 2231da177e4SLinus Torvalds mace->pci.control = macepci_mask; 2241da177e4SLinus Torvalds crime_mask |= 1 << (irq - 1); 2251da177e4SLinus Torvalds crime->imask = crime_mask; 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds static void disable_macepci_irq(unsigned int irq) 2291da177e4SLinus Torvalds { 2301da177e4SLinus Torvalds crime_mask &= ~(1 << (irq - 1)); 2311da177e4SLinus Torvalds crime->imask = crime_mask; 2321da177e4SLinus Torvalds flush_crime_bus(); 2331da177e4SLinus Torvalds macepci_mask &= ~MACEPCI_CONTROL_INT(irq - 9); 2341da177e4SLinus Torvalds mace->pci.control = macepci_mask; 2351da177e4SLinus Torvalds flush_mace_bus(); 2361da177e4SLinus Torvalds } 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds static void end_macepci_irq(unsigned int irq) 2391da177e4SLinus Torvalds { 2401da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 2411da177e4SLinus Torvalds enable_macepci_irq(irq); 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds 24494dee171SRalf Baechle static struct irq_chip ip32_macepci_interrupt = { 24570d21cdeSAtsushi Nemoto .name = "IP32 MACE PCI", 2461603b5acSAtsushi Nemoto .ack = disable_macepci_irq, 2471603b5acSAtsushi Nemoto .mask = disable_macepci_irq, 2481603b5acSAtsushi Nemoto .mask_ack = disable_macepci_irq, 2491603b5acSAtsushi Nemoto .unmask = enable_macepci_irq, 2508ab00b9aSRalf Baechle .end = end_macepci_irq, 2511da177e4SLinus Torvalds }; 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds /* This is used for MACE ISA interrupts. That means bits 4-6 in the 2541da177e4SLinus Torvalds * CRIME register. 2551da177e4SLinus Torvalds */ 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds #define MACEISA_AUDIO_INT (MACEISA_AUDIO_SW_INT | \ 2581da177e4SLinus Torvalds MACEISA_AUDIO_SC_INT | \ 2591da177e4SLinus Torvalds MACEISA_AUDIO1_DMAT_INT | \ 2601da177e4SLinus Torvalds MACEISA_AUDIO1_OF_INT | \ 2611da177e4SLinus Torvalds MACEISA_AUDIO2_DMAT_INT | \ 2621da177e4SLinus Torvalds MACEISA_AUDIO2_MERR_INT | \ 2631da177e4SLinus Torvalds MACEISA_AUDIO3_DMAT_INT | \ 2641da177e4SLinus Torvalds MACEISA_AUDIO3_MERR_INT) 2651da177e4SLinus Torvalds #define MACEISA_MISC_INT (MACEISA_RTC_INT | \ 2661da177e4SLinus Torvalds MACEISA_KEYB_INT | \ 2671da177e4SLinus Torvalds MACEISA_KEYB_POLL_INT | \ 2681da177e4SLinus Torvalds MACEISA_MOUSE_INT | \ 2691da177e4SLinus Torvalds MACEISA_MOUSE_POLL_INT | \ 270cfbae5d3SThiemo Seufer MACEISA_TIMER0_INT | \ 271cfbae5d3SThiemo Seufer MACEISA_TIMER1_INT | \ 272cfbae5d3SThiemo Seufer MACEISA_TIMER2_INT) 2731da177e4SLinus Torvalds #define MACEISA_SUPERIO_INT (MACEISA_PARALLEL_INT | \ 2741da177e4SLinus Torvalds MACEISA_PAR_CTXA_INT | \ 2751da177e4SLinus Torvalds MACEISA_PAR_CTXB_INT | \ 2761da177e4SLinus Torvalds MACEISA_PAR_MERR_INT | \ 2771da177e4SLinus Torvalds MACEISA_SERIAL1_INT | \ 2781da177e4SLinus Torvalds MACEISA_SERIAL1_TDMAT_INT | \ 2791da177e4SLinus Torvalds MACEISA_SERIAL1_TDMAPR_INT | \ 2801da177e4SLinus Torvalds MACEISA_SERIAL1_TDMAME_INT | \ 2811da177e4SLinus Torvalds MACEISA_SERIAL1_RDMAT_INT | \ 2821da177e4SLinus Torvalds MACEISA_SERIAL1_RDMAOR_INT | \ 2831da177e4SLinus Torvalds MACEISA_SERIAL2_INT | \ 2841da177e4SLinus Torvalds MACEISA_SERIAL2_TDMAT_INT | \ 2851da177e4SLinus Torvalds MACEISA_SERIAL2_TDMAPR_INT | \ 2861da177e4SLinus Torvalds MACEISA_SERIAL2_TDMAME_INT | \ 2871da177e4SLinus Torvalds MACEISA_SERIAL2_RDMAT_INT | \ 2881da177e4SLinus Torvalds MACEISA_SERIAL2_RDMAOR_INT) 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds static unsigned long maceisa_mask; 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds static void enable_maceisa_irq (unsigned int irq) 2931da177e4SLinus Torvalds { 2941da177e4SLinus Torvalds unsigned int crime_int = 0; 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds DBG ("maceisa enable: %u\n", irq); 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds switch (irq) { 2991da177e4SLinus Torvalds case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ: 3001da177e4SLinus Torvalds crime_int = MACE_AUDIO_INT; 3011da177e4SLinus Torvalds break; 302cfbae5d3SThiemo Seufer case MACEISA_RTC_IRQ ... MACEISA_TIMER2_IRQ: 3031da177e4SLinus Torvalds crime_int = MACE_MISC_INT; 3041da177e4SLinus Torvalds break; 3051da177e4SLinus Torvalds case MACEISA_PARALLEL_IRQ ... MACEISA_SERIAL2_RDMAOR_IRQ: 3061da177e4SLinus Torvalds crime_int = MACE_SUPERIO_INT; 3071da177e4SLinus Torvalds break; 3081da177e4SLinus Torvalds } 3091da177e4SLinus Torvalds DBG ("crime_int %08x enabled\n", crime_int); 3101da177e4SLinus Torvalds crime_mask |= crime_int; 3111da177e4SLinus Torvalds crime->imask = crime_mask; 3121da177e4SLinus Torvalds maceisa_mask |= 1 << (irq - 33); 3131da177e4SLinus Torvalds mace->perif.ctrl.imask = maceisa_mask; 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds static void disable_maceisa_irq(unsigned int irq) 3171da177e4SLinus Torvalds { 3181da177e4SLinus Torvalds unsigned int crime_int = 0; 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds maceisa_mask &= ~(1 << (irq - 33)); 3211da177e4SLinus Torvalds if(!(maceisa_mask & MACEISA_AUDIO_INT)) 3221da177e4SLinus Torvalds crime_int |= MACE_AUDIO_INT; 3231da177e4SLinus Torvalds if(!(maceisa_mask & MACEISA_MISC_INT)) 3241da177e4SLinus Torvalds crime_int |= MACE_MISC_INT; 3251da177e4SLinus Torvalds if(!(maceisa_mask & MACEISA_SUPERIO_INT)) 3261da177e4SLinus Torvalds crime_int |= MACE_SUPERIO_INT; 3271da177e4SLinus Torvalds crime_mask &= ~crime_int; 3281da177e4SLinus Torvalds crime->imask = crime_mask; 3291da177e4SLinus Torvalds flush_crime_bus(); 3301da177e4SLinus Torvalds mace->perif.ctrl.imask = maceisa_mask; 3311da177e4SLinus Torvalds flush_mace_bus(); 3321da177e4SLinus Torvalds } 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds static void mask_and_ack_maceisa_irq(unsigned int irq) 3351da177e4SLinus Torvalds { 3361603b5acSAtsushi Nemoto unsigned long mace_int; 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds switch (irq) { 3391da177e4SLinus Torvalds case MACEISA_PARALLEL_IRQ: 3401da177e4SLinus Torvalds case MACEISA_SERIAL1_TDMAPR_IRQ: 3411da177e4SLinus Torvalds case MACEISA_SERIAL2_TDMAPR_IRQ: 3421da177e4SLinus Torvalds /* edge triggered */ 3431da177e4SLinus Torvalds mace_int = mace->perif.ctrl.istat; 3441da177e4SLinus Torvalds mace_int &= ~(1 << (irq - 33)); 3451da177e4SLinus Torvalds mace->perif.ctrl.istat = mace_int; 3461da177e4SLinus Torvalds break; 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds disable_maceisa_irq(irq); 3491da177e4SLinus Torvalds } 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds static void end_maceisa_irq(unsigned irq) 3521da177e4SLinus Torvalds { 3531da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 3541da177e4SLinus Torvalds enable_maceisa_irq(irq); 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 35794dee171SRalf Baechle static struct irq_chip ip32_maceisa_interrupt = { 35870d21cdeSAtsushi Nemoto .name = "IP32 MACE ISA", 3598ab00b9aSRalf Baechle .ack = mask_and_ack_maceisa_irq, 3601603b5acSAtsushi Nemoto .mask = disable_maceisa_irq, 3611603b5acSAtsushi Nemoto .mask_ack = mask_and_ack_maceisa_irq, 3621603b5acSAtsushi Nemoto .unmask = enable_maceisa_irq, 3638ab00b9aSRalf Baechle .end = end_maceisa_irq, 3641da177e4SLinus Torvalds }; 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds /* This is used for regular non-ISA, non-PCI MACE interrupts. That means 3671da177e4SLinus Torvalds * bits 0-3 and 7 in the CRIME register. 3681da177e4SLinus Torvalds */ 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds static void enable_mace_irq(unsigned int irq) 3711da177e4SLinus Torvalds { 3721da177e4SLinus Torvalds crime_mask |= 1 << (irq - 1); 3731da177e4SLinus Torvalds crime->imask = crime_mask; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds static void disable_mace_irq(unsigned int irq) 3771da177e4SLinus Torvalds { 3781da177e4SLinus Torvalds crime_mask &= ~(1 << (irq - 1)); 3791da177e4SLinus Torvalds crime->imask = crime_mask; 3801da177e4SLinus Torvalds flush_crime_bus(); 3811da177e4SLinus Torvalds } 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds static void end_mace_irq(unsigned int irq) 3841da177e4SLinus Torvalds { 3851da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 3861da177e4SLinus Torvalds enable_mace_irq(irq); 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds 38994dee171SRalf Baechle static struct irq_chip ip32_mace_interrupt = { 39070d21cdeSAtsushi Nemoto .name = "IP32 MACE", 3911603b5acSAtsushi Nemoto .ack = disable_mace_irq, 3921603b5acSAtsushi Nemoto .mask = disable_mace_irq, 3931603b5acSAtsushi Nemoto .mask_ack = disable_mace_irq, 3941603b5acSAtsushi Nemoto .unmask = enable_mace_irq, 3958ab00b9aSRalf Baechle .end = end_mace_irq, 3961da177e4SLinus Torvalds }; 3971da177e4SLinus Torvalds 398937a8015SRalf Baechle static void ip32_unknown_interrupt(void) 3991da177e4SLinus Torvalds { 4001da177e4SLinus Torvalds printk ("Unknown interrupt occurred!\n"); 4011da177e4SLinus Torvalds printk ("cp0_status: %08x\n", read_c0_status()); 4021da177e4SLinus Torvalds printk ("cp0_cause: %08x\n", read_c0_cause()); 4031da177e4SLinus Torvalds printk ("CRIME intr mask: %016lx\n", crime->imask); 4041da177e4SLinus Torvalds printk ("CRIME intr status: %016lx\n", crime->istat); 4051da177e4SLinus Torvalds printk ("CRIME hardware intr register: %016lx\n", crime->hard_int); 4061da177e4SLinus Torvalds printk ("MACE ISA intr mask: %08lx\n", mace->perif.ctrl.imask); 4071da177e4SLinus Torvalds printk ("MACE ISA intr status: %08lx\n", mace->perif.ctrl.istat); 4081da177e4SLinus Torvalds printk ("MACE PCI control register: %08x\n", mace->pci.control); 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds printk("Register dump:\n"); 411937a8015SRalf Baechle show_regs(get_irq_regs()); 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds printk("Please mail this report to linux-mips@linux-mips.org\n"); 4141da177e4SLinus Torvalds printk("Spinning..."); 4151da177e4SLinus Torvalds while(1) ; 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds /* CRIME 1.1 appears to deliver all interrupts to this one pin. */ 4191da177e4SLinus Torvalds /* change this to loop over all edge-triggered irqs, exception masked out ones */ 420937a8015SRalf Baechle static void ip32_irq0(void) 4211da177e4SLinus Torvalds { 4221da177e4SLinus Torvalds uint64_t crime_int; 4231da177e4SLinus Torvalds int irq = 0; 4241da177e4SLinus Torvalds 4251da177e4SLinus Torvalds crime_int = crime->istat & crime_mask; 4266f8782c4SAtsushi Nemoto irq = __ffs(crime_int); 4276f8782c4SAtsushi Nemoto crime_int = 1 << irq; 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds if (crime_int & CRIME_MACEISA_INT_MASK) { 4301da177e4SLinus Torvalds unsigned long mace_int = mace->perif.ctrl.istat; 4316f8782c4SAtsushi Nemoto irq = __ffs(mace_int & maceisa_mask) + 32; 4321da177e4SLinus Torvalds } 4336f8782c4SAtsushi Nemoto irq++; 4341da177e4SLinus Torvalds DBG("*irq %u*\n", irq); 435937a8015SRalf Baechle do_IRQ(irq); 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 438937a8015SRalf Baechle static void ip32_irq1(void) 4391da177e4SLinus Torvalds { 440937a8015SRalf Baechle ip32_unknown_interrupt(); 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds 443937a8015SRalf Baechle static void ip32_irq2(void) 4441da177e4SLinus Torvalds { 445937a8015SRalf Baechle ip32_unknown_interrupt(); 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds 448937a8015SRalf Baechle static void ip32_irq3(void) 4491da177e4SLinus Torvalds { 450937a8015SRalf Baechle ip32_unknown_interrupt(); 4511da177e4SLinus Torvalds } 4521da177e4SLinus Torvalds 453937a8015SRalf Baechle static void ip32_irq4(void) 4541da177e4SLinus Torvalds { 455937a8015SRalf Baechle ip32_unknown_interrupt(); 4561da177e4SLinus Torvalds } 4571da177e4SLinus Torvalds 458937a8015SRalf Baechle static void ip32_irq5(void) 4591da177e4SLinus Torvalds { 460937a8015SRalf Baechle ll_timer_interrupt(IP32_R4K_TIMER_IRQ); 4611da177e4SLinus Torvalds } 4621da177e4SLinus Torvalds 463937a8015SRalf Baechle asmlinkage void plat_irq_dispatch(void) 464e4ac58afSRalf Baechle { 465119537c0SThiemo Seufer unsigned int pending = read_c0_status() & read_c0_cause(); 466e4ac58afSRalf Baechle 467e4ac58afSRalf Baechle if (likely(pending & IE_IRQ0)) 468937a8015SRalf Baechle ip32_irq0(); 469e4ac58afSRalf Baechle else if (unlikely(pending & IE_IRQ1)) 470937a8015SRalf Baechle ip32_irq1(); 471e4ac58afSRalf Baechle else if (unlikely(pending & IE_IRQ2)) 472937a8015SRalf Baechle ip32_irq2(); 473e4ac58afSRalf Baechle else if (unlikely(pending & IE_IRQ3)) 474937a8015SRalf Baechle ip32_irq3(); 475e4ac58afSRalf Baechle else if (unlikely(pending & IE_IRQ4)) 476937a8015SRalf Baechle ip32_irq4(); 477e4ac58afSRalf Baechle else if (likely(pending & IE_IRQ5)) 478937a8015SRalf Baechle ip32_irq5(); 479e4ac58afSRalf Baechle } 480e4ac58afSRalf Baechle 4811da177e4SLinus Torvalds void __init arch_init_irq(void) 4821da177e4SLinus Torvalds { 4831da177e4SLinus Torvalds unsigned int irq; 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds /* Install our interrupt handler, then clear and disable all 4861da177e4SLinus Torvalds * CRIME and MACE interrupts. */ 4871da177e4SLinus Torvalds crime->imask = 0; 4881da177e4SLinus Torvalds crime->hard_int = 0; 4891da177e4SLinus Torvalds crime->soft_int = 0; 4901da177e4SLinus Torvalds mace->perif.ctrl.istat = 0; 4911da177e4SLinus Torvalds mace->perif.ctrl.imask = 0; 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds for (irq = 0; irq <= IP32_IRQ_MAX; irq++) { 49494dee171SRalf Baechle struct irq_chip *controller; 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds if (irq == IP32_R4K_TIMER_IRQ) 4971da177e4SLinus Torvalds controller = &ip32_cpu_interrupt; 4981da177e4SLinus Torvalds else if (irq <= MACE_PCI_BRIDGE_IRQ && irq >= MACE_VID_IN1_IRQ) 4991da177e4SLinus Torvalds controller = &ip32_mace_interrupt; 5001da177e4SLinus Torvalds else if (irq <= MACEPCI_SHARED2_IRQ && irq >= MACEPCI_SCSI0_IRQ) 5011da177e4SLinus Torvalds controller = &ip32_macepci_interrupt; 5021da177e4SLinus Torvalds else if (irq <= CRIME_VICE_IRQ && irq >= CRIME_GBE0_IRQ) 5031da177e4SLinus Torvalds controller = &ip32_crime_interrupt; 5041da177e4SLinus Torvalds else 5051da177e4SLinus Torvalds controller = &ip32_maceisa_interrupt; 5061da177e4SLinus Torvalds 5071603b5acSAtsushi Nemoto set_irq_chip(irq, controller); 5081da177e4SLinus Torvalds } 5091da177e4SLinus Torvalds setup_irq(CRIME_MEMERR_IRQ, &memerr_irq); 5101da177e4SLinus Torvalds setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq); 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) 5131da177e4SLinus Torvalds change_c0_status(ST0_IM, ALLINTS); 5141da177e4SLinus Torvalds } 515