* [PATCH v3 0/4] irq: sun4i IRQ 0 / ENMI fixes @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: linux-arm-kernel Hi All, Here is v3 of my sun4i IRQ 0 / ENMI fixes patch-set, changelog below: v2: PATCH 1/4 irq: Add handle_fasteoi_late_irq irq handler New patch by Thomas Gleixner, adding a new irq handler with the "call eoi after the irq-handler has run its course" behavior we need to avoid double irqs on the ENMI. PATCH 2/4 irqchip: sun4i: Fix irq 0 not working Modified to avoid spurious calls to the irq 0 handler, as suggested by Maxime. PATCH 3/4 irqchip: sun4i: Fix a comment about mask register Added Maxime's Acked-by PATCH 4/4 irqchip: sun4i: Use handle_fasteoi_late_irq for the New patch switching the handler for irq 0 over to the new handle_fasteoi_late_irq handler, thereby fixing the double interrupts issue v3: PATCH 1/4 irq: Add a new IRQCHIP_EOI_THREADED flag New patch by Thomas Gleixner, replacing his "irq: Add handle_fasteoi_late_irq irq handler" patch. PATCH 2/4 irqchip: sun4i: Fix irq 0 not working Added Maxime's Acked-by PATCH 4/4 irqchip: sun4i: Don't ack IRQs != 0, fix acking of IRQ New patch replacing my "irqchip: sun4i: Use handle_fasteoi_late_irq ..." patch. This also drops acking for IRQ != 0. I've done both changes in one patch to avoid regressing for IRQ 0. Thanks for all the help to all involved. Regards, Hans ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 0/4] irq: sun4i IRQ 0 / ENMI fixes @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: Thomas Gleixner, Maxime Ripard Cc: linux-arm-kernel, devicetree, linux-kernel, linux-sunxi Hi All, Here is v3 of my sun4i IRQ 0 / ENMI fixes patch-set, changelog below: v2: PATCH 1/4 irq: Add handle_fasteoi_late_irq irq handler New patch by Thomas Gleixner, adding a new irq handler with the "call eoi after the irq-handler has run its course" behavior we need to avoid double irqs on the ENMI. PATCH 2/4 irqchip: sun4i: Fix irq 0 not working Modified to avoid spurious calls to the irq 0 handler, as suggested by Maxime. PATCH 3/4 irqchip: sun4i: Fix a comment about mask register Added Maxime's Acked-by PATCH 4/4 irqchip: sun4i: Use handle_fasteoi_late_irq for the New patch switching the handler for irq 0 over to the new handle_fasteoi_late_irq handler, thereby fixing the double interrupts issue v3: PATCH 1/4 irq: Add a new IRQCHIP_EOI_THREADED flag New patch by Thomas Gleixner, replacing his "irq: Add handle_fasteoi_late_irq irq handler" patch. PATCH 2/4 irqchip: sun4i: Fix irq 0 not working Added Maxime's Acked-by PATCH 4/4 irqchip: sun4i: Don't ack IRQs != 0, fix acking of IRQ New patch replacing my "irqchip: sun4i: Use handle_fasteoi_late_irq ..." patch. This also drops acking for IRQ != 0. I've done both changes in one patch to avoid regressing for IRQ 0. Thanks for all the help to all involved. Regards, Hans ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 0/4] irq: sun4i IRQ 0 / ENMI fixes @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: Thomas Gleixner, Maxime Ripard Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-sunxi-/JYPxA39Uh5TLH3MbocFFw Hi All, Here is v3 of my sun4i IRQ 0 / ENMI fixes patch-set, changelog below: v2: PATCH 1/4 irq: Add handle_fasteoi_late_irq irq handler New patch by Thomas Gleixner, adding a new irq handler with the "call eoi after the irq-handler has run its course" behavior we need to avoid double irqs on the ENMI. PATCH 2/4 irqchip: sun4i: Fix irq 0 not working Modified to avoid spurious calls to the irq 0 handler, as suggested by Maxime. PATCH 3/4 irqchip: sun4i: Fix a comment about mask register Added Maxime's Acked-by PATCH 4/4 irqchip: sun4i: Use handle_fasteoi_late_irq for the New patch switching the handler for irq 0 over to the new handle_fasteoi_late_irq handler, thereby fixing the double interrupts issue v3: PATCH 1/4 irq: Add a new IRQCHIP_EOI_THREADED flag New patch by Thomas Gleixner, replacing his "irq: Add handle_fasteoi_late_irq irq handler" patch. PATCH 2/4 irqchip: sun4i: Fix irq 0 not working Added Maxime's Acked-by PATCH 4/4 irqchip: sun4i: Don't ack IRQs != 0, fix acking of IRQ New patch replacing my "irqchip: sun4i: Use handle_fasteoi_late_irq ..." patch. This also drops acking for IRQ != 0. I've done both changes in one patch to avoid regressing for IRQ 0. Thanks for all the help to all involved. Regards, Hans ^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 1/4] irq: Add a new IRQCHIP_EOI_THREADED flag @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: linux-arm-kernel From: Thomas Gleixner <tglx@linutronix.de> This flag must be used in combination with handle_fasteoi_irq, when set handle_fasteoi_irq will delay the calling of chip->irq_eoi until the threaded handler has run. Reviewed-by: Hans de Goede <hdegoede@redhat.com> Tested-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- include/linux/irq.h | 3 +++ kernel/irq/chip.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- kernel/irq/internals.h | 1 + kernel/irq/manage.c | 2 +- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index 7dc1003..0f036fb 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -349,6 +349,8 @@ struct irq_chip { * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks * when irq enabled * IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip + * IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask + * IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode */ enum { IRQCHIP_SET_TYPE_MASKED = (1 << 0), @@ -357,6 +359,7 @@ enum { IRQCHIP_ONOFFLINE_ENABLED = (1 << 3), IRQCHIP_SKIP_SET_WAKE = (1 << 4), IRQCHIP_ONESHOT_SAFE = (1 << 5), + IRQCHIP_EOI_THREADED = (1 << 6), }; /* This include will go away once we isolated irq_desc usage to core code */ diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index dc04c16..6397df2 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -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 * @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) { } #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 * @irq: the interrupt number @@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { } void handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = desc->irq_data.chip; + raw_spin_lock(&desc->lock); 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); handle_irq_event(desc); - if (desc->istate & IRQS_ONESHOT) - cond_unmask_irq(desc); + cond_unmask_eoi_irq(desc, chip); -out_eoi: - desc->irq_data.chip->irq_eoi(&desc->irq_data); -out_unlock: raw_spin_unlock(&desc->lock); return; out: - if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED)) - goto out_eoi; - goto out_unlock; + if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED)) + chip->irq_eoi(&desc->irq_data); + raw_spin_unlock(&desc->lock); } /** diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 001fa5b..e98bb56 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -73,6 +73,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 mask_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); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 481a13c..9147fef 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -718,7 +718,7 @@ again: if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && irqd_irq_masked(&desc->irq_data)) - unmask_irq(desc); + unmask_threaded_irq(desc); out_unlock: raw_spin_unlock_irq(&desc->lock); -- 1.9.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 1/4] irq: Add a new IRQCHIP_EOI_THREADED flag @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: Thomas Gleixner, Maxime Ripard Cc: linux-arm-kernel, devicetree, linux-kernel, linux-sunxi, Hans de Goede From: Thomas Gleixner <tglx@linutronix.de> This flag must be used in combination with handle_fasteoi_irq, when set handle_fasteoi_irq will delay the calling of chip->irq_eoi until the threaded handler has run. Reviewed-by: Hans de Goede <hdegoede@redhat.com> Tested-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- include/linux/irq.h | 3 +++ kernel/irq/chip.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- kernel/irq/internals.h | 1 + kernel/irq/manage.c | 2 +- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index 7dc1003..0f036fb 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -349,6 +349,8 @@ struct irq_chip { * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks * when irq enabled * IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip + * IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask + * IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode */ enum { IRQCHIP_SET_TYPE_MASKED = (1 << 0), @@ -357,6 +359,7 @@ enum { IRQCHIP_ONOFFLINE_ENABLED = (1 << 3), IRQCHIP_SKIP_SET_WAKE = (1 << 4), IRQCHIP_ONESHOT_SAFE = (1 << 5), + IRQCHIP_EOI_THREADED = (1 << 6), }; /* This include will go away once we isolated irq_desc usage to core code */ diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index dc04c16..6397df2 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -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 * @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) { } #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 * @irq: the interrupt number @@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { } void handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = desc->irq_data.chip; + raw_spin_lock(&desc->lock); 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); handle_irq_event(desc); - if (desc->istate & IRQS_ONESHOT) - cond_unmask_irq(desc); + cond_unmask_eoi_irq(desc, chip); -out_eoi: - desc->irq_data.chip->irq_eoi(&desc->irq_data); -out_unlock: raw_spin_unlock(&desc->lock); return; out: - if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED)) - goto out_eoi; - goto out_unlock; + if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED)) + chip->irq_eoi(&desc->irq_data); + raw_spin_unlock(&desc->lock); } /** diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 001fa5b..e98bb56 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -73,6 +73,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 mask_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); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 481a13c..9147fef 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -718,7 +718,7 @@ again: if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && irqd_irq_masked(&desc->irq_data)) - unmask_irq(desc); + unmask_threaded_irq(desc); out_unlock: raw_spin_unlock_irq(&desc->lock); -- 1.9.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 1/4] irq: Add a new IRQCHIP_EOI_THREADED flag @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: Thomas Gleixner, Maxime Ripard Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede From: Thomas Gleixner <tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org> This flag must be used in combination with handle_fasteoi_irq, when set handle_fasteoi_irq will delay the calling of chip->irq_eoi until the threaded handler has run. Reviewed-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> Tested-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> --- include/linux/irq.h | 3 +++ kernel/irq/chip.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- kernel/irq/internals.h | 1 + kernel/irq/manage.c | 2 +- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index 7dc1003..0f036fb 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -349,6 +349,8 @@ struct irq_chip { * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks * when irq enabled * IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip + * IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask + * IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode */ enum { IRQCHIP_SET_TYPE_MASKED = (1 << 0), @@ -357,6 +359,7 @@ enum { IRQCHIP_ONOFFLINE_ENABLED = (1 << 3), IRQCHIP_SKIP_SET_WAKE = (1 << 4), IRQCHIP_ONESHOT_SAFE = (1 << 5), + IRQCHIP_EOI_THREADED = (1 << 6), }; /* This include will go away once we isolated irq_desc usage to core code */ diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index dc04c16..6397df2 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -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 * @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) { } #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 * @irq: the interrupt number @@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { } void handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = desc->irq_data.chip; + raw_spin_lock(&desc->lock); 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); handle_irq_event(desc); - if (desc->istate & IRQS_ONESHOT) - cond_unmask_irq(desc); + cond_unmask_eoi_irq(desc, chip); -out_eoi: - desc->irq_data.chip->irq_eoi(&desc->irq_data); -out_unlock: raw_spin_unlock(&desc->lock); return; out: - if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED)) - goto out_eoi; - goto out_unlock; + if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED)) + chip->irq_eoi(&desc->irq_data); + raw_spin_unlock(&desc->lock); } /** diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 001fa5b..e98bb56 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -73,6 +73,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 mask_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); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 481a13c..9147fef 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -718,7 +718,7 @@ again: if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && irqd_irq_masked(&desc->irq_data)) - unmask_irq(desc); + unmask_threaded_irq(desc); out_unlock: raw_spin_unlock_irq(&desc->lock); -- 1.9.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 1/4] irq: Add a new IRQCHIP_EOI_THREADED flag @ 2014-03-13 18:17 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:17 UTC (permalink / raw) To: linux-arm-kernel Hi, On 03/13/2014 07:03 PM, Hans de Goede wrote: > From: Thomas Gleixner <tglx@linutronix.de> > > This flag must be used in combination with handle_fasteoi_irq, when set > handle_fasteoi_irq will delay the calling of chip->irq_eoi until the threaded > handler has run. > > Reviewed-by: Hans de Goede <hdegoede@redhat.com> > Tested-by: Hans de Goede <hdegoede@redhat.com> > Signed-off-by: Hans de Goede <hdegoede@redhat.com> Note: I just noticed that we should also update the comment above kernel/irq/chip.c: cond_unmask_irq() to no longer mention its gets called from handle_fasteoi_irq() as that is no longer true. Regards, Hans > --- > include/linux/irq.h | 3 +++ > kernel/irq/chip.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- > kernel/irq/internals.h | 1 + > kernel/irq/manage.c | 2 +- > 4 files changed, 45 insertions(+), 9 deletions(-) > > diff --git a/include/linux/irq.h b/include/linux/irq.h > index 7dc1003..0f036fb 100644 > --- a/include/linux/irq.h > +++ b/include/linux/irq.h > @@ -349,6 +349,8 @@ struct irq_chip { > * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks > * when irq enabled > * IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip > + * IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask > + * IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode > */ > enum { > IRQCHIP_SET_TYPE_MASKED = (1 << 0), > @@ -357,6 +359,7 @@ enum { > IRQCHIP_ONOFFLINE_ENABLED = (1 << 3), > IRQCHIP_SKIP_SET_WAKE = (1 << 4), > IRQCHIP_ONESHOT_SAFE = (1 << 5), > + IRQCHIP_EOI_THREADED = (1 << 6), > }; > > /* This include will go away once we isolated irq_desc usage to core code */ > diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c > index dc04c16..6397df2 100644 > --- a/kernel/irq/chip.c > +++ b/kernel/irq/chip.c > @@ -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 > * @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) { } > #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 > * @irq: the interrupt number > @@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { } > void > handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) > { > + struct irq_chip *chip = desc->irq_data.chip; > + > raw_spin_lock(&desc->lock); > > 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); > handle_irq_event(desc); > > - if (desc->istate & IRQS_ONESHOT) > - cond_unmask_irq(desc); > + cond_unmask_eoi_irq(desc, chip); > > -out_eoi: > - desc->irq_data.chip->irq_eoi(&desc->irq_data); > -out_unlock: > raw_spin_unlock(&desc->lock); > return; > out: > - if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED)) > - goto out_eoi; > - goto out_unlock; > + if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED)) > + chip->irq_eoi(&desc->irq_data); > + raw_spin_unlock(&desc->lock); > } > > /** > diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h > index 001fa5b..e98bb56 100644 > --- a/kernel/irq/internals.h > +++ b/kernel/irq/internals.h > @@ -73,6 +73,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 mask_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); > > diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c > index 481a13c..9147fef 100644 > --- a/kernel/irq/manage.c > +++ b/kernel/irq/manage.c > @@ -718,7 +718,7 @@ again: > > if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && > irqd_irq_masked(&desc->irq_data)) > - unmask_irq(desc); > + unmask_threaded_irq(desc); > > out_unlock: > raw_spin_unlock_irq(&desc->lock); > ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v3 1/4] irq: Add a new IRQCHIP_EOI_THREADED flag @ 2014-03-13 18:17 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:17 UTC (permalink / raw) To: Thomas Gleixner, Maxime Ripard Cc: linux-arm-kernel, devicetree, linux-kernel, linux-sunxi Hi, On 03/13/2014 07:03 PM, Hans de Goede wrote: > From: Thomas Gleixner <tglx@linutronix.de> > > This flag must be used in combination with handle_fasteoi_irq, when set > handle_fasteoi_irq will delay the calling of chip->irq_eoi until the threaded > handler has run. > > Reviewed-by: Hans de Goede <hdegoede@redhat.com> > Tested-by: Hans de Goede <hdegoede@redhat.com> > Signed-off-by: Hans de Goede <hdegoede@redhat.com> Note: I just noticed that we should also update the comment above kernel/irq/chip.c: cond_unmask_irq() to no longer mention its gets called from handle_fasteoi_irq() as that is no longer true. Regards, Hans > --- > include/linux/irq.h | 3 +++ > kernel/irq/chip.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- > kernel/irq/internals.h | 1 + > kernel/irq/manage.c | 2 +- > 4 files changed, 45 insertions(+), 9 deletions(-) > > diff --git a/include/linux/irq.h b/include/linux/irq.h > index 7dc1003..0f036fb 100644 > --- a/include/linux/irq.h > +++ b/include/linux/irq.h > @@ -349,6 +349,8 @@ struct irq_chip { > * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks > * when irq enabled > * IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip > + * IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask > + * IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode > */ > enum { > IRQCHIP_SET_TYPE_MASKED = (1 << 0), > @@ -357,6 +359,7 @@ enum { > IRQCHIP_ONOFFLINE_ENABLED = (1 << 3), > IRQCHIP_SKIP_SET_WAKE = (1 << 4), > IRQCHIP_ONESHOT_SAFE = (1 << 5), > + IRQCHIP_EOI_THREADED = (1 << 6), > }; > > /* This include will go away once we isolated irq_desc usage to core code */ > diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c > index dc04c16..6397df2 100644 > --- a/kernel/irq/chip.c > +++ b/kernel/irq/chip.c > @@ -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 > * @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) { } > #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 > * @irq: the interrupt number > @@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { } > void > handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) > { > + struct irq_chip *chip = desc->irq_data.chip; > + > raw_spin_lock(&desc->lock); > > 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); > handle_irq_event(desc); > > - if (desc->istate & IRQS_ONESHOT) > - cond_unmask_irq(desc); > + cond_unmask_eoi_irq(desc, chip); > > -out_eoi: > - desc->irq_data.chip->irq_eoi(&desc->irq_data); > -out_unlock: > raw_spin_unlock(&desc->lock); > return; > out: > - if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED)) > - goto out_eoi; > - goto out_unlock; > + if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED)) > + chip->irq_eoi(&desc->irq_data); > + raw_spin_unlock(&desc->lock); > } > > /** > diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h > index 001fa5b..e98bb56 100644 > --- a/kernel/irq/internals.h > +++ b/kernel/irq/internals.h > @@ -73,6 +73,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 mask_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); > > diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c > index 481a13c..9147fef 100644 > --- a/kernel/irq/manage.c > +++ b/kernel/irq/manage.c > @@ -718,7 +718,7 @@ again: > > if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && > irqd_irq_masked(&desc->irq_data)) > - unmask_irq(desc); > + unmask_threaded_irq(desc); > > out_unlock: > raw_spin_unlock_irq(&desc->lock); > ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v3 1/4] irq: Add a new IRQCHIP_EOI_THREADED flag @ 2014-03-13 18:17 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:17 UTC (permalink / raw) To: Thomas Gleixner, Maxime Ripard Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-sunxi-/JYPxA39Uh5TLH3MbocFFw Hi, On 03/13/2014 07:03 PM, Hans de Goede wrote: > From: Thomas Gleixner <tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org> > > This flag must be used in combination with handle_fasteoi_irq, when set > handle_fasteoi_irq will delay the calling of chip->irq_eoi until the threaded > handler has run. > > Reviewed-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> > Tested-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> > Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> Note: I just noticed that we should also update the comment above kernel/irq/chip.c: cond_unmask_irq() to no longer mention its gets called from handle_fasteoi_irq() as that is no longer true. Regards, Hans > --- > include/linux/irq.h | 3 +++ > kernel/irq/chip.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- > kernel/irq/internals.h | 1 + > kernel/irq/manage.c | 2 +- > 4 files changed, 45 insertions(+), 9 deletions(-) > > diff --git a/include/linux/irq.h b/include/linux/irq.h > index 7dc1003..0f036fb 100644 > --- a/include/linux/irq.h > +++ b/include/linux/irq.h > @@ -349,6 +349,8 @@ struct irq_chip { > * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks > * when irq enabled > * IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip > + * IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask > + * IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode > */ > enum { > IRQCHIP_SET_TYPE_MASKED = (1 << 0), > @@ -357,6 +359,7 @@ enum { > IRQCHIP_ONOFFLINE_ENABLED = (1 << 3), > IRQCHIP_SKIP_SET_WAKE = (1 << 4), > IRQCHIP_ONESHOT_SAFE = (1 << 5), > + IRQCHIP_EOI_THREADED = (1 << 6), > }; > > /* This include will go away once we isolated irq_desc usage to core code */ > diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c > index dc04c16..6397df2 100644 > --- a/kernel/irq/chip.c > +++ b/kernel/irq/chip.c > @@ -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 > * @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) { } > #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 > * @irq: the interrupt number > @@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { } > void > handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) > { > + struct irq_chip *chip = desc->irq_data.chip; > + > raw_spin_lock(&desc->lock); > > 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); > handle_irq_event(desc); > > - if (desc->istate & IRQS_ONESHOT) > - cond_unmask_irq(desc); > + cond_unmask_eoi_irq(desc, chip); > > -out_eoi: > - desc->irq_data.chip->irq_eoi(&desc->irq_data); > -out_unlock: > raw_spin_unlock(&desc->lock); > return; > out: > - if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED)) > - goto out_eoi; > - goto out_unlock; > + if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED)) > + chip->irq_eoi(&desc->irq_data); > + raw_spin_unlock(&desc->lock); > } > > /** > diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h > index 001fa5b..e98bb56 100644 > --- a/kernel/irq/internals.h > +++ b/kernel/irq/internals.h > @@ -73,6 +73,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 mask_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); > > diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c > index 481a13c..9147fef 100644 > --- a/kernel/irq/manage.c > +++ b/kernel/irq/manage.c > @@ -718,7 +718,7 @@ again: > > if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && > irqd_irq_masked(&desc->irq_data)) > - unmask_irq(desc); > + unmask_threaded_irq(desc); > > out_unlock: > raw_spin_unlock_irq(&desc->lock); > ^ permalink raw reply [flat|nested] 22+ messages in thread
* [tip:irq/core] genirq: Add a new IRQCHIP_EOI_THREADED flag 2014-03-13 18:03 ` Hans de Goede ` (2 preceding siblings ...) (?) @ 2014-03-14 12:55 ` tip-bot for Thomas Gleixner -1 siblings, 0 replies; 22+ messages in thread From: tip-bot for Thomas Gleixner @ 2014-03-14 12:55 UTC (permalink / raw) To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, hdegoede, tglx, maxime.ripard Commit-ID: 328a4978df833249b099c9875738d7b72042ffe1 Gitweb: http://git.kernel.org/tip/328a4978df833249b099c9875738d7b72042ffe1 Author: Thomas Gleixner <tglx@linutronix.de> AuthorDate: Thu, 13 Mar 2014 19:03:51 +0100 Committer: Thomas Gleixner <tglx@linutronix.de> CommitDate: Fri, 14 Mar 2014 13:43:33 +0100 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> --- include/linux/irq.h | 2 ++ kernel/irq/chip.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- kernel/irq/internals.h | 1 + kernel/irq/manage.c | 2 +- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/include/linux/irq.h b/include/linux/irq.h index 67ace7a..d278838 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -356,6 +356,7 @@ struct irq_chip { * when irq enabled * IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip * IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask + * IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode */ enum { IRQCHIP_SET_TYPE_MASKED = (1 << 0), @@ -364,6 +365,7 @@ enum { IRQCHIP_ONOFFLINE_ENABLED = (1 << 3), IRQCHIP_SKIP_SET_WAKE = (1 << 4), IRQCHIP_ONESHOT_SAFE = (1 << 5), + IRQCHIP_EOI_THREADED = (1 << 6), }; /* This include will go away once we isolated irq_desc usage to core code */ diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index dc04c16..6397df2 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -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 * @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) { } #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 * @irq: the interrupt number @@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { } void handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) { + struct irq_chip *chip = desc->irq_data.chip; + raw_spin_lock(&desc->lock); 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); handle_irq_event(desc); - if (desc->istate & IRQS_ONESHOT) - cond_unmask_irq(desc); + cond_unmask_eoi_irq(desc, chip); -out_eoi: - desc->irq_data.chip->irq_eoi(&desc->irq_data); -out_unlock: raw_spin_unlock(&desc->lock); return; out: - if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED)) - goto out_eoi; - goto out_unlock; + if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED)) + chip->irq_eoi(&desc->irq_data); + raw_spin_unlock(&desc->lock); } /** diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 17b6717..ddf1ffe 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -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 mask_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); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index de1a8ed..2486a4c 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -748,7 +748,7 @@ again: if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && irqd_irq_masked(&desc->irq_data)) - unmask_irq(desc); + unmask_threaded_irq(desc); out_unlock: raw_spin_unlock_irq(&desc->lock); ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 2/4] irqchip: sun4i: Fix irq 0 not working @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: linux-arm-kernel SUN4I_IRQ_VECTOR_REG containing 0 can mean one of 3 things: 1) no more irqs pending 2) irq 0 pending 3) spurious irq So if we immediately get a reading of 0, check the irq-pending reg to differentiate between 2 and 3. We only do this once to avoid the extra check in the common case of 1) hapening after having read the vector-reg once. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> --- drivers/irqchip/irq-sun4i.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index a5438d8..5c25048 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -140,10 +140,24 @@ static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *re { u32 irq, hwirq; + /* + * hwirq == 0 can mean one of 3 things: + * 1) no more irqs pending + * 2) irq 0 pending + * 3) spurious irq + * So if we immediately get a reading of 0, check the irq-pending reg + * to differentiate between 2 and 3. We only do this once to avoid + * the extra check in the common case of 1 hapening after having + * read the vector-reg once. + */ hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; - while (hwirq != 0) { + if (hwirq == 0 && + !(readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)) & BIT(0))) + return; + + do { irq = irq_find_mapping(sun4i_irq_domain, hwirq); handle_IRQ(irq, regs); hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; - } + } while (hwirq != 0); } -- 1.9.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 2/4] irqchip: sun4i: Fix irq 0 not working @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: Thomas Gleixner, Maxime Ripard Cc: linux-arm-kernel, devicetree, linux-kernel, linux-sunxi, Hans de Goede SUN4I_IRQ_VECTOR_REG containing 0 can mean one of 3 things: 1) no more irqs pending 2) irq 0 pending 3) spurious irq So if we immediately get a reading of 0, check the irq-pending reg to differentiate between 2 and 3. We only do this once to avoid the extra check in the common case of 1) hapening after having read the vector-reg once. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> --- drivers/irqchip/irq-sun4i.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index a5438d8..5c25048 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -140,10 +140,24 @@ static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *re { u32 irq, hwirq; + /* + * hwirq == 0 can mean one of 3 things: + * 1) no more irqs pending + * 2) irq 0 pending + * 3) spurious irq + * So if we immediately get a reading of 0, check the irq-pending reg + * to differentiate between 2 and 3. We only do this once to avoid + * the extra check in the common case of 1 hapening after having + * read the vector-reg once. + */ hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; - while (hwirq != 0) { + if (hwirq == 0 && + !(readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)) & BIT(0))) + return; + + do { irq = irq_find_mapping(sun4i_irq_domain, hwirq); handle_IRQ(irq, regs); hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; - } + } while (hwirq != 0); } -- 1.9.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 2/4] irqchip: sun4i: Fix irq 0 not working @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: Thomas Gleixner, Maxime Ripard Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede SUN4I_IRQ_VECTOR_REG containing 0 can mean one of 3 things: 1) no more irqs pending 2) irq 0 pending 3) spurious irq So if we immediately get a reading of 0, check the irq-pending reg to differentiate between 2 and 3. We only do this once to avoid the extra check in the common case of 1) hapening after having read the vector-reg once. Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> --- drivers/irqchip/irq-sun4i.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index a5438d8..5c25048 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -140,10 +140,24 @@ static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *re { u32 irq, hwirq; + /* + * hwirq == 0 can mean one of 3 things: + * 1) no more irqs pending + * 2) irq 0 pending + * 3) spurious irq + * So if we immediately get a reading of 0, check the irq-pending reg + * to differentiate between 2 and 3. We only do this once to avoid + * the extra check in the common case of 1 hapening after having + * read the vector-reg once. + */ hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; - while (hwirq != 0) { + if (hwirq == 0 && + !(readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)) & BIT(0))) + return; + + do { irq = irq_find_mapping(sun4i_irq_domain, hwirq); handle_IRQ(irq, regs); hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; - } + } while (hwirq != 0); } -- 1.9.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [tip:irq/core] irqchip: sun4i: Fix irq 0 not working 2014-03-13 18:03 ` Hans de Goede (?) (?) @ 2014-03-14 12:55 ` tip-bot for Hans de Goede -1 siblings, 0 replies; 22+ messages in thread From: tip-bot for Hans de Goede @ 2014-03-14 12:55 UTC (permalink / raw) To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, hdegoede, tglx, maxime.ripard Commit-ID: 56af0416b00f6edc7845a7b3f2ef179e385c8e15 Gitweb: http://git.kernel.org/tip/56af0416b00f6edc7845a7b3f2ef179e385c8e15 Author: Hans de Goede <hdegoede@redhat.com> AuthorDate: Thu, 13 Mar 2014 19:03:52 +0100 Committer: Thomas Gleixner <tglx@linutronix.de> CommitDate: Fri, 14 Mar 2014 13:43:33 +0100 irqchip: sun4i: Fix irq 0 not working SUN4I_IRQ_VECTOR_REG containing 0 can mean one of 3 things: 1) no more irqs pending 2) irq 0 pending 3) spurious irq So if we immediately get a reading of 0, check the irq-pending reg to differentiate between 2 and 3. We only do this once to avoid the extra check in the common case of 1) hapening after having read the vector-reg once. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> Cc: linux-arm-kernel@lists.infradead.org Cc: linux-sunxi@googlegroups.com Link: http://lkml.kernel.org/r/1394733834-26839-3-git-send-email-hdegoede@redhat.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- drivers/irqchip/irq-sun4i.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 1599955..7ae85ec 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -140,10 +140,24 @@ static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs) { u32 irq, hwirq; + /* + * hwirq == 0 can mean one of 3 things: + * 1) no more irqs pending + * 2) irq 0 pending + * 3) spurious irq + * So if we immediately get a reading of 0, check the irq-pending reg + * to differentiate between 2 and 3. We only do this once to avoid + * the extra check in the common case of 1 hapening after having + * read the vector-reg once. + */ hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; - while (hwirq != 0) { + if (hwirq == 0 && + !(readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)) & BIT(0))) + return; + + do { irq = irq_find_mapping(sun4i_irq_domain, hwirq); handle_IRQ(irq, regs); hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; - } + } while (hwirq != 0); } ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 3/4] irqchip: sun4i: Fix a comment about mask register initialization @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: linux-arm-kernel The comment was claiming that we were masking all irqs, while the code actually *un*masks all of them. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> --- drivers/irqchip/irq-sun4i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 5c25048..8a2fbee 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -109,7 +109,7 @@ static int __init sun4i_of_init(struct device_node *node, writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1)); writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2)); - /* Mask all the interrupts */ + /* Unmask all the interrupts, ENABLE_REG(x) is used for masking */ writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0)); writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1)); writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2)); -- 1.9.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 3/4] irqchip: sun4i: Fix a comment about mask register initialization @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: Thomas Gleixner, Maxime Ripard Cc: linux-arm-kernel, devicetree, linux-kernel, linux-sunxi, Hans de Goede The comment was claiming that we were masking all irqs, while the code actually *un*masks all of them. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> --- drivers/irqchip/irq-sun4i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 5c25048..8a2fbee 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -109,7 +109,7 @@ static int __init sun4i_of_init(struct device_node *node, writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1)); writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2)); - /* Mask all the interrupts */ + /* Unmask all the interrupts, ENABLE_REG(x) is used for masking */ writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0)); writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1)); writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2)); -- 1.9.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 3/4] irqchip: sun4i: Fix a comment about mask register initialization @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: Thomas Gleixner, Maxime Ripard Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede The comment was claiming that we were masking all irqs, while the code actually *un*masks all of them. Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> --- drivers/irqchip/irq-sun4i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 5c25048..8a2fbee 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -109,7 +109,7 @@ static int __init sun4i_of_init(struct device_node *node, writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1)); writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2)); - /* Mask all the interrupts */ + /* Unmask all the interrupts, ENABLE_REG(x) is used for masking */ writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0)); writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1)); writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2)); -- 1.9.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [tip:irq/core] irqchip: sun4i: Fix a comment about mask register initialization 2014-03-13 18:03 ` Hans de Goede (?) (?) @ 2014-03-14 12:55 ` tip-bot for Hans de Goede -1 siblings, 0 replies; 22+ messages in thread From: tip-bot for Hans de Goede @ 2014-03-14 12:55 UTC (permalink / raw) To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, hdegoede, tglx, maxime.ripard Commit-ID: 649ff46e5e29868e915354ed1e9bebcf0faec3ae Gitweb: http://git.kernel.org/tip/649ff46e5e29868e915354ed1e9bebcf0faec3ae Author: Hans de Goede <hdegoede@redhat.com> AuthorDate: Thu, 13 Mar 2014 19:03:53 +0100 Committer: Thomas Gleixner <tglx@linutronix.de> CommitDate: Fri, 14 Mar 2014 13:43:33 +0100 irqchip: sun4i: Fix a comment about mask register initialization The comment was claiming that we were masking all irqs, while the code actually *un*masks all of them. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> Cc: linux-arm-kernel@lists.infradead.org Cc: linux-sunxi@googlegroups.com Link: http://lkml.kernel.org/r/1394733834-26839-4-git-send-email-hdegoede@redhat.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- drivers/irqchip/irq-sun4i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 7ae85ec..60a28c6 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -109,7 +109,7 @@ static int __init sun4i_of_init(struct device_node *node, writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1)); writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2)); - /* Mask all the interrupts */ + /* Unmask all the interrupts, ENABLE_REG(x) is used for masking */ writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0)); writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1)); writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2)); ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 4/4] irqchip: sun4i: Don't ack IRQs != 0, fix acking of IRQ 0 @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: linux-arm-kernel All IRQs except for IRQ 0 seem to not need acking, so drop acking for them. The ENMI needs to have the ack done *after* clearing the interrupt source, otherwise we will get a spurious interrupt for each real interrupt. So use the new IRQCHIP_EOI_THREADED flag for this in combination with handle_fasteoi_irq. This uses a separate irq_chip struct for IRQ 0, since we only want this behavior for IRQ 0. Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- drivers/irqchip/irq-sun4i.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 8a2fbee..a0ed1ea 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -76,16 +76,29 @@ static void sun4i_irq_unmask(struct irq_data *irqd) static struct irq_chip sun4i_irq_chip = { .name = "sun4i_irq", - .irq_ack = sun4i_irq_ack, .irq_mask = sun4i_irq_mask, .irq_unmask = sun4i_irq_unmask, }; +/* IRQ 0 / the ENMI needs a late eoi call */ +static struct irq_chip sun4i_irq_chip_enmi = { + .name = "sun4i_irq", + .irq_eoi = sun4i_irq_ack, + .irq_mask = sun4i_irq_mask, + .irq_unmask = sun4i_irq_unmask, + .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED, +}; + static int sun4i_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) { - irq_set_chip_and_handler(virq, &sun4i_irq_chip, - handle_level_irq); + if (hw == 0) + irq_set_chip_and_handler(virq, &sun4i_irq_chip_enmi, + handle_fasteoi_irq); + else + irq_set_chip_and_handler(virq, &sun4i_irq_chip, + handle_level_irq); + set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); return 0; -- 1.9.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 4/4] irqchip: sun4i: Don't ack IRQs != 0, fix acking of IRQ 0 @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: Thomas Gleixner, Maxime Ripard Cc: linux-arm-kernel, devicetree, linux-kernel, linux-sunxi, Hans de Goede All IRQs except for IRQ 0 seem to not need acking, so drop acking for them. The ENMI needs to have the ack done *after* clearing the interrupt source, otherwise we will get a spurious interrupt for each real interrupt. So use the new IRQCHIP_EOI_THREADED flag for this in combination with handle_fasteoi_irq. This uses a separate irq_chip struct for IRQ 0, since we only want this behavior for IRQ 0. Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- drivers/irqchip/irq-sun4i.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 8a2fbee..a0ed1ea 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -76,16 +76,29 @@ static void sun4i_irq_unmask(struct irq_data *irqd) static struct irq_chip sun4i_irq_chip = { .name = "sun4i_irq", - .irq_ack = sun4i_irq_ack, .irq_mask = sun4i_irq_mask, .irq_unmask = sun4i_irq_unmask, }; +/* IRQ 0 / the ENMI needs a late eoi call */ +static struct irq_chip sun4i_irq_chip_enmi = { + .name = "sun4i_irq", + .irq_eoi = sun4i_irq_ack, + .irq_mask = sun4i_irq_mask, + .irq_unmask = sun4i_irq_unmask, + .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED, +}; + static int sun4i_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) { - irq_set_chip_and_handler(virq, &sun4i_irq_chip, - handle_level_irq); + if (hw == 0) + irq_set_chip_and_handler(virq, &sun4i_irq_chip_enmi, + handle_fasteoi_irq); + else + irq_set_chip_and_handler(virq, &sun4i_irq_chip, + handle_level_irq); + set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); return 0; -- 1.9.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v3 4/4] irqchip: sun4i: Don't ack IRQs != 0, fix acking of IRQ 0 @ 2014-03-13 18:03 ` Hans de Goede 0 siblings, 0 replies; 22+ messages in thread From: Hans de Goede @ 2014-03-13 18:03 UTC (permalink / raw) To: Thomas Gleixner, Maxime Ripard Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Hans de Goede All IRQs except for IRQ 0 seem to not need acking, so drop acking for them. The ENMI needs to have the ack done *after* clearing the interrupt source, otherwise we will get a spurious interrupt for each real interrupt. So use the new IRQCHIP_EOI_THREADED flag for this in combination with handle_fasteoi_irq. This uses a separate irq_chip struct for IRQ 0, since we only want this behavior for IRQ 0. Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> --- drivers/irqchip/irq-sun4i.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 8a2fbee..a0ed1ea 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -76,16 +76,29 @@ static void sun4i_irq_unmask(struct irq_data *irqd) static struct irq_chip sun4i_irq_chip = { .name = "sun4i_irq", - .irq_ack = sun4i_irq_ack, .irq_mask = sun4i_irq_mask, .irq_unmask = sun4i_irq_unmask, }; +/* IRQ 0 / the ENMI needs a late eoi call */ +static struct irq_chip sun4i_irq_chip_enmi = { + .name = "sun4i_irq", + .irq_eoi = sun4i_irq_ack, + .irq_mask = sun4i_irq_mask, + .irq_unmask = sun4i_irq_unmask, + .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED, +}; + static int sun4i_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) { - irq_set_chip_and_handler(virq, &sun4i_irq_chip, - handle_level_irq); + if (hw == 0) + irq_set_chip_and_handler(virq, &sun4i_irq_chip_enmi, + handle_fasteoi_irq); + else + irq_set_chip_and_handler(virq, &sun4i_irq_chip, + handle_level_irq); + set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); return 0; -- 1.9.0 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* [tip:irq/core] irqchip: sun4i: Don't ack IRQs > 0, fix acking of IRQ 0 2014-03-13 18:03 ` Hans de Goede (?) (?) @ 2014-03-14 12:55 ` tip-bot for Hans de Goede -1 siblings, 0 replies; 22+ messages in thread From: tip-bot for Hans de Goede @ 2014-03-14 12:55 UTC (permalink / raw) To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, hdegoede, tglx, maxime.ripard Commit-ID: e9df9e221665d40928e25a02c2700ac12eda7270 Gitweb: http://git.kernel.org/tip/e9df9e221665d40928e25a02c2700ac12eda7270 Author: Hans de Goede <hdegoede@redhat.com> AuthorDate: Thu, 13 Mar 2014 19:03:54 +0100 Committer: Thomas Gleixner <tglx@linutronix.de> CommitDate: Fri, 14 Mar 2014 13:43:33 +0100 irqchip: sun4i: Don't ack IRQs > 0, fix acking of IRQ 0 All IRQs except for IRQ 0 seem to not need acking, so drop acking for them. The ENMI needs to have the ack done *after* clearing the interrupt source, otherwise we will get a spurious interrupt for each real interrupt. So use the new IRQCHIP_EOI_THREADED flag for this in combination with handle_fasteoi_irq. This uses a separate irq_chip struct for IRQ 0, since we only want this behavior for IRQ 0. Signed-off-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-5-git-send-email-hdegoede@redhat.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- drivers/irqchip/irq-sun4i.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 60a28c6..2029cc5 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -76,16 +76,29 @@ static void sun4i_irq_unmask(struct irq_data *irqd) static struct irq_chip sun4i_irq_chip = { .name = "sun4i_irq", - .irq_ack = sun4i_irq_ack, .irq_mask = sun4i_irq_mask, .irq_unmask = sun4i_irq_unmask, }; +/* IRQ 0 / the ENMI needs a late eoi call */ +static struct irq_chip sun4i_irq_chip_enmi = { + .name = "sun4i_irq", + .irq_eoi = sun4i_irq_ack, + .irq_mask = sun4i_irq_mask, + .irq_unmask = sun4i_irq_unmask, + .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED, +}; + static int sun4i_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) { - irq_set_chip_and_handler(virq, &sun4i_irq_chip, - handle_level_irq); + if (hw == 0) + irq_set_chip_and_handler(virq, &sun4i_irq_chip_enmi, + handle_fasteoi_irq); + else + irq_set_chip_and_handler(virq, &sun4i_irq_chip, + handle_level_irq); + set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); return 0; ^ permalink raw reply related [flat|nested] 22+ messages in thread
end of thread, other threads:[~2014-03-14 12:56 UTC | newest] Thread overview: 22+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-03-13 18:03 [PATCH v3 0/4] irq: sun4i IRQ 0 / ENMI fixes Hans de Goede 2014-03-13 18:03 ` Hans de Goede 2014-03-13 18:03 ` Hans de Goede 2014-03-13 18:03 ` [PATCH v3 1/4] irq: Add a new IRQCHIP_EOI_THREADED flag Hans de Goede 2014-03-13 18:03 ` Hans de Goede 2014-03-13 18:03 ` Hans de Goede 2014-03-13 18:17 ` Hans de Goede 2014-03-13 18:17 ` Hans de Goede 2014-03-13 18:17 ` Hans de Goede 2014-03-14 12:55 ` [tip:irq/core] genirq: " tip-bot for Thomas Gleixner 2014-03-13 18:03 ` [PATCH v3 2/4] irqchip: sun4i: Fix irq 0 not working Hans de Goede 2014-03-13 18:03 ` Hans de Goede 2014-03-13 18:03 ` Hans de Goede 2014-03-14 12:55 ` [tip:irq/core] " tip-bot for Hans de Goede 2014-03-13 18:03 ` [PATCH v3 3/4] irqchip: sun4i: Fix a comment about mask register initialization Hans de Goede 2014-03-13 18:03 ` Hans de Goede 2014-03-13 18:03 ` Hans de Goede 2014-03-14 12:55 ` [tip:irq/core] " tip-bot for Hans de Goede 2014-03-13 18:03 ` [PATCH v3 4/4] irqchip: sun4i: Don't ack IRQs != 0, fix acking of IRQ 0 Hans de Goede 2014-03-13 18:03 ` Hans de Goede 2014-03-13 18:03 ` Hans de Goede 2014-03-14 12:55 ` [tip:irq/core] irqchip: sun4i: Don't ack IRQs > " tip-bot for Hans de Goede
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.