From 286d6f8bc498890a8452d9582643908e892b4a22 Mon Sep 17 00:00:00 2001
From: Mike Baker <mbm@openwrt.org>
Date: Thu, 12 Oct 2006 22:54:48 +0000
Subject: rewrite of platform irq handler

SVN-Revision: 5057
---
 .../target/linux/aruba-2.6/patches/002-irq.patch   | 307 ++++++---------------
 1 file changed, 78 insertions(+), 229 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 <linux/errno.h>
 +#include <linux/init.h>
 +#include <linux/kernel_stat.h>
@@ -65,22 +26,7 @@ diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/arub
 +
 +#include <asm/irq.h>
 +
-+#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;
-+		}
-+
-+		// calc interrupt bit within group
-+		ip -= (group << 5);
-+		intr_bit = 1 << ip;
++				ip &= 0x1f;
 +
-+		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:
-+				group = ip >> 5;
-+				break;
-+			case MACH_ARUBA_AP65:
-+			case MACH_ARUBA_AP60:
-+			default:
-+				group = 0;
-+				break;
-+		}
++				idt_gpio->gpioistat &= ~(1 << ip);
 +
-+		// calc interrupt bit within group
-+		ip -= group << 5;
-+		intr_bit = 1 << ip;
++				// irqs are in groups of 32
++				// ip is set to the remainder
++				group = ip >> 5;
++				ip &= 0x1f;
 +
-+		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)
-+{
-+	aruba_disable_irq(irq_nr);
-+}
++#define aruba_irq_shutdown aruba_irq_disable
 +
-+static void mask_and_ack_irq(unsigned int irq_nr)
++static void aruba_irq_ack(unsigned int irq)
 +{
-+	aruba_disable_irq(irq_nr);
++	aruba_irq_disable(irq);
 +}
 +
-+static void end_irq(unsigned int irq_nr)
++static void aruba_irq_end(unsigned int irq)
 +{
-+
-+	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;
 +	}
-- 
cgit v1.2.3