All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de>
To: LKML <linux-kernel@vger.kernel.org>
Cc: jeffy <jeffy.chen@rock-chips.com>,
	Brian Norris <briannorris@chromium.org>,
	Marc Zyngier <marc.zyngier@arm.com>,
	dianders@chromium.org, tfiga@chromium.org
Subject: [patch 1/2] genirq: Handle NOAUTOEN interrupt setup proper
Date: Wed, 31 May 2017 11:58:32 +0200	[thread overview]
Message-ID: <20170531100212.130986205@linutronix.de> (raw)
In-Reply-To: 20170531095831.291595474@linutronix.de

[-- Attachment #1: genirq--Handle-NOAUTOEN-interrupt-setup-proper.patch --]
[-- Type: text/plain, Size: 5490 bytes --]

If an interrupt is marked NOAUTOEN then request_irq() installs the action,
but does not enable the interrupt via startup_irq().  The interrupt is
enabled via enable_irq() later from the driver. enable_irq() calls
irq_enable().

That means that for interrupts which have a irq_startup() callback this
callback is never invoked. Neither is irq_domain_activate_irq() invoked for
such interrupts.

If an interrupt depends on irq_startup() or irq_domain_activate_irq() then
the enable via irq_enable() is not enough.

Add a status flag IRQD_IRQ_STARTED_UP and use this to select the proper
mechanism in enable_irq(). Use the flag also to avoid pointless calls into
the low level functions.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/irq.h    |    6 ++++
 kernel/irq/chip.c      |   73 +++++++++++++++++++++++++++++++++++++------------
 kernel/irq/internals.h |    1 
 kernel/irq/manage.c    |    2 -
 4 files changed, 64 insertions(+), 18 deletions(-)

--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -216,6 +216,7 @@ enum {
 	IRQD_WAKEUP_ARMED		= (1 << 19),
 	IRQD_FORWARDED_TO_VCPU		= (1 << 20),
 	IRQD_AFFINITY_MANAGED		= (1 << 21),
+	IRQD_IRQ_STARTED_UP		= (1 << 22),
 };
 
 #define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors)
@@ -329,6 +330,11 @@ static inline void irqd_clr_activated(st
 	__irqd_to_state(d) &= ~IRQD_ACTIVATED;
 }
 
+static inline bool irqd_is_started_up(struct irq_data *d)
+{
+	return __irqd_to_state(d) & IRQD_IRQ_STARTED_UP;
+}
+
 #undef __irqd_to_state
 
 static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -185,37 +185,71 @@ static void irq_state_set_masked(struct
 	irqd_set(&desc->irq_data, IRQD_IRQ_MASKED);
 }
 
+static void irq_state_clr_started(struct irq_desc *desc)
+{
+	irqd_clear(&desc->irq_data, IRQD_IRQ_STARTED_UP);
+}
+
+static void irq_state_set_started(struct irq_desc *desc)
+{
+	irqd_set(&desc->irq_data, IRQD_IRQ_STARTED_UP);
+}
+
 int irq_startup(struct irq_desc *desc, bool resend)
 {
 	int ret = 0;
 
-	irq_state_clr_disabled(desc);
+	if (irqd_is_started_up(&desc->irq_data))
+		return 0;
+
 	desc->depth = 0;
 
 	irq_domain_activate_irq(&desc->irq_data);
 	if (desc->irq_data.chip->irq_startup) {
 		ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
+		irq_state_clr_disabled(desc);
 		irq_state_clr_masked(desc);
 	} else {
 		irq_enable(desc);
 	}
+	irq_state_set_started(desc);
+
 	if (resend)
 		check_irq_resend(desc);
+
 	return ret;
 }
 
+static void __irq_disable(struct irq_desc *desc, bool mask);
+
 void irq_shutdown(struct irq_desc *desc)
 {
-	irq_state_set_disabled(desc);
-	desc->depth = 1;
-	if (desc->irq_data.chip->irq_shutdown)
-		desc->irq_data.chip->irq_shutdown(&desc->irq_data);
-	else if (desc->irq_data.chip->irq_disable)
-		desc->irq_data.chip->irq_disable(&desc->irq_data);
-	else
-		desc->irq_data.chip->irq_mask(&desc->irq_data);
+	if (irqd_is_started_up(&desc->irq_data)) {
+		desc->depth = 1;
+		if (desc->irq_data.chip->irq_shutdown) {
+			desc->irq_data.chip->irq_shutdown(&desc->irq_data);
+			irq_state_set_disabled(desc);
+			irq_state_set_masked(desc);
+		} else {
+			__irq_disable(desc, true);
+		}
+		irq_state_clr_started(desc);
+	}
+	/*
+	 * This must be called even if the interrupt was never started up,
+	 * because the activation can happen before the interrupt is
+	 * available for request/startup. It has it's own state tracking so
+	 * it's safe to call it unconditonally.
+	 */
 	irq_domain_deactivate_irq(&desc->irq_data);
-	irq_state_set_masked(desc);
+}
+
+void irq_enable_or_startup(struct irq_desc *desc)
+{
+	if (!irqd_is_started_up(&desc->irq_data))
+		irq_startup(desc, false);
+	else
+		irq_enable(desc);
 }
 
 void irq_enable(struct irq_desc *desc)
@@ -228,6 +262,17 @@ void irq_enable(struct irq_desc *desc)
 	irq_state_clr_masked(desc);
 }
 
+static void __irq_disable(struct irq_desc *desc, bool mask)
+{
+	irq_state_set_disabled(desc);
+	if (desc->irq_data.chip->irq_disable) {
+		desc->irq_data.chip->irq_disable(&desc->irq_data);
+		irq_state_set_masked(desc);
+	} else if (mask) {
+		mask_irq(desc);
+	}
+}
+
 /**
  * irq_disable - Mark interrupt disabled
  * @desc:	irq descriptor which should be disabled
@@ -250,13 +295,7 @@ void irq_enable(struct irq_desc *desc)
  */
 void irq_disable(struct irq_desc *desc)
 {
-	irq_state_set_disabled(desc);
-	if (desc->irq_data.chip->irq_disable) {
-		desc->irq_data.chip->irq_disable(&desc->irq_data);
-		irq_state_set_masked(desc);
-	} else if (irq_settings_disable_unlazy(desc)) {
-		mask_irq(desc);
-	}
+	__irq_disable(desc, irq_settings_disable_unlazy(desc));
 }
 
 void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu)
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -68,6 +68,7 @@ extern void __enable_irq(struct irq_desc
 
 extern int irq_startup(struct irq_desc *desc, bool resend);
 extern void irq_shutdown(struct irq_desc *desc);
+extern void irq_enable_or_startup(struct irq_desc *desc);
 extern void irq_enable(struct irq_desc *desc);
 extern void irq_disable(struct irq_desc *desc);
 extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -533,7 +533,7 @@ void __enable_irq(struct irq_desc *desc)
 			goto err_out;
 		/* Prevent probing on this irq: */
 		irq_settings_set_noprobe(desc);
-		irq_enable(desc);
+		irq_enable_or_startup(desc);
 		check_irq_resend(desc);
 		/* fall-through */
 	}

  reply	other threads:[~2017-05-31 10:05 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-31  9:58 [patch 0/2] genirq: Handle NOAUTOEN interrupts correctly Thomas Gleixner
2017-05-31  9:58 ` Thomas Gleixner [this message]
2017-05-31 13:54   ` [patch 1/2] genirq: Handle NOAUTOEN interrupt setup proper Marc Zyngier
2017-05-31 15:18     ` Thomas Gleixner
2017-06-04 12:47   ` [tip:irq/core] " tip-bot for Thomas Gleixner
2017-05-31  9:58 ` [patch 2/2] genirq: Warn when IRQ_NOAUTOEN is used with shared interrupts Thomas Gleixner
2017-06-04 12:48   ` [tip:irq/core] " tip-bot for Thomas Gleixner
2017-09-06  6:00   ` [2/2] " Paul Burton
2017-09-06  8:16     ` Thomas Gleixner
2017-09-06 14:01       ` Paul Burton
2017-09-06 14:14         ` Thomas Gleixner
2017-09-07  1:18           ` Paul Burton
2017-09-07 23:25             ` [RFC PATCH v1 0/9] Support shared percpu interrupts; clean up MIPS hacks Paul Burton
2017-09-07 23:25               ` Paul Burton
2017-09-07 23:25               ` [RFC PATCH v1 1/9] genirq: Allow shared interrupt users to opt into IRQ_NOAUTOEN Paul Burton
2017-09-07 23:25                 ` Paul Burton
2017-09-07 23:25               ` [RFC PATCH v1 2/9] genirq: Support shared per_cpu_devid interrupts Paul Burton
2017-09-07 23:25                 ` Paul Burton
2017-09-25 21:06                 ` Thomas Gleixner
2017-09-26 12:00                   ` Thomas Gleixner
2017-10-19 14:08                     ` Thomas Gleixner
2017-09-07 23:25               ` [RFC PATCH v1 3/9] genirq: Introduce irq_is_percpu_devid() Paul Burton
2017-09-07 23:25                 ` Paul Burton
2017-09-07 23:25               ` [RFC PATCH v1 4/9] MIPS: Remove perf_irq interrupt sharing fallback Paul Burton
2017-09-07 23:25                 ` Paul Burton
2017-09-07 23:25               ` [RFC PATCH v1 5/9] MIPS: Remove perf_irq Paul Burton
2017-09-07 23:25                 ` Paul Burton
2017-09-07 23:25               ` [RFC PATCH v1 6/9] MIPS: perf: percpu_devid interrupt support Paul Burton
2017-09-07 23:25                 ` Paul Burton
2017-10-19 14:12                 ` Thomas Gleixner
2017-09-07 23:25               ` [RFC PATCH v1 7/9] MIPS: cevt-r4k: " Paul Burton
2017-09-07 23:25                 ` Paul Burton
2017-09-07 23:25               ` [RFC PATCH v1 8/9] irqchip: mips-cpu: Set timer, FDC & perf interrupts percpu_devid Paul Burton
2017-09-07 23:25                 ` Paul Burton
2017-09-07 23:25               ` [RFC PATCH v1 9/9] irqchip: mips-gic: Remove gic_all_vpes_local_irq_controller Paul Burton
2017-09-07 23:25                 ` Paul Burton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170531100212.130986205@linutronix.de \
    --to=tglx@linutronix.de \
    --cc=briannorris@chromium.org \
    --cc=dianders@chromium.org \
    --cc=jeffy.chen@rock-chips.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=marc.zyngier@arm.com \
    --cc=tfiga@chromium.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.