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 { 341da177e4SLinus Torvalds volatile unsigned long junk = crime->control; 351da177e4SLinus Torvalds } 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds static void inline flush_mace_bus(void) 381da177e4SLinus Torvalds { 391da177e4SLinus Torvalds volatile unsigned long junk = 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 /* 1171da177e4SLinus Torvalds * IRQ spinlock - Ralf says not to disable CPU interrupts, 1181da177e4SLinus Torvalds * and I think he knows better. 1191da177e4SLinus Torvalds */ 1201da177e4SLinus Torvalds static DEFINE_SPINLOCK(ip32_irq_lock); 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds /* Some initial interrupts to set up */ 1231da177e4SLinus Torvalds extern irqreturn_t crime_memerr_intr (int irq, void *dev_id, 1241da177e4SLinus Torvalds struct pt_regs *regs); 1251da177e4SLinus Torvalds extern irqreturn_t crime_cpuerr_intr (int irq, void *dev_id, 1261da177e4SLinus Torvalds struct pt_regs *regs); 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds struct irqaction memerr_irq = { crime_memerr_intr, SA_INTERRUPT, 1291da177e4SLinus Torvalds CPU_MASK_NONE, "CRIME memory error", NULL, NULL }; 1301da177e4SLinus Torvalds struct irqaction cpuerr_irq = { crime_cpuerr_intr, SA_INTERRUPT, 1311da177e4SLinus Torvalds CPU_MASK_NONE, "CRIME CPU error", NULL, NULL }; 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 unsigned int startup_cpu_irq(unsigned int irq) 1441da177e4SLinus Torvalds { 1451da177e4SLinus Torvalds enable_cpu_irq(irq); 1461da177e4SLinus Torvalds return 0; 1471da177e4SLinus Torvalds } 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds static void disable_cpu_irq(unsigned int irq) 1501da177e4SLinus Torvalds { 1511da177e4SLinus Torvalds clear_c0_status(STATUSF_IP7); 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds static void end_cpu_irq(unsigned int irq) 1551da177e4SLinus Torvalds { 1561da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 1571da177e4SLinus Torvalds enable_cpu_irq (irq); 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds #define shutdown_cpu_irq disable_cpu_irq 1611da177e4SLinus Torvalds #define mask_and_ack_cpu_irq disable_cpu_irq 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds static struct hw_interrupt_type ip32_cpu_interrupt = { 1648ab00b9aSRalf Baechle .typename = "IP32 CPU", 1658ab00b9aSRalf Baechle .startup = startup_cpu_irq, 1668ab00b9aSRalf Baechle .shutdown = shutdown_cpu_irq, 1678ab00b9aSRalf Baechle .enable = enable_cpu_irq, 1688ab00b9aSRalf Baechle .disable = disable_cpu_irq, 1698ab00b9aSRalf Baechle .ack = mask_and_ack_cpu_irq, 1708ab00b9aSRalf Baechle .end = end_cpu_irq, 1711da177e4SLinus Torvalds }; 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds /* 1741da177e4SLinus Torvalds * This is for pure CRIME interrupts - ie not MACE. The advantage? 1751da177e4SLinus Torvalds * We get to split the register in half and do faster lookups. 1761da177e4SLinus Torvalds */ 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds static uint64_t crime_mask; 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds static void enable_crime_irq(unsigned int irq) 1811da177e4SLinus Torvalds { 1821da177e4SLinus Torvalds unsigned long flags; 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds spin_lock_irqsave(&ip32_irq_lock, flags); 1851da177e4SLinus Torvalds crime_mask |= 1 << (irq - 1); 1861da177e4SLinus Torvalds crime->imask = crime_mask; 1871da177e4SLinus Torvalds spin_unlock_irqrestore(&ip32_irq_lock, flags); 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds static unsigned int startup_crime_irq(unsigned int irq) 1911da177e4SLinus Torvalds { 1921da177e4SLinus Torvalds enable_crime_irq(irq); 1931da177e4SLinus Torvalds return 0; /* This is probably not right; we could have pending irqs */ 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds static void disable_crime_irq(unsigned int irq) 1971da177e4SLinus Torvalds { 1981da177e4SLinus Torvalds unsigned long flags; 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds spin_lock_irqsave(&ip32_irq_lock, flags); 2011da177e4SLinus Torvalds crime_mask &= ~(1 << (irq - 1)); 2021da177e4SLinus Torvalds crime->imask = crime_mask; 2031da177e4SLinus Torvalds flush_crime_bus(); 2041da177e4SLinus Torvalds spin_unlock_irqrestore(&ip32_irq_lock, flags); 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds static void mask_and_ack_crime_irq(unsigned int irq) 2081da177e4SLinus Torvalds { 2091da177e4SLinus Torvalds unsigned long flags; 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds /* Edge triggered interrupts must be cleared. */ 2121da177e4SLinus Torvalds if ((irq >= CRIME_GBE0_IRQ && irq <= CRIME_GBE3_IRQ) 2131da177e4SLinus Torvalds || (irq >= CRIME_RE_EMPTY_E_IRQ && irq <= CRIME_RE_IDLE_E_IRQ) 2141da177e4SLinus Torvalds || (irq >= CRIME_SOFT0_IRQ && irq <= CRIME_SOFT2_IRQ)) { 2151da177e4SLinus Torvalds uint64_t crime_int; 2161da177e4SLinus Torvalds spin_lock_irqsave(&ip32_irq_lock, flags); 2171da177e4SLinus Torvalds crime_int = crime->hard_int; 2181da177e4SLinus Torvalds crime_int &= ~(1 << (irq - 1)); 2191da177e4SLinus Torvalds crime->hard_int = crime_int; 2201da177e4SLinus Torvalds spin_unlock_irqrestore(&ip32_irq_lock, flags); 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds disable_crime_irq(irq); 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds static void end_crime_irq(unsigned int irq) 2261da177e4SLinus Torvalds { 2271da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 2281da177e4SLinus Torvalds enable_crime_irq(irq); 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds #define shutdown_crime_irq disable_crime_irq 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds static struct hw_interrupt_type ip32_crime_interrupt = { 2348ab00b9aSRalf Baechle .typename = "IP32 CRIME", 2358ab00b9aSRalf Baechle .startup = startup_crime_irq, 2368ab00b9aSRalf Baechle .shutdown = shutdown_crime_irq, 2378ab00b9aSRalf Baechle .enable = enable_crime_irq, 2388ab00b9aSRalf Baechle .disable = disable_crime_irq, 2398ab00b9aSRalf Baechle .ack = mask_and_ack_crime_irq, 2408ab00b9aSRalf Baechle .end = end_crime_irq, 2411da177e4SLinus Torvalds }; 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds /* 2441da177e4SLinus Torvalds * This is for MACE PCI interrupts. We can decrease bus traffic by masking 2451da177e4SLinus Torvalds * as close to the source as possible. This also means we can take the 2461da177e4SLinus Torvalds * next chunk of the CRIME register in one piece. 2471da177e4SLinus Torvalds */ 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds static unsigned long macepci_mask; 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds static void enable_macepci_irq(unsigned int irq) 2521da177e4SLinus Torvalds { 2531da177e4SLinus Torvalds unsigned long flags; 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds spin_lock_irqsave(&ip32_irq_lock, flags); 2561da177e4SLinus Torvalds macepci_mask |= MACEPCI_CONTROL_INT(irq - 9); 2571da177e4SLinus Torvalds mace->pci.control = macepci_mask; 2581da177e4SLinus Torvalds crime_mask |= 1 << (irq - 1); 2591da177e4SLinus Torvalds crime->imask = crime_mask; 2601da177e4SLinus Torvalds spin_unlock_irqrestore(&ip32_irq_lock, flags); 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds static unsigned int startup_macepci_irq(unsigned int irq) 2641da177e4SLinus Torvalds { 2651da177e4SLinus Torvalds enable_macepci_irq (irq); 2661da177e4SLinus Torvalds return 0; 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds static void disable_macepci_irq(unsigned int irq) 2701da177e4SLinus Torvalds { 2711da177e4SLinus Torvalds unsigned long flags; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds spin_lock_irqsave(&ip32_irq_lock, flags); 2741da177e4SLinus Torvalds crime_mask &= ~(1 << (irq - 1)); 2751da177e4SLinus Torvalds crime->imask = crime_mask; 2761da177e4SLinus Torvalds flush_crime_bus(); 2771da177e4SLinus Torvalds macepci_mask &= ~MACEPCI_CONTROL_INT(irq - 9); 2781da177e4SLinus Torvalds mace->pci.control = macepci_mask; 2791da177e4SLinus Torvalds flush_mace_bus(); 2801da177e4SLinus Torvalds spin_unlock_irqrestore(&ip32_irq_lock, flags); 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds static void end_macepci_irq(unsigned int irq) 2841da177e4SLinus Torvalds { 2851da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 2861da177e4SLinus Torvalds enable_macepci_irq(irq); 2871da177e4SLinus Torvalds } 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds #define shutdown_macepci_irq disable_macepci_irq 2901da177e4SLinus Torvalds #define mask_and_ack_macepci_irq disable_macepci_irq 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds static struct hw_interrupt_type ip32_macepci_interrupt = { 2938ab00b9aSRalf Baechle .typename = "IP32 MACE PCI", 2948ab00b9aSRalf Baechle .startup = startup_macepci_irq, 2958ab00b9aSRalf Baechle .shutdown = shutdown_macepci_irq, 2968ab00b9aSRalf Baechle .enable = enable_macepci_irq, 2978ab00b9aSRalf Baechle .disable = disable_macepci_irq, 2988ab00b9aSRalf Baechle .ack = mask_and_ack_macepci_irq, 2998ab00b9aSRalf Baechle .end = end_macepci_irq, 3001da177e4SLinus Torvalds }; 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds /* This is used for MACE ISA interrupts. That means bits 4-6 in the 3031da177e4SLinus Torvalds * CRIME register. 3041da177e4SLinus Torvalds */ 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds #define MACEISA_AUDIO_INT (MACEISA_AUDIO_SW_INT | \ 3071da177e4SLinus Torvalds MACEISA_AUDIO_SC_INT | \ 3081da177e4SLinus Torvalds MACEISA_AUDIO1_DMAT_INT | \ 3091da177e4SLinus Torvalds MACEISA_AUDIO1_OF_INT | \ 3101da177e4SLinus Torvalds MACEISA_AUDIO2_DMAT_INT | \ 3111da177e4SLinus Torvalds MACEISA_AUDIO2_MERR_INT | \ 3121da177e4SLinus Torvalds MACEISA_AUDIO3_DMAT_INT | \ 3131da177e4SLinus Torvalds MACEISA_AUDIO3_MERR_INT) 3141da177e4SLinus Torvalds #define MACEISA_MISC_INT (MACEISA_RTC_INT | \ 3151da177e4SLinus Torvalds MACEISA_KEYB_INT | \ 3161da177e4SLinus Torvalds MACEISA_KEYB_POLL_INT | \ 3171da177e4SLinus Torvalds MACEISA_MOUSE_INT | \ 3181da177e4SLinus Torvalds MACEISA_MOUSE_POLL_INT | \ 3191da177e4SLinus Torvalds MACEISA_TIMER0_INT | \ 3201da177e4SLinus Torvalds MACEISA_TIMER1_INT | \ 3211da177e4SLinus Torvalds MACEISA_TIMER2_INT) 3221da177e4SLinus Torvalds #define MACEISA_SUPERIO_INT (MACEISA_PARALLEL_INT | \ 3231da177e4SLinus Torvalds MACEISA_PAR_CTXA_INT | \ 3241da177e4SLinus Torvalds MACEISA_PAR_CTXB_INT | \ 3251da177e4SLinus Torvalds MACEISA_PAR_MERR_INT | \ 3261da177e4SLinus Torvalds MACEISA_SERIAL1_INT | \ 3271da177e4SLinus Torvalds MACEISA_SERIAL1_TDMAT_INT | \ 3281da177e4SLinus Torvalds MACEISA_SERIAL1_TDMAPR_INT | \ 3291da177e4SLinus Torvalds MACEISA_SERIAL1_TDMAME_INT | \ 3301da177e4SLinus Torvalds MACEISA_SERIAL1_RDMAT_INT | \ 3311da177e4SLinus Torvalds MACEISA_SERIAL1_RDMAOR_INT | \ 3321da177e4SLinus Torvalds MACEISA_SERIAL2_INT | \ 3331da177e4SLinus Torvalds MACEISA_SERIAL2_TDMAT_INT | \ 3341da177e4SLinus Torvalds MACEISA_SERIAL2_TDMAPR_INT | \ 3351da177e4SLinus Torvalds MACEISA_SERIAL2_TDMAME_INT | \ 3361da177e4SLinus Torvalds MACEISA_SERIAL2_RDMAT_INT | \ 3371da177e4SLinus Torvalds MACEISA_SERIAL2_RDMAOR_INT) 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds static unsigned long maceisa_mask; 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds static void enable_maceisa_irq (unsigned int irq) 3421da177e4SLinus Torvalds { 3431da177e4SLinus Torvalds unsigned int crime_int = 0; 3441da177e4SLinus Torvalds unsigned long flags; 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds DBG ("maceisa enable: %u\n", irq); 3471da177e4SLinus Torvalds 3481da177e4SLinus Torvalds switch (irq) { 3491da177e4SLinus Torvalds case MACEISA_AUDIO_SW_IRQ ... MACEISA_AUDIO3_MERR_IRQ: 3501da177e4SLinus Torvalds crime_int = MACE_AUDIO_INT; 3511da177e4SLinus Torvalds break; 3521da177e4SLinus Torvalds case MACEISA_RTC_IRQ ... MACEISA_TIMER2_IRQ: 3531da177e4SLinus Torvalds crime_int = MACE_MISC_INT; 3541da177e4SLinus Torvalds break; 3551da177e4SLinus Torvalds case MACEISA_PARALLEL_IRQ ... MACEISA_SERIAL2_RDMAOR_IRQ: 3561da177e4SLinus Torvalds crime_int = MACE_SUPERIO_INT; 3571da177e4SLinus Torvalds break; 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds DBG ("crime_int %08x enabled\n", crime_int); 3601da177e4SLinus Torvalds spin_lock_irqsave(&ip32_irq_lock, flags); 3611da177e4SLinus Torvalds crime_mask |= crime_int; 3621da177e4SLinus Torvalds crime->imask = crime_mask; 3631da177e4SLinus Torvalds maceisa_mask |= 1 << (irq - 33); 3641da177e4SLinus Torvalds mace->perif.ctrl.imask = maceisa_mask; 3651da177e4SLinus Torvalds spin_unlock_irqrestore(&ip32_irq_lock, flags); 3661da177e4SLinus Torvalds } 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds static unsigned int startup_maceisa_irq(unsigned int irq) 3691da177e4SLinus Torvalds { 3701da177e4SLinus Torvalds enable_maceisa_irq(irq); 3711da177e4SLinus Torvalds return 0; 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds static void disable_maceisa_irq(unsigned int irq) 3751da177e4SLinus Torvalds { 3761da177e4SLinus Torvalds unsigned int crime_int = 0; 3771da177e4SLinus Torvalds unsigned long flags; 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds spin_lock_irqsave(&ip32_irq_lock, flags); 3801da177e4SLinus Torvalds maceisa_mask &= ~(1 << (irq - 33)); 3811da177e4SLinus Torvalds if(!(maceisa_mask & MACEISA_AUDIO_INT)) 3821da177e4SLinus Torvalds crime_int |= MACE_AUDIO_INT; 3831da177e4SLinus Torvalds if(!(maceisa_mask & MACEISA_MISC_INT)) 3841da177e4SLinus Torvalds crime_int |= MACE_MISC_INT; 3851da177e4SLinus Torvalds if(!(maceisa_mask & MACEISA_SUPERIO_INT)) 3861da177e4SLinus Torvalds crime_int |= MACE_SUPERIO_INT; 3871da177e4SLinus Torvalds crime_mask &= ~crime_int; 3881da177e4SLinus Torvalds crime->imask = crime_mask; 3891da177e4SLinus Torvalds flush_crime_bus(); 3901da177e4SLinus Torvalds mace->perif.ctrl.imask = maceisa_mask; 3911da177e4SLinus Torvalds flush_mace_bus(); 3921da177e4SLinus Torvalds spin_unlock_irqrestore(&ip32_irq_lock, flags); 3931da177e4SLinus Torvalds } 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds static void mask_and_ack_maceisa_irq(unsigned int irq) 3961da177e4SLinus Torvalds { 3971da177e4SLinus Torvalds unsigned long mace_int, flags; 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds switch (irq) { 4001da177e4SLinus Torvalds case MACEISA_PARALLEL_IRQ: 4011da177e4SLinus Torvalds case MACEISA_SERIAL1_TDMAPR_IRQ: 4021da177e4SLinus Torvalds case MACEISA_SERIAL2_TDMAPR_IRQ: 4031da177e4SLinus Torvalds /* edge triggered */ 4041da177e4SLinus Torvalds spin_lock_irqsave(&ip32_irq_lock, flags); 4051da177e4SLinus Torvalds mace_int = mace->perif.ctrl.istat; 4061da177e4SLinus Torvalds mace_int &= ~(1 << (irq - 33)); 4071da177e4SLinus Torvalds mace->perif.ctrl.istat = mace_int; 4081da177e4SLinus Torvalds spin_unlock_irqrestore(&ip32_irq_lock, flags); 4091da177e4SLinus Torvalds break; 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds disable_maceisa_irq(irq); 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds static void end_maceisa_irq(unsigned irq) 4151da177e4SLinus Torvalds { 4161da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) 4171da177e4SLinus Torvalds enable_maceisa_irq(irq); 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds #define shutdown_maceisa_irq disable_maceisa_irq 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds static struct hw_interrupt_type ip32_maceisa_interrupt = { 4238ab00b9aSRalf Baechle .typename = "IP32 MACE ISA", 4248ab00b9aSRalf Baechle .startup = startup_maceisa_irq, 4258ab00b9aSRalf Baechle .shutdown = shutdown_maceisa_irq, 4268ab00b9aSRalf Baechle .enable = enable_maceisa_irq, 4278ab00b9aSRalf Baechle .disable = disable_maceisa_irq, 4288ab00b9aSRalf Baechle .ack = mask_and_ack_maceisa_irq, 4298ab00b9aSRalf Baechle .end = end_maceisa_irq, 4301da177e4SLinus Torvalds }; 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds /* This is used for regular non-ISA, non-PCI MACE interrupts. That means 4331da177e4SLinus Torvalds * bits 0-3 and 7 in the CRIME register. 4341da177e4SLinus Torvalds */ 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds static void enable_mace_irq(unsigned int irq) 4371da177e4SLinus Torvalds { 4381da177e4SLinus Torvalds unsigned long flags; 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds spin_lock_irqsave(&ip32_irq_lock, flags); 4411da177e4SLinus Torvalds crime_mask |= 1 << (irq - 1); 4421da177e4SLinus Torvalds crime->imask = crime_mask; 4431da177e4SLinus Torvalds spin_unlock_irqrestore(&ip32_irq_lock, flags); 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds static unsigned int startup_mace_irq(unsigned int irq) 4471da177e4SLinus Torvalds { 4481da177e4SLinus Torvalds enable_mace_irq(irq); 4491da177e4SLinus Torvalds return 0; 4501da177e4SLinus Torvalds } 4511da177e4SLinus Torvalds 4521da177e4SLinus Torvalds static void disable_mace_irq(unsigned int irq) 4531da177e4SLinus Torvalds { 4541da177e4SLinus Torvalds unsigned long flags; 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds spin_lock_irqsave(&ip32_irq_lock, flags); 4571da177e4SLinus Torvalds crime_mask &= ~(1 << (irq - 1)); 4581da177e4SLinus Torvalds crime->imask = crime_mask; 4591da177e4SLinus Torvalds flush_crime_bus(); 4601da177e4SLinus Torvalds spin_unlock_irqrestore(&ip32_irq_lock, flags); 4611da177e4SLinus Torvalds } 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds static void end_mace_irq(unsigned int irq) 4641da177e4SLinus Torvalds { 4651da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 4661da177e4SLinus Torvalds enable_mace_irq(irq); 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds #define shutdown_mace_irq disable_mace_irq 4701da177e4SLinus Torvalds #define mask_and_ack_mace_irq disable_mace_irq 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds static struct hw_interrupt_type ip32_mace_interrupt = { 4738ab00b9aSRalf Baechle .typename = "IP32 MACE", 4748ab00b9aSRalf Baechle .startup = startup_mace_irq, 4758ab00b9aSRalf Baechle .shutdown = shutdown_mace_irq, 4768ab00b9aSRalf Baechle .enable = enable_mace_irq, 4778ab00b9aSRalf Baechle .disable = disable_mace_irq, 4788ab00b9aSRalf Baechle .ack = mask_and_ack_mace_irq, 4798ab00b9aSRalf Baechle .end = end_mace_irq, 4801da177e4SLinus Torvalds }; 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds static void ip32_unknown_interrupt(struct pt_regs *regs) 4831da177e4SLinus Torvalds { 4841da177e4SLinus Torvalds printk ("Unknown interrupt occurred!\n"); 4851da177e4SLinus Torvalds printk ("cp0_status: %08x\n", read_c0_status()); 4861da177e4SLinus Torvalds printk ("cp0_cause: %08x\n", read_c0_cause()); 4871da177e4SLinus Torvalds printk ("CRIME intr mask: %016lx\n", crime->imask); 4881da177e4SLinus Torvalds printk ("CRIME intr status: %016lx\n", crime->istat); 4891da177e4SLinus Torvalds printk ("CRIME hardware intr register: %016lx\n", crime->hard_int); 4901da177e4SLinus Torvalds printk ("MACE ISA intr mask: %08lx\n", mace->perif.ctrl.imask); 4911da177e4SLinus Torvalds printk ("MACE ISA intr status: %08lx\n", mace->perif.ctrl.istat); 4921da177e4SLinus Torvalds printk ("MACE PCI control register: %08x\n", mace->pci.control); 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds printk("Register dump:\n"); 4951da177e4SLinus Torvalds show_regs(regs); 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds printk("Please mail this report to linux-mips@linux-mips.org\n"); 4981da177e4SLinus Torvalds printk("Spinning..."); 4991da177e4SLinus Torvalds while(1) ; 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds /* CRIME 1.1 appears to deliver all interrupts to this one pin. */ 5031da177e4SLinus Torvalds /* change this to loop over all edge-triggered irqs, exception masked out ones */ 504*e4ac58afSRalf Baechle static void ip32_irq0(struct pt_regs *regs) 5051da177e4SLinus Torvalds { 5061da177e4SLinus Torvalds uint64_t crime_int; 5071da177e4SLinus Torvalds int irq = 0; 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds crime_int = crime->istat & crime_mask; 5101da177e4SLinus Torvalds irq = ffs(crime_int); 5111da177e4SLinus Torvalds crime_int = 1 << (irq - 1); 5121da177e4SLinus Torvalds 5131da177e4SLinus Torvalds if (crime_int & CRIME_MACEISA_INT_MASK) { 5141da177e4SLinus Torvalds unsigned long mace_int = mace->perif.ctrl.istat; 5151da177e4SLinus Torvalds irq = ffs(mace_int & maceisa_mask) + 32; 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds DBG("*irq %u*\n", irq); 5181da177e4SLinus Torvalds do_IRQ(irq, regs); 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds 521*e4ac58afSRalf Baechle static void ip32_irq1(struct pt_regs *regs) 5221da177e4SLinus Torvalds { 5231da177e4SLinus Torvalds ip32_unknown_interrupt(regs); 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds 526*e4ac58afSRalf Baechle static void ip32_irq2(struct pt_regs *regs) 5271da177e4SLinus Torvalds { 5281da177e4SLinus Torvalds ip32_unknown_interrupt(regs); 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds 531*e4ac58afSRalf Baechle static void ip32_irq3(struct pt_regs *regs) 5321da177e4SLinus Torvalds { 5331da177e4SLinus Torvalds ip32_unknown_interrupt(regs); 5341da177e4SLinus Torvalds } 5351da177e4SLinus Torvalds 536*e4ac58afSRalf Baechle static void ip32_irq4(struct pt_regs *regs) 5371da177e4SLinus Torvalds { 5381da177e4SLinus Torvalds ip32_unknown_interrupt(regs); 5391da177e4SLinus Torvalds } 5401da177e4SLinus Torvalds 541*e4ac58afSRalf Baechle static void ip32_irq5(struct pt_regs *regs) 5421da177e4SLinus Torvalds { 5431da177e4SLinus Torvalds ll_timer_interrupt(IP32_R4K_TIMER_IRQ, regs); 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds 546*e4ac58afSRalf Baechle asmlinkage void plat_irq_dispatch(struct pt_regs *regs) 547*e4ac58afSRalf Baechle { 548*e4ac58afSRalf Baechle unsigned int pending = read_c0_cause(); 549*e4ac58afSRalf Baechle 550*e4ac58afSRalf Baechle if (likely(pending & IE_IRQ0)) 551*e4ac58afSRalf Baechle ip32_irq0(regs); 552*e4ac58afSRalf Baechle else if (unlikely(pending & IE_IRQ1)) 553*e4ac58afSRalf Baechle ip32_irq1(regs); 554*e4ac58afSRalf Baechle else if (unlikely(pending & IE_IRQ2)) 555*e4ac58afSRalf Baechle ip32_irq2(regs); 556*e4ac58afSRalf Baechle else if (unlikely(pending & IE_IRQ3)) 557*e4ac58afSRalf Baechle ip32_irq3(regs); 558*e4ac58afSRalf Baechle else if (unlikely(pending & IE_IRQ4)) 559*e4ac58afSRalf Baechle ip32_irq4(regs); 560*e4ac58afSRalf Baechle else if (likely(pending & IE_IRQ5)) 561*e4ac58afSRalf Baechle ip32_irq5(regs); 562*e4ac58afSRalf Baechle } 563*e4ac58afSRalf Baechle 5641da177e4SLinus Torvalds void __init arch_init_irq(void) 5651da177e4SLinus Torvalds { 5661da177e4SLinus Torvalds unsigned int irq; 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds /* Install our interrupt handler, then clear and disable all 5691da177e4SLinus Torvalds * CRIME and MACE interrupts. */ 5701da177e4SLinus Torvalds crime->imask = 0; 5711da177e4SLinus Torvalds crime->hard_int = 0; 5721da177e4SLinus Torvalds crime->soft_int = 0; 5731da177e4SLinus Torvalds mace->perif.ctrl.istat = 0; 5741da177e4SLinus Torvalds mace->perif.ctrl.imask = 0; 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds for (irq = 0; irq <= IP32_IRQ_MAX; irq++) { 5771da177e4SLinus Torvalds hw_irq_controller *controller; 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds if (irq == IP32_R4K_TIMER_IRQ) 5801da177e4SLinus Torvalds controller = &ip32_cpu_interrupt; 5811da177e4SLinus Torvalds else if (irq <= MACE_PCI_BRIDGE_IRQ && irq >= MACE_VID_IN1_IRQ) 5821da177e4SLinus Torvalds controller = &ip32_mace_interrupt; 5831da177e4SLinus Torvalds else if (irq <= MACEPCI_SHARED2_IRQ && irq >= MACEPCI_SCSI0_IRQ) 5841da177e4SLinus Torvalds controller = &ip32_macepci_interrupt; 5851da177e4SLinus Torvalds else if (irq <= CRIME_VICE_IRQ && irq >= CRIME_GBE0_IRQ) 5861da177e4SLinus Torvalds controller = &ip32_crime_interrupt; 5871da177e4SLinus Torvalds else 5881da177e4SLinus Torvalds controller = &ip32_maceisa_interrupt; 5891da177e4SLinus Torvalds 5901da177e4SLinus Torvalds irq_desc[irq].status = IRQ_DISABLED; 5911da177e4SLinus Torvalds irq_desc[irq].action = 0; 5921da177e4SLinus Torvalds irq_desc[irq].depth = 0; 5931da177e4SLinus Torvalds irq_desc[irq].handler = controller; 5941da177e4SLinus Torvalds } 5951da177e4SLinus Torvalds setup_irq(CRIME_MEMERR_IRQ, &memerr_irq); 5961da177e4SLinus Torvalds setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq); 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) 5991da177e4SLinus Torvalds change_c0_status(ST0_IM, ALLINTS); 6001da177e4SLinus Torvalds } 601