diff options
Diffstat (limited to 'arch/sh/kernel/irq.c')
-rw-r--r-- | arch/sh/kernel/irq.c | 91 |
1 files changed, 71 insertions, 20 deletions
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index d2d41d046657..257de1f0692b 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -12,6 +12,7 @@ #include <linux/kernel_stat.h> #include <linux/seq_file.h> #include <linux/ftrace.h> +#include <linux/delay.h> #include <asm/processor.h> #include <asm/machvec.h> #include <asm/uaccess.h> @@ -113,19 +114,14 @@ union irq_ctx { static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly; static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly; -#endif -asmlinkage __irq_entry int do_IRQ(unsigned int irq, struct pt_regs *regs) +static char softirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss; +static char hardirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss; + +static inline void handle_one_irq(unsigned int irq) { - struct pt_regs *old_regs = set_irq_regs(regs); -#ifdef CONFIG_IRQSTACKS union irq_ctx *curctx, *irqctx; -#endif - - irq_enter(); - irq = irq_demux(irq); -#ifdef CONFIG_IRQSTACKS curctx = (union irq_ctx *)current_thread_info(); irqctx = hardirq_ctx[smp_processor_id()]; @@ -164,20 +160,9 @@ asmlinkage __irq_entry int do_IRQ(unsigned int irq, struct pt_regs *regs) "r5", "r6", "r7", "r8", "t", "pr" ); } else -#endif generic_handle_irq(irq); - - irq_exit(); - - set_irq_regs(old_regs); - return 1; } -#ifdef CONFIG_IRQSTACKS -static char softirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss; - -static char hardirq_stack[NR_CPUS * THREAD_SIZE] __page_aligned_bss; - /* * allocate per-cpu stacks for hardirq and for softirq processing */ @@ -257,8 +242,33 @@ asmlinkage void do_softirq(void) local_irq_restore(flags); } +#else +static inline void handle_one_irq(unsigned int irq) +{ + generic_handle_irq(irq); +} #endif +asmlinkage __irq_entry int do_IRQ(unsigned int irq, struct pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + + irq_enter(); + + irq = irq_demux(irq_lookup(irq)); + + if (irq != NO_IRQ_IGNORE) { + handle_one_irq(irq); + irq_finish(irq); + } + + irq_exit(); + + set_irq_regs(old_regs); + + return IRQ_HANDLED; +} + void __init init_IRQ(void) { plat_irq_setup(); @@ -283,3 +293,44 @@ int __init arch_probe_nr_irqs(void) return 0; } #endif + +#ifdef CONFIG_HOTPLUG_CPU +static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu) +{ + printk(KERN_INFO "IRQ%u: moving from cpu%u to cpu%u\n", + irq, desc->node, cpu); + + raw_spin_lock_irq(&desc->lock); + desc->chip->set_affinity(irq, cpumask_of(cpu)); + raw_spin_unlock_irq(&desc->lock); +} + +/* + * The CPU has been marked offline. Migrate IRQs off this CPU. If + * the affinity settings do not allow other CPUs, force them onto any + * available CPU. + */ +void migrate_irqs(void) +{ + struct irq_desc *desc; + unsigned int irq, cpu = smp_processor_id(); + + for_each_irq_desc(irq, desc) { + if (desc->node == cpu) { + unsigned int newcpu = cpumask_any_and(desc->affinity, + cpu_online_mask); + if (newcpu >= nr_cpu_ids) { + if (printk_ratelimit()) + printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n", + irq, cpu); + + cpumask_setall(desc->affinity); + newcpu = cpumask_any_and(desc->affinity, + cpu_online_mask); + } + + route_irq(desc, irq, newcpu); + } + } +} +#endif |