2005-04-17 02:20:36 +04:00
/*
* linux / arch / alpha / kernel / irq . c
*
* Copyright ( C ) 1995 Linus Torvalds
*
* This file contains the code used by various IRQ handling routines :
* asking for different IRQ ' s should be done through these routines
* instead of just grabbing them . Thus setups with different IRQ numbers
* shouldn ' t result in any weird surprises , and installing new handlers
* should be easier .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/kernel_stat.h>
# include <linux/signal.h>
# include <linux/sched.h>
# include <linux/ptrace.h>
# include <linux/interrupt.h>
# include <linux/random.h>
# include <linux/init.h>
# include <linux/irq.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <linux/profile.h>
# include <linux/bitops.h>
# include <asm/system.h>
# include <asm/io.h>
# include <asm/uaccess.h>
volatile unsigned long irq_err_count ;
2010-08-10 04:20:05 +04:00
DEFINE_PER_CPU ( unsigned long , irq_pmi_count ) ;
2005-04-17 02:20:36 +04:00
2006-01-06 11:12:22 +03:00
void ack_bad_irq ( unsigned int irq )
2005-04-17 02:20:36 +04:00
{
irq_err_count + + ;
printk ( KERN_CRIT " Unexpected IRQ trap at vector %u \n " , irq ) ;
}
# ifdef CONFIG_SMP
static char irq_user_affinity [ NR_IRQS ] ;
2008-05-29 22:02:52 +04:00
int irq_select_affinity ( unsigned int irq )
2005-04-17 02:20:36 +04:00
{
2011-01-23 15:40:47 +03:00
struct irq_desc * desc = irq_to_desc ( irq ) ;
2005-04-17 02:20:36 +04:00
static int last_cpu ;
int cpu = last_cpu + 1 ;
2010-10-15 06:31:25 +04:00
if ( ! desc | | ! get_irq_desc_chip ( desc ) - > set_affinity | | irq_user_affinity [ irq ] )
2006-01-06 11:12:22 +03:00
return 1 ;
2005-04-17 02:20:36 +04:00
2009-01-01 02:42:26 +03:00
while ( ! cpu_possible ( cpu ) | |
! cpumask_test_cpu ( cpu , irq_default_affinity ) )
2005-04-17 02:20:36 +04:00
cpu = ( cpu < ( NR_CPUS - 1 ) ? cpu + 1 : 0 ) ;
last_cpu = cpu ;
2010-10-15 06:31:25 +04:00
cpumask_copy ( desc - > affinity , cpumask_of ( cpu ) ) ;
get_irq_desc_chip ( desc ) - > set_affinity ( irq , cpumask_of ( cpu ) ) ;
2006-01-06 11:12:22 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
# endif /* CONFIG_SMP */
int
show_interrupts ( struct seq_file * p , void * v )
{
int j ;
2006-02-01 14:06:13 +03:00
int irq = * ( loff_t * ) v ;
2005-04-17 02:20:36 +04:00
struct irqaction * action ;
2010-10-15 06:31:25 +04:00
struct irq_desc * desc ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
# ifdef CONFIG_SMP
2006-02-01 14:06:13 +03:00
if ( irq = = 0 ) {
2005-04-17 02:20:36 +04:00
seq_puts ( p , " " ) ;
2006-02-01 14:06:13 +03:00
for_each_online_cpu ( j )
seq_printf ( p , " CPU%d " , j ) ;
2005-04-17 02:20:36 +04:00
seq_putc ( p , ' \n ' ) ;
}
# endif
2006-02-01 14:06:13 +03:00
if ( irq < ACTUAL_NR_IRQS ) {
2010-10-15 06:31:25 +04:00
desc = irq_to_desc ( irq ) ;
if ( ! desc )
return 0 ;
raw_spin_lock_irqsave ( & desc - > lock , flags ) ;
action = desc - > action ;
2005-04-17 02:20:36 +04:00
if ( ! action )
goto unlock ;
2006-02-01 14:06:13 +03:00
seq_printf ( p , " %3d: " , irq ) ;
2005-04-17 02:20:36 +04:00
# ifndef CONFIG_SMP
2006-02-01 14:06:13 +03:00
seq_printf ( p , " %10u " , kstat_irqs ( irq ) ) ;
2005-04-17 02:20:36 +04:00
# else
2006-02-01 14:06:13 +03:00
for_each_online_cpu ( j )
2009-01-30 01:29:10 +03:00
seq_printf ( p , " %10u " , kstat_irqs_cpu ( irq , j ) ) ;
2005-04-17 02:20:36 +04:00
# endif
2010-10-15 06:31:25 +04:00
seq_printf ( p , " %14s " , get_irq_desc_chip ( desc ) - > name ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( p , " %c%s " ,
2006-07-02 06:29:11 +04:00
( action - > flags & IRQF_DISABLED ) ? ' + ' : ' ' ,
2005-04-17 02:20:36 +04:00
action - > name ) ;
for ( action = action - > next ; action ; action = action - > next ) {
seq_printf ( p , " , %c%s " ,
2006-07-02 06:29:11 +04:00
( action - > flags & IRQF_DISABLED ) ? ' + ' : ' ' ,
2005-04-17 02:20:36 +04:00
action - > name ) ;
}
seq_putc ( p , ' \n ' ) ;
unlock :
2010-10-15 06:31:25 +04:00
raw_spin_unlock_irqrestore ( & desc - > lock , flags ) ;
2006-02-01 14:06:13 +03:00
} else if ( irq = = ACTUAL_NR_IRQS ) {
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_SMP
seq_puts ( p , " IPI: " ) ;
2006-02-01 14:06:13 +03:00
for_each_online_cpu ( j )
seq_printf ( p , " %10lu " , cpu_data [ j ] . ipi_count ) ;
2005-04-17 02:20:36 +04:00
seq_putc ( p , ' \n ' ) ;
# endif
2010-08-10 04:20:05 +04:00
seq_puts ( p , " PMI: " ) ;
for_each_online_cpu ( j )
seq_printf ( p , " %10lu " , per_cpu ( irq_pmi_count , j ) ) ;
seq_puts ( p , " Performance Monitoring \n " ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( p , " ERR: %10lu \n " , irq_err_count ) ;
}
return 0 ;
}
/*
* handle_irq handles all normal device IRQ ' s ( the special
* SMP cross - CPU interrupts have their own specific
* handlers ) .
*/
# define MAX_ILLEGAL_IRQS 16
void
2006-10-08 17:37:32 +04:00
handle_irq ( int irq )
2005-04-17 02:20:36 +04:00
{
/*
* We ack quickly , we don ' t want the irq controller
* thinking we ' re snobs just because some other CPU has
* disabled global interrupts ( we have already done the
* INT_ACK cycles , it ' s too late to try to pretend to the
* controller that we aren ' t taking the interrupt ) .
*
* 0 return value means that this irq is already being
* handled by some other CPU . ( or is disabled )
*/
static unsigned int illegal_count = 0 ;
2010-10-15 06:31:25 +04:00
struct irq_desc * desc = irq_to_desc ( irq ) ;
2005-04-17 02:20:36 +04:00
2010-10-15 06:31:25 +04:00
if ( ! desc | | ( ( unsigned ) irq > ACTUAL_NR_IRQS & &
illegal_count < MAX_ILLEGAL_IRQS ) ) {
2005-04-17 02:20:36 +04:00
irq_err_count + + ;
illegal_count + + ;
printk ( KERN_CRIT " device_interrupt: invalid interrupt %d \n " ,
irq ) ;
return ;
}
2006-03-10 04:33:37 +03:00
/*
2011-01-13 01:02:24 +03:00
* From here we must proceed with IPL_MAX . Note that we do not
2006-03-10 04:33:37 +03:00
* explicitly enable interrupts afterwards - some MILO PALcode
* ( namely LX164 one ) seems to have severe problems with RTI
* at IPL 0.
*/
2006-01-06 11:12:22 +03:00
local_irq_disable ( ) ;
2011-01-13 01:02:24 +03:00
irq_enter ( ) ;
2010-10-15 06:31:25 +04:00
generic_handle_irq_desc ( irq , desc ) ;
2005-04-17 02:20:36 +04:00
irq_exit ( ) ;
}