LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING
@ 2015-01-23 17:09 Boris Brezillon
  2015-01-23 17:09 ` [PATCH v3 1/5] genirq: Authorize chained handlers to remain disabled when initialized Boris Brezillon
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: Boris Brezillon @ 2015-01-23 17:09 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni, Rob Herring
  Cc: Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Rafael J. Wysocki, linux-arm-kernel, linux-kernel,
	Boris Brezillon

Commit cab303be91dc47942bc25de33dc1140123540800 [1] introduced a WARN_ON
test which triggers a WARNING backtrace on at91 platforms.
While this WARN_ON is absolutely necessary to warn users that they should
not mix request with and without IRQF_NO_SUSPEND flags on shared IRQs,
there is no easy way to solve this issue on at91 platforms.

The main reason is that the init timer is often using a shared irq line
and thus request this irq with IRQF_NO_SUSPEND flag set, while other
peripherals request the same irq line without this flag.

As suggested by Thomas, the first 3 patches of this series add a dumb
demultiplexer irqchip implementation.
This demuxer registers to a source interrupt and then forwards all received
interrupts to its children (it they are enabled).

The last two patches rework at91 DTs and config to make use of this dumb
demuxer implementation.

Rob, I know you were not in favor of exposing this in the DT but we really
need to quickly a solution: more and more people complain about this warning.
If you see a better way to handle this case please share it.

Best Regards,

Boris

Changes since v2:
 - removed unneeded dumb demux flags passed to irq_alloc_dumb_demux_chip
 - set nested lockdep class for all requested irqs
 - add some explanation to the DT binding doc
 - change the compatible string to clearly show that this chip is purely
   virtual
 - added dumb demuxer to all at91 impacted SoCs

Changes since v1:
 - went for an dumb irq demuxer approach instead of trying to fix the
   current shared irq code

Boris Brezillon (5):
  genirq: Authorize chained handlers to remain disabled when initialized
  irqchip: add dumb demultiplexer implementation
  irqchip: Add DT binding doc for dumb demuxer chips
  ARM: at91/dt: select DUMB_IRQ_DEMUX for all at91 SoCs
  ARM: at91/dt: define a dumb irq demultiplexer chip connected on irq1

 .../bindings/interrupt-controller/dumb-demux.txt   |  41 ++++++
 arch/arm/boot/dts/at91rm9200.dtsi                  |  20 ++-
 arch/arm/boot/dts/at91sam9260.dtsi                 |  26 +++-
 arch/arm/boot/dts/at91sam9261.dtsi                 |  26 +++-
 arch/arm/boot/dts/at91sam9263.dtsi                 |  29 ++++-
 arch/arm/boot/dts/at91sam9g45.dtsi                 |  29 ++++-
 arch/arm/boot/dts/at91sam9n12.dtsi                 |  25 +++-
 arch/arm/boot/dts/at91sam9rl.dtsi                  |  29 ++++-
 arch/arm/boot/dts/at91sam9x5.dtsi                  |  26 +++-
 arch/arm/mach-at91/Kconfig                         |   2 +
 drivers/irqchip/Kconfig                            |   4 +
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-dumb-demux.c                   |  72 +++++++++++
 include/linux/irq.h                                |  64 +++++++++-
 include/linux/irqdomain.h                          |   1 +
 kernel/irq/Kconfig                                 |   5 +
 kernel/irq/Makefile                                |   1 +
 kernel/irq/chip.c                                  |  53 +++++++-
 kernel/irq/dumb-demux-chip.c                       | 140 +++++++++++++++++++++
 kernel/irq/handle.c                                |  31 ++++-
 kernel/irq/internals.h                             |   3 +
 kernel/irq/irqdomain.c                             |   2 +-
 kernel/irq/msi.c                                   |   3 +-
 23 files changed, 580 insertions(+), 53 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/dumb-demux.txt
 create mode 100644 drivers/irqchip/irq-dumb-demux.c
 create mode 100644 kernel/irq/dumb-demux-chip.c

-- 
1.9.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 1/5] genirq: Authorize chained handlers to remain disabled when initialized
  2015-01-23 17:09 [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING Boris Brezillon
@ 2015-01-23 17:09 ` Boris Brezillon
  2015-01-23 17:09 ` [PATCH v3 2/5] irqchip: add dumb demultiplexer implementation Boris Brezillon
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Boris Brezillon @ 2015-01-23 17:09 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni, Rob Herring
  Cc: Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Rafael J. Wysocki, linux-arm-kernel, linux-kernel,
	Boris Brezillon

Currently there is no way to keep a chained handler disabled when
registering it.
This might be annoying for irq demuxer that want to keep the source irq
disabled until at least one of their child irq is requested.

Replace the is_chained argument of __irq_set_handler by an enum, thus
adding a new CHAINED_NOSTARTUP mode which explicitly ask for the
interruption to remain disabled.
Update all __irq_set_handler users to use the enum value instead of a
numerical one and add a new irq_set_chained_handler_nostartup helper
function (as done for irq_set_handler and irq_set_chained_handler).

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 include/linux/irq.h    | 26 ++++++++++++++++++++++----
 kernel/irq/chip.c      | 12 +++++++-----
 kernel/irq/irqdomain.c |  2 +-
 kernel/irq/msi.c       |  3 ++-
 4 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/include/linux/irq.h b/include/linux/irq.h
index d09ec7a..247b2d1 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -489,25 +489,43 @@ static inline void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *c
 
 extern int irq_set_percpu_devid(unsigned int irq);
 
+enum chained_mode {
+	IRQ_CHAINED_NONE,
+	IRQ_CHAINED_STARTUP,
+	IRQ_CHAINED_NOSTARTUP,
+};
+
 extern void
-__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
+__irq_set_handler(unsigned int irq, irq_flow_handler_t handle,
+		  enum chained_mode chained_mode,
 		  const char *name);
 
 static inline void
 irq_set_handler(unsigned int irq, irq_flow_handler_t handle)
 {
-	__irq_set_handler(irq, handle, 0, NULL);
+	__irq_set_handler(irq, handle, IRQ_CHAINED_NONE, NULL);
 }
 
 /*
  * Set a highlevel chained flow handler for a given IRQ.
- * (a chained handler is automatically enabled and set to
+ * (this chained handler is automatically enabled and set to
  *  IRQ_NOREQUEST, IRQ_NOPROBE, and IRQ_NOTHREAD)
  */
 static inline void
 irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle)
 {
-	__irq_set_handler(irq, handle, 1, NULL);
+	__irq_set_handler(irq, handle, IRQ_CHAINED_STARTUP, NULL);
+}
+
+/*
+ * Set a highlevel chained flow handler for a given IRQ without starting it.
+ * (this chained handler is kept disabled and set to IRQ_NOREQUEST,
+ * IRQ_NOPROBE, and IRQ_NOTHREAD)
+ */
+static inline void
+irq_set_chained_handler_nostartup(unsigned int irq, irq_flow_handler_t handle)
+{
+	__irq_set_handler(irq, handle, IRQ_CHAINED_NOSTARTUP, NULL);
 }
 
 void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set);
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 6f1c7a5..5de82dc0 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -719,7 +719,8 @@ void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc)
 }
 
 void
-__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
+__irq_set_handler(unsigned int irq, irq_flow_handler_t handle,
+		  enum chained_mode chained_mode,
 		  const char *name)
 {
 	unsigned long flags;
@@ -748,7 +749,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 			 * and the interrrupt supposed to be started
 			 * right away.
 			 */
-			if (WARN_ON(is_chained))
+			if (WARN_ON(chained_mode != IRQ_CHAINED_NONE))
 				goto out;
 			/* Try the parent */
 			irq_data = irq_data->parent_data;
@@ -768,11 +769,12 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 	desc->handle_irq = handle;
 	desc->name = name;
 
-	if (handle != handle_bad_irq && is_chained) {
+	if (handle != handle_bad_irq && chained_mode != IRQ_CHAINED_NONE) {
 		irq_settings_set_noprobe(desc);
 		irq_settings_set_norequest(desc);
 		irq_settings_set_nothread(desc);
-		irq_startup(desc, true);
+		if (chained_mode == IRQ_CHAINED_STARTUP)
+			irq_startup(desc, true);
 	}
 out:
 	irq_put_desc_busunlock(desc, flags);
@@ -784,7 +786,7 @@ irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
 			      irq_flow_handler_t handle, const char *name)
 {
 	irq_set_chip(irq, chip);
-	__irq_set_handler(irq, handle, 0, name);
+	__irq_set_handler(irq, handle, IRQ_CHAINED_NONE, name);
 }
 EXPORT_SYMBOL_GPL(irq_set_chip_and_handler_name);
 
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 7fac311..d5aee6c 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -943,7 +943,7 @@ void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
 			 void *handler_data, const char *handler_name)
 {
 	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
-	__irq_set_handler(virq, handler, 0, handler_name);
+	__irq_set_handler(virq, handler, IRQ_CHAINED_NONE, handler_name);
 	irq_set_handler_data(virq, handler_data);
 }
 
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 3e18163..84b626c 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -164,7 +164,8 @@ static int msi_domain_ops_init(struct irq_domain *domain,
 	irq_domain_set_hwirq_and_chip(domain, virq, hwirq, info->chip,
 				      info->chip_data);
 	if (info->handler && info->handler_name) {
-		__irq_set_handler(virq, info->handler, 0, info->handler_name);
+		__irq_set_handler(virq, info->handler, IRQ_CHAINED_NONE,
+				  info->handler_name);
 		if (info->handler_data)
 			irq_set_handler_data(virq, info->handler_data);
 	}
-- 
1.9.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 2/5] irqchip: add dumb demultiplexer implementation
  2015-01-23 17:09 [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING Boris Brezillon
  2015-01-23 17:09 ` [PATCH v3 1/5] genirq: Authorize chained handlers to remain disabled when initialized Boris Brezillon
@ 2015-01-23 17:09 ` Boris Brezillon
  2015-01-23 17:09 ` [PATCH v3 3/5] irqchip: Add DT binding doc for dumb demuxer chips Boris Brezillon
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Boris Brezillon @ 2015-01-23 17:09 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni, Rob Herring
  Cc: Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Rafael J. Wysocki, linux-arm-kernel, linux-kernel,
	Boris Brezillon

Some interrupt controllers are multiplexing several peripheral IRQs on
a single interrupt line.
While this is not a problem for most IRQs (as long as all peripherals
request the interrupt with IRQF_SHARED flag set), multiplexing timers and
other type of peripherals will generate a WARNING (mixing IRQF_NO_SUSPEND
and !IRQF_NO_SUSPEND is prohibited).

Create a dumb irq demultiplexer which simply forwards interrupts to all
peripherals (exactly what's happening with IRQ_SHARED) but keep a unique
irq number for each peripheral, thus preventing the IRQF_NO_SUSPEND
and !IRQF_NO_SUSPEND mix on a given interrupt.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
 drivers/irqchip/Kconfig          |   4 ++
 drivers/irqchip/Makefile         |   1 +
 drivers/irqchip/irq-dumb-demux.c |  72 ++++++++++++++++++++
 include/linux/irq.h              |  38 +++++++++++
 include/linux/irqdomain.h        |   1 +
 kernel/irq/Kconfig               |   5 ++
 kernel/irq/Makefile              |   1 +
 kernel/irq/chip.c                |  41 ++++++++++++
 kernel/irq/dumb-demux-chip.c     | 140 +++++++++++++++++++++++++++++++++++++++
 kernel/irq/handle.c              |  31 ++++++++-
 kernel/irq/internals.h           |   3 +
 11 files changed, 335 insertions(+), 2 deletions(-)
 create mode 100644 drivers/irqchip/irq-dumb-demux.c
 create mode 100644 kernel/irq/dumb-demux-chip.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index cc79d2a..8a9df88 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -70,6 +70,10 @@ config BRCMSTB_L2_IRQ
 	select GENERIC_IRQ_CHIP
 	select IRQ_DOMAIN
 
+config DUMB_DEMUX_IRQ
+	bool
+	select DUMB_IRQ_DEMUX_CHIP
+
 config DW_APB_ICTL
 	bool
 	select GENERIC_IRQ_CHIP
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 9516a32..77f3c51 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_ARCH_MVEBU)		+= irq-armada-370-xp.o
 obj-$(CONFIG_ARCH_MXS)			+= irq-mxs.o
 obj-$(CONFIG_ARCH_S3C24XX)		+= irq-s3c24xx.o
 obj-$(CONFIG_DW_APB_ICTL)		+= irq-dw-apb-ictl.o
+obj-$(CONFIG_DUMB_DEMUX_IRQ)		+= irq-dumb-demux.o
 obj-$(CONFIG_METAG)			+= irq-metag-ext.o
 obj-$(CONFIG_METAG_PERFCOUNTER_IRQS)	+= irq-metag.o
 obj-$(CONFIG_ARCH_MOXART)		+= irq-moxart.o
diff --git a/drivers/irqchip/irq-dumb-demux.c b/drivers/irqchip/irq-dumb-demux.c
new file mode 100644
index 0000000..e4b8905
--- /dev/null
+++ b/drivers/irqchip/irq-dumb-demux.c
@@ -0,0 +1,72 @@
+/*
+ * Dumb irq demux chip driver
+ *
+ * Copyright (C) 2015 Atmel
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ * This file is licensed under GPLv2.
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+
+#include "irqchip.h"
+
+static int __init dumb_irq_demux_of_init(struct device_node *node,
+					 struct device_node *parent)
+{
+	struct irq_chip_dumb_demux *demux;
+	unsigned int irq;
+	u32 valid_irqs;
+	int ret;
+
+	irq = irq_of_parse_and_map(node, 0);
+	if (!irq) {
+		pr_err("Failed to retrieve dumb irq demuxer source\n");
+		return -EINVAL;
+	}
+
+	ret = of_property_read_u32(node, "irqs", &valid_irqs);
+	if (ret) {
+		pr_err("Invalid of missing 'irqs' property\n");
+		return ret;
+	}
+
+	demux = irq_alloc_dumb_demux_chip(irq, valid_irqs,
+					  IRQ_NOREQUEST | IRQ_NOPROBE |
+					  IRQ_NOAUTOEN, 0);
+	if (!demux) {
+		pr_err("Failed to allocate dumb irq demuxer struct\n");
+		return -ENOMEM;
+	}
+
+	demux->domain = irq_domain_add_linear(node, BITS_PER_LONG,
+					      &irq_dumb_demux_domain_ops,
+					      demux);
+	if (!demux->domain) {
+		ret = -ENOMEM;
+		goto err_free_demux;
+	}
+
+	ret = irq_set_handler_data(irq, demux);
+	if (ret) {
+		pr_err("Failed to assign handler data\n");
+		goto err_free_domain;
+	}
+
+	irq_set_chained_handler_nostartup(irq, irq_dumb_demux_handler);
+
+	return 0;
+
+err_free_domain:
+	irq_domain_remove(demux->domain);
+
+err_free_demux:
+	kfree(demux);
+
+	return ret;
+}
+IRQCHIP_DECLARE(dumb_irq_demux, "virtual,dumb-irq-demux", dumb_irq_demux_of_init);
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 247b2d1..281bed7 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -445,6 +445,10 @@ extern void handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_edge_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_simple_irq(unsigned int irq, struct irq_desc *desc);
+#ifdef CONFIG_DUMB_IRQ_DEMUX_CHIP
+extern irqreturn_t handle_dumb_demux_irq(unsigned int irq,
+					 struct irq_desc *desc);
+#endif
 extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc);
@@ -880,4 +884,38 @@ static inline u32 irq_reg_readl(struct irq_chip_generic *gc,
 		return readl(gc->reg_base + reg_offset);
 }
 
+#ifdef CONFIG_DUMB_IRQ_DEMUX_CHIP
+/**
+ * struct irq_chip_dumb_demux - Dumb demultiplexer irq chip data structure
+ * @domain:		irq domain pointer
+ * @available:		Bitfield of valid irqs
+ * @unmasked:		Bitfield containing irqs status
+ * @flags:		irq_dumb_demux_flags flags
+ * @src_irq:		irq feeding the dumb demux chip
+ *
+ * Note, that irq_chip_generic can have multiple irq_chip_type
+ * implementations which can be associated to a particular irq line of
+ * an irq_chip_generic instance. That allows to share and protect
+ * state in an irq_chip_generic instance when we need to implement
+ * different flow mechanisms (level/edge) for it.
+ */
+struct irq_chip_dumb_demux {
+	struct irq_domain *domain;
+	unsigned long available;
+	unsigned long unmasked;
+	unsigned int flags;
+	unsigned int src_irq;
+	unsigned int irq_flags_to_clear;
+	unsigned int irq_flags_to_set;
+};
+
+void irq_dumb_demux_handler(unsigned int irq, struct irq_desc *desc);
+
+struct irq_chip_dumb_demux *
+irq_alloc_dumb_demux_chip(unsigned int src_irq,
+			  unsigned long valid_irqs,
+			  unsigned int clr_flags,
+			  unsigned int set_flags);
+#endif /* CONFIG_DUMB_IRQ_DEMUX_CHIP */
+
 #endif /* _LINUX_IRQ_H */
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 676d730..1de3808 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -80,6 +80,7 @@ struct irq_domain_ops {
 };
 
 extern struct irq_domain_ops irq_generic_chip_ops;
+extern struct irq_domain_ops irq_dumb_demux_domain_ops;
 
 struct irq_domain_chip_generic;
 
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index 9a76e3b..d01554a 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -51,6 +51,11 @@ config GENERIC_IRQ_CHIP
        bool
        select IRQ_DOMAIN
 
+# Dumb interrupt demuxer chip implementation
+config DUMB_IRQ_DEMUX_CHIP
+	bool
+	select IRQ_DOMAIN
+
 # Generic irq_domain hw <--> linux irq number translation
 config IRQ_DOMAIN
 	bool
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile
index d121235..1cd4e42 100644
--- a/kernel/irq/Makefile
+++ b/kernel/irq/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
 obj-$(CONFIG_PM_SLEEP) += pm.o
 obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o
+obj-$(CONFIG_DUMB_IRQ_DEMUX_CHIP) += dumb-demux-chip.o
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 5de82dc0..5f516af 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -405,6 +405,47 @@ out_unlock:
 }
 EXPORT_SYMBOL_GPL(handle_simple_irq);
 
+#ifdef CONFIG_DUMB_IRQ_DEMUX_CHIP
+/**
+ *	handle_dumb_demux_irq - Dumb demuxer irq handle function.
+ *	@irq:	the interrupt number
+ *	@desc:	the interrupt description structure for this irq
+ *
+ *	Dumb demux interrupts are sent from a demultiplexing interrupt handler
+ *	which is not able to decide which child interrupt handler should be
+ *	called.
+ *
+ *	Note: The caller is expected to handle the ack, clear, mask and
+ *	unmask issues if necessary.
+ */
+irqreturn_t
+handle_dumb_demux_irq(unsigned int irq, struct irq_desc *desc)
+{
+	irqreturn_t retval = IRQ_NONE;
+
+	raw_spin_lock(&desc->lock);
+
+	if (!irq_may_run(desc))
+		goto out_unlock;
+
+	desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
+	kstat_incr_irqs_this_cpu(irq, desc);
+
+	if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
+		desc->istate |= IRQS_PENDING;
+		goto out_unlock;
+	}
+
+	retval = handle_irq_event_no_spurious_check(desc);
+
+out_unlock:
+	raw_spin_unlock(&desc->lock);
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(handle_dumb_demux_irq);
+#endif /* CONFIG_DUMB_IRQ_DEMUX_CHIP */
+
 /*
  * Called unconditionally from handle_level_irq() and only for oneshot
  * interrupts from handle_fasteoi_irq()
diff --git a/kernel/irq/dumb-demux-chip.c b/kernel/irq/dumb-demux-chip.c
new file mode 100644
index 0000000..6b88c88
--- /dev/null
+++ b/kernel/irq/dumb-demux-chip.c
@@ -0,0 +1,140 @@
+/*
+ * Library implementing common dumb irq demux chip functions
+ *
+ * Copyright (C) 2015 Atmel
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ *
+ * This file is licensed under GPLv2.
+ */
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/syscore_ops.h>
+
+#include "internals.h"
+
+static void irq_dumb_demux_mask(struct irq_data *d)
+{
+	struct irq_chip_dumb_demux *demux = irq_data_get_irq_chip_data(d);
+
+	clear_bit(d->hwirq, &demux->unmasked);
+
+	if (!demux->unmasked)
+		disable_irq_nosync(demux->src_irq);
+}
+
+static void irq_dumb_demux_unmask(struct irq_data *d)
+{
+	struct irq_chip_dumb_demux *demux = irq_data_get_irq_chip_data(d);
+	bool enable_src_irq = !demux->unmasked;
+
+	set_bit(d->hwirq, &demux->unmasked);
+
+	if (enable_src_irq)
+		enable_irq(demux->src_irq);
+}
+
+static struct irq_chip irq_dumb_demux_chip = {
+	.name =		"dumb-demux-irq",
+	.irq_mask =	irq_dumb_demux_mask,
+	.irq_unmask =	irq_dumb_demux_unmask,
+};
+
+/*
+ * Separate lockdep class for interrupt chip which can nest irq_desc
+ * lock.
+ */
+static struct lock_class_key irq_nested_lock_class;
+
+/*
+ * irq_map_dumb_demux_chip - Map a dumb demux chip for an irq domain
+ */
+static int irq_map_dumb_demux_chip(struct irq_domain *d,
+				   unsigned int virq,
+				   irq_hw_number_t hw_irq)
+{
+	struct irq_chip_dumb_demux *demux = d->host_data;
+
+	if (!test_bit(hw_irq, &demux->available))
+		return -EINVAL;
+
+	irq_set_lockdep_class(virq, &irq_nested_lock_class);
+
+	irq_set_chip(virq, &irq_dumb_demux_chip);
+	irq_set_chip_data(virq, demux);
+	irq_modify_status(virq, demux->irq_flags_to_clear,
+			  demux->irq_flags_to_set);
+
+	return 0;
+}
+
+struct irq_domain_ops irq_dumb_demux_domain_ops = {
+	.map	= irq_map_dumb_demux_chip,
+	.xlate	= irq_domain_xlate_onecell,
+};
+EXPORT_SYMBOL_GPL(irq_dumb_demux_domain_ops);
+
+/**
+ * irq_dumb_demux_handler - Dumb demux flow handler
+ * @irq:		Virtual irq number
+ * @irq_desc:		irq descriptor
+ */
+void irq_dumb_demux_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct irq_chip_dumb_demux *demux = irq_get_handler_data(irq);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	irqreturn_t ret = IRQ_NONE;
+	int i;
+
+	chained_irq_enter(chip, desc);
+	for_each_set_bit(i, &demux->unmasked, BITS_PER_LONG) {
+		int demuxed_irq = irq_find_mapping(demux->domain, i);
+		struct irq_desc *desc = irq_to_desc(demuxed_irq);
+
+		ret |= handle_dumb_demux_irq(demuxed_irq, desc);
+	}
+	chained_irq_exit(chip, desc);
+
+	if (!noirqdebug)
+		note_interrupt(irq, desc, ret);
+}
+EXPORT_SYMBOL_GPL(irq_dumb_demux_handler);
+
+/**
+ * irq_alloc_dumb_demux_chip - Allocate a dumb demux chip
+ * @src_irq:		irq feeding the dumb demux chip
+ * @valid_irqs:		Bitmask representing valid irqs
+ * @clr_flags:		irq_flags to clear when mapping an interrupt
+ * @set_flags:		irq_flags to set when mapping an interrupt
+ */
+struct irq_chip_dumb_demux *
+irq_alloc_dumb_demux_chip(unsigned int src_irq,
+			  unsigned long valid_irqs,
+			  unsigned int clr_flags,
+			  unsigned int set_flags)
+{
+	struct irq_chip_dumb_demux *demux;
+
+	if (!src_irq)
+		return ERR_PTR(-EINVAL);
+
+	demux = kzalloc(sizeof(*demux), GFP_KERNEL);
+	if (!demux)
+		return ERR_PTR(-ENOMEM);
+
+	demux->available = valid_irqs;
+	demux->src_irq = src_irq;
+	demux->irq_flags_to_clear = clr_flags;
+	demux->irq_flags_to_set = set_flags;
+
+	return demux;
+}
+EXPORT_SYMBOL_GPL(irq_alloc_dumb_demux_chip);
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 6354802..f786850 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -131,7 +131,8 @@ void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
 }
 
 irqreturn_t
-handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
+handle_irq_event_percpu_no_spurious_check(struct irq_desc *desc,
+					  struct irqaction *action)
 {
 	irqreturn_t retval = IRQ_NONE;
 	unsigned int flags = 0, irq = desc->irq_data.irq;
@@ -175,8 +176,18 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
 
 	add_interrupt_randomness(irq, flags);
 
+	return retval;
+}
+
+irqreturn_t
+handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
+{
+	irqreturn_t retval;
+
+	retval = handle_irq_event_percpu_no_spurious_check(desc, action);
+
 	if (!noirqdebug)
-		note_interrupt(irq, desc, retval);
+		note_interrupt(desc->irq_data.irq, desc, retval);
 	return retval;
 }
 
@@ -195,3 +206,19 @@ irqreturn_t handle_irq_event(struct irq_desc *desc)
 	irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
 	return ret;
 }
+
+irqreturn_t handle_irq_event_no_spurious_check(struct irq_desc *desc)
+{
+	struct irqaction *action = desc->action;
+	irqreturn_t ret;
+
+	desc->istate &= ~IRQS_PENDING;
+	irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
+	raw_spin_unlock(&desc->lock);
+
+	ret = handle_irq_event_percpu_no_spurious_check(desc, action);
+
+	raw_spin_lock(&desc->lock);
+	irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
+	return ret;
+}
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index df553b0..fe056fb 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -90,6 +90,9 @@ extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
 
 irqreturn_t handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action);
 irqreturn_t handle_irq_event(struct irq_desc *desc);
+irqreturn_t handle_irq_event_percpu_no_spurious_check(struct irq_desc *desc,
+						      struct irqaction *action);
+irqreturn_t handle_irq_event_no_spurious_check(struct irq_desc *desc);
 
 /* Resending of interrupts :*/
 void check_irq_resend(struct irq_desc *desc, unsigned int irq);
-- 
1.9.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 3/5] irqchip: Add DT binding doc for dumb demuxer chips
  2015-01-23 17:09 [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING Boris Brezillon
  2015-01-23 17:09 ` [PATCH v3 1/5] genirq: Authorize chained handlers to remain disabled when initialized Boris Brezillon
  2015-01-23 17:09 ` [PATCH v3 2/5] irqchip: add dumb demultiplexer implementation Boris Brezillon
@ 2015-01-23 17:09 ` Boris Brezillon
  2015-01-23 17:09 ` [PATCH v3 4/5] ARM: at91/dt: select DUMB_IRQ_DEMUX for all at91 SoCs Boris Brezillon
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Boris Brezillon @ 2015-01-23 17:09 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni, Rob Herring
  Cc: Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Rafael J. Wysocki, linux-arm-kernel, linux-kernel,
	Boris Brezillon

Add documentation for the dumb demuxer.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
 .../bindings/interrupt-controller/dumb-demux.txt   | 41 ++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/dumb-demux.txt

diff --git a/Documentation/devicetree/bindings/interrupt-controller/dumb-demux.txt b/Documentation/devicetree/bindings/interrupt-controller/dumb-demux.txt
new file mode 100644
index 0000000..6199923
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/dumb-demux.txt
@@ -0,0 +1,41 @@
+* Generic Dumb Interrupt Demultiplexer
+
+This Dumb demultiplexer simply forward all incoming interrupts to its
+enabled/unmasked children.
+It is only intended to be used by hardware that do not provide a proper way
+to demultiplex a source interrupt, and thus have to wake all their children
+up so that they can possibly handle the interrupt (if needed).
+This can be seen as an alternative to shared interrupts when at least one
+of the interrupt children is a timer (and require the irq to be stay enabled
+on suspend) while others are not. This will prevent calling irq handlers of
+non timer devices while they are suspended.
+
+Required properties:
+- compatible: Should be "virtual,dumb-irq-demux".
+- interrupt-controller: Identifies the node as an interrupt controller.
+- interrupts-extended or interrupt-parent and interrupts: Reference the source
+  interrupt connected to this dumb demuxer.
+- #interrupt-cells: The number of cells to define the interrupts (should be 1).
+  The only cell is the IRQ number.
+- irqs: u32 bitfield specifying the interrupts provided by the demuxer.
+
+Examples:
+	/*
+	 * Dumb demuxer controller
+	 */
+	dumb_irq1_demux: dumb-irq-demux@1 {
+		compatible = "virtual,dumb-irq-demux";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupts-extended = <&aic 1 IRQ_TYPE_LEVEL_HIGH 7>;
+		irqs = <0x3f>;
+	};
+
+	/*
+	 * Device connected on this dumb demuxer
+	 */
+	dma: dma-controller@ffffec00 {
+		compatible = "atmel,at91sam9g45-dma";
+		reg = <0xffffec00 0x200>;
+		interrupts-extended = <&dumb_irq1_demux 0>;
+	};
-- 
1.9.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 4/5] ARM: at91/dt: select DUMB_IRQ_DEMUX for all at91 SoCs
  2015-01-23 17:09 [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING Boris Brezillon
                   ` (2 preceding siblings ...)
  2015-01-23 17:09 ` [PATCH v3 3/5] irqchip: Add DT binding doc for dumb demuxer chips Boris Brezillon
@ 2015-01-23 17:09 ` Boris Brezillon
  2015-01-23 17:09 ` [PATCH v3 5/5] ARM: at91/dt: define a dumb irq demultiplexer chip connected on irq1 Boris Brezillon
  2015-01-24 16:37 ` [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING Thomas Gleixner
  5 siblings, 0 replies; 8+ messages in thread
From: Boris Brezillon @ 2015-01-23 17:09 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni, Rob Herring
  Cc: Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Rafael J. Wysocki, linux-arm-kernel, linux-kernel,
	Boris Brezillon

Older at91 SoCs need a virtual dumb irq demuxer to gracefully support the
fact that irq1 is shared by several devices and a timer.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
 arch/arm/mach-at91/Kconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 2395c68..8ff2c2a 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -28,6 +28,7 @@ config HAVE_AT91_H32MX
 config SOC_AT91SAM9
 	bool
 	select ATMEL_AIC_IRQ
+	select DUMB_DEMUX_IRQ
 	select COMMON_CLK_AT91
 	select CPU_ARM926T
 	select GENERIC_CLOCKEVENTS
@@ -98,6 +99,7 @@ if SOC_SAM_V4_V5
 config SOC_AT91RM9200
 	bool "AT91RM9200"
 	select ATMEL_AIC_IRQ
+	select DUMB_DEMUX_IRQ
 	select COMMON_CLK_AT91
 	select CPU_ARM920T
 	select GENERIC_CLOCKEVENTS
-- 
1.9.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 5/5] ARM: at91/dt: define a dumb irq demultiplexer chip connected on irq1
  2015-01-23 17:09 [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING Boris Brezillon
                   ` (3 preceding siblings ...)
  2015-01-23 17:09 ` [PATCH v3 4/5] ARM: at91/dt: select DUMB_IRQ_DEMUX for all at91 SoCs Boris Brezillon
@ 2015-01-23 17:09 ` Boris Brezillon
  2015-01-24 16:37 ` [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING Thomas Gleixner
  5 siblings, 0 replies; 8+ messages in thread
From: Boris Brezillon @ 2015-01-23 17:09 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Nicolas Ferre,
	Jean-Christophe Plagniol-Villard, Alexandre Belloni, Rob Herring
  Cc: Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Rafael J. Wysocki, linux-arm-kernel, linux-kernel,
	Boris Brezillon

IRQ is multiplexing several peripheral IRQs, but there's no way to
properly demultiplex those IRQs.
Use a dumb irq demux chip to achieve this demultiplexing operation.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 arch/arm/boot/dts/at91rm9200.dtsi  | 20 +++++++++++++++++---
 arch/arm/boot/dts/at91sam9260.dtsi | 26 +++++++++++++++++++++-----
 arch/arm/boot/dts/at91sam9261.dtsi | 26 +++++++++++++++++++++-----
 arch/arm/boot/dts/at91sam9263.dtsi | 29 +++++++++++++++++++++++------
 arch/arm/boot/dts/at91sam9g45.dtsi | 29 +++++++++++++++++++++++------
 arch/arm/boot/dts/at91sam9n12.dtsi | 25 +++++++++++++++++++++----
 arch/arm/boot/dts/at91sam9rl.dtsi  | 29 +++++++++++++++++++++++------
 arch/arm/boot/dts/at91sam9x5.dtsi  | 26 +++++++++++++++++++++-----
 8 files changed, 170 insertions(+), 40 deletions(-)

diff --git a/arch/arm/boot/dts/at91rm9200.dtsi b/arch/arm/boot/dts/at91rm9200.dtsi
index 6c97d4a..9612d7c 100644
--- a/arch/arm/boot/dts/at91rm9200.dtsi
+++ b/arch/arm/boot/dts/at91rm9200.dtsi
@@ -94,7 +94,7 @@
 			pmc: pmc@fffffc00 {
 				compatible = "atmel,at91rm9200-pmc";
 				reg = <0xfffffc00 0x100>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 0>;
 				interrupt-controller;
 				#address-cells = <1>;
 				#size-cells = <0>;
@@ -353,7 +353,7 @@
 			st: timer@fffffd00 {
 				compatible = "atmel,at91rm9200-st";
 				reg = <0xfffffd00 0x100>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 1>;
 			};
 
 			tcb0: timer@fffa0000 {
@@ -820,7 +820,7 @@
 			dbgu: serial@fffff200 {
 				compatible = "atmel,at91rm9200-usart";
 				reg = <0xfffff200 0x200>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 2>;
 				pinctrl-names = "default";
 				pinctrl-0 = <&pinctrl_dbgu>;
 				clocks = <&mck>;
@@ -944,4 +944,18 @@
 		#size-cells = <0>;
 		status = "disabled";
 	};
+
+	dumb_irq1_demux: dumb-irq-demux@1 {
+		compatible = "virtual,dumb-irq-demux";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+		/*
+		 * Interrupt lines:
+		 * 0: PMC
+		 * 1: ST
+		 * 2: DBGU
+		 */
+		irqs = <0x7>;
+	};
 };
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index dd1313c..2cc31a3 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -97,7 +97,7 @@
 			pmc: pmc@fffffc00 {
 				compatible = "atmel,at91sam9260-pmc";
 				reg = <0xfffffc00 0x100>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 0>;
 				interrupt-controller;
 				#address-cells = <1>;
 				#size-cells = <0>;
@@ -364,7 +364,7 @@
 			pit: timer@fffffd30 {
 				compatible = "atmel,at91sam9260-pit";
 				reg = <0xfffffd30 0xf>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 1>;
 				clocks = <&mck>;
 			};
 
@@ -750,7 +750,7 @@
 			dbgu: serial@fffff200 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfffff200 0x200>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 2>;
 				pinctrl-names = "default";
 				pinctrl-0 = <&pinctrl_dbgu>;
 				clocks = <&mck>;
@@ -959,7 +959,7 @@
 			rtc@fffffd20 {
 				compatible = "atmel,at91sam9260-rtt";
 				reg = <0xfffffd20 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 3>;
 				clocks = <&clk32k>;
 				status = "disabled";
 			};
@@ -967,7 +967,7 @@
 			watchdog@fffffd40 {
 				compatible = "atmel,at91sam9260-wdt";
 				reg = <0xfffffd40 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 4>;
 				atmel,watchdog-type = "hardware";
 				atmel,reset-type = "all";
 				atmel,dbg-halt;
@@ -1010,6 +1010,22 @@
 		};
 	};
 
+	dumb_irq1_demux: dumb-irq-demux@1 {
+		compatible = "virtual,dumb-irq-demux";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+		/*
+		 * Interrupt lines:
+		 * 0: PMC
+		 * 1: PIT
+		 * 2: DBGU
+		 * 3: RTT
+		 * 4: WATCHDOG
+		 */
+		irqs = <0x1f>;
+	};
+
 	i2c@0 {
 		compatible = "i2c-gpio";
 		gpios = <&pioA 23 GPIO_ACTIVE_HIGH /* sda */
diff --git a/arch/arm/boot/dts/at91sam9261.dtsi b/arch/arm/boot/dts/at91sam9261.dtsi
index cdb9ed6..b1d96bd 100644
--- a/arch/arm/boot/dts/at91sam9261.dtsi
+++ b/arch/arm/boot/dts/at91sam9261.dtsi
@@ -272,7 +272,7 @@
 			dbgu: serial@fffff200 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfffff200 0x200>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 2>;
 				pinctrl-names = "default";
 				pinctrl-0 = <&pinctrl_dbgu>;
 				clocks = <&mck>;
@@ -564,7 +564,7 @@
 			pmc: pmc@fffffc00 {
 				compatible = "atmel,at91rm9200-pmc";
 				reg = <0xfffffc00 0x100>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 0>;
 				interrupt-controller;
 				#address-cells = <1>;
 				#size-cells = <0>;
@@ -824,14 +824,14 @@
 			pit: timer@fffffd30 {
 				compatible = "atmel,at91sam9260-pit";
 				reg = <0xfffffd30 0xf>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 1>;
 				clocks = <&mck>;
 			};
 
 			rtc@fffffd20 {
 				compatible = "atmel,at91sam9260-rtt";
 				reg = <0xfffffd20 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 3>;
 				clocks = <&slow_xtal>;
 				status = "disabled";
 			};
@@ -839,7 +839,7 @@
 			watchdog@fffffd40 {
 				compatible = "atmel,at91sam9260-wdt";
 				reg = <0xfffffd40 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 4>;
 				status = "disabled";
 			};
 
@@ -864,4 +864,20 @@
 		#size-cells = <0>;
 		status = "disabled";
 	};
+
+	dumb_irq1_demux: dumb-irq-demux@1 {
+		compatible = "virtual,dumb-irq-demux";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+		/*
+		 * Interrupt lines:
+		 * 0: PMC
+		 * 1: ST
+		 * 2: DBGU
+		 * 3: RTT
+		 * 4: WATCHDOG
+		 */
+		irqs = <0x1f>;
+	};
 };
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index e8c6c60..7810eb2 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -85,7 +85,7 @@
 			pmc: pmc@fffffc00 {
 				compatible = "atmel,at91rm9200-pmc";
 				reg = <0xfffffc00 0x100>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 0>;
 				interrupt-controller;
 				#address-cells = <1>;
 				#size-cells = <0>;
@@ -359,7 +359,7 @@
 			pit: timer@fffffd30 {
 				compatible = "atmel,at91sam9260-pit";
 				reg = <0xfffffd30 0xf>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 1>;
 				clocks = <&mck>;
 			};
 
@@ -744,7 +744,7 @@
 			dbgu: serial@ffffee00 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xffffee00 0x200>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 2>;
 				pinctrl-names = "default";
 				pinctrl-0 = <&pinctrl_dbgu>;
 				clocks = <&mck>;
@@ -870,7 +870,7 @@
 			watchdog@fffffd40 {
 				compatible = "atmel,at91sam9260-wdt";
 				reg = <0xfffffd40 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 4>;
 				atmel,watchdog-type = "hardware";
 				atmel,reset-type = "all";
 				atmel,dbg-halt;
@@ -927,7 +927,7 @@
 			rtc@fffffd20 {
 				compatible = "atmel,at91sam9260-rtt";
 				reg = <0xfffffd20 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 3>;
 				clocks = <&slow_xtal>;
 				status = "disabled";
 			};
@@ -935,7 +935,7 @@
 			rtc@fffffd50 {
 				compatible = "atmel,at91sam9260-rtt";
 				reg = <0xfffffd50 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 5>;
 				clocks = <&slow_xtal>;
 				status = "disabled";
 			};
@@ -998,4 +998,21 @@
 		#size-cells = <0>;
 		status = "disabled";
 	};
+
+	dumb_irq1_demux: dumb-irq-demux@1 {
+		compatible = "virtual,dumb-irq-demux";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+		/*
+		 * Interrupt lines:
+		 * 0: PMC
+		 * 1: PIT
+		 * 2: DBGU
+		 * 3: RTT1
+		 * 4: WATCHDOG
+		 * 5: RTT2
+		 */
+		irqs = <0x3f>;
+	};
 };
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index 2a8da8a..97f0ca6 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -111,7 +111,7 @@
 			pmc: pmc@fffffc00 {
 				compatible = "atmel,at91sam9g45-pmc";
 				reg = <0xfffffc00 0x100>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 0>;
 				interrupt-controller;
 				#address-cells = <1>;
 				#size-cells = <0>;
@@ -387,7 +387,7 @@
 			pit: timer@fffffd30 {
 				compatible = "atmel,at91sam9260-pit";
 				reg = <0xfffffd30 0xf>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 1>;
 				clocks = <&mck>;
 			};
 
@@ -890,7 +890,7 @@
 			dbgu: serial@ffffee00 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xffffee00 0x200>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 2>;
 				pinctrl-names = "default";
 				pinctrl-0 = <&pinctrl_dbgu>;
 				clocks = <&mck>;
@@ -1107,7 +1107,7 @@
 			watchdog@fffffd40 {
 				compatible = "atmel,at91sam9260-wdt";
 				reg = <0xfffffd40 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 4>;
 				atmel,watchdog-type = "hardware";
 				atmel,reset-type = "all";
 				atmel,dbg-halt;
@@ -1234,7 +1234,7 @@
 			rtc@fffffd20 {
 				compatible = "atmel,at91sam9260-rtt";
 				reg = <0xfffffd20 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 3>;
 				clocks = <&clk32k>;
 				status = "disabled";
 			};
@@ -1242,7 +1242,7 @@
 			rtc@fffffdb0 {
 				compatible = "atmel,at91rm9200-rtc";
 				reg = <0xfffffdb0 0x30>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 5>;
 				status = "disabled";
 			};
 
@@ -1316,4 +1316,21 @@
 		#size-cells = <0>;
 		status = "disabled";
 	};
+
+	dumb_irq1_demux: dumb-irq-demux@1 {
+		compatible = "virtual,dumb-irq-demux";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+		/*
+		 * Interrupt lines:
+		 * 0: PMC
+		 * 1: PIT
+		 * 2: DBGU
+		 * 3: RTT
+		 * 4: WATCHDOG
+		 * 5: RTC
+		 */
+		irqs = <0x3f>;
+	};
 };
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
index 68eb9ad..e2b9fe5 100644
--- a/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -94,7 +94,7 @@
 			pmc: pmc@fffffc00 {
 				compatible = "atmel,at91sam9n12-pmc";
 				reg = <0xfffffc00 0x200>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 0>;
 				interrupt-controller;
 				#address-cells = <1>;
 				#size-cells = <0>;
@@ -376,7 +376,7 @@
 			pit: timer@fffffe30 {
 				compatible = "atmel,at91sam9260-pit";
 				reg = <0xfffffe30 0xf>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 1>;
 				clocks = <&mck>;
 			};
 
@@ -754,7 +754,7 @@
 			dbgu: serial@fffff200 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfffff200 0x200>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 2>;
 				pinctrl-names = "default";
 				pinctrl-0 = <&pinctrl_dbgu>;
 				clocks = <&mck>;
@@ -885,7 +885,8 @@
 			watchdog@fffffe40 {
 				compatible = "atmel,at91sam9260-wdt";
 				reg = <0xfffffe40 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 4>;
+				interrupts-extended = <&dumb_irq1_demux 4>;
 				atmel,watchdog-type = "hardware";
 				atmel,reset-type = "all";
 				atmel,dbg-halt;
@@ -948,4 +949,20 @@
 		#size-cells = <0>;
 		status = "disabled";
 	};
+
+	dumb_irq1_demux: dumb-irq-demux@1 {
+		compatible = "virtual,dumb-irq-demux";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+		/*
+		 * Interrupt lines:
+		 * 0: PMC
+		 * 1: PIT
+		 * 2: DBGU
+		 * 3: RTC
+		 * 4: WATCHDOG
+		 */
+		irqs = <0x1f>;
+	};
 };
diff --git a/arch/arm/boot/dts/at91sam9rl.dtsi b/arch/arm/boot/dts/at91sam9rl.dtsi
index 7242437..4838e11 100644
--- a/arch/arm/boot/dts/at91sam9rl.dtsi
+++ b/arch/arm/boot/dts/at91sam9rl.dtsi
@@ -374,7 +374,7 @@
 			dbgu: serial@fffff200 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfffff200 0x200>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 2>;
 				pinctrl-names = "default";
 				pinctrl-0 = <&pinctrl_dbgu>;
 				clocks = <&mck>;
@@ -811,7 +811,7 @@
 			pmc: pmc@fffffc00 {
 				compatible = "atmel,at91sam9g45-pmc";
 				reg = <0xfffffc00 0x100>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 0>;
 				interrupt-controller;
 				#address-cells = <1>;
 				#size-cells = <0>;
@@ -1023,14 +1023,14 @@
 			pit: timer@fffffd30 {
 				compatible = "atmel,at91sam9260-pit";
 				reg = <0xfffffd30 0xf>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 1>;
 				clocks = <&mck>;
 			};
 
 			watchdog@fffffd40 {
 				compatible = "atmel,at91sam9260-wdt";
 				reg = <0xfffffd40 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 4>;
 				status = "disabled";
 			};
 
@@ -1063,14 +1063,14 @@
 			rtc@fffffeb0 {
 				compatible = "atmel,at91rm9200-rtc";
 				reg = <0xfffffeb0 0x40>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 5>;
 				status = "disabled";
 			};
 
 			rtc@fffffd20 {
 				compatible = "atmel,at91sam9260-rtt";
 				reg = <0xfffffd20 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 3>;
 				clocks = <&clk32k>;
 				status = "disabled";
 			};
@@ -1110,4 +1110,21 @@
 		pinctrl-0 = <&pinctrl_i2c_gpio1>;
 		status = "disabled";
 	};
+
+	dumb_irq1_demux: dumb-irq-demux@1 {
+		compatible = "virtual,dumb-irq-demux";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+		/*
+		 * Interrupt lines:
+		 * 0: PMC
+		 * 1: PIT
+		 * 2: DBGU
+		 * 3: RTT
+		 * 4: WATCHDOG
+		 * 5: RTC
+		 */
+		irqs = <0x3f>;
+	};
 };
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index bbb3ba6..cfbf458 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -102,7 +102,7 @@
 			pmc: pmc@fffffc00 {
 				compatible = "atmel,at91sam9x5-pmc";
 				reg = <0xfffffc00 0x100>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 0>;
 				interrupt-controller;
 				#address-cells = <1>;
 				#size-cells = <0>;
@@ -381,7 +381,7 @@
 			pit: timer@fffffe30 {
 				compatible = "atmel,at91sam9260-pit";
 				reg = <0xfffffe30 0xf>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 1>;
 				clocks = <&mck>;
 			};
 
@@ -857,7 +857,7 @@
 			dbgu: serial@fffff200 {
 				compatible = "atmel,at91sam9260-usart";
 				reg = <0xfffff200 0x200>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 2>;
 				pinctrl-names = "default";
 				pinctrl-0 = <&pinctrl_dbgu>;
 				dmas = <&dma1 1 AT91_DMA_CFG_PER_ID(8)>,
@@ -1121,7 +1121,7 @@
 			watchdog@fffffe40 {
 				compatible = "atmel,at91sam9260-wdt";
 				reg = <0xfffffe40 0x10>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 4>;
 				atmel,watchdog-type = "hardware";
 				atmel,reset-type = "all";
 				atmel,dbg-halt;
@@ -1132,7 +1132,7 @@
 			rtc@fffffeb0 {
 				compatible = "atmel,at91sam9x5-rtc";
 				reg = <0xfffffeb0 0x40>;
-				interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+				interrupts-extended = <&dumb_irq1_demux 3>;
 				status = "disabled";
 			};
 
@@ -1231,4 +1231,20 @@
 		pinctrl-0 = <&pinctrl_i2c_gpio2>;
 		status = "disabled";
 	};
+
+	dumb_irq1_demux: dumb-irq-demux@1 {
+		compatible = "virtual,dumb-irq-demux";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+		/*
+		 * Interrupt lines:
+		 * 0: PMC
+		 * 1: PIT
+		 * 2: DBGU
+		 * 3: RTC
+		 * 4: WATCHDOG
+		 */
+		irqs = <0x1f>;
+	};
 };
-- 
1.9.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING
  2015-01-23 17:09 [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING Boris Brezillon
                   ` (4 preceding siblings ...)
  2015-01-23 17:09 ` [PATCH v3 5/5] ARM: at91/dt: define a dumb irq demultiplexer chip connected on irq1 Boris Brezillon
@ 2015-01-24 16:37 ` Thomas Gleixner
  2015-01-24 17:20   ` Boris Brezillon
  5 siblings, 1 reply; 8+ messages in thread
From: Thomas Gleixner @ 2015-01-24 16:37 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Jason Cooper, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Rafael J. Wysocki,
	linux-arm-kernel, linux-kernel

On Fri, 23 Jan 2015, Boris Brezillon wrote:
>  - change the compatible string to clearly show that this chip is purely
>    virtual

So we probably want to do : s/dumb/virt/ for both DT and code to make
it clear from the names as well.

Thanks,

	tglx

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING
  2015-01-24 16:37 ` [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING Thomas Gleixner
@ 2015-01-24 17:20   ` Boris Brezillon
  0 siblings, 0 replies; 8+ messages in thread
From: Boris Brezillon @ 2015-01-24 17:20 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Jason Cooper, Nicolas Ferre, Jean-Christophe Plagniol-Villard,
	Alexandre Belloni, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Rafael J. Wysocki,
	linux-arm-kernel, linux-kernel

Hi Thomas,

On Sat, 24 Jan 2015 17:37:48 +0100 (CET)
Thomas Gleixner <tglx@linutronix.de> wrote:

> On Fri, 23 Jan 2015, Boris Brezillon wrote:
> >  - change the compatible string to clearly show that this chip is purely
> >    virtual
> 
> So we probably want to do : s/dumb/virt/ for both DT and code to make
> it clear from the names as well.

I thought the dumb word was denoting the simplicity (stupidity ?) of
the irq demultiplexer, but indeed, I don't see how a virtual irq demuxer
could have enough information to do a better job (if there's an
interrupt cause register, then it's not a virtual/software demuxer
anymore).
So replacing dumb by virt or virtual makes sense here.


Best Regards,

Boris


-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2015-01-24 17:20 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-23 17:09 [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING Boris Brezillon
2015-01-23 17:09 ` [PATCH v3 1/5] genirq: Authorize chained handlers to remain disabled when initialized Boris Brezillon
2015-01-23 17:09 ` [PATCH v3 2/5] irqchip: add dumb demultiplexer implementation Boris Brezillon
2015-01-23 17:09 ` [PATCH v3 3/5] irqchip: Add DT binding doc for dumb demuxer chips Boris Brezillon
2015-01-23 17:09 ` [PATCH v3 4/5] ARM: at91/dt: select DUMB_IRQ_DEMUX for all at91 SoCs Boris Brezillon
2015-01-23 17:09 ` [PATCH v3 5/5] ARM: at91/dt: define a dumb irq demultiplexer chip connected on irq1 Boris Brezillon
2015-01-24 16:37 ` [PATCH v3 0/5] ARM: at91: fix irq_pm_install_action WARNING Thomas Gleixner
2015-01-24 17:20   ` Boris Brezillon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).