Commit a8416961 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'irq-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'irq-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (32 commits)
  x86: disable __do_IRQ support
  sparseirq, powerpc/cell: fix unused variable warning in interrupt.c
  genirq: deprecate obsolete typedefs and defines
  genirq: deprecate __do_IRQ
  genirq: add doc to struct irqaction
  genirq: use kzalloc instead of explicit zero initialization
  genirq: make irqreturn_t an enum
  genirq: remove redundant if condition
  genirq: remove unused hw_irq_controller typedef
  irq: export remove_irq() and setup_irq() symbols
  irq: match remove_irq() args with setup_irq()
  irq: add remove_irq() for freeing of setup_irq() irqs
  genirq: assert that irq handlers are indeed running in hardirq context
  irq: name 'p' variables a bit better
  irq: further clean up the free_irq() code flow
  irq: refactor and clean up the free_irq() code flow
  irq: clean up manage.c
  irq: use GFP_KERNEL for action allocation in request_irq()
  kernel/irq: fix sparse warning: make symbol static
  irq: optimize init_kstat_irqs/init_copy_kstat_irqs
  ...
parents 6671de34 fc2869f6
...@@ -440,6 +440,7 @@ desc->chip->end(); ...@@ -440,6 +440,7 @@ desc->chip->end();
used in the generic IRQ layer. used in the generic IRQ layer.
</para> </para>
!Iinclude/linux/irq.h !Iinclude/linux/irq.h
!Iinclude/linux/interrupt.h
</chapter> </chapter>
<chapter id="pubfunctions"> <chapter id="pubfunctions">
......
...@@ -346,3 +346,20 @@ Why: See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and ...@@ -346,3 +346,20 @@ Why: See commits 129f8ae9b1b5be94517da76009ea956e89104ce8 and
Removal is subject to fixing any remaining bugs in ACPI which may Removal is subject to fixing any remaining bugs in ACPI which may
cause the thermal throttling not to happen at the right time. cause the thermal throttling not to happen at the right time.
Who: Dave Jones <davej@redhat.com>, Matthew Garrett <mjg@redhat.com> Who: Dave Jones <davej@redhat.com>, Matthew Garrett <mjg@redhat.com>
-----------------------------
What: __do_IRQ all in one fits nothing interrupt handler
When: 2.6.32
Why: __do_IRQ was kept for easy migration to the type flow handlers.
More than two years of migration time is enough.
Who: Thomas Gleixner <tglx@linutronix.de>
-----------------------------
What: obsolete generic irq defines and typedefs
When: 2.6.30
Why: The defines and typedefs (hw_interrupt_type, no_irq_type, irq_desc_t)
have been kept around for migration reasons. After more than two years
it's time to remove them finally
Who: Thomas Gleixner <tglx@linutronix.de>
...@@ -90,7 +90,7 @@ show_interrupts(struct seq_file *p, void *v) ...@@ -90,7 +90,7 @@ show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%10u ", kstat_irqs(irq)); seq_printf(p, "%10u ", kstat_irqs(irq));
#else #else
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[irq]); seq_printf(p, "%10u ", kstat_irqs_cpu(irq, j));
#endif #endif
seq_printf(p, " %14s", irq_desc[irq].chip->typename); seq_printf(p, " %14s", irq_desc[irq].chip->typename);
seq_printf(p, " %c%s", seq_printf(p, " %c%s",
......
...@@ -64,7 +64,7 @@ do_entInt(unsigned long type, unsigned long vector, ...@@ -64,7 +64,7 @@ do_entInt(unsigned long type, unsigned long vector,
smp_percpu_timer_interrupt(regs); smp_percpu_timer_interrupt(regs);
cpu = smp_processor_id(); cpu = smp_processor_id();
if (cpu != boot_cpuid) { if (cpu != boot_cpuid) {
kstat_cpu(cpu).irqs[RTC_IRQ]++; kstat_incr_irqs_this_cpu(RTC_IRQ, irq_to_desc(RTC_IRQ));
} else { } else {
handle_irq(RTC_IRQ); handle_irq(RTC_IRQ);
} }
......
...@@ -76,7 +76,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -76,7 +76,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%3d: ", i); seq_printf(p, "%3d: ", i);
for_each_present_cpu(cpu) for_each_present_cpu(cpu)
seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu));
seq_printf(p, " %10s", irq_desc[i].chip->name ? : "-"); seq_printf(p, " %10s", irq_desc[i].chip->name ? : "-");
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
for (action = action->next; action; action = action->next) for (action = action->next; action; action = action->next)
......
...@@ -63,7 +63,6 @@ static struct irq_chip ns9xxx_chip = { ...@@ -63,7 +63,6 @@ static struct irq_chip ns9xxx_chip = {
#else #else
static void handle_prio_irq(unsigned int irq, struct irq_desc *desc) static void handle_prio_irq(unsigned int irq, struct irq_desc *desc)
{ {
unsigned int cpu = smp_processor_id();
struct irqaction *action; struct irqaction *action;
irqreturn_t action_ret; irqreturn_t action_ret;
...@@ -72,7 +71,7 @@ static void handle_prio_irq(unsigned int irq, struct irq_desc *desc) ...@@ -72,7 +71,7 @@ static void handle_prio_irq(unsigned int irq, struct irq_desc *desc)
BUG_ON(desc->status & IRQ_INPROGRESS); BUG_ON(desc->status & IRQ_INPROGRESS);
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
kstat_cpu(cpu).irqs[irq]++; kstat_incr_irqs_this_cpu(irq, desc);
action = desc->action; action = desc->action;
if (unlikely(!action || (desc->status & IRQ_DISABLED))) if (unlikely(!action || (desc->status & IRQ_DISABLED)))
......
...@@ -58,7 +58,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -58,7 +58,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%3d: ", i); seq_printf(p, "%3d: ", i);
for_each_online_cpu(cpu) for_each_online_cpu(cpu)
seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu));
seq_printf(p, " %8s", irq_desc[i].chip->name ? : "-"); seq_printf(p, " %8s", irq_desc[i].chip->name ? : "-");
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
for (action = action->next; action; action = action->next) for (action = action->next; action; action = action->next)
......
...@@ -83,7 +83,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -83,7 +83,7 @@ int show_interrupts(struct seq_file *p, void *v)
goto skip; goto skip;
seq_printf(p, "%3d: ", i); seq_printf(p, "%3d: ", i);
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
seq_printf(p, " %8s", irq_desc[i].chip->name); seq_printf(p, " %8s", irq_desc[i].chip->name);
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
for (action = action->next; action; action = action->next) for (action = action->next; action; action = action->next)
......
...@@ -66,7 +66,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -66,7 +66,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%10u ", kstat_irqs(i)); seq_printf(p, "%10u ", kstat_irqs(i));
#else #else
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#endif #endif
seq_printf(p, " %14s", irq_desc[i].chip->typename); seq_printf(p, " %14s", irq_desc[i].chip->typename);
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
......
...@@ -74,7 +74,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -74,7 +74,7 @@ int show_interrupts(struct seq_file *p, void *v)
if (action) { if (action) {
seq_printf(p, "%3d: ", i); seq_printf(p, "%3d: ", i);
for_each_present_cpu(cpu) for_each_present_cpu(cpu)
seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu));
seq_printf(p, " %10s", irq_desc[i].chip->name ? : "-"); seq_printf(p, " %10s", irq_desc[i].chip->name ? : "-");
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
for (action = action->next; for (action = action->next;
......
...@@ -183,7 +183,7 @@ asmlinkage void do_IRQ(int irq) ...@@ -183,7 +183,7 @@ asmlinkage void do_IRQ(int irq)
#if defined(CONFIG_PROC_FS) #if defined(CONFIG_PROC_FS)
int show_interrupts(struct seq_file *p, void *v) int show_interrupts(struct seq_file *p, void *v)
{ {
int i = *(loff_t *) v, j; int i = *(loff_t *) v;
struct irqaction * action; struct irqaction * action;
unsigned long flags; unsigned long flags;
...@@ -196,7 +196,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -196,7 +196,7 @@ int show_interrupts(struct seq_file *p, void *v)
if (!action) if (!action)
goto unlock; goto unlock;
seq_printf(p, "%3d: ",i); seq_printf(p, "%3d: ",i);
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); seq_printf(p, "%10u ", kstat_irqs(i));
seq_printf(p, " %14s", irq_desc[i].chip->name); seq_printf(p, " %14s", irq_desc[i].chip->name);
seq_printf(p, "-%-8s", irq_desc[i].name); seq_printf(p, "-%-8s", irq_desc[i].name);
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
......
...@@ -80,7 +80,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -80,7 +80,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%10u ", kstat_irqs(i)); seq_printf(p, "%10u ", kstat_irqs(i));
#else #else
for_each_online_cpu(j) { for_each_online_cpu(j) {
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
} }
#endif #endif
seq_printf(p, " %14s", irq_desc[i].chip->name); seq_printf(p, " %14s", irq_desc[i].chip->name);
......
...@@ -49,7 +49,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -49,7 +49,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%10u ", kstat_irqs(i)); seq_printf(p, "%10u ", kstat_irqs(i));
#else #else
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#endif #endif
seq_printf(p, " %14s", irq_desc[i].chip->typename); seq_printf(p, " %14s", irq_desc[i].chip->typename);
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
......
...@@ -108,7 +108,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -108,7 +108,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%10u ", kstat_irqs(i)); seq_printf(p, "%10u ", kstat_irqs(i));
#else #else
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#endif #endif
seq_printf(p, " %14s", irq_desc[i].chip->name); seq_printf(p, " %14s", irq_desc[i].chip->name);
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
......
...@@ -221,7 +221,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -221,7 +221,7 @@ int show_interrupts(struct seq_file *p, void *v)
if (action) { if (action) {
seq_printf(p, "%3d: ", i); seq_printf(p, "%3d: ", i);
for_each_present_cpu(cpu) for_each_present_cpu(cpu)
seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu));
seq_printf(p, " %14s.%u", irq_desc[i].chip->name, seq_printf(p, " %14s.%u", irq_desc[i].chip->name,
(GxICR(i) & GxICR_LEVEL) >> (GxICR(i) & GxICR_LEVEL) >>
GxICR_LEVEL_SHIFT); GxICR_LEVEL_SHIFT);
......
...@@ -185,7 +185,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -185,7 +185,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%3d: ", i); seq_printf(p, "%3d: ", i);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#else #else
seq_printf(p, "%10u ", kstat_irqs(i)); seq_printf(p, "%10u ", kstat_irqs(i));
#endif #endif
......
...@@ -190,7 +190,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -190,7 +190,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%3d: ", i); seq_printf(p, "%3d: ", i);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#else #else
seq_printf(p, "%10u ", kstat_irqs(i)); seq_printf(p, "%10u ", kstat_irqs(i));
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
......
...@@ -237,8 +237,6 @@ extern int noirqdebug; ...@@ -237,8 +237,6 @@ extern int noirqdebug;
static void handle_iic_irq(unsigned int irq, struct irq_desc *desc) static void handle_iic_irq(unsigned int irq, struct irq_desc *desc)
{ {
const unsigned int cpu = smp_processor_id();
spin_lock(&desc->lock); spin_lock(&desc->lock);
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
...@@ -254,7 +252,7 @@ static void handle_iic_irq(unsigned int irq, struct irq_desc *desc) ...@@ -254,7 +252,7 @@ static void handle_iic_irq(unsigned int irq, struct irq_desc *desc)
goto out_eoi; goto out_eoi;
} }
kstat_cpu(cpu).irqs[irq]++; kstat_incr_irqs_this_cpu(irq, desc);
/* Mark the IRQ currently in progress.*/ /* Mark the IRQ currently in progress.*/
desc->status |= IRQ_INPROGRESS; desc->status |= IRQ_INPROGRESS;
......
...@@ -51,7 +51,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -51,7 +51,7 @@ int show_interrupts(struct seq_file *p, void *v)
goto unlock; goto unlock;
seq_printf(p, "%3d: ",i); seq_printf(p, "%3d: ",i);
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
seq_printf(p, " %14s", irq_desc[i].chip->name); seq_printf(p, " %14s", irq_desc[i].chip->name);
seq_printf(p, "-%-8s", irq_desc[i].name); seq_printf(p, "-%-8s", irq_desc[i].name);
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
......
...@@ -185,7 +185,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -185,7 +185,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%10u ", kstat_irqs(i)); seq_printf(p, "%10u ", kstat_irqs(i));
#else #else
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#endif #endif
seq_printf(p, " %9s", irq_desc[i].chip->typename); seq_printf(p, " %9s", irq_desc[i].chip->typename);
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
......
...@@ -36,10 +36,10 @@ ...@@ -36,10 +36,10 @@
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/irq.h>
#include <asm/oplib.h> #include <asm/oplib.h>
#include <asm/timer.h> #include <asm/timer.h>
#include <asm/irq.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/starfire.h> #include <asm/starfire.h>
......
...@@ -42,7 +42,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -42,7 +42,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%10u ", kstat_irqs(i)); seq_printf(p, "%10u ", kstat_irqs(i));
#else #else
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#endif #endif
seq_printf(p, " %14s", irq_desc[i].chip->typename); seq_printf(p, " %14s", irq_desc[i].chip->typename);
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
......
...@@ -165,6 +165,9 @@ config GENERIC_HARDIRQS ...@@ -165,6 +165,9 @@ config GENERIC_HARDIRQS
bool bool
default y default y
config GENERIC_HARDIRQS_NO__DO_IRQ
def_bool y
config GENERIC_IRQ_PROBE config GENERIC_IRQ_PROBE
bool bool
default y default y
......
...@@ -99,7 +99,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -99,7 +99,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, "%10u ", kstat_irqs(i)); seq_printf(p, "%10u ", kstat_irqs(i));
#else #else
for_each_online_cpu(j) for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
#endif #endif
seq_printf(p, " %14s", irq_desc[i].chip->typename); seq_printf(p, " %14s", irq_desc[i].chip->typename);
seq_printf(p, " %s", action->name); seq_printf(p, " %s", action->name);
......
...@@ -241,6 +241,10 @@ ...@@ -241,6 +241,10 @@
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/cryptohash.h> #include <linux/cryptohash.h>
#ifdef CONFIG_GENERIC_HARDIRQS
# include <linux/irq.h>
#endif
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -558,7 +562,7 @@ struct timer_rand_state { ...@@ -558,7 +562,7 @@ struct timer_rand_state {
unsigned dont_count_entropy:1; unsigned dont_count_entropy:1;
}; };
#ifndef CONFIG_SPARSE_IRQ #ifndef CONFIG_GENERIC_HARDIRQS
static struct timer_rand_state *irq_timer_state[NR_IRQS]; static struct timer_rand_state *irq_timer_state[NR_IRQS];
......
...@@ -20,7 +20,7 @@ struct irq_2_iommu { ...@@ -20,7 +20,7 @@ struct irq_2_iommu {
u8 irte_mask; u8 irte_mask;
}; };
#ifdef CONFIG_SPARSE_IRQ #ifdef CONFIG_GENERIC_HARDIRQS
static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu) static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu)
{ {
struct irq_2_iommu *iommu; struct irq_2_iommu *iommu;
......
...@@ -61,6 +61,17 @@ ...@@ -61,6 +61,17 @@
typedef irqreturn_t (*irq_handler_t)(int, void *); typedef irqreturn_t (*irq_handler_t)(int, void *);
/**
* struct irqaction - per interrupt action descriptor
* @handler: interrupt handler function
* @flags: flags (see IRQF_* above)
* @mask: no comment as it is useless and about to be removed
* @name: name of the device
* @dev_id: cookie to identify the device
* @next: pointer to the next irqaction for shared interrupts
* @irq: interrupt number
* @dir: pointer to the proc/irq/NN/name entry
*/
struct irqaction { struct irqaction {
irq_handler_t handler; irq_handler_t handler;
unsigned long flags; unsigned long flags;
...@@ -462,6 +473,12 @@ static inline void init_irq_proc(void) ...@@ -462,6 +473,12 @@ static inline void init_irq_proc(void)
} }
#endif #endif
#if defined(CONFIG_GENERIC_HARDIRQS) && defined(CONFIG_DEBUG_SHIRQ)
extern void debug_poll_all_shared_irqs(void);
#else
static inline void debug_poll_all_shared_irqs(void) { }
#endif
int show_interrupts(struct seq_file *p, void *v); int show_interrupts(struct seq_file *p, void *v);
struct irq_desc; struct irq_desc;
......
...@@ -160,12 +160,10 @@ struct irq_2_iommu; ...@@ -160,12 +160,10 @@ struct irq_2_iommu;
*/ */
struct irq_desc { struct irq_desc {
unsigned int irq; unsigned int irq;
#ifdef CONFIG_SPARSE_IRQ
struct timer_rand_state *timer_rand_state; struct timer_rand_state *timer_rand_state;
unsigned int *kstat_irqs; unsigned int *kstat_irqs;
# ifdef CONFIG_INTR_REMAP #ifdef CONFIG_INTR_REMAP
struct irq_2_iommu *irq_2_iommu; struct irq_2_iommu *irq_2_iommu;
# endif
#endif #endif
irq_flow_handler_t handle_irq; irq_flow_handler_t handle_irq;
struct irq_chip *chip; struct irq_chip *chip;
...@@ -202,12 +200,6 @@ extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc ...@@ -202,12 +200,6 @@ extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc
extern struct irq_desc irq_desc[NR_IRQS]; extern struct irq_desc irq_desc[NR_IRQS];
#else /* CONFIG_SPARSE_IRQ */ #else /* CONFIG_SPARSE_IRQ */
extern struct irq_desc *move_irq_desc(struct irq_desc *old_desc, int cpu); extern struct irq_desc *move_irq_desc(struct irq_desc *old_desc, int cpu);
#define kstat_irqs_this_cpu(DESC) \
((DESC)->kstat_irqs[smp_processor_id()])
#define kstat_incr_irqs_this_cpu(irqno, DESC) \
((DESC)->kstat_irqs[smp_processor_id()]++)
#endif /* CONFIG_SPARSE_IRQ */ #endif /* CONFIG_SPARSE_IRQ */
extern struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu); extern struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu);
...@@ -226,7 +218,6 @@ irq_remap_to_desc(unsigned int irq, struct irq_desc *desc) ...@@ -226,7 +218,6 @@ irq_remap_to_desc(unsigned int irq, struct irq_desc *desc)
* Migration helpers for obsolete names, they will go away: * Migration helpers for obsolete names, they will go away:
*/ */
#define hw_interrupt_type irq_chip #define hw_interrupt_type irq_chip
typedef struct irq_chip hw_irq_controller;
#define no_irq_type no_irq_chip #define no_irq_type no_irq_chip
typedef struct irq_desc irq_desc_t; typedef struct irq_desc irq_desc_t;
...@@ -236,6 +227,7 @@ typedef struct irq_desc irq_desc_t; ...@@ -236,6 +227,7 @@ typedef struct irq_desc irq_desc_t;
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
extern int setup_irq(unsigned int irq, struct irqaction *new); extern int setup_irq(unsigned int irq, struct irqaction *new);
extern void remove_irq(unsigned int irq, struct irqaction *act);
#ifdef CONFIG_GENERIC_HARDIRQS #ifdef CONFIG_GENERIC_HARDIRQS
...@@ -280,7 +272,7 @@ static inline int irq_balancing_disabled(unsigned int irq) ...@@ -280,7 +272,7 @@ static inline int irq_balancing_disabled(unsigned int irq)
} }
/* Handle irq action chains: */ /* Handle irq action chains: */
extern int handle_IRQ_event(unsigned int irq, struct irqaction *action); extern irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action);
/* /*
* Built-in IRQ handlers for various IRQ types, * Built-in IRQ handlers for various IRQ types,
...@@ -325,7 +317,7 @@ static inline void generic_handle_irq(unsigned int irq) ...@@ -325,7 +317,7 @@ static inline void generic_handle_irq(unsigned int irq)
/* Handling of unhandled and spurious interrupts: */ /* Handling of unhandled and spurious interrupts: */
extern void note_interrupt(unsigned int irq, struct irq_desc *desc, extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
int action_ret); irqreturn_t action_ret);
/* Resending of interrupts :*/ /* Resending of interrupts :*/
void check_irq_resend(struct irq_desc *desc, unsigned int irq); void check_irq_resend(struct irq_desc *desc, unsigned int irq);
......
...@@ -28,13 +28,17 @@ extern struct irq_desc *irq_to_desc(unsigned int irq); ...@@ -28,13 +28,17 @@ extern struct irq_desc *irq_to_desc(unsigned int irq);
# define for_each_irq_desc(irq, desc) \ # define for_each_irq_desc(irq, desc) \
for (irq = 0, desc = irq_to_desc(irq); irq < nr_irqs; \ for (irq = 0, desc = irq_to_desc(irq); irq < nr_irqs; \
irq++, desc = irq_to_desc(irq)) \ irq++, desc = irq_to_desc(irq)) \
if (desc) if (!desc) \
; \
else
# define for_each_irq_desc_reverse(irq, desc) \ # define for_each_irq_desc_reverse(irq, desc) \
for (irq = nr_irqs - 1, desc = irq_to_desc(irq); irq >= 0; \ for (irq = nr_irqs - 1, desc = irq_to_desc(irq); irq >= 0; \
irq--, desc = irq_to_desc(irq)) \ irq--, desc = irq_to_desc(irq)) \
if (desc) if (!desc) \
; \
else
#endif /* CONFIG_GENERIC_HARDIRQS */ #endif /* CONFIG_GENERIC_HARDIRQS */
......
/* irqreturn.h */
#ifndef _LINUX_IRQRETURN_H #ifndef _LINUX_IRQRETURN_H
#define _LINUX_IRQRETURN_H #define _LINUX_IRQRETURN_H
/* /**
* For 2.4.x compatibility, 2.4.x can use * enum irqreturn
* * @IRQ_NONE interrupt was not from this device
* typedef void irqreturn_t; * @IRQ_HANDLED interrupt was handled by this device
* #define IRQ_NONE
* #define IRQ_HANDLED
* #define IRQ_RETVAL(x)
*
* To mix old-style and new-style irq handler returns.
*
* IRQ_NONE means we didn't handle it.
* IRQ_HANDLED means that we did have a valid interrupt and handled it.
* IRQ_RETVAL(x) selects on the two depending on x being non-zero (for handled)
*/ */
typedef int irqreturn_t; enum irqreturn {
IRQ_NONE,
IRQ_HANDLED,
};
#define IRQ_NONE (0) typedef enum irqreturn irqreturn_t;
#define IRQ_HANDLED (1) #define IRQ_RETVAL(x) ((x) != IRQ_NONE)
#define IRQ_RETVAL(x) ((x) != 0)
#endif #endif
...@@ -28,7 +28,7 @@ struct cpu_usage_stat { ...@@ -28,7 +28,7 @@ struct cpu_usage_stat {
struct kernel_stat { struct kernel_stat {
struct cpu_usage_stat cpustat; struct cpu_usage_stat cpustat;
#ifndef CONFIG_SPARSE_IRQ #ifndef CONFIG_GENERIC_HARDIRQS
unsigned int irqs[NR_IRQS]; unsigned int irqs[NR_IRQS];
#endif #endif
}; };
...@@ -41,7 +41,7 @@ DECLARE_PER_CPU(struct kernel_stat, kstat); ...@@ -41,7 +41,7 @@ DECLARE_PER_CPU(struct kernel_stat, kstat);
extern unsigned long long nr_context_switches(void); extern unsigned long long nr_context_switches(void);
#ifndef CONFIG_SPARSE_IRQ #ifndef CONFIG_GENERIC_HARDIRQS
#define kstat_irqs_this_cpu(irq) \ #define kstat_irqs_this_cpu(irq) \
(kstat_this_cpu.irqs[irq]) (kstat_this_cpu.irqs[irq])
...@@ -52,16 +52,19 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq, ...@@ -52,16 +52,19 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
{ {
kstat_this_cpu.irqs[irq]++; kstat_this_cpu.irqs[irq]++;
} }
#endif
#ifndef CONFIG_SPARSE_IRQ
static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
{ {
return kstat_cpu(cpu).irqs[irq]; return kstat_cpu(cpu).irqs[irq];
} }
#else #else
#include <linux/irq.h>
extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu); extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
#define kstat_irqs_this_cpu(DESC) \
((DESC)->kstat_irqs[smp_processor_id()])
#define kstat_incr_irqs_this_cpu(irqno, DESC) \
((DESC)->kstat_irqs[smp_processor_id()]++)
#endif #endif
/* /*
......
...@@ -78,6 +78,7 @@ void dynamic_irq_cleanup(unsigned int irq) ...@@ -78,6 +78,7 @@ void dynamic_irq_cleanup(unsigned int irq)
desc->handle_irq = handle_bad_irq; desc->handle_irq = handle_bad_irq;
desc->chip = &no_irq_chip; desc->chip = &no_irq_chip;
desc->name = NULL; desc->name = NULL;
clear_kstat_irqs(desc);
spin_unlock_irqrestore(&desc->lock, flags); spin_unlock_irqrestore(&desc->lock, flags);
} }
...@@ -290,7 +291,8 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq) ...@@ -290,7 +291,8 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq)
desc->chip->mask_ack(irq); desc->chip->mask_ack(irq);
else { else {
desc->chip->mask(irq); desc->chip->mask(irq);
desc->chip->ack(irq); if (desc->chip->ack)
desc->chip->ack(irq);
} }
} }
...@@ -476,7 +478,8 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) ...@@ -476,7 +478,8 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
kstat_incr_irqs_this_cpu(irq, desc); kstat_incr_irqs_this_cpu(irq, desc);
/* Start handling the irq */ /* Start handling the irq */
desc->chip->ack(irq); if (desc->chip->ack)
desc->chip->ack(irq);
desc = irq_remap_to_desc(irq, desc); desc = irq_remap_to_desc(irq, desc);
/* Mark the IRQ currently in progress.*/ /* Mark the IRQ currently in progress.*/
......
...@@ -83,19 +83,21 @@ static struct irq_desc irq_desc_init = { ...@@ -83,19 +83,21 @@ static struct irq_desc irq_desc_init = {
void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr) void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr)
{ {
unsigned long bytes;
char *ptr;
int node; int node;
void *ptr;
/* Compute how many bytes we need per irq and allocate them */
bytes = nr * sizeof(unsigned int);
node = cpu_to_node(cpu); node = cpu_to_node(cpu);
ptr = kzalloc_node(bytes, GFP_ATOMIC, node); ptr = kzalloc_node(nr * sizeof(*desc->kstat_irqs), GFP_ATOMIC, node);
printk(KERN_DEBUG " alloc kstat_irqs on cpu %d node %d\n", cpu, node);
if (ptr) /*
desc->kstat_irqs = (unsigned int *)ptr; * don't overwite if can not get new one
* init_copy_kstat_irqs() could still use old one
*/
if (ptr) {
printk(KERN_DEBUG " alloc kstat_irqs on cpu %d node %d\n",
cpu, node);
desc->kstat_irqs = ptr;
}
} }
static void init_one_irq_desc(int irq, struct irq_desc *desc, int cpu) static void init_one_irq_desc(int irq, struct irq_desc *desc, int cpu)
...@@ -227,6 +229,7 @@ struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { ...@@ -227,6 +229,7 @@ struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
} }
}; };
static unsigned int kstat_irqs_all[NR_IRQS][NR_CPUS];
int __init early_irq_init(void) int __init early_irq_init(void)
{ {
struct irq_desc *desc; struct irq_desc *desc;
...@@ -238,8 +241,10 @@ int __init early_irq_init(void) ...@@ -238,8 +241,10 @@ int __init early_irq_init(void)
desc = irq_desc; desc = irq_desc;
count = ARRAY_SIZE(irq_desc); count = ARRAY_SIZE(irq_desc);
for (i = 0; i < count; i++) for (i = 0; i < count; i++) {
desc[i].irq = i; desc[i].irq = i;
desc[i].kstat_irqs = kstat_irqs_all[i];
}
return arch_early_irq_init(); return arch_early_irq_init();
} }
...@@ -255,6 +260,11 @@ struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu) ...@@ -255,6 +260,11 @@ struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu)
} }
#endif /* !CONFIG_SPARSE_IRQ */ #endif /* !CONFIG_SPARSE_IRQ */
void clear_kstat_irqs(struct irq_desc *desc)
{
memset(desc->kstat_irqs, 0, nr_cpu_ids * sizeof(*(desc->kstat_irqs)));
}
/* /*
* What should we do if we get a hw irq event on an illegal vector? * What should we do if we get a hw irq event on an illegal vector?
* Each architecture has to answer this themself. * Each architecture has to answer this themself.
...@@ -328,6 +338,8 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) ...@@ -328,6 +338,8 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
irqreturn_t ret, retval = IRQ_NONE; irqreturn_t ret, retval = IRQ_NONE;
unsigned int status = 0; unsigned int status = 0;
WARN_ONCE(!in_irq(), "BUG: IRQ handler called from non-hardirq context!");
if (!(action->flags & IRQF_DISABLED)) if (!(action->flags & IRQF_DISABLED))
local_irq_enable_in_hardirq(); local_irq_enable_in_hardirq();
...@@ -347,6 +359,11 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) ...@@ -347,6 +359,11 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
} }
#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ #ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
#ifdef CONFIG_ENABLE_WARN_DEPRECATED
# warning __do_IRQ is deprecated. Please convert to proper flow handlers
#endif
/** /**
* __do_IRQ - original all in one highlevel IRQ handler * __do_IRQ - original all in one highlevel IRQ handler
* @irq: the interrupt number * @irq: the interrupt number
...@@ -467,12 +484,10 @@ void early_init_irq_lock_class(void) ...@@ -467,12 +484,10 @@ void early_init_irq_lock_class(void)
} }
} }
#ifdef CONFIG_SPARSE_IRQ
unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
{ {
struct irq_desc *desc = irq_to_desc(irq); struct irq_desc *desc = irq_to_desc(irq);
return desc ? desc->kstat_irqs[cpu] : 0; return desc ? desc->kstat_irqs[cpu] : 0;
} }
#endif
EXPORT_SYMBOL(kstat_irqs_cpu); EXPORT_SYMBOL(kstat_irqs_cpu);
...@@ -15,6 +15,7 @@ extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, ...@@ -15,6 +15,7 @@ extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
extern struct lock_class_key irq_desc_lock_class; extern struct lock_class_key irq_desc_lock_class;
extern void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr); extern void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr);
extern void clear_kstat_irqs(struct irq_desc *desc);
extern spinlock_t sparse_irq_lock; extern spinlock_t sparse_irq_lock;
extern struct irq_desc *irq_desc_ptrs[NR_IRQS]; extern struct irq_desc *irq_desc_ptrs[NR_IRQS];
......
...@@ -109,7 +109,7 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask) ...@@ -109,7 +109,7 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
/* /*
* Generic version of the affinity autoselector. * Generic version of the affinity autoselector.
*/ */
int do_irq_select_affinity(unsigned int irq, struct irq_desc *desc) static int setup_affinity(unsigned int irq, struct irq_desc *desc)
{ {
if (!irq_can_set_affinity(irq)) if (!irq_can_set_affinity(irq))
return 0; return 0;
...@@ -133,7 +133,7 @@ int do_irq_select_affinity(unsigned int irq, struct irq_desc *desc) ...@@ -133,7 +133,7 @@ int do_irq_select_affinity(unsigned int irq, struct irq_desc *desc)
return 0; return 0;
} }
#else #else
static inline int do_irq_select_affinity(unsigned int irq, struct irq_desc *d) static inline int setup_affinity(unsigned int irq, struct irq_desc *d)
{ {
return irq_select_affinity(irq); return irq_select_affinity(irq);
} }
...@@ -149,14 +149,14 @@ int irq_select_affinity_usr(unsigned int irq) ...@@ -149,14 +149,14 @@ int irq_select_affinity_usr(unsigned int irq)
int ret; int ret;
spin_lock_irqsave(&desc->lock, flags); spin_lock_irqsave(&desc->lock, flags);
ret = do_irq_select_affinity(irq, desc); ret = setup_affinity(irq, desc);
spin_unlock_irqrestore(&desc->lock, flags); spin_unlock_irqrestore(&desc->lock, flags);
return ret; return ret;
} }
#else #else
static inline int do_irq_select_affinity(int irq, struct irq_desc *desc) static inline int setup_affinity(unsigned int irq, struct irq_desc *desc)
{ {
return 0; return 0;
} }
...@@ -389,9 +389,9 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, ...@@ -389,9 +389,9 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
* allocate special interrupts that are part of the architecture. * allocate special interrupts that are part of the architecture.
*/ */
static int static int
__setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new) __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
{ {
struct irqaction *old, **p; struct irqaction *old, **old_ptr;
const char *old_name = NULL; const char *old_name = NULL;
unsigned long flags; unsigned long flags;
int shared = 0; int shared = 0;
...@@ -423,8 +423,8 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new) ...@@ -423,8 +423,8 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
* The following block of code has to be executed atomically * The following block of code has to be executed atomically
*/ */
spin_lock_irqsave(&desc->lock, flags); spin_lock_irqsave(&desc->lock, flags);
p = &desc->action; old_ptr = &desc->action;
old = *p; old = *old_ptr;
if (old) { if (old) {
/* /*
* Can't share interrupts unless both agree to and are * Can't share interrupts unless both agree to and are
...@@ -447,8 +447,8 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new) ...@@ -447,8 +447,8 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
/* add new interrupt at end of irq queue */ /* add new interrupt at end of irq queue */
do { do {
p = &old->next; old_ptr = &old->next;
old = *p; old = *old_ptr;
} while (old); } while (old);
shared = 1; shared = 1;
} }
...@@ -488,7 +488,7 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new) ...@@ -488,7 +488,7 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
desc->status |= IRQ_NO_BALANCING; desc->status |= IRQ_NO_BALANCING;
/* Set default affinity mask once everything is setup */ /* Set default affinity mask once everything is setup */
do_irq_select_affinity(irq, desc); setup_affinity(irq, desc);
} else if ((new->flags & IRQF_TRIGGER_MASK) } else if ((new->flags & IRQF_TRIGGER_MASK)
&& (new->flags & IRQF_TRIGGER_MASK) && (new->flags & IRQF_TRIGGER_MASK)
...@@ -499,7 +499,7 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new) ...@@ -499,7 +499,7 @@ __setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
(int)(new->flags & IRQF_TRIGGER_MASK)); (int)(new->flags & IRQF_TRIGGER_MASK));
} }
*p = new; *old_ptr = new;
/* Reset broken irq detection when installing new handler */ /* Reset broken irq detection when installing new handler */
desc->irq_count = 0; desc->irq_count = 0;
...@@ -549,90 +549,117 @@ int setup_irq(unsigned int irq, struct irqaction *act) ...@@ -549,90 +549,117 @@ int setup_irq(unsigned int irq, struct irqaction *act)
return __setup_irq(irq, desc, act); return __setup_irq(irq, desc, act);
} }
EXPORT_SYMBOL_GPL(setup_irq);
/** /*
* free_irq - free an interrupt * Internal function to unregister an irqaction - used to free
* @irq: Interrupt line to free * regular and special interrupts that are part of the architecture.
* @dev_id: Device identity to free
*
* Remove an interrupt handler. The handler is removed and if the
* interrupt line is no longer in use by any driver it is disabled.
* On a shared IRQ the caller must ensure the interrupt is disabled
* on the card it drives before calling this function. The function
* does not return until any executing interrupts for this IRQ
* have completed.
*
* This function must not be called from interrupt context.
*/ */
void free_irq(unsigned int irq, void *dev_id) static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
{ {
struct irq_desc *desc = irq_to_desc(irq); struct irq_desc *desc = irq_to_desc(irq);
struct irqaction **p; struct irqaction *action, **action_ptr;
unsigned long flags; unsigned long flags;
WARN_ON(in_interrupt()); WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
if (!desc) if (!desc)
return; return NULL;
spin_lock_irqsave(&desc->lock, flags); spin_lock_irqsave(&desc->lock, flags);
p = &desc->action;
/*
* There can be multiple actions per IRQ descriptor, find the right
* one based on the dev_id:
*/
action_ptr = &desc->action;
for (;;) { for (;;) {
struct irqaction *action = *p; action = *action_ptr;
if (action) { if (!action) {
struct irqaction **pp = p; WARN(1, "Trying to free already-free IRQ %d\n", irq);
spin_unlock_irqrestore(&desc->lock, flags);
p = &action->next; return NULL;
if (action->dev_id != dev_id) }
continue;
/* Found it - now remove it from the list of entries */ if (action->dev_id == dev_id)
*pp = action->next; break;
action_ptr = &action->next;
}
/* Currently used only by UML, might disappear one day.*/ /* Found it - now remove it from the list of entries: */
*action_ptr = action->next;
/* Currently used only by UML, might disappear one day: */
#ifdef CONFIG_IRQ_RELEASE_METHOD #ifdef CONFIG_IRQ_RELEASE_METHOD
if (desc->chip->release) if (desc->chip->release)
desc->chip->release(irq, dev_id); desc->chip->release(irq, dev_id);
#endif #endif
if (!desc->action) { /* If this was the last handler, shut down the IRQ line: */
desc->status |= IRQ_DISABLED; if (!desc->action) {
if (desc->chip->shutdown) desc->status |= IRQ_DISABLED;
desc->chip->shutdown(irq); if (desc->chip->shutdown)
else desc->chip->shutdown(irq);
desc->chip->disable(irq); else
} desc->chip->disable(irq);
spin_unlock_irqrestore(&desc->lock, flags); }
unregister_handler_proc(irq, action); spin_unlock_irqrestore(&desc->lock, flags);
unregister_handler_proc(irq, action);
/* Make sure it's not being used on another CPU: */
synchronize_irq(irq);
/* Make sure it's not being used on another CPU */
synchronize_irq(irq);
#ifdef CONFIG_DEBUG_SHIRQ
/*
* It's a shared IRQ -- the driver ought to be
* prepared for it to happen even now it's
* being freed, so let's make sure.... We do
* this after actually deregistering it, to
* make sure that a 'real' IRQ doesn't run in
* parallel with our fake
*/
if (action->flags & IRQF_SHARED) {
local_irq_save(flags);
action->handler(irq, dev_id);
local_irq_restore(flags);
}
#endif
kfree(action);
return;
}
printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);
#ifdef CONFIG_DEBUG_SHIRQ #ifdef CONFIG_DEBUG_SHIRQ
dump_stack(); /*
#endif * It's a shared IRQ -- the driver ought to be prepared for an IRQ
spin_unlock_irqrestore(&desc->lock, flags); * event to happen even now it's being freed, so let's make sure that
return; * is so by doing an extra call to the handler ....
*
* ( We do this after actually deregistering it, to make sure that a
* 'real' IRQ doesn't run in * parallel with our fake. )
*/
if (action->flags & IRQF_SHARED) {
local_irq_save(flags);
action->handler(irq, dev_id);
local_irq_restore(flags);
} }
#endif
return action;
}
/**
* remove_irq - free an interrupt
* @irq: Interrupt line to free
* @act: irqaction for the interrupt
*
* Used to remove interrupts statically setup by the early boot process.
*/
void remove_irq(unsigned int irq, struct irqaction *act)
{
__free_irq(irq, act->dev_id);
}
EXPORT_SYMBOL_GPL(remove_irq);
/**
* free_irq - free an interrupt allocated with request_irq
* @irq: Interrupt line to free
* @dev_id: Device identity to free
*
* Remove an interrupt handler. The handler is removed and if the
* interrupt line is no longer in use by any driver it is disabled.
* On a shared IRQ the caller must ensure the interrupt is disabled
* on the card it drives before calling this function. The function
* does not return until any executing interrupts for this IRQ
* have completed.
*
* This function must not be called from interrupt context.
*/
void free_irq(unsigned int irq, void *dev_id)
{
kfree(__free_irq(irq, dev_id));
} }
EXPORT_SYMBOL(free_irq); EXPORT_SYMBOL(free_irq);
...@@ -679,11 +706,12 @@ int request_irq(unsigned int irq, irq_handler_t handler, ...@@ -679,11 +706,12 @@ int request_irq(unsigned int irq, irq_handler_t handler,
* the behavior is classified as "will not fix" so we need to * the behavior is classified as "will not fix" so we need to
* start nudging drivers away from using that idiom. * start nudging drivers away from using that idiom.
*/ */
if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) ==
== (IRQF_SHARED|IRQF_DISABLED)) (IRQF_SHARED|IRQF_DISABLED)) {
pr_warning("IRQ %d/%s: IRQF_DISABLED is not " pr_warning(
"guaranteed on shared IRQs\n", "IRQ %d/%s: IRQF_DISABLED is not guaranteed on shared IRQs\n",
irq, devname); irq, devname);
}
#ifdef CONFIG_LOCKDEP #ifdef CONFIG_LOCKDEP
/* /*
...@@ -709,15 +737,13 @@ int request_irq(unsigned int irq, irq_handler_t handler, ...@@ -709,15 +737,13 @@ int request_irq(unsigned int irq, irq_handler_t handler,
if (!handler) if (!handler)
return -EINVAL; return -EINVAL;
action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC); action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action) if (!action)
return -ENOMEM; return -ENOMEM;
action->handler = handler; action->handler = handler;
action->flags = irqflags; action->flags = irqflags;
cpus_clear(action->mask);
action->name = devname; action->name = devname;
action->next = NULL;
action->dev_id = dev_id; action->dev_id = dev_id;
retval = __setup_irq(irq, desc, action); retval = __setup_irq(irq, desc, action);
......
...@@ -17,16 +17,11 @@ static void init_copy_kstat_irqs(struct irq_desc *old_desc, ...@@ -17,16 +17,11 @@ static void init_copy_kstat_irqs(struct irq_desc *old_desc,
struct irq_desc *desc, struct irq_desc *desc,
int cpu, int nr) int cpu, int nr)
{ {
unsigned long bytes;
init_kstat_irqs(desc, cpu, nr); init_kstat_irqs(desc, cpu, nr);
if (desc->kstat_irqs != old_desc->kstat_irqs) { if (desc->kstat_irqs != old_desc->kstat_irqs)
/* Compute how many bytes we need per irq and allocate them */ memcpy(desc->kstat_irqs, old_desc->kstat_irqs,
bytes = nr * sizeof(unsigned int); nr * sizeof(*desc->kstat_irqs));
memcpy(desc->kstat_irqs, old_desc->kstat_irqs, bytes);
}
} }
static void free_kstat_irqs(struct irq_desc *old_desc, struct irq_desc *desc) static void free_kstat_irqs(struct irq_desc *old_desc, struct irq_desc *desc)
......
...@@ -104,7 +104,7 @@ static int misrouted_irq(int irq) ...@@ -104,7 +104,7 @@ static int misrouted_irq(int irq)
return ok; return ok;
} }
static void poll_spurious_irqs(unsigned long dummy) static void poll_all_shared_irqs(void)
{ {
struct irq_desc *desc; struct irq_desc *desc;
int i; int i;
...@@ -123,11 +123,23 @@ static void poll_spurious_irqs(unsigned long dummy) ...@@ -123,11 +123,23 @@ static void poll_spurious_irqs(unsigned long dummy)
try_one_irq(i, desc); try_one_irq(i, desc);
} }
}
static void poll_spurious_irqs(unsigned long dummy)
{
poll_all_shared_irqs();
mod_timer(&poll_spurious_irq_timer, mod_timer(&poll_spurious_irq_timer,
jiffies + POLL_SPURIOUS_IRQ_INTERVAL); jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
} }
#ifdef CONFIG_DEBUG_SHIRQ
void debug_poll_all_shared_irqs(void)
{
poll_all_shared_irqs();
}
#endif
/* /*
* If 99,900 of the previous 100,000 interrupts have not been handled * If 99,900 of the previous 100,000 interrupts have not been handled
* then assume that the IRQ is stuck in some manner. Drop a diagnostic * then assume that the IRQ is stuck in some manner. Drop a diagnostic
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment