2005-09-04 02:56:04 +04:00
/*
* Interrupt handing routines for NEC VR4100 series .
*
2009-07-02 19:39:38 +04:00
* Copyright ( C ) 2005 - 2007 Yoichi Yuasa < yuasa @ linux - mips . org >
2005-09-04 02:56:04 +04:00
*
* 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/interrupt.h>
# include <linux/module.h>
# include <asm/irq_cpu.h>
# include <asm/system.h>
2006-07-13 12:33:03 +04:00
# include <asm/vr41xx/irq.h>
2005-09-04 02:56:04 +04:00
typedef struct irq_cascade {
2006-10-07 22:44:33 +04:00
int ( * get_irq ) ( unsigned int ) ;
2005-09-04 02:56:04 +04:00
} irq_cascade_t ;
static irq_cascade_t irq_cascade [ NR_IRQS ] __cacheline_aligned ;
static struct irqaction cascade_irqaction = {
. handler = no_action ,
. name = " cascade " ,
} ;
2006-10-07 22:44:33 +04:00
int cascade_irq ( unsigned int irq , int ( * get_irq ) ( unsigned int ) )
2005-09-04 02:56:04 +04:00
{
int retval = 0 ;
if ( irq > = NR_IRQS )
return - EINVAL ;
if ( irq_cascade [ irq ] . get_irq ! = NULL )
free_irq ( irq , NULL ) ;
irq_cascade [ irq ] . get_irq = get_irq ;
if ( get_irq ! = NULL ) {
retval = setup_irq ( irq , & cascade_irqaction ) ;
if ( retval < 0 )
irq_cascade [ irq ] . get_irq = NULL ;
}
return retval ;
}
EXPORT_SYMBOL_GPL ( cascade_irq ) ;
2006-10-07 22:44:33 +04:00
static void irq_dispatch ( unsigned int irq )
2005-09-04 02:56:04 +04:00
{
irq_cascade_t * cascade ;
2006-07-02 17:41:42 +04:00
struct irq_desc * desc ;
2005-09-04 02:56:04 +04:00
if ( irq > = NR_IRQS ) {
atomic_inc ( & irq_err_count ) ;
return ;
}
cascade = irq_cascade + irq ;
if ( cascade - > get_irq ! = NULL ) {
unsigned int source_irq = irq ;
2008-09-16 04:50:54 +04:00
int ret ;
2005-09-04 02:56:04 +04:00
desc = irq_desc + source_irq ;
2007-01-22 17:01:06 +03:00
if ( desc - > chip - > mask_ack )
desc - > chip - > mask_ack ( source_irq ) ;
else {
desc - > chip - > mask ( source_irq ) ;
desc - > chip - > ack ( source_irq ) ;
}
2008-09-16 04:50:54 +04:00
ret = cascade - > get_irq ( irq ) ;
irq = ret ;
if ( ret < 0 )
2005-09-04 02:56:04 +04:00
atomic_inc ( & irq_err_count ) ;
else
2006-10-07 22:44:33 +04:00
irq_dispatch ( irq ) ;
2007-01-22 17:01:06 +03:00
if ( ! ( desc - > status & IRQ_DISABLED ) & & desc - > chip - > unmask )
desc - > chip - > unmask ( source_irq ) ;
2005-09-04 02:56:04 +04:00
} else
2006-10-07 22:44:33 +04:00
do_IRQ ( irq ) ;
2005-09-04 02:56:04 +04:00
}
2006-10-07 22:44:33 +04:00
asmlinkage void plat_irq_dispatch ( void )
2006-04-03 20:56:36 +04:00
{
unsigned int pending = read_c0_cause ( ) & read_c0_status ( ) & ST0_IM ;
if ( pending & CAUSEF_IP7 )
2007-01-18 16:27:11 +03:00
do_IRQ ( TIMER_IRQ ) ;
2006-04-03 20:56:36 +04:00
else if ( pending & 0x7800 ) {
if ( pending & CAUSEF_IP3 )
2007-01-18 16:27:11 +03:00
irq_dispatch ( INT1_IRQ ) ;
2006-04-03 20:56:36 +04:00
else if ( pending & CAUSEF_IP4 )
2007-01-18 16:27:11 +03:00
irq_dispatch ( INT2_IRQ ) ;
2006-04-03 20:56:36 +04:00
else if ( pending & CAUSEF_IP5 )
2007-01-18 16:27:11 +03:00
irq_dispatch ( INT3_IRQ ) ;
2006-04-03 20:56:36 +04:00
else if ( pending & CAUSEF_IP6 )
2007-01-18 16:27:11 +03:00
irq_dispatch ( INT4_IRQ ) ;
2006-04-03 20:56:36 +04:00
} else if ( pending & CAUSEF_IP2 )
2007-01-18 16:27:11 +03:00
irq_dispatch ( INT0_IRQ ) ;
2006-04-03 20:56:36 +04:00
else if ( pending & CAUSEF_IP0 )
2007-01-18 16:27:11 +03:00
do_IRQ ( MIPS_SOFTINT0_IRQ ) ;
2006-04-03 20:56:36 +04:00
else if ( pending & CAUSEF_IP1 )
2007-01-18 16:27:11 +03:00
do_IRQ ( MIPS_SOFTINT1_IRQ ) ;
2006-04-03 20:56:36 +04:00
else
2006-10-07 22:44:33 +04:00
spurious_interrupt ( ) ;
2006-04-03 20:56:36 +04:00
}
2005-09-04 02:56:04 +04:00
void __init arch_init_irq ( void )
{
2007-01-07 20:14:29 +03:00
mips_cpu_irq_init ( ) ;
2005-09-04 02:56:04 +04:00
}