X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/2bf999256c36fedccf995c6301c15006eb22fe08..569469732686781aefa920944fa95495e1210c73:/target/linux/aruba-2.6/patches/002-irq.patch?ds=sidebyside diff --git a/target/linux/aruba-2.6/patches/002-irq.patch b/target/linux/aruba-2.6/patches/002-irq.patch index d789a2104..101ed78a5 100644 --- a/target/linux/aruba-2.6/patches/002-irq.patch +++ b/target/linux/aruba-2.6/patches/002-irq.patch @@ -1,102 +1,12 @@ -diff -Nur linux-2.6.15/arch/mips/aruba/idtIRQ.S linux-2.6.15-openwrt/arch/mips/aruba/idtIRQ.S ---- linux-2.6.15/arch/mips/aruba/idtIRQ.S 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.15-openwrt/arch/mips/aruba/idtIRQ.S 2006-01-10 00:32:32.000000000 +0100 -@@ -0,0 +1,87 @@ +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 -+ * Intterrupt dispatcher code for IDT boards -+ * -+ * 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 -+ * -+ * -+ * -+ ************************************************************************** -+ */ -+ -+ -+#include -+#include -+#include -+#include -+ -+ .text -+ .set noreorder -+ .set noat -+ .align 5 -+ NESTED(idtIRQ, PT_SIZE, sp) -+ .set noat -+ SAVE_ALL -+ CLI -+ -+ .set at -+ .set noreorder -+ -+ /* Get the pending interrupts */ -+ mfc0 t0, CP0_CAUSE -+ nop -+ -+ /* Isolate the allowed ones by anding the irq mask */ -+ mfc0 t2, CP0_STATUS -+ move a1, sp /* need a nop here, hence we anticipate */ -+ andi t0, CAUSEF_IP -+ and t0, t2 -+ -+ /* check for r4k counter/timer IRQ. */ -+ -+ andi t1, t0, CAUSEF_IP7 -+ beqz t1, 1f -+ nop -+ -+ jal aruba_timer_interrupt -+ -+ li a0, 7 -+ -+ j ret_from_irq -+ nop -+1: -+ jal aruba_irqdispatch -+ move a0, t0 -+ j ret_from_irq -+ nop -+ -+ END(idtIRQ) -+ -+ -diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/aruba/irq.c ---- linux-2.6.15/arch/mips/aruba/irq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.15-openwrt/arch/mips/aruba/irq.c 2006-01-10 00:32:32.000000000 +0100 -@@ -0,0 +1,393 @@ -+/************************************************************************** -+ * -+ * BRIEF MODULE DESCRIPTION -+ * Interrupt routines for IDT EB434 boards ++ * Interrupt routines for IDT EB434 boards / Atheros boards ++ * Modified by Aruba Networks + * + * Copyright 2004 IDT Inc. (rischelp@idt.com) + * @@ -163,7 +73,7 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub +#define DPRINTK(fmt, args...) +#endif + -+extern asmlinkage void idtIRQ(void); ++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); @@ -182,8 +92,8 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub +}; + +#define READ_PEND_MERLOT(base) (*((volatile unsigned long *)(0xbc003010))) -+#define READ_MASK_MERLOT(base) (*((volatile unsigned long *)(0xbc003010 + 4))) -+#define WRITE_MASK_MERLOT(base, val) ((*((volatile unsigned long *)((0xbc003010) + 4))) = (val)) ++#define READ_MASK_MERLOT(base) (*((volatile unsigned long *)(0xbc003014))) ++#define WRITE_MASK_MERLOT(base, val) ((*((volatile unsigned long *)(0xbc003014))) = (val), READ_MASK_MERLOT()) + +static const intr_group_t intr_group_muscat[NUM_INTR_GROUPS] = { + {0x0000efff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)}, @@ -223,28 +133,26 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub + +static inline void enable_local_irq(unsigned int ip) +{ -+ int ipnum = 0x100 << ip; -+ clear_c0_cause(ipnum); -+ set_c0_status(ipnum); ++ set_c0_status(0x100 << ip); ++ irq_enable_hazard(); +} + +static inline void disable_local_irq(unsigned int ip) +{ -+ int ipnum = 0x100 << ip; -+ clear_c0_status(ipnum); -+} -+ -+static inline void ack_local_irq(unsigned int ip) -+{ -+ int ipnum = 0x100 << ip; -+ clear_c0_cause(ipnum); ++ clear_c0_status(0x100 << ip); ++ irq_disable_hazard(); +} + +static void aruba_enable_irq(unsigned int irq_nr) +{ ++ unsigned long flags; + int ip = irq_nr - GROUP0_IRQ_BASE; + unsigned int group, intr_bit; + volatile unsigned int *addr; ++ ++ ++ local_irq_save(flags); ++ + if (ip < 0) { + enable_local_irq(irq_nr); + } else { @@ -264,13 +172,9 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub + ip -= (group << 5); + intr_bit = 1 << ip; + -+ // first enable the IP mapped to this IRQ -+ enable_local_irq(group_to_ip(group)); -+ + switch (mips_machtype) { + case MACH_ARUBA_AP70: + 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: @@ -280,58 +184,73 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub + WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit); + break; + } ++ enable_local_irq(group_to_ip(group)); + } ++ ++ back_to_back_c0_hazard(); ++ local_irq_restore(flags); ++ +} + +static void aruba_disable_irq(unsigned int irq_nr) +{ ++ unsigned long flags; + int ip = irq_nr - GROUP0_IRQ_BASE; + unsigned int group, intr_bit, mask; + volatile unsigned int *addr; + -+ // calculate group -+ switch (mips_machtype) { -+ case MACH_ARUBA_AP70: -+ group = ip >> 5; -+ break; -+ case MACH_ARUBA_AP65: -+ case MACH_ARUBA_AP60: -+ default: -+ group = 0; -+ break; -+ } ++ local_irq_save(flags); ++ ++ if (ip < 0) { ++ disable_local_irq(irq_nr); ++ } else { ++ // calculate group ++ switch (mips_machtype) { ++ case MACH_ARUBA_AP70: ++ group = ip >> 5; ++ break; ++ case MACH_ARUBA_AP65: ++ case MACH_ARUBA_AP60: ++ default: ++ group = 0; ++ break; ++ } + -+ // calc interrupt bit within group -+ ip -= group << 5; -+ intr_bit = 1 << ip; ++ // calc interrupt bit within group ++ ip -= group << 5; ++ intr_bit = 1 << ip; + -+ switch (mips_machtype) { -+ case MACH_ARUBA_AP70: -+ addr = intr_group_muscat[group].base_addr; -+ // mask intr within group -+ mask = READ_MASK_MUSCAT(addr); -+ mask |= intr_bit; -+ WRITE_MASK_MUSCAT(addr, mask); ++ switch (mips_machtype) { ++ case MACH_ARUBA_AP70: ++ 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) -+ disable_local_irq(group_to_ip(group)); -+ break; -+ case MACH_ARUBA_AP65: -+ case MACH_ARUBA_AP60: -+ default: -+ addr = intr_group_merlot[group].base_addr; -+ // mask intr within group -+ mask = READ_MASK_MERLOT(addr); -+ mask &= ~intr_bit; -+ WRITE_MASK_MERLOT(addr, mask); -+ if (!mask) -+ disable_local_irq(group_to_ip(group)); -+ break; ++ /* ++ if there are no more interrupts enabled in this ++ group, disable corresponding IP ++ */ ++ if (mask == intr_group_muscat[group].mask) ++ disable_local_irq(group_to_ip(group)); ++ break; ++ case MACH_ARUBA_AP65: ++ case MACH_ARUBA_AP60: ++ default: ++ 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); ++ break; ++ } + } ++ ++ back_to_back_c0_hazard(); ++ local_irq_restore(flags); +} + +static unsigned int startup_irq(unsigned int irq_nr) @@ -343,13 +262,11 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub +static void shutdown_irq(unsigned int irq_nr) +{ + aruba_disable_irq(irq_nr); -+ return; +} + +static void mask_and_ack_irq(unsigned int irq_nr) +{ + aruba_disable_irq(irq_nr); -+ ack_local_irq(group_to_ip(irq_to_group(irq_nr))); +} + +static void end_irq(unsigned int irq_nr) @@ -359,50 +276,62 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub + 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 ++ */ + -+ 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: -+ group = 0; ++ } + -+ // calc interrupt bit within group -+ intr_bit = 1 << ip; ++ if (ip<0) { ++ enable_local_irq(irq_nr); ++ } else { + -+ // first enable the IP mapped to this IRQ -+ enable_local_irq(group_to_ip(group)); ++ 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; + -+ addr = intr_group_merlot[group].base_addr; -+ // unmask intr within group -+ WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(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; ++ } + } +} + +static struct hw_interrupt_type aruba_irq_type = { -+ .typename = "IDT434", ++ .typename = "ARUBA", + .startup = startup_irq, + .shutdown = shutdown_irq, + .enable = aruba_enable_irq, @@ -416,7 +345,8 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub + int i; + printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS); + memset(irq_desc, 0, sizeof(irq_desc)); -+ set_except_vector(0, idtIRQ); ++ ++ set_c0_status(0xFF00); + + for (i = 0; i < RC32434_NR_IRQS; i++) { + irq_desc[i].status = IRQ_DISABLED; @@ -425,24 +355,36 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub + irq_desc[i].handler = &aruba_irq_type; + spin_lock_init(&irq_desc[i].lock); + } -+ -+ switch (mips_machtype) { -+ case MACH_ARUBA_AP70: -+ break; -+ case MACH_ARUBA_AP65: -+ case MACH_ARUBA_AP60: -+ default: -+ WRITE_MASK_MERLOT(intr_group_merlot[0].base_addr, 0); -+ *((volatile unsigned long *)0xbc003014) = 0x10; -+ break; -+ } +} + +/* Main Interrupt dispatcher */ -+void aruba_irqdispatch(unsigned long cp0_cause, struct pt_regs *regs) ++ ++void plat_irq_dispatch(struct pt_regs *regs) +{ + unsigned int pend, group, ip; + volatile unsigned int *addr; ++ unsigned long cp0_cause = read_c0_cause() & read_c0_status() & CAUSEF_IP; ++ ++ if (cp0_cause & CAUSEF_IP7) ++ return aruba_timer_interrupt(regs); ++ ++ if(cp0_cause == 0) { ++ printk("INTERRUPT(S) FIRED WHILE MASKED\n"); ++#ifdef ARUBA_DEBUG ++ // debuging use -- figure out which interrupt(s) fired ++ cp0_cause = read_c0_cause() & CAUSEF_IP; ++ 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; ++ printk(" ---> MASKED IRQ %d\n",irq_nr); ++ cp0_cause &= ~(1 << intr_bit); ++ } ++#endif ++ return; ++ } ++ + switch (mips_machtype) { + case MACH_ARUBA_AP70: + if ((ip = (cp0_cause & 0x7c00))) { @@ -459,28 +401,35 @@ diff -Nur linux-2.6.15/arch/mips/aruba/irq.c linux-2.6.15-openwrt/arch/mips/arub + case MACH_ARUBA_AP65: + case MACH_ARUBA_AP60: + default: -+ if (cp0_cause & 0x4000) { ++ 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 int intr_bit, irq_nr; -+ intr_bit = pend ^ (pend - 1); -+ irq_nr = ((31 - rc32434_clz(pend)) + GROUP0_IRQ_BASE); ++ 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 &= ~intr_bit; ++ pend &= ~(1 << intr_bit); + } -+ } -+ if (cp0_cause & 0x3c00) { -+ while (cp0_cause) { -+ unsigned int intr_bit, irq_nr; -+ intr_bit = cp0_cause ^ (cp0_cause - 1); -+ irq_nr = ((31 - rc32434_clz(cp0_cause)) - GROUP0_IRQ_BASE); ++ } 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 &= ~intr_bit; ++ cp0_cause &= ~(1 << intr_bit); + } + } + break;