2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 1992 , 1998 Linus Torvalds , Ingo Molnar
*
* This file contains the lowest level x86_64 - specific interrupt
* entry and irq statistics code . All the remaining irq logic is
* done by the generic kernel / irq / code and in the
* x86_64 - specific irq controller code . ( e . g . i8259 . c and
* io_apic . c . )
*/
# include <linux/kernel_stat.h>
# include <linux/interrupt.h>
# include <linux/seq_file.h>
# include <linux/module.h>
2005-06-26 01:55:00 +04:00
# include <linux/delay.h>
2008-12-10 01:54:20 +03:00
# include <linux/ftrace.h>
2009-01-04 13:55:19 +03:00
# include <linux/uaccess.h>
# include <linux/smp.h>
2005-04-17 02:20:36 +04:00
# include <asm/io_apic.h>
2006-01-12 00:44:36 +03:00
# include <asm/idle.h>
2009-01-23 05:03:29 +03:00
# include <asm/apic.h>
2005-04-17 02:20:36 +04:00
2009-01-18 18:38:57 +03:00
DEFINE_PER_CPU_SHARED_ALIGNED ( irq_cpustat_t , irq_stat ) ;
EXPORT_PER_CPU_SYMBOL ( irq_stat ) ;
2009-01-21 11:26:06 +03:00
DEFINE_PER_CPU ( struct pt_regs * , irq_regs ) ;
EXPORT_PER_CPU_SYMBOL ( irq_regs ) ;
2006-06-26 16:00:05 +04:00
/*
* Probabilistic stack overflow check :
*
* Only check the stack in process context , because everything else
* runs on the big interrupt stacks . Checking reliably is too expensive ,
* so we just check from interrupts .
*/
static inline void stack_overflow_check ( struct pt_regs * regs )
{
2008-11-23 11:02:26 +03:00
# ifdef CONFIG_DEBUG_STACKOVERFLOW
2007-05-09 13:35:16 +04:00
u64 curbase = ( u64 ) task_stack_page ( current ) ;
2008-11-23 11:02:26 +03:00
WARN_ONCE ( regs - > sp > = curbase & &
regs - > sp < = curbase + THREAD_SIZE & &
regs - > sp < curbase + sizeof ( struct thread_info ) +
sizeof ( struct pt_regs ) + 128 ,
" do_IRQ: %s near stack overflow (cur:%Lx,sp:%lx) \n " ,
current - > comm , curbase , regs - > sp ) ;
2006-06-26 16:00:05 +04:00
# endif
2008-11-23 11:02:26 +03:00
}
2006-06-26 16:00:05 +04:00
2009-02-07 01:09:40 +03:00
bool handle_irq ( unsigned irq , struct pt_regs * regs )
{
struct irq_desc * desc ;
stack_overflow_check ( regs ) ;
desc = irq_to_desc ( irq ) ;
if ( unlikely ( ! desc ) )
return false ;
generic_handle_irq_desc ( irq , desc ) ;
return true ;
}
2005-07-29 08:15:49 +04:00
extern void call_softirq ( void ) ;
asmlinkage void do_softirq ( void )
{
2009-01-04 13:55:19 +03:00
__u32 pending ;
unsigned long flags ;
2005-07-29 08:15:49 +04:00
2009-01-04 13:55:19 +03:00
if ( in_interrupt ( ) )
return ;
2005-07-29 08:15:49 +04:00
2009-01-04 13:55:19 +03:00
local_irq_save ( flags ) ;
pending = local_softirq_pending ( ) ;
/* Switch to interrupt stack */
if ( pending ) {
2005-07-29 08:15:49 +04:00
call_softirq ( ) ;
2006-07-03 11:24:45 +04:00
WARN_ON_ONCE ( softirq_count ( ) ) ;
}
2009-01-04 13:55:19 +03:00
local_irq_restore ( flags ) ;
2005-07-29 08:15:49 +04:00
}