From 286d6f8bc498890a8452d9582643908e892b4a22 Mon Sep 17 00:00:00 2001 From: Mike Baker Date: Thu, 12 Oct 2006 22:54:48 +0000 Subject: [PATCH] rewrite of platform irq handler SVN-Revision: 5057 --- .../linux/aruba-2.6/patches/002-irq.patch | 309 +++++------------- 1 file changed, 79 insertions(+), 230 deletions(-) diff --git a/openwrt/target/linux/aruba-2.6/patches/002-irq.patch b/openwrt/target/linux/aruba-2.6/patches/002-irq.patch index 101ed78a55..f6b9425d8d 100644 --- a/openwrt/target/linux/aruba-2.6/patches/002-irq.patch +++ b/openwrt/target/linux/aruba-2.6/patches/002-irq.patch @@ -1,46 +1,7 @@ diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/aruba/irq.c --- linux-2.6.17/arch/mips/aruba/irq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.17-openwrt/arch/mips/aruba/irq.c 2006-01-10 00:32:32.000000000 +0100 -@@ -0,0 +1,433 @@ -+/************************************************************************** -+ * -+ * BRIEF MODULE DESCRIPTION -+ * Interrupt routines for IDT EB434 boards / Atheros boards -+ * Modified by Aruba Networks -+ * -+ * Copyright 2004 IDT Inc. (rischelp@idt.com) -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN -+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * -+ ************************************************************************** -+ * May 2004 rkt, neb -+ * -+ * Initial Release -+ * -+ * -+ * -+ ************************************************************************** -+ */ -+ ++++ linux-2.6.17-openwrt/arch/mips/aruba/irq.c 2006-10-12 14:32:40.026285000 -0700 +@@ -0,0 +1,282 @@ +#include +#include +#include @@ -65,22 +26,7 @@ diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/arub + +#include + -+#undef DEBUG_IRQ -+#ifdef DEBUG_IRQ -+/* note: prints function name for you */ -+#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) -+#else -+#define DPRINTK(fmt, args...) -+#endif -+ +extern void aruba_timer_interrupt(struct pt_regs *regs); -+static unsigned int startup_irq(unsigned int irq); -+static void end_irq(unsigned int irq_nr); -+static void mask_and_ack_irq(unsigned int irq_nr); -+static void aruba_enable_irq(unsigned int irq_nr); -+static void aruba_disable_irq(unsigned int irq_nr); -+ -+extern void __init init_generic_irq(void); + +typedef struct { + u32 mask; @@ -88,7 +34,7 @@ diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/arub +} intr_group_t; + +static const intr_group_t intr_group_merlot[NUM_INTR_GROUPS] = { -+ {0xffffffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0)}, ++ {0x00000000, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0)}, +}; + +#define READ_PEND_MERLOT(base) (*((volatile unsigned long *)(0xbc003010))) @@ -107,18 +53,6 @@ diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/arub +#define READ_MASK_MUSCAT(base) (*(base + 2)) +#define WRITE_MASK_MUSCAT(base, val) (*(base + 2) = (val)) + -+static inline int irq_to_group(unsigned int irq_nr) -+{ -+ switch (mips_machtype) { -+ case MACH_ARUBA_AP70: -+ return ((irq_nr - GROUP0_IRQ_BASE) >> 5); -+ case MACH_ARUBA_AP65: -+ case MACH_ARUBA_AP60: -+ default: -+ return 0; -+ } -+} -+ +static inline int group_to_ip(unsigned int group) +{ + switch (mips_machtype) { @@ -131,55 +65,51 @@ diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/arub + } +} + -+static inline void enable_local_irq(unsigned int ip) ++static inline void enable_local_irq(unsigned int irq) +{ -+ set_c0_status(0x100 << ip); ++ clear_c0_cause(0x100 << irq); ++ set_c0_status(0x100 << irq); + irq_enable_hazard(); +} + -+static inline void disable_local_irq(unsigned int ip) ++static inline void disable_local_irq(unsigned int irq) +{ -+ clear_c0_status(0x100 << ip); ++ clear_c0_status(0x100 << irq); ++ clear_c0_cause(0x100 << irq); + irq_disable_hazard(); +} + -+static void aruba_enable_irq(unsigned int irq_nr) ++static inline void aruba_irq_enable(unsigned int irq) +{ + unsigned long flags; -+ int ip = irq_nr - GROUP0_IRQ_BASE; -+ unsigned int group, intr_bit; -+ volatile unsigned int *addr; -+ ++ unsigned int group, intr_bit; ++ volatile unsigned int *addr; + + local_irq_save(flags); -+ -+ if (ip < 0) { -+ enable_local_irq(irq_nr); ++ ++ if (irq < GROUP0_IRQ_BASE) { ++ enable_local_irq(irq); + } else { -+ // calculate group ++ int ip = irq - GROUP0_IRQ_BASE; + switch (mips_machtype) { + case MACH_ARUBA_AP70: ++ // irqs are in groups of 32 ++ // ip is set to the remainder + group = ip >> 5; -+ break; -+ case MACH_ARUBA_AP65: -+ case MACH_ARUBA_AP60: -+ default: -+ group = 0; -+ break; -+ } ++ ip &= 0x1f; + -+ // calc interrupt bit within group -+ ip -= (group << 5); -+ intr_bit = 1 << ip; -+ -+ switch (mips_machtype) { -+ case MACH_ARUBA_AP70: ++ // bit -> 0 = unmask ++ intr_bit = 1 << ip; + addr = intr_group_muscat[group].base_addr; + WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit); + break; ++ + case MACH_ARUBA_AP65: + case MACH_ARUBA_AP60: -+ default: ++ group = 0; ++ ++ // bit -> 1 = unmasked ++ intr_bit = 1 << ip; + addr = intr_group_merlot[group].base_addr; + WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit); + break; @@ -189,62 +119,57 @@ diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/arub + + back_to_back_c0_hazard(); + local_irq_restore(flags); -+ +} + -+static void aruba_disable_irq(unsigned int irq_nr) ++static void aruba_irq_disable(unsigned int irq) +{ + unsigned long flags; -+ int ip = irq_nr - GROUP0_IRQ_BASE; -+ unsigned int group, intr_bit, mask; -+ volatile unsigned int *addr; ++ unsigned int group, intr_bit, mask; ++ volatile unsigned int *addr; + + local_irq_save(flags); + -+ if (ip < 0) { -+ disable_local_irq(irq_nr); ++ if (irq < GROUP0_IRQ_BASE) { ++ disable_local_irq(irq); + } else { -+ // calculate group ++ int ip = irq - GROUP0_IRQ_BASE; + switch (mips_machtype) { + case MACH_ARUBA_AP70: ++ idt_gpio->gpioistat &= ~(1 << ip); ++ ++ // irqs are in groups of 32 ++ // ip is set to the remainder + group = ip >> 5; -+ break; -+ case MACH_ARUBA_AP65: -+ case MACH_ARUBA_AP60: -+ default: -+ group = 0; -+ break; -+ } ++ ip &= 0x1f; + -+ // calc interrupt bit within group -+ ip -= group << 5; -+ intr_bit = 1 << ip; -+ -+ switch (mips_machtype) { -+ case MACH_ARUBA_AP70: ++ // bit -> 1 = mask ++ intr_bit = 1 << ip; + addr = intr_group_muscat[group].base_addr; -+ // mask intr within group ++ + mask = READ_MASK_MUSCAT(addr); + mask |= intr_bit; + WRITE_MASK_MUSCAT(addr, mask); -+ -+ /* -+ if there are no more interrupts enabled in this -+ group, disable corresponding IP -+ */ -+ if (mask == intr_group_muscat[group].mask) ++ ++ if (mask == intr_group_muscat[group].mask) { + disable_local_irq(group_to_ip(group)); ++ } + break; ++ + case MACH_ARUBA_AP65: + case MACH_ARUBA_AP60: -+ default: ++ group = 0; ++ ++ // bit -> 0 = masked ++ intr_bit = 1 << ip; + addr = intr_group_merlot[group].base_addr; -+ // mask intr within group ++ + mask = READ_MASK_MERLOT(addr); + mask &= ~intr_bit; -+ if (!mask) -+ disable_local_irq(group_to_ip(group)); + WRITE_MASK_MERLOT(addr, mask); ++ ++ if (mask == intr_group_merlot[group].mask) { ++ disable_local_irq(group_to_ip(group)); ++ } + break; + } + } @@ -253,91 +178,33 @@ diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/arub + local_irq_restore(flags); +} + -+static unsigned int startup_irq(unsigned int irq_nr) ++static unsigned int aruba_irq_startup(unsigned int irq) +{ -+ aruba_enable_irq(irq_nr); ++ aruba_irq_enable(irq); + return 0; +} + -+static void shutdown_irq(unsigned int irq_nr) ++#define aruba_irq_shutdown aruba_irq_disable ++ ++static void aruba_irq_ack(unsigned int irq) +{ -+ aruba_disable_irq(irq_nr); ++ aruba_irq_disable(irq); +} + -+static void mask_and_ack_irq(unsigned int irq_nr) ++static void aruba_irq_end(unsigned int irq) +{ -+ aruba_disable_irq(irq_nr); -+} -+ -+static void end_irq(unsigned int irq_nr) -+{ -+ -+ int ip = irq_nr - GROUP0_IRQ_BASE; -+ unsigned int intr_bit, group; -+ volatile unsigned int *addr; -+ -+ -+ if (irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS)) { -+ printk("warning: end_irq %d did not enable (%x)\n", -+ irq_nr, irq_desc[irq_nr].status); -+ /* fall through; enable the interrupt -+ * -- It'll get stuck otherwise -+ */ -+ -+ } -+ -+ if (ip<0) { -+ enable_local_irq(irq_nr); -+ } else { -+ -+ switch (mips_machtype) { -+ case MACH_ARUBA_AP70: -+ if (irq_nr == GROUP4_IRQ_BASE + 9) idt_gpio->gpioistat &= 0xfffffdff; -+ else if (irq_nr == GROUP4_IRQ_BASE + 10) idt_gpio->gpioistat &= 0xfffffbff; -+ else if (irq_nr == GROUP4_IRQ_BASE + 11) idt_gpio->gpioistat &= 0xfffff7ff; -+ else if (irq_nr == GROUP4_IRQ_BASE + 12) idt_gpio->gpioistat &= 0xffffefff; -+ -+ group = ip >> 5; -+ -+ // calc interrupt bit within group -+ ip -= (group << 5); -+ intr_bit = 1 << ip; -+ -+ // first enable the IP mapped to this IRQ -+ enable_local_irq(group_to_ip(group)); -+ -+ addr = intr_group_muscat[group].base_addr; -+ // unmask intr within group -+ WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit); -+ break; -+ -+ case MACH_ARUBA_AP65: -+ case MACH_ARUBA_AP60: -+ default: -+ group = 0; -+ -+ // calc interrupt bit within group -+ intr_bit = 1 << ip; -+ -+ // first enable the IP mapped to this IRQ -+ enable_local_irq(group_to_ip(group)); -+ -+ addr = intr_group_merlot[group].base_addr; -+ // unmask intr within group -+ WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit); -+ break; -+ } -+ } ++ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) ++ aruba_irq_enable(irq); +} + +static struct hw_interrupt_type aruba_irq_type = { -+ .typename = "ARUBA", -+ .startup = startup_irq, -+ .shutdown = shutdown_irq, -+ .enable = aruba_enable_irq, -+ .disable = aruba_disable_irq, -+ .ack = mask_and_ack_irq, -+ .end = end_irq, ++ .typename = "ARUBA", ++ .startup = aruba_irq_startup, ++ .shutdown = aruba_irq_shutdown, ++ .enable = aruba_irq_enable, ++ .disable = aruba_irq_disable, ++ .ack = aruba_irq_ack, ++ .end = aruba_irq_end, +}; + +void __init arch_init_irq(void) @@ -346,8 +213,6 @@ diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/arub + printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS); + memset(irq_desc, 0, sizeof(irq_desc)); + -+ set_c0_status(0xFF00); -+ + for (i = 0; i < RC32434_NR_IRQS; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; @@ -393,9 +258,9 @@ diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/arub + addr = intr_group_muscat[group].base_addr; + + pend = READ_PEND_MUSCAT(addr); -+ pend &= ~READ_MASK_MUSCAT(addr); // only unmasked interrupts ++ pend &= ~READ_MASK_MUSCAT(addr); // only unmasked interrupts + pend = 39 - rc32434_clz(pend); -+ do_IRQ((group << 5) + pend, regs); ++ do_IRQ(pend + (group << 5), regs); + } + break; + case MACH_ARUBA_AP65: @@ -404,33 +269,17 @@ diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/arub + if (cp0_cause & 0x4000) { // 1 << (8 +6) == irq 6 + // Misc Interrupt + group = 0; ++ + addr = intr_group_merlot[group].base_addr; ++ + pend = READ_PEND_MERLOT(addr); + pend &= READ_MASK_MERLOT(addr); // only unmasked interrupts -+ /* handle one misc interrupt at a time */ -+ while (pend) -+ { -+ unsigned long intr_bit; -+ unsigned int irq_nr; -+ -+ intr_bit = (31 - rc32434_clz(pend)); -+ irq_nr = intr_bit + GROUP0_IRQ_BASE; -+ -+ do_IRQ(irq_nr, regs); -+ pend &= ~(1 << intr_bit); -+ } -+ } else if (cp0_cause & 0x3c00) { // irq 2-5 -+ while (cp0_cause) -+ { -+ unsigned long intr_bit; -+ unsigned int irq_nr; -+ -+ intr_bit = (31 - rc32434_clz(cp0_cause)); -+ irq_nr = intr_bit - GROUP0_IRQ_BASE; -+ -+ do_IRQ(irq_nr, regs); -+ cp0_cause &= ~(1 << intr_bit); -+ } ++ pend = 31 - rc32434_clz(pend); ++ do_IRQ(pend + GROUP0_IRQ_BASE, regs); ++ } ++ if ((ip = (cp0_cause & 0x3c00))) { // irq 2-5 ++ pend = 31 - rc32434_clz(ip); ++ do_IRQ(pend - GROUP0_IRQ_BASE, regs); + } + break; + }