forked from Minki/linux
genirq: Add a new IRQCHIP_EOI_THREADED flag
The flag is necessary for interrupt chips which require an ACK/EOI after the handler has run. In case of threaded handlers this needs to happen after the threaded handler has completed before the unmask of the interrupt. The flag is only unseful in combination with the handle_fasteoi_irq flow control handler. It can be combined with the flag IRQCHIP_EOI_IF_HANDLED, so the EOI is not issued when the interrupt is disabled or in progress. Tested-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Cc: linux-arm-kernel@lists.infradead.org Cc: linux-sunxi@googlegroups.com Cc: Maxime Ripard <maxime.ripard@free-electrons.com> Link: http://lkml.kernel.org/r/1394733834-26839-2-git-send-email-hdegoede@redhat.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
parent
4f6e4f71c9
commit
328a4978df
@ -356,6 +356,7 @@ struct irq_chip {
|
|||||||
* when irq enabled
|
* when irq enabled
|
||||||
* IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip
|
* IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip
|
||||||
* IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask
|
* IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask
|
||||||
|
* IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode
|
||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
IRQCHIP_SET_TYPE_MASKED = (1 << 0),
|
IRQCHIP_SET_TYPE_MASKED = (1 << 0),
|
||||||
@ -364,6 +365,7 @@ enum {
|
|||||||
IRQCHIP_ONOFFLINE_ENABLED = (1 << 3),
|
IRQCHIP_ONOFFLINE_ENABLED = (1 << 3),
|
||||||
IRQCHIP_SKIP_SET_WAKE = (1 << 4),
|
IRQCHIP_SKIP_SET_WAKE = (1 << 4),
|
||||||
IRQCHIP_ONESHOT_SAFE = (1 << 5),
|
IRQCHIP_ONESHOT_SAFE = (1 << 5),
|
||||||
|
IRQCHIP_EOI_THREADED = (1 << 6),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This include will go away once we isolated irq_desc usage to core code */
|
/* This include will go away once we isolated irq_desc usage to core code */
|
||||||
|
@ -281,6 +281,19 @@ void unmask_irq(struct irq_desc *desc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unmask_threaded_irq(struct irq_desc *desc)
|
||||||
|
{
|
||||||
|
struct irq_chip *chip = desc->irq_data.chip;
|
||||||
|
|
||||||
|
if (chip->flags & IRQCHIP_EOI_THREADED)
|
||||||
|
chip->irq_eoi(&desc->irq_data);
|
||||||
|
|
||||||
|
if (chip->irq_unmask) {
|
||||||
|
chip->irq_unmask(&desc->irq_data);
|
||||||
|
irq_state_clr_masked(desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* handle_nested_irq - Handle a nested irq from a irq thread
|
* handle_nested_irq - Handle a nested irq from a irq thread
|
||||||
* @irq: the interrupt number
|
* @irq: the interrupt number
|
||||||
@ -435,6 +448,27 @@ static inline void preflow_handler(struct irq_desc *desc)
|
|||||||
static inline void preflow_handler(struct irq_desc *desc) { }
|
static inline void preflow_handler(struct irq_desc *desc) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
|
||||||
|
{
|
||||||
|
if (!(desc->istate & IRQS_ONESHOT)) {
|
||||||
|
chip->irq_eoi(&desc->irq_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We need to unmask in the following cases:
|
||||||
|
* - Oneshot irq which did not wake the thread (caused by a
|
||||||
|
* spurious interrupt or a primary handler handling it
|
||||||
|
* completely).
|
||||||
|
*/
|
||||||
|
if (!irqd_irq_disabled(&desc->irq_data) &&
|
||||||
|
irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) {
|
||||||
|
chip->irq_eoi(&desc->irq_data);
|
||||||
|
unmask_irq(desc);
|
||||||
|
} else if (!(chip->flags & IRQCHIP_EOI_THREADED)) {
|
||||||
|
chip->irq_eoi(&desc->irq_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handle_fasteoi_irq - irq handler for transparent controllers
|
* handle_fasteoi_irq - irq handler for transparent controllers
|
||||||
* @irq: the interrupt number
|
* @irq: the interrupt number
|
||||||
@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { }
|
|||||||
void
|
void
|
||||||
handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
|
handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
|
||||||
{
|
{
|
||||||
|
struct irq_chip *chip = desc->irq_data.chip;
|
||||||
|
|
||||||
raw_spin_lock(&desc->lock);
|
raw_spin_lock(&desc->lock);
|
||||||
|
|
||||||
if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
|
if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
|
||||||
@ -473,18 +509,14 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
|
|||||||
preflow_handler(desc);
|
preflow_handler(desc);
|
||||||
handle_irq_event(desc);
|
handle_irq_event(desc);
|
||||||
|
|
||||||
if (desc->istate & IRQS_ONESHOT)
|
cond_unmask_eoi_irq(desc, chip);
|
||||||
cond_unmask_irq(desc);
|
|
||||||
|
|
||||||
out_eoi:
|
|
||||||
desc->irq_data.chip->irq_eoi(&desc->irq_data);
|
|
||||||
out_unlock:
|
|
||||||
raw_spin_unlock(&desc->lock);
|
raw_spin_unlock(&desc->lock);
|
||||||
return;
|
return;
|
||||||
out:
|
out:
|
||||||
if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED))
|
if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))
|
||||||
goto out_eoi;
|
chip->irq_eoi(&desc->irq_data);
|
||||||
goto out_unlock;
|
raw_spin_unlock(&desc->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,6 +74,7 @@ extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
|
|||||||
extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu);
|
extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu);
|
||||||
extern void mask_irq(struct irq_desc *desc);
|
extern void mask_irq(struct irq_desc *desc);
|
||||||
extern void unmask_irq(struct irq_desc *desc);
|
extern void unmask_irq(struct irq_desc *desc);
|
||||||
|
extern void unmask_threaded_irq(struct irq_desc *desc);
|
||||||
|
|
||||||
extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
|
extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
|
||||||
|
|
||||||
|
@ -748,7 +748,7 @@ again:
|
|||||||
|
|
||||||
if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) &&
|
if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) &&
|
||||||
irqd_irq_masked(&desc->irq_data))
|
irqd_irq_masked(&desc->irq_data))
|
||||||
unmask_irq(desc);
|
unmask_threaded_irq(desc);
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
raw_spin_unlock_irq(&desc->lock);
|
raw_spin_unlock_irq(&desc->lock);
|
||||||
|
Loading…
Reference in New Issue
Block a user