2005-04-16 15:20:36 -07:00
/*
* linux / arch / m68k / kernel / ints . c - - Linux / m68k general interrupt handling code
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file COPYING in the main directory of this archive
* for more details .
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/sched.h>
2007-02-17 21:22:39 -08:00
# include <linux/interrupt.h>
2005-04-16 15:20:36 -07:00
# include <linux/errno.h>
# include <linux/init.h>
2014-03-05 13:28:32 +01:00
# include <linux/irq.h>
2005-04-16 15:20:36 -07:00
# include <asm/setup.h>
# include <asm/irq.h>
# include <asm/traps.h>
# include <asm/page.h>
# include <asm/machdep.h>
2006-06-25 05:47:01 -07:00
# include <asm/cacheflush.h>
2006-10-07 14:16:45 +01:00
# include <asm/irq_regs.h>
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_Q40
# include <asm/q40ints.h>
# endif
2006-06-25 05:47:01 -07:00
extern u32 auto_irqhandler_fixup [ ] ;
extern u16 user_irqvec_fixup [ ] ;
static int m68k_first_user_vec ;
2006-06-25 05:47:00 -07:00
2011-04-13 22:31:28 +02:00
static struct irq_chip auto_irq_chip = {
2006-06-25 05:47:00 -07:00
. name = " auto " ,
2011-04-13 22:31:28 +02:00
. irq_startup = m68k_irq_startup ,
. irq_shutdown = m68k_irq_shutdown ,
2006-06-25 05:47:00 -07:00
} ;
2005-04-16 15:20:36 -07:00
2011-04-13 22:31:28 +02:00
static struct irq_chip user_irq_chip = {
2006-06-25 05:47:01 -07:00
. name = " user " ,
2011-04-13 22:31:28 +02:00
. irq_startup = m68k_irq_startup ,
. irq_shutdown = m68k_irq_shutdown ,
2005-04-16 15:20:36 -07:00
} ;
/*
* void init_IRQ ( void )
*
* Parameters : None
*
* Returns : Nothing
*
* This function should be called during kernel startup to initialize
* the IRQ handling routines .
*/
void __init init_IRQ ( void )
{
int i ;
2006-06-25 05:47:01 -07:00
for ( i = IRQ_AUTO_1 ; i < = IRQ_AUTO_7 ; i + + )
2011-04-21 22:50:52 +02:00
irq_set_chip_and_handler ( i , & auto_irq_chip , handle_simple_irq ) ;
2005-04-16 15:20:36 -07:00
2006-06-25 05:47:01 -07:00
mach_init_IRQ ( ) ;
}
/**
* m68k_setup_auto_interrupt
* @ handler : called from auto vector interrupts
*
* setup the handler to be called from auto vector interrupts instead of the
2011-07-01 20:39:19 +02:00
* standard do_IRQ ( ) , it will be called with irq numbers in the range
2006-06-25 05:47:01 -07:00
* from IRQ_AUTO_1 - IRQ_AUTO_7 .
*/
void __init m68k_setup_auto_interrupt ( void ( * handler ) ( unsigned int , struct pt_regs * ) )
{
if ( handler )
* auto_irqhandler_fixup = ( u32 ) handler ;
flush_icache ( ) ;
}
/**
* m68k_setup_user_interrupt
* @ vec : first user vector interrupt to handle
* @ cnt : number of active user vector interrupts
*
* setup user vector interrupts , this includes activating the specified range
* of interrupts , only then these interrupts can be requested ( note : this is
2011-09-11 11:54:50 +02:00
* different from auto vector interrupts ) .
2006-06-25 05:47:01 -07:00
*/
2011-09-11 11:54:50 +02:00
void __init m68k_setup_user_interrupt ( unsigned int vec , unsigned int cnt )
2006-06-25 05:47:01 -07:00
{
int i ;
2008-11-14 08:10:19 +01:00
BUG_ON ( IRQ_USER + cnt > NR_IRQS ) ;
2006-06-25 05:47:01 -07:00
m68k_first_user_vec = vec ;
for ( i = 0 ; i < cnt ; i + + )
2013-06-03 12:53:01 +02:00
irq_set_chip_and_handler ( i , & user_irq_chip , handle_simple_irq ) ;
2006-06-25 05:47:01 -07:00
* user_irqvec_fixup = vec - IRQ_USER ;
flush_icache ( ) ;
}
2011-04-21 22:50:52 +02:00
/**
* m68k_setup_irq_controller
* @ chip : irq chip which controls specified irq
* @ handle : flow handler which handles specified irq
* @ irq : first irq to be managed by the controller
* @ cnt : number of irqs to be managed by the controller
*
* Change the controller for the specified range of irq , which will be used to
* manage these irq . auto / user irq already have a default controller , which can
* be changed as well , but the controller probably should use m68k_irq_startup /
* m68k_irq_shutdown .
*/
void m68k_setup_irq_controller ( struct irq_chip * chip ,
irq_flow_handler_t handle , unsigned int irq ,
unsigned int cnt )
{
int i ;
for ( i = 0 ; i < cnt ; i + + ) {
irq_set_chip ( irq + i , chip ) ;
if ( handle )
irq_set_handler ( irq + i , handle ) ;
}
}
2011-04-17 22:53:04 +02:00
unsigned int m68k_irq_startup_irq ( unsigned int irq )
2006-06-25 05:47:00 -07:00
{
if ( irq < = IRQ_AUTO_7 )
vectors [ VEC_SPUR + irq ] = auto_inthandler ;
2006-06-25 05:47:01 -07:00
else
vectors [ m68k_first_user_vec + irq - IRQ_USER ] = user_inthandler ;
2006-06-25 05:47:00 -07:00
return 0 ;
}
2011-04-17 22:53:04 +02:00
unsigned int m68k_irq_startup ( struct irq_data * data )
2006-06-25 05:47:00 -07:00
{
2011-04-17 22:53:04 +02:00
return m68k_irq_startup_irq ( data - > irq ) ;
}
void m68k_irq_shutdown ( struct irq_data * data )
{
unsigned int irq = data - > irq ;
2006-06-25 05:47:00 -07:00
if ( irq < = IRQ_AUTO_7 )
vectors [ VEC_SPUR + irq ] = bad_inthandler ;
2006-06-25 05:47:01 -07:00
else
vectors [ m68k_first_user_vec + irq - IRQ_USER ] = bad_inthandler ;
2006-06-25 05:47:00 -07:00
}
2006-06-25 05:47:01 -07:00
unsigned int irq_canonicalize ( unsigned int irq )
2005-04-16 15:20:36 -07:00
{
2006-06-25 05:47:01 -07:00
# ifdef CONFIG_Q40
if ( MACH_IS_Q40 & & irq = = 11 )
irq = 10 ;
# endif
return irq ;
2005-04-16 15:20:36 -07:00
}
2006-06-25 05:47:01 -07:00
EXPORT_SYMBOL ( irq_canonicalize ) ;
2005-04-16 15:20:36 -07:00
2011-04-21 22:50:52 +02:00
asmlinkage void handle_badint ( struct pt_regs * regs )
{
atomic_inc ( & irq_err_count ) ;
pr_warn ( " unexpected interrupt from %u \n " , regs - > vector ) ;
}