Merge branch 'genirq-v28-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
This merges branches irq/genirq, irq/sparseirq-v4, timers/hpet-percpu and x86/uv. The sparseirq branch is just preliminary groundwork: no sparse IRQs are actually implemented by this tree anymore - just the new APIs are added while keeping the old way intact as well (the new APIs map 1:1 to irq_desc[]). The 'real' sparse IRQ support will then be a relatively small patch ontop of this - with a v2.6.29 merge target. * 'genirq-v28-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (178 commits) genirq: improve include files intr_remapping: fix typo io_apic: make irq_mis_count available on 64-bit too genirq: fix name space collisions of nr_irqs in arch/* genirq: fix name space collision of nr_irqs in autoprobe.c genirq: use iterators for irq_desc loops proc: fixup irq iterator genirq: add reverse iterator for irq_desc x86: move ack_bad_irq() to irq.c x86: unify show_interrupts() and proc helpers x86: cleanup show_interrupts genirq: cleanup the sparseirq modifications genirq: remove artifacts from sparseirq removal genirq: revert dynarray genirq: remove irq_to_desc_alloc genirq: remove sparse irq code genirq: use inline function for irq_to_desc genirq: consolidate nr_irqs and for_each_irq_desc() x86: remove sparse irq from Kconfig genirq: define nr_irqs for architectures with GENERIC_HARDIRQS=n ...
This commit is contained in:
+16
-27
@@ -30,17 +30,16 @@ static DEFINE_MUTEX(probing_active);
|
||||
unsigned long probe_irq_on(void)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
unsigned long mask;
|
||||
unsigned int i;
|
||||
unsigned long mask = 0;
|
||||
unsigned int status;
|
||||
int i;
|
||||
|
||||
mutex_lock(&probing_active);
|
||||
/*
|
||||
* something may have generated an irq long ago and we want to
|
||||
* flush such a longstanding irq before considering it as spurious.
|
||||
*/
|
||||
for (i = NR_IRQS-1; i > 0; i--) {
|
||||
desc = irq_desc + i;
|
||||
|
||||
for_each_irq_desc_reverse(i, desc) {
|
||||
spin_lock_irq(&desc->lock);
|
||||
if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
|
||||
/*
|
||||
@@ -68,9 +67,7 @@ unsigned long probe_irq_on(void)
|
||||
* (we must startup again here because if a longstanding irq
|
||||
* happened in the previous stage, it may have masked itself)
|
||||
*/
|
||||
for (i = NR_IRQS-1; i > 0; i--) {
|
||||
desc = irq_desc + i;
|
||||
|
||||
for_each_irq_desc_reverse(i, desc) {
|
||||
spin_lock_irq(&desc->lock);
|
||||
if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
|
||||
desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
|
||||
@@ -88,11 +85,7 @@ unsigned long probe_irq_on(void)
|
||||
/*
|
||||
* Now filter out any obviously spurious interrupts
|
||||
*/
|
||||
mask = 0;
|
||||
for (i = 0; i < NR_IRQS; i++) {
|
||||
unsigned int status;
|
||||
|
||||
desc = irq_desc + i;
|
||||
for_each_irq_desc(i, desc) {
|
||||
spin_lock_irq(&desc->lock);
|
||||
status = desc->status;
|
||||
|
||||
@@ -126,14 +119,11 @@ EXPORT_SYMBOL(probe_irq_on);
|
||||
*/
|
||||
unsigned int probe_irq_mask(unsigned long val)
|
||||
{
|
||||
unsigned int mask;
|
||||
unsigned int status, mask = 0;
|
||||
struct irq_desc *desc;
|
||||
int i;
|
||||
|
||||
mask = 0;
|
||||
for (i = 0; i < NR_IRQS; i++) {
|
||||
struct irq_desc *desc = irq_desc + i;
|
||||
unsigned int status;
|
||||
|
||||
for_each_irq_desc(i, desc) {
|
||||
spin_lock_irq(&desc->lock);
|
||||
status = desc->status;
|
||||
|
||||
@@ -171,20 +161,19 @@ EXPORT_SYMBOL(probe_irq_mask);
|
||||
*/
|
||||
int probe_irq_off(unsigned long val)
|
||||
{
|
||||
int i, irq_found = 0, nr_irqs = 0;
|
||||
|
||||
for (i = 0; i < NR_IRQS; i++) {
|
||||
struct irq_desc *desc = irq_desc + i;
|
||||
unsigned int status;
|
||||
int i, irq_found = 0, nr_of_irqs = 0;
|
||||
struct irq_desc *desc;
|
||||
unsigned int status;
|
||||
|
||||
for_each_irq_desc(i, desc) {
|
||||
spin_lock_irq(&desc->lock);
|
||||
status = desc->status;
|
||||
|
||||
if (status & IRQ_AUTODETECT) {
|
||||
if (!(status & IRQ_WAITING)) {
|
||||
if (!nr_irqs)
|
||||
if (!nr_of_irqs)
|
||||
irq_found = i;
|
||||
nr_irqs++;
|
||||
nr_of_irqs++;
|
||||
}
|
||||
desc->status = status & ~IRQ_AUTODETECT;
|
||||
desc->chip->shutdown(i);
|
||||
@@ -193,7 +182,7 @@ int probe_irq_off(unsigned long val)
|
||||
}
|
||||
mutex_unlock(&probing_active);
|
||||
|
||||
if (nr_irqs > 1)
|
||||
if (nr_of_irqs > 1)
|
||||
irq_found = -irq_found;
|
||||
|
||||
return irq_found;
|
||||
|
||||
+45
-56
@@ -24,16 +24,15 @@
|
||||
*/
|
||||
void dynamic_irq_init(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
if (irq >= NR_IRQS) {
|
||||
if (!desc) {
|
||||
WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ensure we don't have left over values from a previous use of this irq */
|
||||
desc = irq_desc + irq;
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
desc->status = IRQ_DISABLED;
|
||||
desc->chip = &no_irq_chip;
|
||||
@@ -57,15 +56,14 @@ void dynamic_irq_init(unsigned int irq)
|
||||
*/
|
||||
void dynamic_irq_cleanup(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
if (irq >= NR_IRQS) {
|
||||
if (!desc) {
|
||||
WARN(1, KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq);
|
||||
return;
|
||||
}
|
||||
|
||||
desc = irq_desc + irq;
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
if (desc->action) {
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
@@ -89,10 +87,10 @@ void dynamic_irq_cleanup(unsigned int irq)
|
||||
*/
|
||||
int set_irq_chip(unsigned int irq, struct irq_chip *chip)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
if (irq >= NR_IRQS) {
|
||||
if (!desc) {
|
||||
WARN(1, KERN_ERR "Trying to install chip for IRQ%d\n", irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -100,7 +98,6 @@ int set_irq_chip(unsigned int irq, struct irq_chip *chip)
|
||||
if (!chip)
|
||||
chip = &no_irq_chip;
|
||||
|
||||
desc = irq_desc + irq;
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
irq_chip_set_defaults(chip);
|
||||
desc->chip = chip;
|
||||
@@ -111,27 +108,27 @@ int set_irq_chip(unsigned int irq, struct irq_chip *chip)
|
||||
EXPORT_SYMBOL(set_irq_chip);
|
||||
|
||||
/**
|
||||
* set_irq_type - set the irq type for an irq
|
||||
* set_irq_type - set the irq trigger type for an irq
|
||||
* @irq: irq number
|
||||
* @type: interrupt type - see include/linux/interrupt.h
|
||||
* @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
|
||||
*/
|
||||
int set_irq_type(unsigned int irq, unsigned int type)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
int ret = -ENXIO;
|
||||
|
||||
if (irq >= NR_IRQS) {
|
||||
if (!desc) {
|
||||
printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
desc = irq_desc + irq;
|
||||
if (desc->chip->set_type) {
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
ret = desc->chip->set_type(irq, type);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
if (type == IRQ_TYPE_NONE)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
ret = __irq_set_trigger(desc, irq, flags);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(set_irq_type);
|
||||
@@ -145,16 +142,15 @@ EXPORT_SYMBOL(set_irq_type);
|
||||
*/
|
||||
int set_irq_data(unsigned int irq, void *data)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
if (irq >= NR_IRQS) {
|
||||
if (!desc) {
|
||||
printk(KERN_ERR
|
||||
"Trying to install controller data for IRQ%d\n", irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
desc = irq_desc + irq;
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
desc->handler_data = data;
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
@@ -171,15 +167,15 @@ EXPORT_SYMBOL(set_irq_data);
|
||||
*/
|
||||
int set_irq_msi(unsigned int irq, struct msi_desc *entry)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
if (irq >= NR_IRQS) {
|
||||
if (!desc) {
|
||||
printk(KERN_ERR
|
||||
"Trying to install msi data for IRQ%d\n", irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
desc = irq_desc + irq;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
desc->msi_desc = entry;
|
||||
if (entry)
|
||||
@@ -197,10 +193,16 @@ int set_irq_msi(unsigned int irq, struct msi_desc *entry)
|
||||
*/
|
||||
int set_irq_chip_data(unsigned int irq, void *data)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
if (irq >= NR_IRQS || !desc->chip) {
|
||||
if (!desc) {
|
||||
printk(KERN_ERR
|
||||
"Trying to install chip data for IRQ%d\n", irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!desc->chip) {
|
||||
printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d)\n", irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -218,7 +220,7 @@ EXPORT_SYMBOL(set_irq_chip_data);
|
||||
*/
|
||||
static void default_enable(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
desc->chip->unmask(irq);
|
||||
desc->status &= ~IRQ_MASKED;
|
||||
@@ -236,8 +238,9 @@ static void default_disable(unsigned int irq)
|
||||
*/
|
||||
static unsigned int default_startup(unsigned int irq)
|
||||
{
|
||||
irq_desc[irq].chip->enable(irq);
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
desc->chip->enable(irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -246,7 +249,7 @@ static unsigned int default_startup(unsigned int irq)
|
||||
*/
|
||||
static void default_shutdown(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
desc->chip->mask(irq);
|
||||
desc->status |= IRQ_MASKED;
|
||||
@@ -305,14 +308,13 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
struct irqaction *action;
|
||||
irqreturn_t action_ret;
|
||||
const unsigned int cpu = smp_processor_id();
|
||||
|
||||
spin_lock(&desc->lock);
|
||||
|
||||
if (unlikely(desc->status & IRQ_INPROGRESS))
|
||||
goto out_unlock;
|
||||
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
|
||||
kstat_cpu(cpu).irqs[irq]++;
|
||||
kstat_incr_irqs_this_cpu(irq, desc);
|
||||
|
||||
action = desc->action;
|
||||
if (unlikely(!action || (desc->status & IRQ_DISABLED)))
|
||||
@@ -344,7 +346,6 @@ out_unlock:
|
||||
void
|
||||
handle_level_irq(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
struct irqaction *action;
|
||||
irqreturn_t action_ret;
|
||||
|
||||
@@ -354,7 +355,7 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
|
||||
if (unlikely(desc->status & IRQ_INPROGRESS))
|
||||
goto out_unlock;
|
||||
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
|
||||
kstat_cpu(cpu).irqs[irq]++;
|
||||
kstat_incr_irqs_this_cpu(irq, desc);
|
||||
|
||||
/*
|
||||
* If its disabled or no action available
|
||||
@@ -392,7 +393,6 @@ out_unlock:
|
||||
void
|
||||
handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
struct irqaction *action;
|
||||
irqreturn_t action_ret;
|
||||
|
||||
@@ -402,7 +402,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
|
||||
goto out;
|
||||
|
||||
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
|
||||
kstat_cpu(cpu).irqs[irq]++;
|
||||
kstat_incr_irqs_this_cpu(irq, desc);
|
||||
|
||||
/*
|
||||
* If its disabled or no action available
|
||||
@@ -451,8 +451,6 @@ out:
|
||||
void
|
||||
handle_edge_irq(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
const unsigned int cpu = smp_processor_id();
|
||||
|
||||
spin_lock(&desc->lock);
|
||||
|
||||
desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
|
||||
@@ -468,8 +466,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
|
||||
mask_ack_irq(desc, irq);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
kstat_cpu(cpu).irqs[irq]++;
|
||||
kstat_incr_irqs_this_cpu(irq, desc);
|
||||
|
||||
/* Start handling the irq */
|
||||
desc->chip->ack(irq);
|
||||
@@ -524,7 +521,7 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
irqreturn_t action_ret;
|
||||
|
||||
kstat_this_cpu.irqs[irq]++;
|
||||
kstat_incr_irqs_this_cpu(irq, desc);
|
||||
|
||||
if (desc->chip->ack)
|
||||
desc->chip->ack(irq);
|
||||
@@ -541,17 +538,15 @@ void
|
||||
__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
|
||||
const char *name)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
if (irq >= NR_IRQS) {
|
||||
if (!desc) {
|
||||
printk(KERN_ERR
|
||||
"Trying to install type control for IRQ%d\n", irq);
|
||||
return;
|
||||
}
|
||||
|
||||
desc = irq_desc + irq;
|
||||
|
||||
if (!handle)
|
||||
handle = handle_bad_irq;
|
||||
else if (desc->chip == &no_irq_chip) {
|
||||
@@ -583,7 +578,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
|
||||
desc->status &= ~IRQ_DISABLED;
|
||||
desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
|
||||
desc->depth = 0;
|
||||
desc->chip->unmask(irq);
|
||||
desc->chip->startup(irq);
|
||||
}
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
@@ -606,17 +601,14 @@ set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
|
||||
|
||||
void __init set_irq_noprobe(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
if (irq >= NR_IRQS) {
|
||||
if (!desc) {
|
||||
printk(KERN_ERR "Trying to mark IRQ%d non-probeable\n", irq);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
desc = irq_desc + irq;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
desc->status |= IRQ_NOPROBE;
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
@@ -624,17 +616,14 @@ void __init set_irq_noprobe(unsigned int irq)
|
||||
|
||||
void __init set_irq_probe(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
if (irq >= NR_IRQS) {
|
||||
if (!desc) {
|
||||
printk(KERN_ERR "Trying to mark IRQ%d probeable\n", irq);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
desc = irq_desc + irq;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
desc->status &= ~IRQ_NOPROBE;
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
|
||||
+15
-12
@@ -25,11 +25,10 @@
|
||||
*
|
||||
* Handles spurious and unhandled IRQ's. It also prints a debugmessage.
|
||||
*/
|
||||
void
|
||||
handle_bad_irq(unsigned int irq, struct irq_desc *desc)
|
||||
void handle_bad_irq(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
print_irq_desc(irq, desc);
|
||||
kstat_this_cpu.irqs[irq]++;
|
||||
kstat_incr_irqs_this_cpu(irq, desc);
|
||||
ack_bad_irq(irq);
|
||||
}
|
||||
|
||||
@@ -47,6 +46,9 @@ handle_bad_irq(unsigned int irq, struct irq_desc *desc)
|
||||
*
|
||||
* Controller mappings for all interrupt sources:
|
||||
*/
|
||||
int nr_irqs = NR_IRQS;
|
||||
EXPORT_SYMBOL_GPL(nr_irqs);
|
||||
|
||||
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
|
||||
[0 ... NR_IRQS-1] = {
|
||||
.status = IRQ_DISABLED,
|
||||
@@ -66,7 +68,9 @@ struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
|
||||
*/
|
||||
static void ack_bad(unsigned int irq)
|
||||
{
|
||||
print_irq_desc(irq, irq_desc + irq);
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
print_irq_desc(irq, desc);
|
||||
ack_bad_irq(irq);
|
||||
}
|
||||
|
||||
@@ -131,8 +135,6 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
|
||||
irqreturn_t ret, retval = IRQ_NONE;
|
||||
unsigned int status = 0;
|
||||
|
||||
handle_dynamic_tick(action);
|
||||
|
||||
if (!(action->flags & IRQF_DISABLED))
|
||||
local_irq_enable_in_hardirq();
|
||||
|
||||
@@ -165,11 +167,12 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
|
||||
*/
|
||||
unsigned int __do_IRQ(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
struct irqaction *action;
|
||||
unsigned int status;
|
||||
|
||||
kstat_this_cpu.irqs[irq]++;
|
||||
kstat_incr_irqs_this_cpu(irq, desc);
|
||||
|
||||
if (CHECK_IRQ_PER_CPU(desc->status)) {
|
||||
irqreturn_t action_ret;
|
||||
|
||||
@@ -256,8 +259,8 @@ out:
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
/*
|
||||
* lockdep: we want to handle all irq_desc locks as a single lock-class:
|
||||
*/
|
||||
@@ -265,10 +268,10 @@ static struct lock_class_key irq_desc_lock_class;
|
||||
|
||||
void early_init_irq_lock_class(void)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NR_IRQS; i++)
|
||||
lockdep_set_class(&irq_desc[i].lock, &irq_desc_lock_class);
|
||||
for_each_irq_desc(i, desc)
|
||||
lockdep_set_class(&desc->lock, &irq_desc_lock_class);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,12 +10,15 @@ extern void irq_chip_set_defaults(struct irq_chip *chip);
|
||||
/* Set default handler: */
|
||||
extern void compat_irq_chip_set_default_handler(struct irq_desc *desc);
|
||||
|
||||
extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
|
||||
unsigned long flags);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
extern void register_irq_proc(unsigned int irq);
|
||||
extern void register_irq_proc(unsigned int irq, struct irq_desc *desc);
|
||||
extern void register_handler_proc(unsigned int irq, struct irqaction *action);
|
||||
extern void unregister_handler_proc(unsigned int irq, struct irqaction *action);
|
||||
#else
|
||||
static inline void register_irq_proc(unsigned int irq) { }
|
||||
static inline void register_irq_proc(unsigned int irq, struct irq_desc *desc) { }
|
||||
static inline void register_handler_proc(unsigned int irq,
|
||||
struct irqaction *action) { }
|
||||
static inline void unregister_handler_proc(unsigned int irq,
|
||||
|
||||
+80
-43
@@ -31,10 +31,10 @@ cpumask_t irq_default_affinity = CPU_MASK_ALL;
|
||||
*/
|
||||
void synchronize_irq(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned int status;
|
||||
|
||||
if (irq >= NR_IRQS)
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
do {
|
||||
@@ -64,7 +64,7 @@ EXPORT_SYMBOL(synchronize_irq);
|
||||
*/
|
||||
int irq_can_set_affinity(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
if (CHECK_IRQ_PER_CPU(desc->status) || !desc->chip ||
|
||||
!desc->chip->set_affinity)
|
||||
@@ -81,18 +81,17 @@ int irq_can_set_affinity(unsigned int irq)
|
||||
*/
|
||||
int irq_set_affinity(unsigned int irq, cpumask_t cpumask)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
if (!desc->chip->set_affinity)
|
||||
return -EINVAL;
|
||||
|
||||
set_balance_irq_affinity(irq, cpumask);
|
||||
|
||||
#ifdef CONFIG_GENERIC_PENDING_IRQ
|
||||
if (desc->status & IRQ_MOVE_PCNTXT) {
|
||||
if (desc->status & IRQ_MOVE_PCNTXT || desc->status & IRQ_DISABLED) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
desc->affinity = cpumask;
|
||||
desc->chip->set_affinity(irq, cpumask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
} else
|
||||
@@ -111,16 +110,17 @@ int irq_set_affinity(unsigned int irq, cpumask_t cpumask)
|
||||
int irq_select_affinity(unsigned int irq)
|
||||
{
|
||||
cpumask_t mask;
|
||||
struct irq_desc *desc;
|
||||
|
||||
if (!irq_can_set_affinity(irq))
|
||||
return 0;
|
||||
|
||||
cpus_and(mask, cpu_online_map, irq_default_affinity);
|
||||
|
||||
irq_desc[irq].affinity = mask;
|
||||
irq_desc[irq].chip->set_affinity(irq, mask);
|
||||
desc = irq_to_desc(irq);
|
||||
desc->affinity = mask;
|
||||
desc->chip->set_affinity(irq, mask);
|
||||
|
||||
set_balance_irq_affinity(irq, mask);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -140,10 +140,10 @@ int irq_select_affinity(unsigned int irq)
|
||||
*/
|
||||
void disable_irq_nosync(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
if (irq >= NR_IRQS)
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
@@ -169,9 +169,9 @@ EXPORT_SYMBOL(disable_irq_nosync);
|
||||
*/
|
||||
void disable_irq(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
if (irq >= NR_IRQS)
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
disable_irq_nosync(irq);
|
||||
@@ -211,10 +211,10 @@ static void __enable_irq(struct irq_desc *desc, unsigned int irq)
|
||||
*/
|
||||
void enable_irq(unsigned int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
if (irq >= NR_IRQS)
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
@@ -223,9 +223,9 @@ void enable_irq(unsigned int irq)
|
||||
}
|
||||
EXPORT_SYMBOL(enable_irq);
|
||||
|
||||
int set_irq_wake_real(unsigned int irq, unsigned int on)
|
||||
static int set_irq_wake_real(unsigned int irq, unsigned int on)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
int ret = -ENXIO;
|
||||
|
||||
if (desc->chip->set_wake)
|
||||
@@ -248,7 +248,7 @@ int set_irq_wake_real(unsigned int irq, unsigned int on)
|
||||
*/
|
||||
int set_irq_wake(unsigned int irq, unsigned int on)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
@@ -288,12 +288,16 @@ EXPORT_SYMBOL(set_irq_wake);
|
||||
*/
|
||||
int can_request_irq(unsigned int irq, unsigned long irqflags)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
struct irqaction *action;
|
||||
|
||||
if (irq >= NR_IRQS || irq_desc[irq].status & IRQ_NOREQUEST)
|
||||
if (!desc)
|
||||
return 0;
|
||||
|
||||
action = irq_desc[irq].action;
|
||||
if (desc->status & IRQ_NOREQUEST)
|
||||
return 0;
|
||||
|
||||
action = desc->action;
|
||||
if (action)
|
||||
if (irqflags & action->flags & IRQF_SHARED)
|
||||
action = NULL;
|
||||
@@ -312,10 +316,11 @@ void compat_irq_chip_set_default_handler(struct irq_desc *desc)
|
||||
desc->handle_irq = NULL;
|
||||
}
|
||||
|
||||
static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq,
|
||||
int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
|
||||
unsigned long flags)
|
||||
{
|
||||
int ret;
|
||||
struct irq_chip *chip = desc->chip;
|
||||
|
||||
if (!chip || !chip->set_type) {
|
||||
/*
|
||||
@@ -333,6 +338,11 @@ static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq,
|
||||
pr_err("setting trigger mode %d for irq %u failed (%pF)\n",
|
||||
(int)(flags & IRQF_TRIGGER_MASK),
|
||||
irq, chip->set_type);
|
||||
else {
|
||||
/* note that IRQF_TRIGGER_MASK == IRQ_TYPE_SENSE_MASK */
|
||||
desc->status &= ~IRQ_TYPE_SENSE_MASK;
|
||||
desc->status |= flags & IRQ_TYPE_SENSE_MASK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -341,16 +351,16 @@ static int __irq_set_trigger(struct irq_chip *chip, unsigned int irq,
|
||||
* Internal function to register an irqaction - typically used to
|
||||
* allocate special interrupts that are part of the architecture.
|
||||
*/
|
||||
int setup_irq(unsigned int irq, struct irqaction *new)
|
||||
static int
|
||||
__setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irqaction *old, **p;
|
||||
const char *old_name = NULL;
|
||||
unsigned long flags;
|
||||
int shared = 0;
|
||||
int ret;
|
||||
|
||||
if (irq >= NR_IRQS)
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
if (desc->chip == &no_irq_chip)
|
||||
@@ -411,7 +421,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
|
||||
|
||||
/* Setup the type (level, edge polarity) if configured: */
|
||||
if (new->flags & IRQF_TRIGGER_MASK) {
|
||||
ret = __irq_set_trigger(desc->chip, irq, new->flags);
|
||||
ret = __irq_set_trigger(desc, irq, new->flags);
|
||||
|
||||
if (ret) {
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
@@ -430,16 +440,21 @@ int setup_irq(unsigned int irq, struct irqaction *new)
|
||||
if (!(desc->status & IRQ_NOAUTOEN)) {
|
||||
desc->depth = 0;
|
||||
desc->status &= ~IRQ_DISABLED;
|
||||
if (desc->chip->startup)
|
||||
desc->chip->startup(irq);
|
||||
else
|
||||
desc->chip->enable(irq);
|
||||
desc->chip->startup(irq);
|
||||
} else
|
||||
/* Undo nested disables: */
|
||||
desc->depth = 1;
|
||||
|
||||
/* Set default affinity mask once everything is setup */
|
||||
irq_select_affinity(irq);
|
||||
|
||||
} else if ((new->flags & IRQF_TRIGGER_MASK)
|
||||
&& (new->flags & IRQF_TRIGGER_MASK)
|
||||
!= (desc->status & IRQ_TYPE_SENSE_MASK)) {
|
||||
/* hope the handler works with the actual trigger mode... */
|
||||
pr_warning("IRQ %d uses trigger mode %d; requested %d\n",
|
||||
irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK),
|
||||
(int)(new->flags & IRQF_TRIGGER_MASK));
|
||||
}
|
||||
|
||||
*p = new;
|
||||
@@ -464,7 +479,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
|
||||
new->irq = irq;
|
||||
register_irq_proc(irq);
|
||||
register_irq_proc(irq, desc);
|
||||
new->dir = NULL;
|
||||
register_handler_proc(irq, new);
|
||||
|
||||
@@ -483,6 +498,20 @@ mismatch:
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
* setup_irq - setup an interrupt
|
||||
* @irq: Interrupt line to setup
|
||||
* @act: irqaction for the interrupt
|
||||
*
|
||||
* Used to statically setup interrupts in the early boot process.
|
||||
*/
|
||||
int setup_irq(unsigned int irq, struct irqaction *act)
|
||||
{
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
return __setup_irq(irq, desc, act);
|
||||
}
|
||||
|
||||
/**
|
||||
* free_irq - free an interrupt
|
||||
* @irq: Interrupt line to free
|
||||
@@ -499,15 +528,15 @@ mismatch:
|
||||
*/
|
||||
void free_irq(unsigned int irq, void *dev_id)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
struct irqaction **p;
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON(in_interrupt());
|
||||
if (irq >= NR_IRQS)
|
||||
|
||||
if (!desc)
|
||||
return;
|
||||
|
||||
desc = irq_desc + irq;
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
p = &desc->action;
|
||||
for (;;) {
|
||||
@@ -596,12 +625,14 @@ EXPORT_SYMBOL(free_irq);
|
||||
* IRQF_SHARED Interrupt is shared
|
||||
* IRQF_DISABLED Disable local interrupts while processing
|
||||
* IRQF_SAMPLE_RANDOM The interrupt can be used for entropy
|
||||
* IRQF_TRIGGER_* Specify active edge(s) or level
|
||||
*
|
||||
*/
|
||||
int request_irq(unsigned int irq, irq_handler_t handler,
|
||||
unsigned long irqflags, const char *devname, void *dev_id)
|
||||
{
|
||||
struct irqaction *action;
|
||||
struct irq_desc *desc;
|
||||
int retval;
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
@@ -618,9 +649,12 @@ int request_irq(unsigned int irq, irq_handler_t handler,
|
||||
*/
|
||||
if ((irqflags & IRQF_SHARED) && !dev_id)
|
||||
return -EINVAL;
|
||||
if (irq >= NR_IRQS)
|
||||
|
||||
desc = irq_to_desc(irq);
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
if (irq_desc[irq].status & IRQ_NOREQUEST)
|
||||
|
||||
if (desc->status & IRQ_NOREQUEST)
|
||||
return -EINVAL;
|
||||
if (!handler)
|
||||
return -EINVAL;
|
||||
@@ -636,26 +670,29 @@ int request_irq(unsigned int irq, irq_handler_t handler,
|
||||
action->next = NULL;
|
||||
action->dev_id = dev_id;
|
||||
|
||||
retval = __setup_irq(irq, desc, action);
|
||||
if (retval)
|
||||
kfree(action);
|
||||
|
||||
#ifdef CONFIG_DEBUG_SHIRQ
|
||||
if (irqflags & IRQF_SHARED) {
|
||||
/*
|
||||
* It's a shared IRQ -- the driver ought to be prepared for it
|
||||
* to happen immediately, so let's make sure....
|
||||
* We do this before actually registering it, to make sure that
|
||||
* a 'real' IRQ doesn't run in parallel with our fake
|
||||
* We disable the irq to make sure that a 'real' IRQ doesn't
|
||||
* run in parallel with our fake.
|
||||
*/
|
||||
unsigned long flags;
|
||||
|
||||
disable_irq(irq);
|
||||
local_irq_save(flags);
|
||||
|
||||
handler(irq, dev_id);
|
||||
|
||||
local_irq_restore(flags);
|
||||
enable_irq(irq);
|
||||
}
|
||||
#endif
|
||||
|
||||
retval = setup_irq(irq, action);
|
||||
if (retval)
|
||||
kfree(action);
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(request_irq);
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
|
||||
void set_pending_irq(unsigned int irq, cpumask_t mask)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
desc->status |= IRQ_MOVE_PENDING;
|
||||
irq_desc[irq].pending_mask = mask;
|
||||
desc->pending_mask = mask;
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
void move_masked_irq(int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
cpumask_t tmp;
|
||||
|
||||
if (likely(!(desc->status & IRQ_MOVE_PENDING)))
|
||||
@@ -30,7 +30,7 @@ void move_masked_irq(int irq)
|
||||
|
||||
desc->status &= ~IRQ_MOVE_PENDING;
|
||||
|
||||
if (unlikely(cpus_empty(irq_desc[irq].pending_mask)))
|
||||
if (unlikely(cpus_empty(desc->pending_mask)))
|
||||
return;
|
||||
|
||||
if (!desc->chip->set_affinity)
|
||||
@@ -38,7 +38,7 @@ void move_masked_irq(int irq)
|
||||
|
||||
assert_spin_locked(&desc->lock);
|
||||
|
||||
cpus_and(tmp, irq_desc[irq].pending_mask, cpu_online_map);
|
||||
cpus_and(tmp, desc->pending_mask, cpu_online_map);
|
||||
|
||||
/*
|
||||
* If there was a valid mask to work with, please
|
||||
@@ -55,12 +55,12 @@ void move_masked_irq(int irq)
|
||||
if (likely(!cpus_empty(tmp))) {
|
||||
desc->chip->set_affinity(irq,tmp);
|
||||
}
|
||||
cpus_clear(irq_desc[irq].pending_mask);
|
||||
cpus_clear(desc->pending_mask);
|
||||
}
|
||||
|
||||
void move_native_irq(int irq)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
if (likely(!(desc->status & IRQ_MOVE_PENDING)))
|
||||
return;
|
||||
|
||||
+24
-21
@@ -19,7 +19,7 @@ static struct proc_dir_entry *root_irq_dir;
|
||||
|
||||
static int irq_affinity_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + (long)m->private;
|
||||
struct irq_desc *desc = irq_to_desc((long)m->private);
|
||||
cpumask_t *mask = &desc->affinity;
|
||||
|
||||
#ifdef CONFIG_GENERIC_PENDING_IRQ
|
||||
@@ -43,7 +43,7 @@ static ssize_t irq_affinity_proc_write(struct file *file,
|
||||
cpumask_t new_value;
|
||||
int err;
|
||||
|
||||
if (!irq_desc[irq].chip->set_affinity || no_irq_affinity ||
|
||||
if (!irq_to_desc(irq)->chip->set_affinity || no_irq_affinity ||
|
||||
irq_balancing_disabled(irq))
|
||||
return -EIO;
|
||||
|
||||
@@ -132,20 +132,20 @@ static const struct file_operations default_affinity_proc_fops = {
|
||||
static int irq_spurious_read(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
struct irq_desc *d = &irq_desc[(long) data];
|
||||
struct irq_desc *desc = irq_to_desc((long) data);
|
||||
return sprintf(page, "count %u\n"
|
||||
"unhandled %u\n"
|
||||
"last_unhandled %u ms\n",
|
||||
d->irq_count,
|
||||
d->irqs_unhandled,
|
||||
jiffies_to_msecs(d->last_unhandled));
|
||||
desc->irq_count,
|
||||
desc->irqs_unhandled,
|
||||
jiffies_to_msecs(desc->last_unhandled));
|
||||
}
|
||||
|
||||
#define MAX_NAMELEN 128
|
||||
|
||||
static int name_unique(unsigned int irq, struct irqaction *new_action)
|
||||
{
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
struct irqaction *action;
|
||||
unsigned long flags;
|
||||
int ret = 1;
|
||||
@@ -165,8 +165,9 @@ static int name_unique(unsigned int irq, struct irqaction *new_action)
|
||||
void register_handler_proc(unsigned int irq, struct irqaction *action)
|
||||
{
|
||||
char name [MAX_NAMELEN];
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
if (!irq_desc[irq].dir || action->dir || !action->name ||
|
||||
if (!desc->dir || action->dir || !action->name ||
|
||||
!name_unique(irq, action))
|
||||
return;
|
||||
|
||||
@@ -174,36 +175,34 @@ void register_handler_proc(unsigned int irq, struct irqaction *action)
|
||||
snprintf(name, MAX_NAMELEN, "%s", action->name);
|
||||
|
||||
/* create /proc/irq/1234/handler/ */
|
||||
action->dir = proc_mkdir(name, irq_desc[irq].dir);
|
||||
action->dir = proc_mkdir(name, desc->dir);
|
||||
}
|
||||
|
||||
#undef MAX_NAMELEN
|
||||
|
||||
#define MAX_NAMELEN 10
|
||||
|
||||
void register_irq_proc(unsigned int irq)
|
||||
void register_irq_proc(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
char name [MAX_NAMELEN];
|
||||
struct proc_dir_entry *entry;
|
||||
|
||||
if (!root_irq_dir ||
|
||||
(irq_desc[irq].chip == &no_irq_chip) ||
|
||||
irq_desc[irq].dir)
|
||||
if (!root_irq_dir || (desc->chip == &no_irq_chip) || desc->dir)
|
||||
return;
|
||||
|
||||
memset(name, 0, MAX_NAMELEN);
|
||||
sprintf(name, "%d", irq);
|
||||
|
||||
/* create /proc/irq/1234 */
|
||||
irq_desc[irq].dir = proc_mkdir(name, root_irq_dir);
|
||||
desc->dir = proc_mkdir(name, root_irq_dir);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* create /proc/irq/<irq>/smp_affinity */
|
||||
proc_create_data("smp_affinity", 0600, irq_desc[irq].dir,
|
||||
proc_create_data("smp_affinity", 0600, desc->dir,
|
||||
&irq_affinity_proc_fops, (void *)(long)irq);
|
||||
#endif
|
||||
|
||||
entry = create_proc_entry("spurious", 0444, irq_desc[irq].dir);
|
||||
entry = create_proc_entry("spurious", 0444, desc->dir);
|
||||
if (entry) {
|
||||
entry->data = (void *)(long)irq;
|
||||
entry->read_proc = irq_spurious_read;
|
||||
@@ -214,8 +213,11 @@ void register_irq_proc(unsigned int irq)
|
||||
|
||||
void unregister_handler_proc(unsigned int irq, struct irqaction *action)
|
||||
{
|
||||
if (action->dir)
|
||||
remove_proc_entry(action->dir->name, irq_desc[irq].dir);
|
||||
if (action->dir) {
|
||||
struct irq_desc *desc = irq_to_desc(irq);
|
||||
|
||||
remove_proc_entry(action->dir->name, desc->dir);
|
||||
}
|
||||
}
|
||||
|
||||
void register_default_affinity_proc(void)
|
||||
@@ -228,7 +230,8 @@ void register_default_affinity_proc(void)
|
||||
|
||||
void init_irq_proc(void)
|
||||
{
|
||||
int i;
|
||||
unsigned int irq;
|
||||
struct irq_desc *desc;
|
||||
|
||||
/* create /proc/irq */
|
||||
root_irq_dir = proc_mkdir("irq", NULL);
|
||||
@@ -240,7 +243,7 @@ void init_irq_proc(void)
|
||||
/*
|
||||
* Create entries for all existing IRQs.
|
||||
*/
|
||||
for (i = 0; i < NR_IRQS; i++)
|
||||
register_irq_proc(i);
|
||||
for_each_irq_desc(irq, desc)
|
||||
register_irq_proc(irq, desc);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -33,10 +33,10 @@ static void resend_irqs(unsigned long arg)
|
||||
struct irq_desc *desc;
|
||||
int irq;
|
||||
|
||||
while (!bitmap_empty(irqs_resend, NR_IRQS)) {
|
||||
irq = find_first_bit(irqs_resend, NR_IRQS);
|
||||
while (!bitmap_empty(irqs_resend, nr_irqs)) {
|
||||
irq = find_first_bit(irqs_resend, nr_irqs);
|
||||
clear_bit(irq, irqs_resend);
|
||||
desc = irq_desc + irq;
|
||||
desc = irq_to_desc(irq);
|
||||
local_irq_disable();
|
||||
desc->handle_irq(irq, desc);
|
||||
local_irq_enable();
|
||||
|
||||
+105
-61
@@ -12,83 +12,122 @@
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
static int irqfixup __read_mostly;
|
||||
|
||||
#define POLL_SPURIOUS_IRQ_INTERVAL (HZ/10)
|
||||
static void poll_spurious_irqs(unsigned long dummy);
|
||||
static DEFINE_TIMER(poll_spurious_irq_timer, poll_spurious_irqs, 0, 0);
|
||||
|
||||
/*
|
||||
* Recovery handler for misrouted interrupts.
|
||||
*/
|
||||
static int try_one_irq(int irq, struct irq_desc *desc)
|
||||
{
|
||||
struct irqaction *action;
|
||||
int ok = 0, work = 0;
|
||||
|
||||
spin_lock(&desc->lock);
|
||||
/* Already running on another processor */
|
||||
if (desc->status & IRQ_INPROGRESS) {
|
||||
/*
|
||||
* Already running: If it is shared get the other
|
||||
* CPU to go looking for our mystery interrupt too
|
||||
*/
|
||||
if (desc->action && (desc->action->flags & IRQF_SHARED))
|
||||
desc->status |= IRQ_PENDING;
|
||||
spin_unlock(&desc->lock);
|
||||
return ok;
|
||||
}
|
||||
/* Honour the normal IRQ locking */
|
||||
desc->status |= IRQ_INPROGRESS;
|
||||
action = desc->action;
|
||||
spin_unlock(&desc->lock);
|
||||
|
||||
while (action) {
|
||||
/* Only shared IRQ handlers are safe to call */
|
||||
if (action->flags & IRQF_SHARED) {
|
||||
if (action->handler(irq, action->dev_id) ==
|
||||
IRQ_HANDLED)
|
||||
ok = 1;
|
||||
}
|
||||
action = action->next;
|
||||
}
|
||||
local_irq_disable();
|
||||
/* Now clean up the flags */
|
||||
spin_lock(&desc->lock);
|
||||
action = desc->action;
|
||||
|
||||
/*
|
||||
* While we were looking for a fixup someone queued a real
|
||||
* IRQ clashing with our walk:
|
||||
*/
|
||||
while ((desc->status & IRQ_PENDING) && action) {
|
||||
/*
|
||||
* Perform real IRQ processing for the IRQ we deferred
|
||||
*/
|
||||
work = 1;
|
||||
spin_unlock(&desc->lock);
|
||||
handle_IRQ_event(irq, action);
|
||||
spin_lock(&desc->lock);
|
||||
desc->status &= ~IRQ_PENDING;
|
||||
}
|
||||
desc->status &= ~IRQ_INPROGRESS;
|
||||
/*
|
||||
* If we did actual work for the real IRQ line we must let the
|
||||
* IRQ controller clean up too
|
||||
*/
|
||||
if (work && desc->chip && desc->chip->end)
|
||||
desc->chip->end(irq);
|
||||
spin_unlock(&desc->lock);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int misrouted_irq(int irq)
|
||||
{
|
||||
int i;
|
||||
int ok = 0;
|
||||
int work = 0; /* Did we do work for a real IRQ */
|
||||
struct irq_desc *desc;
|
||||
int i, ok = 0;
|
||||
|
||||
for (i = 1; i < NR_IRQS; i++) {
|
||||
struct irq_desc *desc = irq_desc + i;
|
||||
struct irqaction *action;
|
||||
for_each_irq_desc(i, desc) {
|
||||
if (!i)
|
||||
continue;
|
||||
|
||||
if (i == irq) /* Already tried */
|
||||
continue;
|
||||
|
||||
spin_lock(&desc->lock);
|
||||
/* Already running on another processor */
|
||||
if (desc->status & IRQ_INPROGRESS) {
|
||||
/*
|
||||
* Already running: If it is shared get the other
|
||||
* CPU to go looking for our mystery interrupt too
|
||||
*/
|
||||
if (desc->action && (desc->action->flags & IRQF_SHARED))
|
||||
desc->status |= IRQ_PENDING;
|
||||
spin_unlock(&desc->lock);
|
||||
continue;
|
||||
}
|
||||
/* Honour the normal IRQ locking */
|
||||
desc->status |= IRQ_INPROGRESS;
|
||||
action = desc->action;
|
||||
spin_unlock(&desc->lock);
|
||||
|
||||
while (action) {
|
||||
/* Only shared IRQ handlers are safe to call */
|
||||
if (action->flags & IRQF_SHARED) {
|
||||
if (action->handler(i, action->dev_id) ==
|
||||
IRQ_HANDLED)
|
||||
ok = 1;
|
||||
}
|
||||
action = action->next;
|
||||
}
|
||||
local_irq_disable();
|
||||
/* Now clean up the flags */
|
||||
spin_lock(&desc->lock);
|
||||
action = desc->action;
|
||||
|
||||
/*
|
||||
* While we were looking for a fixup someone queued a real
|
||||
* IRQ clashing with our walk:
|
||||
*/
|
||||
while ((desc->status & IRQ_PENDING) && action) {
|
||||
/*
|
||||
* Perform real IRQ processing for the IRQ we deferred
|
||||
*/
|
||||
work = 1;
|
||||
spin_unlock(&desc->lock);
|
||||
handle_IRQ_event(i, action);
|
||||
spin_lock(&desc->lock);
|
||||
desc->status &= ~IRQ_PENDING;
|
||||
}
|
||||
desc->status &= ~IRQ_INPROGRESS;
|
||||
/*
|
||||
* If we did actual work for the real IRQ line we must let the
|
||||
* IRQ controller clean up too
|
||||
*/
|
||||
if (work && desc->chip && desc->chip->end)
|
||||
desc->chip->end(i);
|
||||
spin_unlock(&desc->lock);
|
||||
if (try_one_irq(i, desc))
|
||||
ok = 1;
|
||||
}
|
||||
/* So the caller can adjust the irq error counts */
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void poll_spurious_irqs(unsigned long dummy)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
int i;
|
||||
|
||||
for_each_irq_desc(i, desc) {
|
||||
unsigned int status;
|
||||
|
||||
if (!i)
|
||||
continue;
|
||||
|
||||
/* Racy but it doesn't matter */
|
||||
status = desc->status;
|
||||
barrier();
|
||||
if (!(status & IRQ_SPURIOUS_DISABLED))
|
||||
continue;
|
||||
|
||||
try_one_irq(i, desc);
|
||||
}
|
||||
|
||||
mod_timer(&poll_spurious_irq_timer,
|
||||
jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -137,7 +176,9 @@ report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int try_misrouted_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
|
||||
static inline int
|
||||
try_misrouted_irq(unsigned int irq, struct irq_desc *desc,
|
||||
irqreturn_t action_ret)
|
||||
{
|
||||
struct irqaction *action;
|
||||
|
||||
@@ -212,6 +253,9 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
|
||||
desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED;
|
||||
desc->depth++;
|
||||
desc->chip->disable(irq);
|
||||
|
||||
mod_timer(&poll_spurious_irq_timer,
|
||||
jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
|
||||
}
|
||||
desc->irqs_unhandled = 0;
|
||||
}
|
||||
@@ -241,7 +285,7 @@ static int __init irqfixup_setup(char *str)
|
||||
|
||||
__setup("irqfixup", irqfixup_setup);
|
||||
module_param(irqfixup, int, 0644);
|
||||
MODULE_PARM_DESC("irqfixup", "0: No fixup, 1: irqfixup mode 2: irqpoll mode");
|
||||
MODULE_PARM_DESC("irqfixup", "0: No fixup, 1: irqfixup mode, 2: irqpoll mode");
|
||||
|
||||
static int __init irqpoll_setup(char *str)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user