2005-04-17 02:20:36 +04:00
/*
* linux / arch / arm / kernel / irq . c
*
* Copyright ( C ) 1992 Linus Torvalds
* Modifications for ARM processor Copyright ( C ) 1995 - 2000 Russell King .
*
2005-06-25 22:39:45 +04:00
* Support for Dynamic Tick Timer Copyright ( C ) 2004 - 2005 Nokia Corporation .
* Dynamic Tick Timer written by Tony Lindgren < tony @ atomide . com > and
* Tuukka Tikkanen < tuukka . tikkanen @ elektrobit . com > .
*
2005-04-17 02:20:36 +04:00
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* 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 .
*
* IRQ ' s are in fact implemented a bit like signal handlers for the kernel .
* Naturally it ' s not a 1 : 1 relation , but there are similarities .
*/
# include <linux/kernel_stat.h>
# include <linux/signal.h>
# include <linux/ioport.h>
# include <linux/interrupt.h>
2006-07-02 01:30:09 +04:00
# include <linux/irq.h>
2013-03-29 00:46:44 +04:00
# include <linux/irqchip.h>
2005-04-17 02:20:36 +04:00
# include <linux/random.h>
# include <linux/smp.h>
# include <linux/init.h>
# include <linux/seq_file.h>
# include <linux/errno.h>
# include <linux/list.h>
# include <linux/kallsyms.h>
# include <linux/proc_fs.h>
2012-08-16 11:49:26 +04:00
# include <linux/export.h>
2005-04-17 02:20:36 +04:00
2011-10-08 14:20:42 +04:00
# include <asm/exception.h>
2010-12-20 13:18:36 +03:00
# include <asm/mach/arch.h>
2008-08-03 18:04:04 +04:00
# include <asm/mach/irq.h>
2005-06-25 22:39:45 +04:00
# include <asm/mach/time.h>
2005-04-17 02:20:36 +04:00
2006-07-02 01:30:09 +04:00
unsigned long irq_err_count ;
2005-04-17 02:20:36 +04:00
2011-03-24 14:02:11 +03:00
int arch_show_interrupts ( struct seq_file * p , int prec )
2005-04-17 02:20:36 +04:00
{
2009-08-03 18:11:29 +04:00
# ifdef CONFIG_FIQ
2011-03-24 14:02:11 +03:00
show_fiq_list ( p , prec ) ;
2005-04-17 02:20:36 +04:00
# endif
# ifdef CONFIG_SMP
2011-03-24 14:02:11 +03:00
show_ipi_list ( p , prec ) ;
2005-04-17 02:20:36 +04:00
# endif
2011-03-24 14:02:11 +03:00
seq_printf ( p , " %*s: %10lu \n " , prec , " Err " , irq_err_count ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
ARM: introduce handle_IRQ() not to dump exception stack
On Mon, Jul 11, 2011 at 3:52 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
...
> The __exception annotation on a function causes this to happen:
>
> [<c002406c>] (asm_do_IRQ+0x6c/0x8c) from [<c0024b84>]
> (__irq_svc+0x44/0xcc)
> Exception stack(0xc3897c78 to 0xc3897cc0)
> 7c60: 4022d320 4022e000
> 7c80: 08000075 00001000 c32273c0 c03ce1c0 c2b49b78 4022d000 c2b420b4 00000001
> 7ca0: 00000000 c3897cfc 00000000 c3897cc0 c00afc54 c002edd8 00000013 ffffffff
>
> Where that stack dump represents the pt_regs for the exception which
> happened. Any function found in while unwinding will cause this to
> be printed.
>
> If you insert a C function between the IRQ assembly and asm_do_IRQ,
> the
> dump you get from asm_do_IRQ will be the stack for your function,
> not
> the pt_regs. That makes the feature useless.
>
When __irq_svc - or any of the other exception handling assembly code -
calls the C code, the stack pointer will be pointing at the pt_regs
structure.
All the entry points into C code from the exception handling code are
marked with __exception or __exception_irq_enter to indicate that they
are one of the functions which has pt_regs above them.
Normally, when you've entered asm_do_IRQ() you will have this stack
layout (higher address towards top):
pt_regs
asm_do_IRQ frame
If you insert a C function between the exception assembly code and
asm_do_IRQ, you end up with this stack layout instead:
pt_regs
your function frame
asm_do_IRQ frame
This means when we unwind, we'll get to asm_do_IRQ, and rather than
dumping out the pt_regs, we'll dump out your functions stack frame
instead, because that's what is above the asm_do_IRQ stack frame
rather than the expected pt_regs structure.
The fix is to introduce handle_IRQ() for no exception stack dump, so
it can be called with MULTI_IRQ_HANDLER is selected and a C function
is between the assembly code and the actual IRQ handling code.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Eric Miao <eric.y.miao@gmail.com>
2011-07-12 01:25:43 +04:00
* handle_IRQ handles all hardware IRQ ' s . Decoded IRQs should
* not come via this function . Instead , they should provide their
* own ' handler ' . Used by platform code implementing C - based 1 st
* level decoding .
2005-04-17 02:20:36 +04:00
*/
ARM: introduce handle_IRQ() not to dump exception stack
On Mon, Jul 11, 2011 at 3:52 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
...
> The __exception annotation on a function causes this to happen:
>
> [<c002406c>] (asm_do_IRQ+0x6c/0x8c) from [<c0024b84>]
> (__irq_svc+0x44/0xcc)
> Exception stack(0xc3897c78 to 0xc3897cc0)
> 7c60: 4022d320 4022e000
> 7c80: 08000075 00001000 c32273c0 c03ce1c0 c2b49b78 4022d000 c2b420b4 00000001
> 7ca0: 00000000 c3897cfc 00000000 c3897cc0 c00afc54 c002edd8 00000013 ffffffff
>
> Where that stack dump represents the pt_regs for the exception which
> happened. Any function found in while unwinding will cause this to
> be printed.
>
> If you insert a C function between the IRQ assembly and asm_do_IRQ,
> the
> dump you get from asm_do_IRQ will be the stack for your function,
> not
> the pt_regs. That makes the feature useless.
>
When __irq_svc - or any of the other exception handling assembly code -
calls the C code, the stack pointer will be pointing at the pt_regs
structure.
All the entry points into C code from the exception handling code are
marked with __exception or __exception_irq_enter to indicate that they
are one of the functions which has pt_regs above them.
Normally, when you've entered asm_do_IRQ() you will have this stack
layout (higher address towards top):
pt_regs
asm_do_IRQ frame
If you insert a C function between the exception assembly code and
asm_do_IRQ, you end up with this stack layout instead:
pt_regs
your function frame
asm_do_IRQ frame
This means when we unwind, we'll get to asm_do_IRQ, and rather than
dumping out the pt_regs, we'll dump out your functions stack frame
instead, because that's what is above the asm_do_IRQ stack frame
rather than the expected pt_regs structure.
The fix is to introduce handle_IRQ() for no exception stack dump, so
it can be called with MULTI_IRQ_HANDLER is selected and a C function
is between the assembly code and the actual IRQ handling code.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Eric Miao <eric.y.miao@gmail.com>
2011-07-12 01:25:43 +04:00
void handle_IRQ ( unsigned int irq , struct pt_regs * regs )
2005-04-17 02:20:36 +04:00
{
2006-10-07 00:11:15 +04:00
struct pt_regs * old_regs = set_irq_regs ( regs ) ;
2008-10-09 16:36:24 +04:00
irq_enter ( ) ;
2005-04-17 02:20:36 +04:00
/*
* Some hardware gives randomly wrong interrupts . Rather
* than crashing , do something sensible .
*/
2010-06-25 12:46:09 +04:00
if ( unlikely ( irq > = nr_irqs ) ) {
2009-06-22 12:23:36 +04:00
if ( printk_ratelimit ( ) )
printk ( KERN_WARNING " Bad IRQ%u \n " , irq ) ;
ack_bad_irq ( irq ) ;
} else {
2008-10-09 16:36:24 +04:00
generic_handle_irq ( irq ) ;
2009-06-22 12:23:36 +04:00
}
2005-04-17 02:20:36 +04:00
irq_exit ( ) ;
2006-10-07 00:11:15 +04:00
set_irq_regs ( old_regs ) ;
2005-04-17 02:20:36 +04:00
}
ARM: introduce handle_IRQ() not to dump exception stack
On Mon, Jul 11, 2011 at 3:52 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
...
> The __exception annotation on a function causes this to happen:
>
> [<c002406c>] (asm_do_IRQ+0x6c/0x8c) from [<c0024b84>]
> (__irq_svc+0x44/0xcc)
> Exception stack(0xc3897c78 to 0xc3897cc0)
> 7c60: 4022d320 4022e000
> 7c80: 08000075 00001000 c32273c0 c03ce1c0 c2b49b78 4022d000 c2b420b4 00000001
> 7ca0: 00000000 c3897cfc 00000000 c3897cc0 c00afc54 c002edd8 00000013 ffffffff
>
> Where that stack dump represents the pt_regs for the exception which
> happened. Any function found in while unwinding will cause this to
> be printed.
>
> If you insert a C function between the IRQ assembly and asm_do_IRQ,
> the
> dump you get from asm_do_IRQ will be the stack for your function,
> not
> the pt_regs. That makes the feature useless.
>
When __irq_svc - or any of the other exception handling assembly code -
calls the C code, the stack pointer will be pointing at the pt_regs
structure.
All the entry points into C code from the exception handling code are
marked with __exception or __exception_irq_enter to indicate that they
are one of the functions which has pt_regs above them.
Normally, when you've entered asm_do_IRQ() you will have this stack
layout (higher address towards top):
pt_regs
asm_do_IRQ frame
If you insert a C function between the exception assembly code and
asm_do_IRQ, you end up with this stack layout instead:
pt_regs
your function frame
asm_do_IRQ frame
This means when we unwind, we'll get to asm_do_IRQ, and rather than
dumping out the pt_regs, we'll dump out your functions stack frame
instead, because that's what is above the asm_do_IRQ stack frame
rather than the expected pt_regs structure.
The fix is to introduce handle_IRQ() for no exception stack dump, so
it can be called with MULTI_IRQ_HANDLER is selected and a C function
is between the assembly code and the actual IRQ handling code.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Eric Miao <eric.y.miao@gmail.com>
2011-07-12 01:25:43 +04:00
/*
* asm_do_IRQ is the interface to be used from assembly code .
*/
asmlinkage void __exception_irq_entry
asm_do_IRQ ( unsigned int irq , struct pt_regs * regs )
{
handle_IRQ ( irq , regs ) ;
}
2005-04-17 02:20:36 +04:00
void set_irq_flags ( unsigned int irq , unsigned int iflags )
{
2011-02-08 00:30:49 +03:00
unsigned long clr = 0 , set = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN ;
2005-04-17 02:20:36 +04:00
2010-06-25 12:46:09 +04:00
if ( irq > = nr_irqs ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " Trying to set irq flags for IRQ%d \n " , irq ) ;
return ;
}
2006-07-02 01:30:09 +04:00
if ( iflags & IRQF_VALID )
2011-02-08 00:30:49 +03:00
clr | = IRQ_NOREQUEST ;
2006-07-02 01:30:09 +04:00
if ( iflags & IRQF_PROBE )
2011-02-08 00:30:49 +03:00
clr | = IRQ_NOPROBE ;
2006-07-02 01:30:09 +04:00
if ( ! ( iflags & IRQF_NOAUTOEN ) )
2011-02-08 00:30:49 +03:00
clr | = IRQ_NOAUTOEN ;
/* Order is clear bits in "clr" then set bits in "set" */
irq_modify_status ( irq , clr , set & ~ clr ) ;
2005-04-17 02:20:36 +04:00
}
2012-08-16 11:49:26 +04:00
EXPORT_SYMBOL_GPL ( set_irq_flags ) ;
2005-04-17 02:20:36 +04:00
void __init init_IRQ ( void )
{
2013-03-29 00:46:44 +04:00
if ( IS_ENABLED ( CONFIG_OF ) & & ! machine_desc - > init_irq )
irqchip_init ( ) ;
else
machine_desc - > init_irq ( ) ;
2005-04-17 02:20:36 +04:00
}
2012-11-21 02:00:53 +04:00
# ifdef CONFIG_MULTI_IRQ_HANDLER
void __init set_handle_irq ( void ( * handle_irq ) ( struct pt_regs * ) )
{
if ( handle_arch_irq )
return ;
handle_arch_irq = handle_irq ;
}
# endif
2010-06-25 12:46:09 +04:00
# ifdef CONFIG_SPARSE_IRQ
int __init arch_probe_nr_irqs ( void )
{
2010-12-20 13:18:36 +03:00
nr_irqs = machine_desc - > nr_irqs ? machine_desc - > nr_irqs : NR_IRQS ;
2010-09-27 22:55:03 +04:00
return nr_irqs ;
2010-06-25 12:46:09 +04:00
}
# endif
2005-11-03 01:24:33 +03:00
# ifdef CONFIG_HOTPLUG_CPU
2006-07-12 01:54:34 +04:00
2011-07-21 18:14:21 +04:00
static bool migrate_one_irq ( struct irq_desc * desc )
2006-07-12 01:54:34 +04:00
{
2011-07-21 18:14:21 +04:00
struct irq_data * d = irq_desc_get_irq_data ( desc ) ;
2011-07-21 18:07:56 +04:00
const struct cpumask * affinity = d - > affinity ;
2011-07-21 18:14:21 +04:00
struct irq_chip * c ;
2011-01-23 15:09:36 +03:00
bool ret = false ;
2006-07-12 01:54:34 +04:00
2011-07-21 18:14:21 +04:00
/*
* If this is a per - CPU interrupt , or the affinity does not
* include this CPU , then we have nothing to do .
*/
if ( irqd_is_per_cpu ( d ) | | ! cpumask_test_cpu ( smp_processor_id ( ) , affinity ) )
return false ;
2011-07-21 18:07:56 +04:00
if ( cpumask_any_and ( affinity , cpu_online_mask ) > = nr_cpu_ids ) {
2011-07-21 18:14:21 +04:00
affinity = cpu_online_mask ;
2011-01-23 15:09:36 +03:00
ret = true ;
}
2011-07-21 18:14:21 +04:00
c = irq_data_get_irq_chip ( d ) ;
2012-04-27 15:56:24 +04:00
if ( ! c - > irq_set_affinity )
2011-07-21 18:14:21 +04:00
pr_debug ( " IRQ%u: unable to set affinity \n " , d - > irq ) ;
2012-04-27 15:56:24 +04:00
else if ( c - > irq_set_affinity ( d , affinity , true ) = = IRQ_SET_MASK_OK & & ret )
cpumask_copy ( d - > affinity , affinity ) ;
2011-01-23 15:09:36 +03:00
return ret ;
2006-07-12 01:54:34 +04:00
}
2005-11-03 01:24:33 +03:00
/*
2011-07-21 18:14:21 +04:00
* The current CPU has been marked offline . Migrate IRQs off this CPU .
* If the affinity settings do not allow other CPUs , force them onto any
2005-11-03 01:24:33 +03:00
* available CPU .
2011-07-21 18:14:21 +04:00
*
* Note : we must iterate over all IRQs , whether they have an attached
* action structure or not , as we need to get chained interrupts too .
2005-11-03 01:24:33 +03:00
*/
void migrate_irqs ( void )
{
2011-07-21 18:14:21 +04:00
unsigned int i ;
2010-06-25 12:46:09 +04:00
struct irq_desc * desc ;
2011-01-23 15:09:36 +03:00
unsigned long flags ;
local_irq_save ( flags ) ;
2005-11-03 01:24:33 +03:00
2010-06-25 12:46:09 +04:00
for_each_irq_desc ( i , desc ) {
2012-02-03 17:50:07 +04:00
bool affinity_broken ;
2011-07-21 18:14:21 +04:00
2011-01-23 15:09:36 +03:00
raw_spin_lock ( & desc - > lock ) ;
2011-07-21 18:14:21 +04:00
affinity_broken = migrate_one_irq ( desc ) ;
2011-01-23 15:09:36 +03:00
raw_spin_unlock ( & desc - > lock ) ;
if ( affinity_broken & & printk_ratelimit ( ) )
2011-07-21 18:14:21 +04:00
pr_warning ( " IRQ%u no longer affine to CPU%u \n " , i ,
smp_processor_id ( ) ) ;
2005-11-03 01:24:33 +03:00
}
2011-01-23 15:09:36 +03:00
local_irq_restore ( flags ) ;
2005-11-03 01:24:33 +03:00
}
# endif /* CONFIG_HOTPLUG_CPU */