diff options
| -rw-r--r-- | target/linux/ar7/files/arch/mips/ar7/irq.c | 172 | 
1 files changed, 78 insertions, 94 deletions
| diff --git a/target/linux/ar7/files/arch/mips/ar7/irq.c b/target/linux/ar7/files/arch/mips/ar7/irq.c index 1a09aedc1..44cce5c40 100644 --- a/target/linux/ar7/files/arch/mips/ar7/irq.c +++ b/target/linux/ar7/files/arch/mips/ar7/irq.c @@ -1,28 +1,26 @@  /*   * $Id$ - *  + *   * Copyright (C) 2006, 2007 OpenWrt.org - *  + *   * 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 program is distributed in the hope that it will be useful,   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * GNU General Public License for more details. - *  + *   * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA   */ -#include <linux/init.h>  #include <linux/interrupt.h> -#include <linux/ioport.h> +#include <linux/io.h> -#include <asm/irq.h>  #include <asm/irq_cpu.h>  #include <asm/mipsregs.h>  #include <asm/ar7/ar7.h> @@ -45,76 +43,75 @@  #define PM_OFFSET(irq)  (REG_OFFSET(irq, 5))    /* 0x50 */  #define TM_OFFSET(irq)  (REG_OFFSET(irq, 6))    /* 0x60 */ -#define REG(addr) (*(volatile u32 *)(KSEG1ADDR(AR7_REGS_IRQ) + addr)) +#define REG(addr) ((u32 *)(KSEG1ADDR(AR7_REGS_IRQ) + addr))  #define CHNL_OFFSET(chnl) (CHNLS_OFFSET + (chnl * 4))  static void ar7_unmask_irq(unsigned int irq_nr);  static void ar7_mask_irq(unsigned int irq_nr); -static void ar7_unmask_secondary_irq(unsigned int irq_nr); -static void ar7_mask_secondary_irq(unsigned int irq_nr); -static irqreturn_t ar7_cascade(int interrupt, void *dev); -static irqreturn_t ar7_secondary_cascade(int interrupt, void *dev); +static void ar7_ack_irq(unsigned int irq_nr); +static void ar7_unmask_sec_irq(unsigned int irq_nr); +static void ar7_mask_sec_irq(unsigned int irq_nr); +static void ar7_ack_sec_irq(unsigned int irq_nr); +static void ar7_cascade(void);  static void ar7_irq_init(int base);  static int ar7_irq_base;  static struct irq_chip ar7_irq_type = { -	.typename = "AR7",  	.name = "AR7",  	.unmask = ar7_unmask_irq,  	.mask = ar7_mask_irq, +	.ack = ar7_ack_irq  }; -static struct irq_chip ar7_secondary_irq_type = { +static struct irq_chip ar7_sec_irq_type = {  	.name = "AR7", -	.unmask = ar7_unmask_secondary_irq, -	.mask = ar7_mask_secondary_irq, +	.unmask = ar7_unmask_sec_irq, +	.mask = ar7_mask_sec_irq, +	.ack = ar7_ack_sec_irq,  };  static struct irqaction ar7_cascade_action = { -	.handler = ar7_cascade,  +	.handler = no_action,  	.name = "AR7 cascade interrupt"  }; -static struct irqaction ar7_secondary_cascade_action = { -	.handler = ar7_secondary_cascade,  +static struct irqaction ar7_sec_cascade_action = { +	.handler = no_action,  	.name = "AR7 secondary cascade interrupt"  };  static void ar7_unmask_irq(unsigned int irq)  { -	unsigned long flags; -	local_irq_save(flags); -	/* enable the interrupt channel  bit */ -	REG(ESR_OFFSET(irq)) = 1 << ((irq - ar7_irq_base) % 32); -	local_irq_restore(flags); +	writel(1 << ((irq - ar7_irq_base) % 32), +	       REG(ESR_OFFSET(irq - ar7_irq_base)));  }  static void ar7_mask_irq(unsigned int irq)  { -	unsigned long flags; -	local_irq_save(flags); -	/* disable the interrupt channel bit */ -	REG(ECR_OFFSET(irq)) = 1 << ((irq - ar7_irq_base) % 32); -	local_irq_restore(flags); +	writel(1 << ((irq - ar7_irq_base) % 32), +	       REG(ECR_OFFSET(irq - ar7_irq_base)));  } -static void ar7_unmask_secondary_irq(unsigned int irq) +static void ar7_ack_irq(unsigned int irq)  { -	unsigned long flags; -	local_irq_save(flags); -	/* enable the interrupt channel  bit */ -	REG(SEC_ESR_OFFSET) = 1 << (irq - ar7_irq_base - 40); -	local_irq_restore(flags); +	writel(1 << ((irq - ar7_irq_base) % 32), +	       REG(CR_OFFSET(irq - ar7_irq_base)));  } -static void ar7_mask_secondary_irq(unsigned int irq) +static void ar7_unmask_sec_irq(unsigned int irq)  { -	unsigned long flags; -	local_irq_save(flags); -	/* disable the interrupt channel bit */ -	REG(SEC_ECR_OFFSET) = 1 << (irq - ar7_irq_base - 40); -	local_irq_restore(flags); +	writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET)); +} + +static void ar7_mask_sec_irq(unsigned int irq) +{ +	writel(1 << (irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET)); +} + +static void ar7_ack_sec_irq(unsigned int irq) +{ +	writel(1 << (irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET));  }  void __init arch_init_irq(void) { @@ -125,81 +122,68 @@ void __init arch_init_irq(void) {  static void __init ar7_irq_init(int base)  {  	int i; -	/*   -	    Disable interrupts and clear pending -	*/ -	REG(ECR_OFFSET(0)) = 0xffffffff; -	REG(ECR_OFFSET(32)) = 0xff; -	REG(SEC_ECR_OFFSET) = 0xffffffff; -	REG(CR_OFFSET(0)) = 0xffffffff; -	REG(CR_OFFSET(32)) = 0xff; -	REG(SEC_CR_OFFSET) = 0xffffffff; +	/* +	 * Disable interrupts and clear pending +	 */ +	writel(0xffffffff, REG(ECR_OFFSET(0))); +	writel(0xff, REG(ECR_OFFSET(32))); +	writel(0xffffffff, REG(SEC_ECR_OFFSET)); +	writel(0xffffffff, REG(CR_OFFSET(0))); +	writel(0xff, REG(CR_OFFSET(32))); +	writel(0xffffffff, REG(SEC_CR_OFFSET));  	ar7_irq_base = base; -	for(i = 0; i < 40; i++) { -		REG(CHNL_OFFSET(i)) = i; +	for (i = 0; i < 40; i++) { +		writel(i, REG(CHNL_OFFSET(i)));  		/* Primary IRQ's */ -		irq_desc[i + base].status = IRQ_DISABLED; -		irq_desc[i + base].action = NULL; -		irq_desc[i + base].depth = 1; -		irq_desc[i + base].chip = &ar7_irq_type; +		set_irq_chip_and_handler(base + i, &ar7_irq_type, +					 handle_level_irq);  		/* Secondary IRQ's */ -		if (i < 32) { -			irq_desc[i + base + 40].status = IRQ_DISABLED; -			irq_desc[i + base + 40].action = NULL; -			irq_desc[i + base + 40].depth = 1; -			irq_desc[i + base + 40].chip = &ar7_secondary_irq_type; -		} +		if (i < 32) +			set_irq_chip_and_handler(base + i + 40, +						 &ar7_sec_irq_type, +						 handle_level_irq);  	}  	setup_irq(2, &ar7_cascade_action); -	setup_irq(ar7_irq_base, &ar7_secondary_cascade_action); +	setup_irq(ar7_irq_base, &ar7_sec_cascade_action);  	set_c0_status(IE_IRQ0);  } -static irqreturn_t ar7_cascade(int interrupt, void *dev) +static void ar7_cascade(void)  { -	int irq; - -	irq = (REG(PIR_OFFSET) & 0x3F); -	REG(CR_OFFSET(irq)) = 1 << (irq % 32); - -	do_IRQ(irq + ar7_irq_base); - -	return IRQ_HANDLED; -} - -static irqreturn_t ar7_secondary_cascade(int interrupt, void *dev) -{ -	int irq = 0, i; -	unsigned long status; - -	status = REG(SEC_SR_OFFSET); -	if (unlikely(!status)) { -		spurious_interrupt(); -		return IRQ_NONE; +	u32 status; +	int i, irq; + +	/* Primary IRQ's */ +	irq = readl(REG(PIR_OFFSET)) & 0x3f; +	if (irq) { +		do_IRQ(ar7_irq_base + irq); +		return;  	} -	for (i = 0; i < 32; i++) -		if (status & (i << 1)) { -			irq = i + 40; -			REG(SEC_CR_OFFSET) = 1 << i; -			break; +	/* Secondary IRQ's are cascaded through primary '0' */ +	writel(1, REG(CR_OFFSET(irq))); +	status = readl(REG(SEC_SR_OFFSET)); +	for (i = 0; i < 32; i++) { +		if (status & 1) { +			do_IRQ(ar7_irq_base + i + 40); +			return;  		} +		status >>= 1; +	} -	do_IRQ(irq + ar7_irq_base); - -	return IRQ_HANDLED; +	spurious_interrupt();  }  asmlinkage void plat_irq_dispatch(void)  { -	unsigned int pending = read_c0_status() & read_c0_cause(); +	unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;  	if (pending & STATUSF_IP7)		/* cpu timer */  		do_IRQ(7);  	else if (pending & STATUSF_IP2)		/* int0 hardware line */ -		do_IRQ(2); -	else  +		ar7_cascade(); +	else  		spurious_interrupt();  } | 
