linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
@ 2015-08-24 19:04 Shenwei Wang
  2015-08-24 19:14 ` Thomas Gleixner
                   ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Shenwei Wang @ 2015-08-24 19:04 UTC (permalink / raw)
  To: shawn.guo, tglx, jason; +Cc: linux-arm-kernel, linux-kernel, b20788

IMX7D contains a new version of GPC IP block (GPCv2). It has two
major functions: power management and wakeup source management.
This patch adds a new irqchip driver to manage the interrupt wakeup
sources on IMX7D.
When the system is in WFI (wait for interrupt) mode, this GPC block
will be the first block on the platform to be activated and signaled.
Under normal wait mode during cpu idle, the system can be woke up
by any enabled interrupts. Under standby or suspend mode, the system
can only be woke up by the pre-defined wakeup sources.

Signed-off-by: Shenwei Wang <shenwei.wang@freescale.com>
Signed-off-by: Anson Huang <b20788@freescale.com>
---
Change log:
	Renamed the enabled_irqs to saved_irq_mask in struct gpcv2_irqchip_data
	Removed "BUG_ON()" in imx_gpcv2_irqchip_init to unify the error handling codes.

 drivers/irqchip/Kconfig         |   7 +
 drivers/irqchip/Makefile        |   1 +
 drivers/irqchip/irq-imx-gpcv2.c | 275 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 283 insertions(+)
 create mode 100644 drivers/irqchip/irq-imx-gpcv2.c

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 120d815..3fc0fac 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -177,3 +177,10 @@ config RENESAS_H8300H_INTC
 config RENESAS_H8S_INTC
         bool
 	select IRQ_DOMAIN
+
+config IMX_GPCV2
+	bool
+	select IRQ_DOMAIN
+	help
+	  Enables the wakeup IRQs for IMX platforms with GPCv2 block
+
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index b8d4e96..8eb5f60 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -52,3 +52,4 @@ obj-$(CONFIG_RENESAS_H8300H_INTC)	+= irq-renesas-h8300h.o
 obj-$(CONFIG_RENESAS_H8S_INTC)		+= irq-renesas-h8s.o
 obj-$(CONFIG_ARCH_SA1100)		+= irq-sa11x0.o
 obj-$(CONFIG_INGENIC_IRQ)		+= irq-ingenic.o
+obj-$(CONFIG_IMX_GPCV2)			+= irq-imx-gpcv2.o
diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c
new file mode 100644
index 0000000..4a97afa
--- /dev/null
+++ b/drivers/irqchip/irq-imx-gpcv2.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/irqchip.h>
+#include <linux/syscore_ops.h>
+
+#define IMR_NUM			4
+#define GPC_MAX_IRQS            (IMR_NUM * 32)
+
+#define GPC_IMR1_CORE0		0x30
+#define GPC_IMR1_CORE1		0x40
+
+struct gpcv2_irqchip_data {
+	struct raw_spinlock    rlock;
+	void __iomem       *gpc_base;
+	u32 wakeup_sources[IMR_NUM];
+	u32 saved_irq_mask[IMR_NUM];
+	u32 cpu2wakeup;
+};
+
+static struct gpcv2_irqchip_data *imx_gpcv2_instance;
+
+u32 imx_gpcv2_get_wakeup_source(u32 **sources)
+{
+	if (!imx_gpcv2_instance)
+		return 0;
+
+	if (sources)
+		*sources = imx_gpcv2_instance->wakeup_sources;
+
+	return IMR_NUM;
+}
+
+static int gpcv2_wakeup_source_save(void)
+{
+	struct gpcv2_irqchip_data *cd;
+	void __iomem *reg;
+	int i;
+
+	cd = imx_gpcv2_instance;
+	if (!cd)
+		return 0;
+
+	for (i = 0; i < IMR_NUM; i++) {
+		reg = cd->gpc_base + cd->cpu2wakeup + i * 4;
+		cd->saved_irq_mask[i] = readl_relaxed(reg);
+		writel_relaxed(cd->wakeup_sources[i], reg);
+	}
+
+	return 0;
+}
+
+static void gpcv2_wakeup_source_restore(void)
+{
+	struct gpcv2_irqchip_data *cd;
+	void __iomem *reg;
+	int i;
+
+	cd = imx_gpcv2_instance;
+	if (!cd)
+		return;
+
+	for (i = 0; i < IMR_NUM; i++) {
+		reg = cd->gpc_base + cd->cpu2wakeup + i * 4;
+		writel_relaxed(cd->saved_irq_mask[i], reg);
+	}
+}
+
+static struct syscore_ops imx_gpcv2_syscore_ops = {
+	.suspend	= gpcv2_wakeup_source_save,
+	.resume		= gpcv2_wakeup_source_restore,
+};
+
+static int imx_gpcv2_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	struct gpcv2_irqchip_data *cd = d->chip_data;
+	unsigned int idx = d->hwirq / 32;
+	unsigned long flags;
+	void __iomem *reg;
+	u32 mask, val;
+
+	raw_spin_lock_irqsave(&cd->rlock, flags);
+	reg = cd->gpc_base + cd->cpu2wakeup + idx * 4;
+	mask = 1 << d->hwirq % 32;
+	val = cd->wakeup_sources[idx];
+
+	cd->wakeup_sources[idx] = on ? (val & ~mask) : (val | mask);
+	raw_spin_unlock_irqrestore(&cd->rlock, flags);
+
+	/*
+	 * Do *not* call into the parent, as the GIC doesn't have any
+	 * wake-up facility...
+	 */
+
+	return 0;
+}
+
+static void imx_gpcv2_irq_unmask(struct irq_data *d)
+{
+	struct gpcv2_irqchip_data *cd = d->chip_data;
+	void __iomem *reg;
+	u32 val;
+
+	raw_spin_lock(&cd->rlock);
+	reg = cd->gpc_base + cd->cpu2wakeup + d->hwirq / 32 * 4;
+	val = readl_relaxed(reg);
+	val &= ~(1 << d->hwirq % 32);
+	writel_relaxed(val, reg);
+	raw_spin_unlock(&cd->rlock);
+
+	irq_chip_unmask_parent(d);
+}
+
+static void imx_gpcv2_irq_mask(struct irq_data *d)
+{
+	struct gpcv2_irqchip_data *cd = d->chip_data;
+	void __iomem *reg;
+	u32 val;
+
+	raw_spin_lock(&cd->rlock);
+	reg = cd->gpc_base + cd->cpu2wakeup + d->hwirq / 32 * 4;
+	val = readl_relaxed(reg);
+	val |= 1 << (d->hwirq % 32);
+	writel_relaxed(val, reg);
+	raw_spin_unlock(&cd->rlock);
+
+	irq_chip_mask_parent(d);
+}
+
+static struct irq_chip gpcv2_irqchip_data_chip = {
+	.name			= "GPCv2",
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_mask		= imx_gpcv2_irq_mask,
+	.irq_unmask		= imx_gpcv2_irq_unmask,
+	.irq_set_wake		= imx_gpcv2_irq_set_wake,
+	.irq_retrigger		= irq_chip_retrigger_hierarchy,
+#ifdef CONFIG_SMP
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+#endif
+};
+
+static int imx_gpcv2_domain_xlate(struct irq_domain *domain,
+				struct device_node *controller,
+				const u32 *intspec,
+				unsigned int intsize,
+				unsigned long *out_hwirq,
+				unsigned int *out_type)
+{
+	/* Shouldn't happen, really... */
+	if (domain->of_node != controller)
+		return -EINVAL;
+
+	/* Not GIC compliant */
+	if (intsize != 3)
+		return -EINVAL;
+
+	/* No PPI should point to this domain */
+	if (intspec[0] != 0)
+		return -EINVAL;
+
+	*out_hwirq = intspec[1];
+	*out_type = intspec[2];
+	return 0;
+}
+
+static int imx_gpcv2_domain_alloc(struct irq_domain *domain,
+				  unsigned int irq, unsigned int nr_irqs,
+				  void *data)
+{
+	struct of_phandle_args *args = data;
+	struct of_phandle_args parent_args;
+	irq_hw_number_t hwirq;
+	int i;
+
+	/* Not GIC compliant */
+	if (args->args_count != 3)
+		return -EINVAL;
+
+	/* No PPI should point to this domain */
+	if (args->args[0] != 0)
+		return -EINVAL;
+
+	/* Can't deal with this */
+	hwirq = args->args[1];
+	if (hwirq >= GPC_MAX_IRQS)
+		return -EINVAL;
+
+	for (i = 0; i < nr_irqs; i++) {
+		irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i,
+				&gpcv2_irqchip_data_chip, domain->host_data);
+	}
+
+	parent_args = *args;
+	parent_args.np = domain->parent->of_node;
+	return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, &parent_args);
+}
+
+static struct irq_domain_ops gpcv2_irqchip_data_domain_ops = {
+	.xlate	= imx_gpcv2_domain_xlate,
+	.alloc	= imx_gpcv2_domain_alloc,
+	.free	= irq_domain_free_irqs_common,
+};
+
+static int __init imx_gpcv2_irqchip_init(struct device_node *node,
+			       struct device_node *parent)
+{
+	struct irq_domain *parent_domain, *domain;
+	struct gpcv2_irqchip_data *cd;
+	int i;
+
+	if (!parent) {
+		pr_err("%s: no parent, giving up\n", node->full_name);
+		return -ENODEV;
+	}
+
+	parent_domain = irq_find_host(parent);
+	if (!parent_domain) {
+		pr_err("%s: unable to get parent domain\n", node->full_name);
+		return -ENXIO;
+	}
+
+	cd = kzalloc(sizeof(struct gpcv2_irqchip_data), GFP_KERNEL);
+	if (!cd) {
+		pr_err("kzalloc failed!\n");
+		return -ENOMEM;
+	}
+
+	cd->gpc_base = of_iomap(node, 0);
+	if (!cd->gpc_base) {
+		pr_err("fsl-gpcv2: unable to map gpc registers\n");
+		kfree(cd);
+		return -ENOMEM;
+	}
+
+	domain = irq_domain_add_hierarchy(parent_domain, 0, GPC_MAX_IRQS,
+				node, &gpcv2_irqchip_data_domain_ops, cd);
+	if (!domain) {
+		iounmap(cd->gpc_base);
+		kfree(cd);
+		return -ENOMEM;
+	}
+	irq_set_default_host(domain);
+
+	/* Initially mask all interrupts */
+	for (i = 0; i < IMR_NUM; i++) {
+		writel_relaxed(~0, cd->gpc_base + GPC_IMR1_CORE0 + i * 4);
+		writel_relaxed(~0, cd->gpc_base + GPC_IMR1_CORE1 + i * 4);
+		cd->wakeup_sources[i] = ~0;
+	}
+
+	/* Let CORE0 as the default CPU to wake up by GPC */
+	cd->cpu2wakeup = GPC_IMR1_CORE0;
+
+	/*
+	 * Due to hardware design failure, need to make sure GPR
+	 * interrupt(#32) is unmasked during RUN mode to avoid entering
+	 * DSM by mistake.
+	 */
+	writel_relaxed(~0x1, cd->gpc_base + cd->cpu2wakeup);
+
+	imx_gpcv2_instance = cd;
+	register_syscore_ops(&imx_gpcv2_syscore_ops);
+
+	return 0;
+}
+
+IRQCHIP_DECLARE(imx_gpcv2, "fsl,imx7d-gpc", imx_gpcv2_irqchip_init);
--
2.5.0.rc2



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

* Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-24 19:04 [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources Shenwei Wang
@ 2015-08-24 19:14 ` Thomas Gleixner
  2015-08-24 19:20   ` Shenwei Wang
  2015-08-24 19:51 ` [tip:irq/core] irqchip/imx-gpcv2: " tip-bot for Shenwei Wang
  2015-08-25  9:24 ` [PATCH v9 1/1] irqchip: imx-gpcv2: " Sudeep Holla
  2 siblings, 1 reply; 22+ messages in thread
From: Thomas Gleixner @ 2015-08-24 19:14 UTC (permalink / raw)
  To: Shenwei Wang; +Cc: shawn.guo, jason, linux-arm-kernel, linux-kernel, b20788

On Mon, 24 Aug 2015, Shenwei Wang wrote:
> 
> Signed-off-by: Shenwei Wang <shenwei.wang@freescale.com>
> Signed-off-by: Anson Huang <b20788@freescale.com>

Ok, last question. How is Anson related to this? He did not convey
your patch and in the first posted versions his SOB was never there.

Thanks,

	tglx

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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-24 19:14 ` Thomas Gleixner
@ 2015-08-24 19:20   ` Shenwei Wang
  2015-08-24 19:30     ` Thomas Gleixner
  0 siblings, 1 reply; 22+ messages in thread
From: Shenwei Wang @ 2015-08-24 19:20 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: shawn.guo, jason, linux-arm-kernel, linux-kernel, Huang Anson

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="gb2312", Size: 1063 bytes --]


> -----Original Message-----
> From: Thomas Gleixner [mailto:tglx@linutronix.de]
> Sent: 2015Äê8ÔÂ24ÈÕ 14:15
> To: Wang Shenwei-B38339
> Cc: shawn.guo@linaro.org; jason@lakedaemon.net;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; Huang
> Yongcai-B20788
> Subject: Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup
> sources
> 
> On Mon, 24 Aug 2015, Shenwei Wang wrote:
> >
> > Signed-off-by: Shenwei Wang <shenwei.wang@freescale.com>
> > Signed-off-by: Anson Huang <b20788@freescale.com>
> 
> Ok, last question. How is Anson related to this? He did not convey your patch and
> in the first posted versions his SOB was never there.

This patch was based on his internal version of GPCv2 driver. I reused some of his
implementation and ported it to latest linux kernel. Adding his name here to give 
the credits to him.

Thanks,
Shenwei
 

> Thanks,
> 
> 	tglx
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-24 19:20   ` Shenwei Wang
@ 2015-08-24 19:30     ` Thomas Gleixner
  2015-08-24 19:32       ` Shenwei Wang
  0 siblings, 1 reply; 22+ messages in thread
From: Thomas Gleixner @ 2015-08-24 19:30 UTC (permalink / raw)
  To: Shenwei Wang
  Cc: shawn.guo, jason, linux-arm-kernel, linux-kernel, Huang Anson

On Mon, 24 Aug 2015, Shenwei Wang wrote:
> > Ok, last question. How is Anson related to this? He did not convey your patch and
> > in the first posted versions his SOB was never there.
> 
> This patch was based on his internal version of GPCv2 driver. I reused some of his
> implementation and ported it to latest linux kernel. Adding his name here to give 
> the credits to him.

So the proper way to express this is:

Based-on-a-patch-by: Anson
Signed-off-by: You

The way you did it suggests that you wrote it and Anson conveyed it,
which is not the case.

I'll change it that way then.

Thanks,

	tglx


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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-24 19:30     ` Thomas Gleixner
@ 2015-08-24 19:32       ` Shenwei Wang
  0 siblings, 0 replies; 22+ messages in thread
From: Shenwei Wang @ 2015-08-24 19:32 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: shawn.guo, jason, linux-arm-kernel, linux-kernel, Huang Anson

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="gb2312", Size: 1205 bytes --]

Thank you, Thomas!

Shenwei

> -----Original Message-----
> From: Thomas Gleixner [mailto:tglx@linutronix.de]
> Sent: 2015Äê8ÔÂ24ÈÕ 14:30
> To: Wang Shenwei-B38339
> Cc: shawn.guo@linaro.org; jason@lakedaemon.net;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; Huang
> Yongcai-B20788
> Subject: RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup
> sources
> 
> On Mon, 24 Aug 2015, Shenwei Wang wrote:
> > > Ok, last question. How is Anson related to this? He did not convey
> > > your patch and in the first posted versions his SOB was never there.
> >
> > This patch was based on his internal version of GPCv2 driver. I reused
> > some of his implementation and ported it to latest linux kernel.
> > Adding his name here to give the credits to him.
> 
> So the proper way to express this is:
> 
> Based-on-a-patch-by: Anson
> Signed-off-by: You
> 
> The way you did it suggests that you wrote it and Anson conveyed it, which is not
> the case.
> 
> I'll change it that way then.
> 
> Thanks,
> 
> 	tglx

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* [tip:irq/core] irqchip/imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-24 19:04 [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources Shenwei Wang
  2015-08-24 19:14 ` Thomas Gleixner
@ 2015-08-24 19:51 ` tip-bot for Shenwei Wang
  2015-08-25  9:24 ` [PATCH v9 1/1] irqchip: imx-gpcv2: " Sudeep Holla
  2 siblings, 0 replies; 22+ messages in thread
From: tip-bot for Shenwei Wang @ 2015-08-24 19:51 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-arm-kernel, shawn.guo, b20788, linux-kernel, jason,
	shenwei.wang, tglx, mingo, hpa

Commit-ID:  e324c4dc4a5991d5b1171f434884a4026345e4b4
Gitweb:     http://git.kernel.org/tip/e324c4dc4a5991d5b1171f434884a4026345e4b4
Author:     Shenwei Wang <shenwei.wang@freescale.com>
AuthorDate: Mon, 24 Aug 2015 14:04:15 -0500
Committer:  Thomas Gleixner <tglx@linutronix.de>
CommitDate: Mon, 24 Aug 2015 21:49:34 +0200

irqchip/imx-gpcv2: IMX GPCv2 driver for wakeup sources

IMX7D contains a new version of GPC IP block (GPCv2). It has two major
functions: power management and wakeup source management.

When the system is in WFI (wait for interrupt) mode, the GPC block
will be the first block on the platform to be activated and signaled.

In normal wait mode during cpu idle, the system can be woken up by any
enabled interrupts. In standby or suspend mode, the system can only be
wokem up by the pre-defined wakeup sources.

Based-on-patch-by: Anson Huang <b20788@freescale.com>
Signed-off-by: Shenwei Wang <shenwei.wang@freescale.com>
Cc: <linux-arm-kernel@lists.infradead.org>
Cc: <shawn.guo@linaro.org>
Cc: <jason@lakedaemon.net>
Link: http://lkml.kernel.org/r/1440443055-7291-1-git-send-email-shenwei.wang@freescale.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 drivers/irqchip/Kconfig         |   6 +
 drivers/irqchip/Makefile        |   1 +
 drivers/irqchip/irq-imx-gpcv2.c | 278 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 285 insertions(+)

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 5b85371..27b52c8 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -181,3 +181,9 @@ config RENESAS_H8300H_INTC
 config RENESAS_H8S_INTC
         bool
 	select IRQ_DOMAIN
+
+config IMX_GPCV2
+	bool
+	select IRQ_DOMAIN
+	help
+	  Enables the wakeup IRQs for IMX platforms with GPCv2 block
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index e5e0069..bb3048f 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -54,3 +54,4 @@ obj-$(CONFIG_RENESAS_H8300H_INTC)	+= irq-renesas-h8300h.o
 obj-$(CONFIG_RENESAS_H8S_INTC)		+= irq-renesas-h8s.o
 obj-$(CONFIG_ARCH_SA1100)		+= irq-sa11x0.o
 obj-$(CONFIG_INGENIC_IRQ)		+= irq-ingenic.o
+obj-$(CONFIG_IMX_GPCV2)			+= irq-imx-gpcv2.o
diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c
new file mode 100644
index 0000000..e48d330
--- /dev/null
+++ b/drivers/irqchip/irq-imx-gpcv2.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/irqchip.h>
+#include <linux/syscore_ops.h>
+
+#define IMR_NUM			4
+#define GPC_MAX_IRQS            (IMR_NUM * 32)
+
+#define GPC_IMR1_CORE0		0x30
+#define GPC_IMR1_CORE1		0x40
+
+struct gpcv2_irqchip_data {
+	struct raw_spinlock	rlock;
+	void __iomem		*gpc_base;
+	u32			wakeup_sources[IMR_NUM];
+	u32			saved_irq_mask[IMR_NUM];
+	u32			cpu2wakeup;
+};
+
+static struct gpcv2_irqchip_data *imx_gpcv2_instance;
+
+/*
+ * Interface for the low level wakeup code.
+ */
+u32 imx_gpcv2_get_wakeup_source(u32 **sources)
+{
+	if (!imx_gpcv2_instance)
+		return 0;
+
+	if (sources)
+		*sources = imx_gpcv2_instance->wakeup_sources;
+
+	return IMR_NUM;
+}
+
+static int gpcv2_wakeup_source_save(void)
+{
+	struct gpcv2_irqchip_data *cd;
+	void __iomem *reg;
+	int i;
+
+	cd = imx_gpcv2_instance;
+	if (!cd)
+		return 0;
+
+	for (i = 0; i < IMR_NUM; i++) {
+		reg = cd->gpc_base + cd->cpu2wakeup + i * 4;
+		cd->saved_irq_mask[i] = readl_relaxed(reg);
+		writel_relaxed(cd->wakeup_sources[i], reg);
+	}
+
+	return 0;
+}
+
+static void gpcv2_wakeup_source_restore(void)
+{
+	struct gpcv2_irqchip_data *cd;
+	void __iomem *reg;
+	int i;
+
+	cd = imx_gpcv2_instance;
+	if (!cd)
+		return;
+
+	for (i = 0; i < IMR_NUM; i++) {
+		reg = cd->gpc_base + cd->cpu2wakeup + i * 4;
+		writel_relaxed(cd->saved_irq_mask[i], reg);
+	}
+}
+
+static struct syscore_ops imx_gpcv2_syscore_ops = {
+	.suspend	= gpcv2_wakeup_source_save,
+	.resume		= gpcv2_wakeup_source_restore,
+};
+
+static int imx_gpcv2_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	struct gpcv2_irqchip_data *cd = d->chip_data;
+	unsigned int idx = d->hwirq / 32;
+	unsigned long flags;
+	void __iomem *reg;
+	u32 mask, val;
+
+	raw_spin_lock_irqsave(&cd->rlock, flags);
+	reg = cd->gpc_base + cd->cpu2wakeup + idx * 4;
+	mask = 1 << d->hwirq % 32;
+	val = cd->wakeup_sources[idx];
+
+	cd->wakeup_sources[idx] = on ? (val & ~mask) : (val | mask);
+	raw_spin_unlock_irqrestore(&cd->rlock, flags);
+
+	/*
+	 * Do *not* call into the parent, as the GIC doesn't have any
+	 * wake-up facility...
+	 */
+
+	return 0;
+}
+
+static void imx_gpcv2_irq_unmask(struct irq_data *d)
+{
+	struct gpcv2_irqchip_data *cd = d->chip_data;
+	void __iomem *reg;
+	u32 val;
+
+	raw_spin_lock(&cd->rlock);
+	reg = cd->gpc_base + cd->cpu2wakeup + d->hwirq / 32 * 4;
+	val = readl_relaxed(reg);
+	val &= ~(1 << d->hwirq % 32);
+	writel_relaxed(val, reg);
+	raw_spin_unlock(&cd->rlock);
+
+	irq_chip_unmask_parent(d);
+}
+
+static void imx_gpcv2_irq_mask(struct irq_data *d)
+{
+	struct gpcv2_irqchip_data *cd = d->chip_data;
+	void __iomem *reg;
+	u32 val;
+
+	raw_spin_lock(&cd->rlock);
+	reg = cd->gpc_base + cd->cpu2wakeup + d->hwirq / 32 * 4;
+	val = readl_relaxed(reg);
+	val |= 1 << (d->hwirq % 32);
+	writel_relaxed(val, reg);
+	raw_spin_unlock(&cd->rlock);
+
+	irq_chip_mask_parent(d);
+}
+
+static struct irq_chip gpcv2_irqchip_data_chip = {
+	.name			= "GPCv2",
+	.irq_eoi		= irq_chip_eoi_parent,
+	.irq_mask		= imx_gpcv2_irq_mask,
+	.irq_unmask		= imx_gpcv2_irq_unmask,
+	.irq_set_wake		= imx_gpcv2_irq_set_wake,
+	.irq_retrigger		= irq_chip_retrigger_hierarchy,
+#ifdef CONFIG_SMP
+	.irq_set_affinity	= irq_chip_set_affinity_parent,
+#endif
+};
+
+static int imx_gpcv2_domain_xlate(struct irq_domain *domain,
+				struct device_node *controller,
+				const u32 *intspec,
+				unsigned int intsize,
+				unsigned long *out_hwirq,
+				unsigned int *out_type)
+{
+	/* Shouldn't happen, really... */
+	if (domain->of_node != controller)
+		return -EINVAL;
+
+	/* Not GIC compliant */
+	if (intsize != 3)
+		return -EINVAL;
+
+	/* No PPI should point to this domain */
+	if (intspec[0] != 0)
+		return -EINVAL;
+
+	*out_hwirq = intspec[1];
+	*out_type = intspec[2];
+	return 0;
+}
+
+static int imx_gpcv2_domain_alloc(struct irq_domain *domain,
+				  unsigned int irq, unsigned int nr_irqs,
+				  void *data)
+{
+	struct of_phandle_args *args = data;
+	struct of_phandle_args parent_args;
+	irq_hw_number_t hwirq;
+	int i;
+
+	/* Not GIC compliant */
+	if (args->args_count != 3)
+		return -EINVAL;
+
+	/* No PPI should point to this domain */
+	if (args->args[0] != 0)
+		return -EINVAL;
+
+	/* Can't deal with this */
+	hwirq = args->args[1];
+	if (hwirq >= GPC_MAX_IRQS)
+		return -EINVAL;
+
+	for (i = 0; i < nr_irqs; i++) {
+		irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i,
+				&gpcv2_irqchip_data_chip, domain->host_data);
+	}
+
+	parent_args = *args;
+	parent_args.np = domain->parent->of_node;
+	return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, &parent_args);
+}
+
+static struct irq_domain_ops gpcv2_irqchip_data_domain_ops = {
+	.xlate	= imx_gpcv2_domain_xlate,
+	.alloc	= imx_gpcv2_domain_alloc,
+	.free	= irq_domain_free_irqs_common,
+};
+
+static int __init imx_gpcv2_irqchip_init(struct device_node *node,
+			       struct device_node *parent)
+{
+	struct irq_domain *parent_domain, *domain;
+	struct gpcv2_irqchip_data *cd;
+	int i;
+
+	if (!parent) {
+		pr_err("%s: no parent, giving up\n", node->full_name);
+		return -ENODEV;
+	}
+
+	parent_domain = irq_find_host(parent);
+	if (!parent_domain) {
+		pr_err("%s: unable to get parent domain\n", node->full_name);
+		return -ENXIO;
+	}
+
+	cd = kzalloc(sizeof(struct gpcv2_irqchip_data), GFP_KERNEL);
+	if (!cd) {
+		pr_err("kzalloc failed!\n");
+		return -ENOMEM;
+	}
+
+	cd->gpc_base = of_iomap(node, 0);
+	if (!cd->gpc_base) {
+		pr_err("fsl-gpcv2: unable to map gpc registers\n");
+		kfree(cd);
+		return -ENOMEM;
+	}
+
+	domain = irq_domain_add_hierarchy(parent_domain, 0, GPC_MAX_IRQS,
+				node, &gpcv2_irqchip_data_domain_ops, cd);
+	if (!domain) {
+		iounmap(cd->gpc_base);
+		kfree(cd);
+		return -ENOMEM;
+	}
+	irq_set_default_host(domain);
+
+	/* Initially mask all interrupts */
+	for (i = 0; i < IMR_NUM; i++) {
+		writel_relaxed(~0, cd->gpc_base + GPC_IMR1_CORE0 + i * 4);
+		writel_relaxed(~0, cd->gpc_base + GPC_IMR1_CORE1 + i * 4);
+		cd->wakeup_sources[i] = ~0;
+	}
+
+	/* Let CORE0 as the default CPU to wake up by GPC */
+	cd->cpu2wakeup = GPC_IMR1_CORE0;
+
+	/*
+	 * Due to hardware design failure, need to make sure GPR
+	 * interrupt(#32) is unmasked during RUN mode to avoid entering
+	 * DSM by mistake.
+	 */
+	writel_relaxed(~0x1, cd->gpc_base + cd->cpu2wakeup);
+
+	imx_gpcv2_instance = cd;
+	register_syscore_ops(&imx_gpcv2_syscore_ops);
+
+	return 0;
+}
+
+IRQCHIP_DECLARE(imx_gpcv2, "fsl,imx7d-gpc", imx_gpcv2_irqchip_init);

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

* Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-24 19:04 [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources Shenwei Wang
  2015-08-24 19:14 ` Thomas Gleixner
  2015-08-24 19:51 ` [tip:irq/core] irqchip/imx-gpcv2: " tip-bot for Shenwei Wang
@ 2015-08-25  9:24 ` Sudeep Holla
  2015-08-25 13:38   ` Shenwei Wang
  2 siblings, 1 reply; 22+ messages in thread
From: Sudeep Holla @ 2015-08-25  9:24 UTC (permalink / raw)
  To: Shenwei Wang
  Cc: shawn.guo, tglx, jason, Sudeep Holla, b20788, linux-kernel,
	linux-arm-kernel



On 24/08/15 20:04, Shenwei Wang wrote:
> IMX7D contains a new version of GPC IP block (GPCv2). It has two
> major functions: power management and wakeup source management.
> This patch adds a new irqchip driver to manage the interrupt wakeup
> sources on IMX7D.

Interesting, you mention that this IP block has mainly power management
and it itself requires save/restore. Is it not in always on domain ?

> When the system is in WFI (wait for interrupt) mode, this GPC block
> will be the first block on the platform to be activated and signaled.
> Under normal wait mode during cpu idle, the system can be woke up
> by any enabled interrupts. Under standby or suspend mode, the system
> can only be woke up by the pre-defined wakeup sources.
>
> Signed-off-by: Shenwei Wang <shenwei.wang@freescale.com>
> Signed-off-by: Anson Huang <b20788@freescale.com>
> ---
> Change log:
> 	Renamed the enabled_irqs to saved_irq_mask in struct gpcv2_irqchip_data
> 	Removed "BUG_ON()" in imx_gpcv2_irqchip_init to unify the error handling codes.
>
>   drivers/irqchip/Kconfig         |   7 +
>   drivers/irqchip/Makefile        |   1 +
>   drivers/irqchip/irq-imx-gpcv2.c | 275 ++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 283 insertions(+)
>   create mode 100644 drivers/irqchip/irq-imx-gpcv2.c
>
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 120d815..3fc0fac 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -177,3 +177,10 @@ config RENESAS_H8300H_INTC
>   config RENESAS_H8S_INTC
>           bool
>   	select IRQ_DOMAIN
> +
> +config IMX_GPCV2
> +	bool
> +	select IRQ_DOMAIN
> +	help
> +	  Enables the wakeup IRQs for IMX platforms with GPCv2 block
> +
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index b8d4e96..8eb5f60 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -52,3 +52,4 @@ obj-$(CONFIG_RENESAS_H8300H_INTC)	+= irq-renesas-h8300h.o
>   obj-$(CONFIG_RENESAS_H8S_INTC)		+= irq-renesas-h8s.o
>   obj-$(CONFIG_ARCH_SA1100)		+= irq-sa11x0.o
>   obj-$(CONFIG_INGENIC_IRQ)		+= irq-ingenic.o
> +obj-$(CONFIG_IMX_GPCV2)			+= irq-imx-gpcv2.o
> diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c
> new file mode 100644
> index 0000000..4a97afa
> --- /dev/null
> +++ b/drivers/irqchip/irq-imx-gpcv2.c
> @@ -0,0 +1,275 @@
> +/*
> + * Copyright (C) 2015 Freescale Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/slab.h>
> +#include <linux/irqchip.h>
> +#include <linux/syscore_ops.h>
> +
> +#define IMR_NUM			4
> +#define GPC_MAX_IRQS            (IMR_NUM * 32)
> +
> +#define GPC_IMR1_CORE0		0x30
> +#define GPC_IMR1_CORE1		0x40
> +
> +struct gpcv2_irqchip_data {
> +	struct raw_spinlock    rlock;
> +	void __iomem       *gpc_base;
> +	u32 wakeup_sources[IMR_NUM];
> +	u32 saved_irq_mask[IMR_NUM];
> +	u32 cpu2wakeup;
> +};
> +
> +static struct gpcv2_irqchip_data *imx_gpcv2_instance;
> +
> +u32 imx_gpcv2_get_wakeup_source(u32 **sources)
> +{
> +	if (!imx_gpcv2_instance)
> +		return 0;
> +
> +	if (sources)
> +		*sources = imx_gpcv2_instance->wakeup_sources;
> +
> +	return IMR_NUM;
> +}
> +
> +static int gpcv2_wakeup_source_save(void)
> +{
> +	struct gpcv2_irqchip_data *cd;
> +	void __iomem *reg;
> +	int i;
> +
> +	cd = imx_gpcv2_instance;
> +	if (!cd)
> +		return 0;
> +
> +	for (i = 0; i < IMR_NUM; i++) {
> +		reg = cd->gpc_base + cd->cpu2wakeup + i * 4;
> +		cd->saved_irq_mask[i] = readl_relaxed(reg);
> +		writel_relaxed(cd->wakeup_sources[i], reg);
> +	}
> +
> +	return 0;
> +}
> +
> +static void gpcv2_wakeup_source_restore(void)
> +{
> +	struct gpcv2_irqchip_data *cd;
> +	void __iomem *reg;
> +	int i;
> +
> +	cd = imx_gpcv2_instance;
> +	if (!cd)
> +		return;
> +
> +	for (i = 0; i < IMR_NUM; i++) {
> +		reg = cd->gpc_base + cd->cpu2wakeup + i * 4;
> +		writel_relaxed(cd->saved_irq_mask[i], reg);

Instead of saving all the non-wakeup sources, can't you use raw
save/restore of these registers and mask all the non-wakeup sources
by setting MASK_ON_SUSPEND ?

Also your interrupt controller seems like has no special way to
configure wakeups, you are just leaving them enabled. i.e. I see
cpu2wakeup used for both {un,}masking and wakeup enable. So you can just
use IRQCHIP_SKIP_SET_WAKE. Correct me if my understanding is wrong.

Regards,
Sudeep

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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25  9:24 ` [PATCH v9 1/1] irqchip: imx-gpcv2: " Sudeep Holla
@ 2015-08-25 13:38   ` Shenwei Wang
  2015-08-25 13:54     ` Sudeep Holla
  0 siblings, 1 reply; 22+ messages in thread
From: Shenwei Wang @ 2015-08-25 13:38 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: shawn.guo, tglx, jason, Huang Anson, linux-kernel, linux-arm-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="gb2312", Size: 2343 bytes --]



> -----Original Message-----
> From: Sudeep Holla [mailto:sudeep.holla@arm.com]
> Sent: 2015Äê8ÔÂ25ÈÕ 4:25
> To: Wang Shenwei-B38339
> Cc: shawn.guo@linaro.org; tglx@linutronix.de; jason@lakedaemon.net; Sudeep
> Holla; Huang Yongcai-B20788; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup
> sources
> 
> 
> 
> On 24/08/15 20:04, Shenwei Wang wrote:
> > IMX7D contains a new version of GPC IP block (GPCv2). It has two major
> > functions: power management and wakeup source management.
> > This patch adds a new irqchip driver to manage the interrupt wakeup
> > sources on IMX7D.
> 
> Interesting, you mention that this IP block has mainly power management and it
> itself requires save/restore. Is it not in always on domain ?

Yes, it is in always on domain.

> > When the system is in WFI (wait for interrupt) mode, this GPC block
> > will be the first block on the platform to be activated and signaled.
> > Under normal wait mode during cpu idle, the system can be woke up by
> > +static void gpcv2_wakeup_source_restore(void) {
> > +	struct gpcv2_irqchip_data *cd;
> > +	void __iomem *reg;
> > +	int i;
> > +
> > +	cd = imx_gpcv2_instance;
> > +	if (!cd)
> > +		return;
> > +
> > +	for (i = 0; i < IMR_NUM; i++) {
> > +		reg = cd->gpc_base + cd->cpu2wakeup + i * 4;
> > +		writel_relaxed(cd->saved_irq_mask[i], reg);
> 
> Instead of saving all the non-wakeup sources, can't you use raw save/restore of
> these registers and mask all the non-wakeup sources by setting
> MASK_ON_SUSPEND ?

I can't catch what you mean. Can you show me an example?

> Also your interrupt controller seems like has no special way to configure wakeups,
> you are just leaving them enabled. i.e. I see cpu2wakeup used for both
> {un,}masking and wakeup enable. So you can just use IRQCHIP_SKIP_SET_WAKE.
> Correct me if my understanding is wrong.

In this driver, the Core0 is configured to be the default core to be woke up, not both. You can
configure it to Core1 by changing the cpu2wakeup value. I don't see any reason to
use IRQCHIP_SKIP_SET_WAKE flag.

Thanks,
Shenwei
 


> Regards,
> Sudeep
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 13:38   ` Shenwei Wang
@ 2015-08-25 13:54     ` Sudeep Holla
  2015-08-25 14:14       ` Shenwei Wang
  0 siblings, 1 reply; 22+ messages in thread
From: Sudeep Holla @ 2015-08-25 13:54 UTC (permalink / raw)
  To: Shenwei Wang
  Cc: Sudeep Holla, shawn.guo, tglx, jason, Huang Anson, linux-kernel,
	linux-arm-kernel



On 25/08/15 14:38, Shenwei Wang wrote:
>
>
>> -----Original Message-----
>> From: Sudeep Holla [mailto:sudeep.holla@arm.com]
>> Sent: 2015年8月25日 4:25
>> To: Wang Shenwei-B38339
>> Cc: shawn.guo@linaro.org; tglx@linutronix.de; jason@lakedaemon.net; Sudeep
>> Holla; Huang Yongcai-B20788; linux-kernel@vger.kernel.org;
>> linux-arm-kernel@lists.infradead.org
>> Subject: Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup
>> sources
>>
>>
>>
>> On 24/08/15 20:04, Shenwei Wang wrote:
>>> IMX7D contains a new version of GPC IP block (GPCv2). It has two major
>>> functions: power management and wakeup source management.
>>> This patch adds a new irqchip driver to manage the interrupt wakeup
>>> sources on IMX7D.
>>
>> Interesting, you mention that this IP block has mainly power management and it
>> itself requires save/restore. Is it not in always on domain ?
>
> Yes, it is in always on domain.
>

Hmm, then why do you need to save and restore the mask ?

>>> When the system is in WFI (wait for interrupt) mode, this GPC block
>>> will be the first block on the platform to be activated and signaled.
>>> Under normal wait mode during cpu idle, the system can be woke up by
>>> +static void gpcv2_wakeup_source_restore(void) {
>>> +	struct gpcv2_irqchip_data *cd;
>>> +	void __iomem *reg;
>>> +	int i;
>>> +
>>> +	cd = imx_gpcv2_instance;
>>> +	if (!cd)
>>> +		return;
>>> +
>>> +	for (i = 0; i < IMR_NUM; i++) {
>>> +		reg = cd->gpc_base + cd->cpu2wakeup + i * 4;
>>> +		writel_relaxed(cd->saved_irq_mask[i], reg);
>>
>> Instead of saving all the non-wakeup sources, can't you use raw save/restore of
>> these registers and mask all the non-wakeup sources by setting
>> MASK_ON_SUSPEND ?
>
> I can't catch what you mean. Can you show me an example?
>

What I meant is instead of you tracking all the enabled irqs(both wakeup
and non-wakeup) in saved_irq_mask, just set MASK_ON_SUSPEND flag
where all the non-wakeup interrupts are masked on suspend and unmasked
on resume by the irq core. You can then just save and restore the wakeup
irq mask, but as I asked above do you have to do that as you are saying
it's in always on domain ?

>> Also your interrupt controller seems like has no special way to configure wakeups,
>> you are just leaving them enabled. i.e. I see cpu2wakeup used for both
>> {un,}masking and wakeup enable. So you can just use IRQCHIP_SKIP_SET_WAKE.
>> Correct me if my understanding is wrong.
>
> In this driver, the Core0 is configured to be the default core to be woke up, not both. You can
> configure it to Core1 by changing the cpu2wakeup value. I don't see any reason to
> use IRQCHIP_SKIP_SET_WAKE flag.
>

I don't see this driver doing anything extra apart from keeping the
wakeup irqs enabled. i.e. You use the same cpu*wake register to
mask/unmask the interrupt as well as set the wakeup source. Since
the wakeup interrupt will be enabled by the driver, you just need to
mark it as wake-up source and nothing extra in the controller right ?
If so, you need to set IRQCHIP_SKIP_SET_WAKE as you are just leaving
that irq enabled and not doing any extra configuration to enable it as
wakeup source. Please correct if that wrong, but from the code that's
what I could infer.

Regards,
Sudeep

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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 13:54     ` Sudeep Holla
@ 2015-08-25 14:14       ` Shenwei Wang
  2015-08-25 14:45         ` Sudeep Holla
  0 siblings, 1 reply; 22+ messages in thread
From: Shenwei Wang @ 2015-08-25 14:14 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: shawn.guo, tglx, jason, Huang Anson, linux-kernel, linux-arm-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 3581 bytes --]



> -----Original Message-----
> From: Sudeep Holla [mailto:sudeep.holla@arm.com]
> >>> IMX7D contains a new version of GPC IP block (GPCv2). It has two
> >>> major
> >>> functions: power management and wakeup source management.
> >>> This patch adds a new irqchip driver to manage the interrupt wakeup
> >>> sources on IMX7D.
> >>
> >> Interesting, you mention that this IP block has mainly power
> >> management and it itself requires save/restore. Is it not in always on
> domain ?
> >
> > Yes, it is in always on domain.
> >
> 
> Hmm, then why do you need to save and restore the mask ?

The save/restore is used to handle the two different low power states: one is
WFI in cpu idle, and the other case is suspend. This has nothing to do with this
IP block itself.

> >>> When the system is in WFI (wait for interrupt) mode, this GPC block
> >>> will be the first block on the platform to be activated and signaled.
> >>> Under normal wait mode during cpu idle, the system can be woke up by
> >>> +static void gpcv2_wakeup_source_restore(void) {
> >>> +	struct gpcv2_irqchip_data *cd;
> >>> +	void __iomem *reg;
> >>> +	int i;
> >>> +
> >>> +	cd = imx_gpcv2_instance;
> >>> +	if (!cd)
> >>> +		return;
> >>> +
> >>> +	for (i = 0; i < IMR_NUM; i++) {
> >>> +		reg = cd->gpc_base + cd->cpu2wakeup + i * 4;
> >>> +		writel_relaxed(cd->saved_irq_mask[i], reg);
> >>
> >> Instead of saving all the non-wakeup sources, can't you use raw
> >> save/restore of these registers and mask all the non-wakeup sources
> >> by setting MASK_ON_SUSPEND ?
> >
> > I can't catch what you mean. Can you show me an example?
> >
> 
> What I meant is instead of you tracking all the enabled irqs(both wakeup and
> non-wakeup) in saved_irq_mask, just set MASK_ON_SUSPEND flag where all the
> non-wakeup interrupts are masked on suspend and unmasked on resume by the
> irq core. You can then just save and restore the wakeup irq mask, but as I asked
> above do you have to do that as you are saying it's in always on domain ?
> 
> >> Also your interrupt controller seems like has no special way to
> >> configure wakeups, you are just leaving them enabled. i.e. I see
> >> cpu2wakeup used for both {un,}masking and wakeup enable. So you can just
> use IRQCHIP_SKIP_SET_WAKE.
> >> Correct me if my understanding is wrong.
> >
> > In this driver, the Core0 is configured to be the default core to be
> > woke up, not both. You can configure it to Core1 by changing the
> > cpu2wakeup value. I don't see any reason to use IRQCHIP_SKIP_SET_WAKE flag.
> >
> 
> I don't see this driver doing anything extra apart from keeping the wakeup irqs
> enabled. i.e. You use the same cpu*wake register to mask/unmask the interrupt
> as well as set the wakeup source. Since the wakeup interrupt will be enabled by
> the driver, you just need to mark it as wake-up source and nothing extra in the
> controller right ?
> If so, you need to set IRQCHIP_SKIP_SET_WAKE as you are just leaving that irq
> enabled and not doing any extra configuration to enable it as wakeup source.
> Please correct if that wrong, but from the code that's what I could infer.

There is no special for this driver. We just use the IRQCHIP driver framework to
manage the wakeup sources. Why did you propose to set IRQCHIP_SKIP_SET_WAKE
flag here? If you don't need the wakeup feature, you should just not enable this
driver in the configuration.

Thanks,
Shenwei

> Regards,
> Sudeep
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 14:14       ` Shenwei Wang
@ 2015-08-25 14:45         ` Sudeep Holla
  2015-08-25 14:54           ` Shenwei Wang
  0 siblings, 1 reply; 22+ messages in thread
From: Sudeep Holla @ 2015-08-25 14:45 UTC (permalink / raw)
  To: Shenwei Wang
  Cc: Sudeep Holla, shawn.guo, tglx, jason, Huang Anson, linux-kernel,
	linux-arm-kernel



On 25/08/15 15:14, Shenwei Wang wrote:
>
>
>> -----Original Message-----
>> From: Sudeep Holla [mailto:sudeep.holla@arm.com]

[...]

>> I don't see this driver doing anything extra apart from keeping the wakeup irqs
>> enabled. i.e. You use the same cpu*wake register to mask/unmask the interrupt
>> as well as set the wakeup source. Since the wakeup interrupt will be enabled by
>> the driver, you just need to mark it as wake-up source and nothing extra in the
>> controller right ?
>> If so, you need to set IRQCHIP_SKIP_SET_WAKE as you are just leaving that irq
>> enabled and not doing any extra configuration to enable it as wakeup source.
>> Please correct if that wrong, but from the code that's what I could infer.
>
> There is no special for this driver. We just use the IRQCHIP driver framework to
> manage the wakeup sources. Why did you propose to set IRQCHIP_SKIP_SET_WAKE
> flag here? If you don't need the wakeup feature, you should just not enable this
> driver in the configuration.
>

No, if the driver doesn't nothing extra to configure the wake up source
other than keeping it enabled, then it fits the case of SKIP_SET_WAKE.
The driver using this wake would have requested and enabled the irq.
When it calls enable_irq_wake, you have nothing extra to set(atleast
from the looks of the driver), so setting SKIP_SET_WAKE will skip the
call and updated the wake flags in irq core.

I don't see the real need of 2 separate sets of irq mask being saved in
either case.

Regards,
Sudeep

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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 14:45         ` Sudeep Holla
@ 2015-08-25 14:54           ` Shenwei Wang
  2015-08-25 16:24             ` Sudeep Holla
  0 siblings, 1 reply; 22+ messages in thread
From: Shenwei Wang @ 2015-08-25 14:54 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: shawn.guo, tglx, jason, Huang Anson, linux-kernel, linux-arm-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 2379 bytes --]



> -----Original Message-----
> From: Sudeep Holla [mailto:sudeep.holla@arm.com]
> Sent: 2015年8月25日 9:46
> To: Wang Shenwei-B38339
> Cc: Sudeep Holla; shawn.guo@linaro.org; tglx@linutronix.de;
> jason@lakedaemon.net; Huang Yongcai-B20788; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup
> sources
> 
> 
> 
> On 25/08/15 15:14, Shenwei Wang wrote:
> >
> >
> >> -----Original Message-----
> >> From: Sudeep Holla [mailto:sudeep.holla@arm.com]
> 
> [...]
> 
> >> I don't see this driver doing anything extra apart from keeping the
> >> wakeup irqs enabled. i.e. You use the same cpu*wake register to
> >> mask/unmask the interrupt as well as set the wakeup source. Since the
> >> wakeup interrupt will be enabled by the driver, you just need to mark
> >> it as wake-up source and nothing extra in the controller right ?
> >> If so, you need to set IRQCHIP_SKIP_SET_WAKE as you are just leaving
> >> that irq enabled and not doing any extra configuration to enable it as wakeup
> source.
> >> Please correct if that wrong, but from the code that's what I could infer.
> >
> > There is no special for this driver. We just use the IRQCHIP driver
> > framework to manage the wakeup sources. Why did you propose to set
> > IRQCHIP_SKIP_SET_WAKE flag here? If you don't need the wakeup feature,
> > you should just not enable this driver in the configuration.
> >
> 
> No, if the driver doesn't nothing extra to configure the wake up source other than
> keeping it enabled, then it fits the case of SKIP_SET_WAKE.
> The driver using this wake would have requested and enabled the irq.
> When it calls enable_irq_wake, you have nothing extra to set(atleast from the
> looks of the driver), so setting SKIP_SET_WAKE will skip the call and updated the
> wake flags in irq core.
> 
> I don't see the real need of 2 separate sets of irq mask being saved in either case.

You don't really understand what happens after a driver calls enable_irq_wake. In suspend state, even the interrupt
controller itself is powered off. How can you get the system up again by just using a SKIP_SET_WAKE.

Regards,
Shenwei

> Regards,
> Sudeep
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 14:54           ` Shenwei Wang
@ 2015-08-25 16:24             ` Sudeep Holla
  2015-08-25 19:24               ` Shenwei Wang
  2015-08-25 19:26               ` Thomas Gleixner
  0 siblings, 2 replies; 22+ messages in thread
From: Sudeep Holla @ 2015-08-25 16:24 UTC (permalink / raw)
  To: Shenwei Wang
  Cc: Sudeep Holla, shawn.guo, tglx, jason, Huang Anson, linux-kernel,
	linux-arm-kernel



On 25/08/15 15:54, Shenwei Wang wrote:
>
>
>> -----Original Message-----
>> From: Sudeep Holla [mailto:sudeep.holla@arm.com]
>> Sent: 2015年8月25日 9:46
>> To: Wang Shenwei-B38339
>> Cc: Sudeep Holla; shawn.guo@linaro.org; tglx@linutronix.de;
>> jason@lakedaemon.net; Huang Yongcai-B20788; linux-kernel@vger.kernel.org;
>> linux-arm-kernel@lists.infradead.org
>> Subject: Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup
>> sources
>>
>>
>>
>> On 25/08/15 15:14, Shenwei Wang wrote:
>>>
>>>
>>>> -----Original Message-----
>>>> From: Sudeep Holla [mailto:sudeep.holla@arm.com]
>>
>> [...]
>>
>>>> I don't see this driver doing anything extra apart from keeping
>>>> the wakeup irqs enabled. i.e. You use the same cpu*wake
>>>> register to mask/unmask the interrupt as well as set the wakeup
>>>> source. Since the wakeup interrupt will be enabled by the
>>>> driver, you just need to mark it as wake-up source and nothing
>>>> extra in the controller right ? If so, you need to set
>>>> IRQCHIP_SKIP_SET_WAKE as you are just leaving that irq enabled
>>>> and not doing any extra configuration to enable it  as wakeup source.
>>>> Please correct if that wrong, but from the code that's what I
>>>> couldinfer.
>>>
>>> There is no special for this driver. We just use the IRQCHIP
>>> driver framework to manage the wakeup sources. Why did you
>>> propose to set IRQCHIP_SKIP_SET_WAKE flag here? If you don't need
>>> the wakeup feature, you should just not enable this driver in the
>>> configuration.
>>>
>>
>> No, if the driver doesn't nothing extra to configure the wake up
>> source other than  keeping it enabled, then it fits the case of
>> SKIP_SET_WAKE. The driver using this wake would have requested
>> and enabled the irq. When it calls enable_irq_wake, you have
>> nothing extra to set(atleast  from the looks of the driver), so
>> setting SKIP_SET_WAKE will skip the call and  updated the wake
>> flags in irq core.
>>
>> I don't see the real need of 2 separate sets of irq mask being
>> saved  in either case.
>
> You don't really understand what happens after a driver calls
> enable_irq_wake. In suspend state, even the interrupt
> controller itself is powered off. How can you get the system up
> again  by just using a SKIP_SET_WAKE.
>

Sorry for that, let me try to understand aloud. So you have
irq_{un,}mask function that are called when interrupts are enabled and
disabled. So suppose you have 3 irqs that are enabled and only one of
then is set as wakeup source.

Now you call enable_irq_wake, you save that in wakeup_sources, fine.
Later when you enter suspend, you save all the 3 active irqs in
saved_irq_mask and over-write cpu2wakeup with wakeup_sources, right?

All fine, what I am saying is let irq-core know that you want to mask
the 2 non-wakeup irqs you have using MASK_ON_SUSPEND. So when
suspend_device_irqs is called in suspend path, that's done for you
automatically and the cpu2wakeup will have just 1 wakeup enabled which
is what you are doing in suspend callback, right ?

Now that it's already done for you, you need not do anything extra and
hence just set SKIP_SET_WAKE to do nothing.

Hope this clarifies, sorry if I am still missing to understand something
here, but I don't see anything. Let me know.

Regards,
Sudeep

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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 16:24             ` Sudeep Holla
@ 2015-08-25 19:24               ` Shenwei Wang
  2015-08-25 19:29                 ` Thomas Gleixner
  2015-08-25 19:26               ` Thomas Gleixner
  1 sibling, 1 reply; 22+ messages in thread
From: Shenwei Wang @ 2015-08-25 19:24 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: shawn.guo, tglx, jason, Huang Anson, linux-kernel, linux-arm-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 2858 bytes --]



> -----Original Message-----
> From: Sudeep Holla [mailto:sudeep.holla@arm.com]
> Sent: 2015年8月25日 11:24
> To: Wang Shenwei-B38339
> Cc: Sudeep Holla; shawn.guo@linaro.org; tglx@linutronix.de;
> jason@lakedaemon.net; Huang Yongcai-B20788; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup
> >
> > You don't really understand what happens after a driver calls
> > enable_irq_wake. In suspend state, even the interrupt controller
> > itself is powered off. How can you get the system up again  by just
> > using a SKIP_SET_WAKE.
> >
> 
> Sorry for that, let me try to understand aloud. So you have irq_{un,}mask function
> that are called when interrupts are enabled and disabled. So suppose you have 3
> irqs that are enabled and only one of then is set as wakeup source.
> 
> Now you call enable_irq_wake, you save that in wakeup_sources, fine.
> Later when you enter suspend, you save all the 3 active irqs in saved_irq_mask
> and over-write cpu2wakeup with wakeup_sources, right?
> 
> All fine, what I am saying is let irq-core know that you want to mask the 2
> non-wakeup irqs you have using MASK_ON_SUSPEND. So when
> suspend_device_irqs is called in suspend path, that's done for you automatically
> and the cpu2wakeup will have just 1 wakeup enabled which is what you are doing
> in suspend callback, right ?

	/*
	 * Hardware which has no wakeup source configuration facility
	 * requires that the non wakeup interrupts are masked at the
	 * chip level. The chip implementation indicates that with
	 * IRQCHIP_MASK_ON_SUSPEND.
	 */
	if (irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND)
		mask_irq(desc);

IRQCHIP_MASK_ON_SUSPEND flag is for the hardware that has no wakeup source capability.
This GPCv2 block is designed to manage the wakeup source, so the flag does not make any sense.

> Now that it's already done for you, you need not do anything extra and hence just
> set SKIP_SET_WAKE to do nothing.

static int set_irq_wake_real(unsigned int irq, unsigned int on)
{
	struct irq_desc *desc = irq_to_desc(irq);
	int ret = -ENXIO;

	if (irq_desc_get_chip(desc)->flags &  IRQCHIP_SKIP_SET_WAKE)
		return 0;

	if (desc->irq_data.chip->irq_set_wake)
		ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on);

	return ret;
}
>From the codes above, if a irqchip can not handle the wakeup sources, it can set SKIP flag.
This driver is intended to manage the wakeup sources, what's the reason to skip here?

Regards,
Shenwei


> Hope this clarifies, sorry if I am still missing to understand something here, but I
> don't see anything. Let me know.
> 
> Regards,
> Sudeep
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 16:24             ` Sudeep Holla
  2015-08-25 19:24               ` Shenwei Wang
@ 2015-08-25 19:26               ` Thomas Gleixner
  2015-08-26  8:52                 ` Sudeep Holla
  1 sibling, 1 reply; 22+ messages in thread
From: Thomas Gleixner @ 2015-08-25 19:26 UTC (permalink / raw)
  To: Sudeep Holla
  Cc: Shenwei Wang, shawn.guo, jason, Huang Anson, linux-kernel,
	linux-arm-kernel

On Tue, 25 Aug 2015, Sudeep Holla wrote:
> On 25/08/15 15:54, Shenwei Wang wrote:
> > You don't really understand what happens after a driver calls
> > enable_irq_wake. In suspend state, even the interrupt
> > controller itself is powered off. How can you get the system up
> > again  by just using a SKIP_SET_WAKE.
> 
> Sorry for that, let me try to understand aloud. So you have
> irq_{un,}mask function that are called when interrupts are enabled and
> disabled. So suppose you have 3 irqs that are enabled and only one of
> then is set as wakeup source.
> 
> Now you call enable_irq_wake, you save that in wakeup_sources, fine.
> Later when you enter suspend, you save all the 3 active irqs in
> saved_irq_mask and over-write cpu2wakeup with wakeup_sources, right?
> 
> All fine, what I am saying is let irq-core know that you want to mask
> the 2 non-wakeup irqs you have using MASK_ON_SUSPEND. So when
> suspend_device_irqs is called in suspend path, that's done for you
> automatically and the cpu2wakeup will have just 1 wakeup enabled which
> is what you are doing in suspend callback, right ?

I missed that when I reviewed the patch. You are right, it can be
simplified.
 
> Now that it's already done for you, you need not do anything extra and
> hence just set SKIP_SET_WAKE to do nothing.

He still needs the set_wake function to capture the wake enabled
interrupts as they are handed over to the low level asm code via
imx_gpcv2_get_wakeup_source(). Though they could be read back from the
hw registers as well.

Thanks,

	tglx

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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 19:24               ` Shenwei Wang
@ 2015-08-25 19:29                 ` Thomas Gleixner
  2015-08-25 19:58                   ` Shenwei Wang
  0 siblings, 1 reply; 22+ messages in thread
From: Thomas Gleixner @ 2015-08-25 19:29 UTC (permalink / raw)
  To: Shenwei Wang
  Cc: Sudeep Holla, shawn.guo, jason, Huang Anson, linux-kernel,
	linux-arm-kernel

On Tue, 25 Aug 2015, Shenwei Wang wrote:
> > From: Sudeep Holla [mailto:sudeep.holla@arm.com]
> > All fine, what I am saying is let irq-core know that you want to mask the 2
> > non-wakeup irqs you have using MASK_ON_SUSPEND. So when
> > suspend_device_irqs is called in suspend path, that's done for you automatically
> > and the cpu2wakeup will have just 1 wakeup enabled which is what you are doing
> > in suspend callback, right ?
> 
> 	/*
> 	 * Hardware which has no wakeup source configuration facility
> 	 * requires that the non wakeup interrupts are masked at the
> 	 * chip level. The chip implementation indicates that with
> 	 * IRQCHIP_MASK_ON_SUSPEND.
> 	 */
> 	if (irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND)
> 		mask_irq(desc);
> 
> IRQCHIP_MASK_ON_SUSPEND flag is for the hardware that has no wakeup
> source capability.  This GPCv2 block is designed to manage the
> wakeup source, so the flag does not make any sense.

You have no seperate wakeup source mechanism. All you do is to mask all
non wakeup sources and keep the wakeup sources unmask.

That's what happens in gpcv2_wakeup_source_save()

       writel_relaxed(cd->wakeup_sources[i], reg);

So it's the same as letting the core mask all non wakeup sources and
leave the wakeup sources unmask.

> > Now that it's already done for you, you need not do anything extra and hence just
> > set SKIP_SET_WAKE to do nothing.
> 
> static int set_irq_wake_real(unsigned int irq, unsigned int on)
> {
> 	struct irq_desc *desc = irq_to_desc(irq);
> 	int ret = -ENXIO;
> 
> 	if (irq_desc_get_chip(desc)->flags &  IRQCHIP_SKIP_SET_WAKE)
> 		return 0;
> 
> 	if (desc->irq_data.chip->irq_set_wake)
> 		ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on);
> 
> 	return ret;
> }
> From the codes above, if a irqchip can not handle the wakeup
> sources, it can set SKIP flag.  This driver is intended to manage
> the wakeup sources, what's the reason to skip here?

To reduce code. Everything the core can do for you is something you
don't have to implement.

Thanks,

	tglx

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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 19:29                 ` Thomas Gleixner
@ 2015-08-25 19:58                   ` Shenwei Wang
  2015-08-25 20:15                     ` Thomas Gleixner
  0 siblings, 1 reply; 22+ messages in thread
From: Shenwei Wang @ 2015-08-25 19:58 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Sudeep Holla, shawn.guo, jason, Huang Anson, linux-kernel,
	linux-arm-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="gb2312", Size: 3090 bytes --]



> -----Original Message-----
> From: Thomas Gleixner [mailto:tglx@linutronix.de]
> Sent: 2015Äê8ÔÂ25ÈÕ 14:30
> To: Wang Shenwei-B38339
> Cc: Sudeep Holla; shawn.guo@linaro.org; jason@lakedaemon.net; Huang
> Yongcai-B20788; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup
> sources
> 
> On Tue, 25 Aug 2015, Shenwei Wang wrote:
> > > From: Sudeep Holla [mailto:sudeep.holla@arm.com] All fine, what I am
> > > saying is let irq-core know that you want to mask the 2 non-wakeup
> > > irqs you have using MASK_ON_SUSPEND. So when suspend_device_irqs is
> > > called in suspend path, that's done for you automatically and the
> > > cpu2wakeup will have just 1 wakeup enabled which is what you are
> > > doing in suspend callback, right ?
> >
> > 	/*
> > 	 * Hardware which has no wakeup source configuration facility
> > 	 * requires that the non wakeup interrupts are masked at the
> > 	 * chip level. The chip implementation indicates that with
> > 	 * IRQCHIP_MASK_ON_SUSPEND.
> > 	 */
> > 	if (irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND)
> > 		mask_irq(desc);
> >
> > IRQCHIP_MASK_ON_SUSPEND flag is for the hardware that has no wakeup
> > source capability.  This GPCv2 block is designed to manage the wakeup
> > source, so the flag does not make any sense.
> 
> You have no seperate wakeup source mechanism. All you do is to mask all non
> wakeup sources and keep the wakeup sources unmask.
> 
> That's what happens in gpcv2_wakeup_source_save()
> 
>        writel_relaxed(cd->wakeup_sources[i], reg);
> 
> So it's the same as letting the core mask all non wakeup sources and leave the
> wakeup sources unmask.

Does it mean an unexpected interrupt may activate the system, and the core will let
the system go into suspend again if the core determines it not a wakeup source? The current design
is to ignore all the unexpected interrupts in the hardware level. Only the presetting 
wakeup sources can activate the platform. Here power consumption is more 
important.

> > > Now that it's already done for you, you need not do anything extra
> > > and hence just set SKIP_SET_WAKE to do nothing.
> >
> > static int set_irq_wake_real(unsigned int irq, unsigned int on) {
> > 	struct irq_desc *desc = irq_to_desc(irq);
> > 	int ret = -ENXIO;
> >
> > 	if (irq_desc_get_chip(desc)->flags &  IRQCHIP_SKIP_SET_WAKE)
> > 		return 0;
> >
> > 	if (desc->irq_data.chip->irq_set_wake)
> > 		ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on);
> >
> > 	return ret;
> > }
> > From the codes above, if a irqchip can not handle the wakeup sources,
> > it can set SKIP flag.  This driver is intended to manage the wakeup
> > sources, what's the reason to skip here?
> 
> To reduce code. Everything the core can do for you is something you don't have to
> implement.

Same as above.

Thanks,
Shenwei

> Thanks,
> 
> 	tglx
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 19:58                   ` Shenwei Wang
@ 2015-08-25 20:15                     ` Thomas Gleixner
  2015-08-25 20:43                       ` Shenwei Wang
  0 siblings, 1 reply; 22+ messages in thread
From: Thomas Gleixner @ 2015-08-25 20:15 UTC (permalink / raw)
  To: Shenwei Wang
  Cc: Sudeep Holla, shawn.guo, jason, Huang Anson, linux-kernel,
	linux-arm-kernel

On Tue, 25 Aug 2015, Shenwei Wang wrote:
> > From: Thomas Gleixner [mailto:tglx@linutronix.de]
> > > IRQCHIP_MASK_ON_SUSPEND flag is for the hardware that has no wakeup
> > > source capability.  This GPCv2 block is designed to manage the wakeup
> > > source, so the flag does not make any sense.
> > 
> > You have no seperate wakeup source mechanism. All you do is to mask all non
> > wakeup sources and keep the wakeup sources unmask.
> > 
> > That's what happens in gpcv2_wakeup_source_save()
> > 
> >        writel_relaxed(cd->wakeup_sources[i], reg);
> > 
> > So it's the same as letting the core mask all non wakeup sources and leave the
> > wakeup sources unmask.
> 
> Does it mean an unexpected interrupt may activate the system, and
> the core will let the system go into suspend again if the core
> determines it not a wakeup source? The current design is to ignore
> all the unexpected interrupts in the hardware level. Only the
> presetting wakeup sources can activate the platform. Here power
> consumption is more important.

Did you actually read, what I wrote?

The core does in case of MASK_ON_SUSPEND

    for_each_irq() {
	if (!irq->wakeupsource)
	   mask(irq)
    }

That's identical to what you are doing. You just do it differently by
saving the active wakeup sources in your own data structure and then
write that info to the mask register, which leaves only the wakeup
sources unmasked.

Thanks,

	tglx

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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 20:15                     ` Thomas Gleixner
@ 2015-08-25 20:43                       ` Shenwei Wang
  2015-08-25 20:49                         ` Thomas Gleixner
  0 siblings, 1 reply; 22+ messages in thread
From: Shenwei Wang @ 2015-08-25 20:43 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Sudeep Holla, shawn.guo, jason, Huang Anson, linux-kernel,
	linux-arm-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="gb2312", Size: 2441 bytes --]



> -----Original Message-----
> From: Thomas Gleixner [mailto:tglx@linutronix.de]
> Sent: 2015Äê8ÔÂ25ÈÕ 15:16
> To: Wang Shenwei-B38339
> Cc: Sudeep Holla; shawn.guo@linaro.org; jason@lakedaemon.net; Huang
> Yongcai-B20788; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup
> sources
> 
> On Tue, 25 Aug 2015, Shenwei Wang wrote:
> > > From: Thomas Gleixner [mailto:tglx@linutronix.de]
> > > > IRQCHIP_MASK_ON_SUSPEND flag is for the hardware that has no
> > > > wakeup source capability.  This GPCv2 block is designed to manage
> > > > the wakeup source, so the flag does not make any sense.
> > >
> > > You have no seperate wakeup source mechanism. All you do is to mask
> > > all non wakeup sources and keep the wakeup sources unmask.
> > >
> > > That's what happens in gpcv2_wakeup_source_save()
> > >
> > >        writel_relaxed(cd->wakeup_sources[i], reg);
> > >
> > > So it's the same as letting the core mask all non wakeup sources and
> > > leave the wakeup sources unmask.
> >
> > Does it mean an unexpected interrupt may activate the system, and the
> > core will let the system go into suspend again if the core determines
> > it not a wakeup source? The current design is to ignore all the
> > unexpected interrupts in the hardware level. Only the presetting
> > wakeup sources can activate the platform. Here power consumption is
> > more important.
> 
> Did you actually read, what I wrote?
> 
> The core does in case of MASK_ON_SUSPEND
> 
>     for_each_irq() {
> 	if (!irq->wakeupsource)
> 	   mask(irq)
>     }
> 
> That's identical to what you are doing. You just do it differently by saving the
> active wakeup sources in your own data structure and then write that info to the
> mask register, which leaves only the wakeup sources unmasked.

Sorry. I just took a study on the two flags: MASK_ON_SUSPEND and IRQCHIP_SKIP_SET_WAKE.
MASK_ON_SUSPEND flag does simply the implementation. 
IRQCHIP_SKIP_SET_WAKE flag can't be used here because the wakeup sources are required for power management.
I will send out a subsequent patch to simply the implementation by using this idea.

Thank you Sudeep for the insightful review!

Thanks,
Shenwei



> Thanks,
> 
> 	tglx
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 20:43                       ` Shenwei Wang
@ 2015-08-25 20:49                         ` Thomas Gleixner
  2015-08-25 20:53                           ` Shenwei Wang
  0 siblings, 1 reply; 22+ messages in thread
From: Thomas Gleixner @ 2015-08-25 20:49 UTC (permalink / raw)
  To: Shenwei Wang
  Cc: Sudeep Holla, shawn.guo, jason, Huang Anson, linux-kernel,
	linux-arm-kernel

On Tue, 25 Aug 2015, Shenwei Wang wrote:
> 
> IRQCHIP_SKIP_SET_WAKE flag can't be used here because the wakeup
> sources are required for power management.

You could use it. Instead of copying the saved values, you can read
the values back from the register.

Thanks,

	tglx

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

* RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 20:49                         ` Thomas Gleixner
@ 2015-08-25 20:53                           ` Shenwei Wang
  0 siblings, 0 replies; 22+ messages in thread
From: Shenwei Wang @ 2015-08-25 20:53 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Sudeep Holla, shawn.guo, jason, Huang Anson, linux-kernel,
	linux-arm-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="gb2312", Size: 880 bytes --]



> -----Original Message-----
> From: Thomas Gleixner [mailto:tglx@linutronix.de]
> Sent: 2015Äê8ÔÂ25ÈÕ 15:50
> To: Wang Shenwei-B38339
> Cc: Sudeep Holla; shawn.guo@linaro.org; jason@lakedaemon.net; Huang
> Yongcai-B20788; linux-kernel@vger.kernel.org;
> linux-arm-kernel@lists.infradead.org
> Subject: RE: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup
> sources
> 
> On Tue, 25 Aug 2015, Shenwei Wang wrote:
> >
> > IRQCHIP_SKIP_SET_WAKE flag can't be used here because the wakeup
> > sources are required for power management.
> 
> You could use it. Instead of copying the saved values, you can read the values
> back from the register.

It is an option too. 

Thanks,
Shenwei

> Thanks,
> 
> 	tglx
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources
  2015-08-25 19:26               ` Thomas Gleixner
@ 2015-08-26  8:52                 ` Sudeep Holla
  0 siblings, 0 replies; 22+ messages in thread
From: Sudeep Holla @ 2015-08-26  8:52 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: Sudeep Holla, Shenwei Wang, shawn.guo, jason, Huang Anson,
	linux-kernel, linux-arm-kernel

Hi Thomas,

On 25/08/15 20:26, Thomas Gleixner wrote:
> On Tue, 25 Aug 2015, Sudeep Holla wrote:
>> On 25/08/15 15:54, Shenwei Wang wrote:
>>> You don't really understand what happens after a driver calls
>>> enable_irq_wake. In suspend state, even the interrupt
>>> controller itself is powered off. How can you get the system up
>>> again  by just using a SKIP_SET_WAKE.
>>
>> Sorry for that, let me try to understand aloud. So you have
>> irq_{un,}mask function that are called when interrupts are enabled and
>> disabled. So suppose you have 3 irqs that are enabled and only one of
>> then is set as wakeup source.
>>
>> Now you call enable_irq_wake, you save that in wakeup_sources, fine.
>> Later when you enter suspend, you save all the 3 active irqs in
>> saved_irq_mask and over-write cpu2wakeup with wakeup_sources, right?
>>
>> All fine, what I am saying is let irq-core know that you want to mask
>> the 2 non-wakeup irqs you have using MASK_ON_SUSPEND. So when
>> suspend_device_irqs is called in suspend path, that's done for you
>> automatically and the cpu2wakeup will have just 1 wakeup enabled which
>> is what you are doing in suspend callback, right ?
>
> I missed that when I reviewed the patch. You are right, it can be
> simplified.
>
>> Now that it's already done for you, you need not do anything extra and
>> hence just set SKIP_SET_WAKE to do nothing.

Thanks for confirming this.

>
> He still needs the set_wake function to capture the wake enabled
> interrupts as they are handed over to the low level asm code via
> imx_gpcv2_get_wakeup_source(). Though they could be read back from the
> hw registers as well.
>

Correct, I have no objection on how it's saved/restored but was against
having 2 different masks and with the approach taken in this patch the
non-wakeup interrupts are enabled until syscore_suspend which is wrong.

There's whole lot of drivers blindly copy pasting this as theme which I
am going through and trying to clean up. I wanted to ensure no more such
additions happen meanwhile, so I am watching such patches closely.

Regards,
Sudeep

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

end of thread, other threads:[~2015-08-26  8:52 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-24 19:04 [PATCH v9 1/1] irqchip: imx-gpcv2: IMX GPCv2 driver for wakeup sources Shenwei Wang
2015-08-24 19:14 ` Thomas Gleixner
2015-08-24 19:20   ` Shenwei Wang
2015-08-24 19:30     ` Thomas Gleixner
2015-08-24 19:32       ` Shenwei Wang
2015-08-24 19:51 ` [tip:irq/core] irqchip/imx-gpcv2: " tip-bot for Shenwei Wang
2015-08-25  9:24 ` [PATCH v9 1/1] irqchip: imx-gpcv2: " Sudeep Holla
2015-08-25 13:38   ` Shenwei Wang
2015-08-25 13:54     ` Sudeep Holla
2015-08-25 14:14       ` Shenwei Wang
2015-08-25 14:45         ` Sudeep Holla
2015-08-25 14:54           ` Shenwei Wang
2015-08-25 16:24             ` Sudeep Holla
2015-08-25 19:24               ` Shenwei Wang
2015-08-25 19:29                 ` Thomas Gleixner
2015-08-25 19:58                   ` Shenwei Wang
2015-08-25 20:15                     ` Thomas Gleixner
2015-08-25 20:43                       ` Shenwei Wang
2015-08-25 20:49                         ` Thomas Gleixner
2015-08-25 20:53                           ` Shenwei Wang
2015-08-25 19:26               ` Thomas Gleixner
2015-08-26  8:52                 ` Sudeep Holla

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).