diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 5fa6198..8e3929b 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -133,7 +133,7 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) handle_dynamic_tick(action); - if (!(action->flags & IRQF_DISABLED)) + if (!(action->flags & IRQF_DISABLED_CUMULATIVE)) local_irq_enable_in_hardirq(); do { diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 08a849a..0d16ff2 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -2,6 +2,13 @@ * IRQ subsystem internal functions and variables: */ +/* + * Internal interrupt flags + * + * IRQF_DISABLED_CUMULATIVE - one handler in the chain has IRQF_DISABLED set + */ +#define IRQF_DISABLED_CUMULATIVE 0x80000000 + extern int noirqdebug; /* Set default functions for irq_chip structures: */ diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 46d6611..890da1e 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -344,6 +344,9 @@ int setup_irq(unsigned int irq, struct irqaction *new) if (new->flags & IRQF_NOBALANCING) desc->status |= IRQ_NO_BALANCING; + if (new->flags & IRQF_DISABLED) + desc->action->flags |= IRQF_DISABLED_CUMULATIVE; + if (!shared) { irq_chip_set_defaults(desc->chip); @@ -464,7 +467,22 @@ void free_irq(unsigned int irq, void *dev_id) desc->chip->release(irq, dev_id); #endif - if (!desc->action) { + if (desc->action) { + /* Update interrupt disabled flag in head */ + struct irqaction *ap; + unsigned long aflags; + + ap = desc->action; + aflags = ap->flags & ~IRQF_DISABLED_CUMULATIVE; + do { + if (ap->flags & IRQF_DISABLED) { + aflags |= IRQF_DISABLED_CUMULATIVE; + break; + } + ap = ap->next; + } while (ap); + desc->action->flags = aflags; + } else { desc->status |= IRQ_DISABLED; if (desc->chip->shutdown) desc->chip->shutdown(irq);