devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/5] GICv3 Save and Restore
@ 2018-01-30  1:00 Derek Basehore
  2018-01-30  1:00 ` [PATCH v3 1/5] cpu_pm: add syscore_suspend error handling Derek Basehore
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Derek Basehore @ 2018-01-30  1:00 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Soby.Mathew-5wv7dgnIgG8, sudeep.holla-5wv7dgnIgG8,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	rafael.j.wysocki-ral2JQCrhuEAvxtiuMwx3w,
	tglx-hfZtesqFncYOwBW4kG4KsQ, briannorris-F7+t8E8rja9g9hUCZPvPmw,
	marc.zyngier-5wv7dgnIgG8, Derek Basehore

A lot of changes in v2. The distributor and redistributor saving and
restoring is left to the PSCI/firmware implementation after
discussions with ARM. This reduces the line changes by a lot and
removes now unneeded patches.

Patches are verified on an RK3399 platform with pending patches in the
ARM-Trusted-Firmware project.

Just a couple minor changes in v3 to formatting.

Derek Basehore (5):
  cpu_pm: add syscore_suspend error handling
  irqchip/gic-v3-its: add ability to save/restore ITS state
  DT/arm,gic-v3-its: add reset-on-suspend property
  irqchip/gic-v3-its: add ability to resend MAPC on resume
  DT/arm,gic-v3: add collections-reset-on-suspend property

 .../bindings/interrupt-controller/arm,gic-v3.txt   |   7 +
 arch/arm64/Kconfig                                 |  10 ++
 drivers/irqchip/irq-gic-v3-its.c                   | 187 ++++++++++++++++-----
 kernel/cpu_pm.c                                    |   3 +
 4 files changed, 169 insertions(+), 38 deletions(-)

-- 
2.16.0.rc1.238.g530d649a79-goog

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 1/5] cpu_pm: add syscore_suspend error handling
  2018-01-30  1:00 [PATCH v3 0/5] GICv3 Save and Restore Derek Basehore
@ 2018-01-30  1:00 ` Derek Basehore
  2018-01-30  1:00 ` [PATCH v3 2/5] irqchip/gic-v3-its: add ability to save/restore ITS state Derek Basehore
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Derek Basehore @ 2018-01-30  1:00 UTC (permalink / raw)
  To: linux-kernel
  Cc: Soby.Mathew, sudeep.holla, devicetree, robh+dt, mark.rutland,
	linux-pm, rafael.j.wysocki, tglx, briannorris, marc.zyngier,
	Derek Basehore

If cpu_cluster_pm_enter() fails, cpu_pm_exit() should be called. This
will put the CPU in the correct state to resume from the failure.

Signed-off-by: Derek Basehore <dbasehore@chromium.org>
---
 kernel/cpu_pm.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c
index 67b02e138a47..03bcc0751a51 100644
--- a/kernel/cpu_pm.c
+++ b/kernel/cpu_pm.c
@@ -186,6 +186,9 @@ static int cpu_pm_suspend(void)
 		return ret;
 
 	ret = cpu_cluster_pm_enter();
+	if (ret)
+		cpu_pm_exit();
+
 	return ret;
 }
 
-- 
2.16.0.rc1.238.g530d649a79-goog

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

* [PATCH v3 2/5] irqchip/gic-v3-its: add ability to save/restore ITS state
  2018-01-30  1:00 [PATCH v3 0/5] GICv3 Save and Restore Derek Basehore
  2018-01-30  1:00 ` [PATCH v3 1/5] cpu_pm: add syscore_suspend error handling Derek Basehore
@ 2018-01-30  1:00 ` Derek Basehore
  2018-02-01 22:54   ` dbasehore .
       [not found] ` <20180130010007.256564-1-dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Derek Basehore @ 2018-01-30  1:00 UTC (permalink / raw)
  To: linux-kernel
  Cc: Soby.Mathew, sudeep.holla, devicetree, robh+dt, mark.rutland,
	linux-pm, rafael.j.wysocki, tglx, briannorris, marc.zyngier,
	Derek Basehore

Some platforms power off GIC logic in suspend, so we need to
save/restore state. The distributor and redistributor registers need
to be handled in platform code due to access permissions on those
registers, but the ITS registers can be restored in the kernel.

Signed-off-by: Derek Basehore <dbasehore@chromium.org>
---
 drivers/irqchip/irq-gic-v3-its.c | 86 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 06f025fd5726..759ede7048ed 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -33,6 +33,7 @@
 #include <linux/of_platform.h>
 #include <linux/percpu.h>
 #include <linux/slab.h>
+#include <linux/syscore_ops.h>
 
 #include <linux/irqchip.h>
 #include <linux/irqchip/arm-gic-v3.h>
@@ -46,6 +47,7 @@
 #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING		(1ULL << 0)
 #define ITS_FLAGS_WORKAROUND_CAVIUM_22375	(1ULL << 1)
 #define ITS_FLAGS_WORKAROUND_CAVIUM_23144	(1ULL << 2)
+#define ITS_FLAGS_SAVE_SUSPEND_STATE		(1ULL << 3)
 
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING	(1 << 0)
 
@@ -83,6 +85,15 @@ struct its_baser {
 	u32		psz;
 };
 
+/*
+ * Saved ITS state - this is where saved state for the ITS is stored
+ * when it's disabled during system suspend.
+ */
+struct its_ctx {
+	u64			cbaser;
+	u32			ctlr;
+};
+
 struct its_device;
 
 /*
@@ -101,6 +112,7 @@ struct its_node {
 	struct its_collection	*collections;
 	struct fwnode_handle	*fwnode_handle;
 	u64			(*get_msi_base)(struct its_device *its_dev);
+	struct its_ctx		its_ctx;
 	struct list_head	its_device_list;
 	u64			flags;
 	unsigned long		list_nr;
@@ -3042,6 +3054,75 @@ static void its_enable_quirks(struct its_node *its)
 	gic_enable_quirks(iidr, its_quirks, its);
 }
 
+static int its_save_disable(void)
+{
+	struct its_node *its;
+	int err = 0;
+
+	spin_lock(&its_lock);
+	list_for_each_entry(its, &its_nodes, entry) {
+		if (its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE) {
+			struct its_ctx *ctx = &its->its_ctx;
+			void __iomem *base = its->base;
+
+			ctx->ctlr = readl_relaxed(base + GITS_CTLR);
+			err = its_force_quiescent(base);
+			if (err) {
+				pr_err("ITS failed to quiesce\n");
+				writel_relaxed(ctx->ctlr, base + GITS_CTLR);
+				goto err;
+			}
+
+			ctx->cbaser = gits_read_cbaser(base + GITS_CBASER);
+		}
+	}
+
+err:
+	if (err) {
+		list_for_each_entry_continue_reverse(its, &its_nodes, entry) {
+			if (its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE) {
+				struct its_ctx *ctx = &its->its_ctx;
+				void __iomem *base = its->base;
+
+				writel_relaxed(ctx->ctlr, base + GITS_CTLR);
+			}
+		}
+	}
+
+	spin_unlock(&its_lock);
+
+	return err;
+}
+
+static void its_restore_enable(void)
+{
+	struct its_node *its;
+
+	spin_lock(&its_lock);
+	list_for_each_entry(its, &its_nodes, entry) {
+		if (its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE) {
+			struct its_ctx *ctx = &its->its_ctx;
+			void __iomem *base = its->base;
+			struct its_baser *baser;
+			int i;
+
+			gits_write_cbaser(ctx->cbaser, base + GITS_CBASER);
+			/* Restore GITS_BASER from the value cache. */
+			for (i = 0; i < GITS_BASER_NR_REGS; i++) {
+				baser = &its->tables[i];
+				its_write_baser(its, baser, baser->val);
+			}
+			writel_relaxed(ctx->ctlr, base + GITS_CTLR);
+		}
+	}
+	spin_unlock(&its_lock);
+}
+
+static struct syscore_ops its_syscore_ops = {
+	.suspend = its_save_disable,
+	.resume = its_restore_enable,
+};
+
 static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
 {
 	struct irq_domain *inner_domain;
@@ -3261,6 +3342,9 @@ static int __init its_probe_one(struct resource *res,
 		ctlr |= GITS_CTLR_ImDe;
 	writel_relaxed(ctlr, its->base + GITS_CTLR);
 
+	if (fwnode_property_present(handle, "reset-on-suspend"))
+		its->flags |= ITS_FLAGS_SAVE_SUSPEND_STATE;
+
 	err = its_init_domain(handle, its);
 	if (err)
 		goto out_free_tables;
@@ -3515,5 +3599,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
 		}
 	}
 
+	register_syscore_ops(&its_syscore_ops);
+
 	return 0;
 }
-- 
2.16.0.rc1.238.g530d649a79-goog

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

* [PATCH v3 3/5] DT/arm,gic-v3-its: add reset-on-suspend property
       [not found] ` <20180130010007.256564-1-dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
@ 2018-01-30  1:00   ` Derek Basehore
  0 siblings, 0 replies; 8+ messages in thread
From: Derek Basehore @ 2018-01-30  1:00 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Soby.Mathew-5wv7dgnIgG8, sudeep.holla-5wv7dgnIgG8,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	linux-pm-u79uwXL29TY76Z2rM5mHXA,
	rafael.j.wysocki-ral2JQCrhuEAvxtiuMwx3w,
	tglx-hfZtesqFncYOwBW4kG4KsQ, briannorris-F7+t8E8rja9g9hUCZPvPmw,
	marc.zyngier-5wv7dgnIgG8, Derek Basehore

This adds documentation for the new reset-on-suspend property. This
property enables saving and restoring the ITS for when it loses state
in system suspend.

Signed-off-by: Derek Basehore <dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
 Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
index 0a57f2f4167d..a470147d4f14 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
@@ -78,6 +78,9 @@ These nodes must have the following properties:
 Optional:
 - socionext,synquacer-pre-its: (u32, u32) tuple describing the untranslated
   address and size of the pre-ITS window.
+- reset-on-suspend: Boolean property. Indicates that the ITS state is
+  reset on suspend. The state is then saved on suspend and restored on
+  resume.
 
 The main GIC node must contain the appropriate #address-cells,
 #size-cells and ranges properties for the reg property of all ITS
-- 
2.16.0.rc1.238.g530d649a79-goog

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 4/5] irqchip/gic-v3-its: add ability to resend MAPC on resume
  2018-01-30  1:00 [PATCH v3 0/5] GICv3 Save and Restore Derek Basehore
                   ` (2 preceding siblings ...)
       [not found] ` <20180130010007.256564-1-dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
@ 2018-01-30  1:00 ` Derek Basehore
       [not found]   ` <20180130010007.256564-5-dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
  2018-01-30  1:00 ` [PATCH v3 5/5] DT/arm,gic-v3: add collections-reset-on-suspend property Derek Basehore
  4 siblings, 1 reply; 8+ messages in thread
From: Derek Basehore @ 2018-01-30  1:00 UTC (permalink / raw)
  To: linux-kernel
  Cc: Soby.Mathew, sudeep.holla, devicetree, robh+dt, mark.rutland,
	linux-pm, rafael.j.wysocki, tglx, briannorris, marc.zyngier,
	Derek Basehore

This adds functionality to resend the MAPC command to an ITS node on
resume. If the ITS is powered down during suspend and the collections
are not backed by memory, the ITS will lose that state. This just sets
up the known state for the collections after the ITS is restored.

This feature is enabled via Kconfig and a device tree entry.

Signed-off-by: Derek Basehore <dbasehore@chromium.org>
---
 arch/arm64/Kconfig               |  10 ++++
 drivers/irqchip/irq-gic-v3-its.c | 101 ++++++++++++++++++++++++---------------
 2 files changed, 73 insertions(+), 38 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 53612879fe56..f38f1a7b4266 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -571,6 +571,16 @@ config HISILICON_ERRATUM_161600802
 
 	  If unsure, say Y.
 
+config ARM_GIC500_COLLECTIONS_RESET
+	bool "GIC-500 Collections: Workaround for GIC-500 Collections on suspend reset"
+	default y
+	help
+	  The GIC-500 can store Collections state internally for the ITS. If
+	  the ITS is reset on suspend (ie from power getting disabled), the
+	  collections need to be reconfigured on resume.
+
+	  If unsure, say Y.
+
 config QCOM_FALKOR_ERRATUM_E1041
 	bool "Falkor E1041: Speculative instruction fetches might cause errant memory access"
 	default y
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 759ede7048ed..7fc533cf3bf7 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -48,6 +48,7 @@
 #define ITS_FLAGS_WORKAROUND_CAVIUM_22375	(1ULL << 1)
 #define ITS_FLAGS_WORKAROUND_CAVIUM_23144	(1ULL << 2)
 #define ITS_FLAGS_SAVE_SUSPEND_STATE		(1ULL << 3)
+#define ITS_FLAGS_WORKAROUND_GIC500_MAPC	(1ULL << 4)
 
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING	(1 << 0)
 
@@ -1950,52 +1951,53 @@ static void its_cpu_init_lpis(void)
 	dsb(sy);
 }
 
-static void its_cpu_init_collection(void)
+static void its_cpu_init_collection(struct its_node *its)
 {
-	struct its_node *its;
-	int cpu;
-
-	spin_lock(&its_lock);
-	cpu = smp_processor_id();
-
-	list_for_each_entry(its, &its_nodes, entry) {
-		u64 target;
+	int cpu = smp_processor_id();
+	u64 target;
 
-		/* avoid cross node collections and its mapping */
-		if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) {
-			struct device_node *cpu_node;
+	/* avoid cross node collections and its mapping */
+	if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) {
+		struct device_node *cpu_node;
 
-			cpu_node = of_get_cpu_node(cpu, NULL);
-			if (its->numa_node != NUMA_NO_NODE &&
-				its->numa_node != of_node_to_nid(cpu_node))
-				continue;
-		}
+		cpu_node = of_get_cpu_node(cpu, NULL);
+		if (its->numa_node != NUMA_NO_NODE &&
+			its->numa_node != of_node_to_nid(cpu_node))
+			return;
+	}
 
+	/*
+	 * We now have to bind each collection to its target
+	 * redistributor.
+	 */
+	if (gic_read_typer(its->base + GITS_TYPER) & GITS_TYPER_PTA) {
 		/*
-		 * We now have to bind each collection to its target
+		 * This ITS wants the physical address of the
 		 * redistributor.
 		 */
-		if (gic_read_typer(its->base + GITS_TYPER) & GITS_TYPER_PTA) {
-			/*
-			 * This ITS wants the physical address of the
-			 * redistributor.
-			 */
-			target = gic_data_rdist()->phys_base;
-		} else {
-			/*
-			 * This ITS wants a linear CPU number.
-			 */
-			target = gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER);
-			target = GICR_TYPER_CPU_NUMBER(target) << 16;
-		}
+		target = gic_data_rdist()->phys_base;
+	} else {
+		/* This ITS wants a linear CPU number. */
+		target = gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER);
+		target = GICR_TYPER_CPU_NUMBER(target) << 16;
+	}
 
-		/* Perform collection mapping */
-		its->collections[cpu].target_address = target;
-		its->collections[cpu].col_id = cpu;
+	/* Perform collection mapping */
+	its->collections[cpu].target_address = target;
+	its->collections[cpu].col_id = cpu;
 
-		its_send_mapc(its, &its->collections[cpu], 1);
-		its_send_invall(its, &its->collections[cpu]);
-	}
+	its_send_mapc(its, &its->collections[cpu], 1);
+	its_send_invall(its, &its->collections[cpu]);
+}
+
+static void its_cpu_init_collections(void)
+{
+	struct its_node *its;
+
+	spin_lock(&its_lock);
+
+	list_for_each_entry(its, &its_nodes, entry)
+		its_cpu_init_collection(its);
 
 	spin_unlock(&its_lock);
 }
@@ -2997,6 +2999,18 @@ static bool __maybe_unused its_enable_quirk_hip07_161600802(void *data)
 	return true;
 }
 
+static bool __maybe_unused its_enable_quirk_gic500_collections(void *data)
+{
+	struct its_node *its = data;
+
+	if (fwnode_property_present(its->fwnode_handle,
+				    "collections-reset-on-suspend")) {
+		its->flags |= ITS_FLAGS_WORKAROUND_GIC500_MAPC;
+		return true;
+	}
+	return false;
+}
+
 static const struct gic_quirk its_quirks[] = {
 #ifdef CONFIG_CAVIUM_ERRATUM_22375
 	{
@@ -3042,6 +3056,14 @@ static const struct gic_quirk its_quirks[] = {
 		.mask	= 0xffffffff,
 		.init	= its_enable_quirk_hip07_161600802,
 	},
+#endif
+#ifdef CONFIG_ARM_GIC500_COLLECTIONS_RESET
+	{
+		.desc	= "ITS: GIC-500 Collections Reset on Resume",
+		.iidr	= 0x00000000,
+		.mask	= 0xff000000,
+		.init	= its_enable_quirk_gic500_collections,
+	},
 #endif
 	{
 	}
@@ -3114,6 +3136,9 @@ static void its_restore_enable(void)
 			}
 			writel_relaxed(ctx->ctlr, base + GITS_CTLR);
 		}
+
+		if (its->flags & ITS_FLAGS_WORKAROUND_GIC500_MAPC)
+			its_cpu_init_collection(its);
 	}
 	spin_unlock(&its_lock);
 }
@@ -3380,7 +3405,7 @@ int its_cpu_init(void)
 			return -ENXIO;
 		}
 		its_cpu_init_lpis();
-		its_cpu_init_collection();
+		its_cpu_init_collections();
 	}
 
 	return 0;
-- 
2.16.0.rc1.238.g530d649a79-goog

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

* [PATCH v3 5/5] DT/arm,gic-v3: add collections-reset-on-suspend property
  2018-01-30  1:00 [PATCH v3 0/5] GICv3 Save and Restore Derek Basehore
                   ` (3 preceding siblings ...)
  2018-01-30  1:00 ` [PATCH v3 4/5] irqchip/gic-v3-its: add ability to resend MAPC on resume Derek Basehore
@ 2018-01-30  1:00 ` Derek Basehore
  4 siblings, 0 replies; 8+ messages in thread
From: Derek Basehore @ 2018-01-30  1:00 UTC (permalink / raw)
  To: linux-kernel
  Cc: Soby.Mathew, sudeep.holla, devicetree, robh+dt, mark.rutland,
	linux-pm, rafael.j.wysocki, tglx, briannorris, marc.zyngier,
	Derek Basehore

This boolean property for the GIC-V3-ITS enables resending the MAP
COLLECTIONS commands when resuming for when the state is reset on
suspend.

Signed-off-by: Derek Basehore <dbasehore@chromium.org>
---
 Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
index a470147d4f14..adb958e046d2 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
@@ -81,6 +81,10 @@ Optional:
 - reset-on-suspend: Boolean property. Indicates that the ITS state is
   reset on suspend. The state is then saved on suspend and restored on
   resume.
+- collections-reset-on-suspend : Boolean property. If the collections for the
+  ITS are stored internally instead of externally, the state will be lost if the
+  GIC loses power. Setting this enables the kernel to reset the collections
+  state on resume for this ITS node.
 
 The main GIC node must contain the appropriate #address-cells,
 #size-cells and ranges properties for the reg property of all ITS
-- 
2.16.0.rc1.238.g530d649a79-goog

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

* Re: [PATCH v3 4/5] irqchip/gic-v3-its: add ability to resend MAPC on resume
       [not found]   ` <20180130010007.256564-5-dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
@ 2018-02-01 22:52     ` dbasehore .
  0 siblings, 0 replies; 8+ messages in thread
From: dbasehore . @ 2018-02-01 22:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Soby Mathew, Sudeep Holla, devicetree-u79uwXL29TY76Z2rM5mHXA,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Mark Rutland,
	Linux-pm mailing list, Wysocki, Rafael J, Thomas Gleixner,
	Brian Norris, Marc Zyngier, Derek Basehore

On Mon, Jan 29, 2018 at 5:00 PM, Derek Basehore <dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> wrote:
> This adds functionality to resend the MAPC command to an ITS node on
> resume. If the ITS is powered down during suspend and the collections
> are not backed by memory, the ITS will lose that state. This just sets
> up the known state for the collections after the ITS is restored.
>
> This feature is enabled via Kconfig and a device tree entry.
>
> Signed-off-by: Derek Basehore <dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> ---
>  arch/arm64/Kconfig               |  10 ++++
>  drivers/irqchip/irq-gic-v3-its.c | 101 ++++++++++++++++++++++++---------------
>  2 files changed, 73 insertions(+), 38 deletions(-)
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 53612879fe56..f38f1a7b4266 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -571,6 +571,16 @@ config HISILICON_ERRATUM_161600802
>
>           If unsure, say Y.
>
> +config ARM_GIC500_COLLECTIONS_RESET
> +       bool "GIC-500 Collections: Workaround for GIC-500 Collections on suspend reset"
> +       default y
> +       help
> +         The GIC-500 can store Collections state internally for the ITS. If
> +         the ITS is reset on suspend (ie from power getting disabled), the
> +         collections need to be reconfigured on resume.
> +
> +         If unsure, say Y.
> +
>  config QCOM_FALKOR_ERRATUM_E1041
>         bool "Falkor E1041: Speculative instruction fetches might cause errant memory access"
>         default y
> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
> index 759ede7048ed..7fc533cf3bf7 100644
> --- a/drivers/irqchip/irq-gic-v3-its.c
> +++ b/drivers/irqchip/irq-gic-v3-its.c
> @@ -48,6 +48,7 @@
>  #define ITS_FLAGS_WORKAROUND_CAVIUM_22375      (1ULL << 1)
>  #define ITS_FLAGS_WORKAROUND_CAVIUM_23144      (1ULL << 2)
>  #define ITS_FLAGS_SAVE_SUSPEND_STATE           (1ULL << 3)
> +#define ITS_FLAGS_WORKAROUND_GIC500_MAPC       (1ULL << 4)
>
>  #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING    (1 << 0)
>
> @@ -1950,52 +1951,53 @@ static void its_cpu_init_lpis(void)
>         dsb(sy);
>  }
>
> -static void its_cpu_init_collection(void)
> +static void its_cpu_init_collection(struct its_node *its)
>  {
> -       struct its_node *its;
> -       int cpu;
> -
> -       spin_lock(&its_lock);
> -       cpu = smp_processor_id();
> -
> -       list_for_each_entry(its, &its_nodes, entry) {
> -               u64 target;
> +       int cpu = smp_processor_id();
> +       u64 target;
>
> -               /* avoid cross node collections and its mapping */
> -               if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) {
> -                       struct device_node *cpu_node;
> +       /* avoid cross node collections and its mapping */
> +       if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) {
> +               struct device_node *cpu_node;
>
> -                       cpu_node = of_get_cpu_node(cpu, NULL);
> -                       if (its->numa_node != NUMA_NO_NODE &&
> -                               its->numa_node != of_node_to_nid(cpu_node))
> -                               continue;
> -               }
> +               cpu_node = of_get_cpu_node(cpu, NULL);
> +               if (its->numa_node != NUMA_NO_NODE &&
> +                       its->numa_node != of_node_to_nid(cpu_node))
> +                       return;
> +       }
>
> +       /*
> +        * We now have to bind each collection to its target
> +        * redistributor.
> +        */
> +       if (gic_read_typer(its->base + GITS_TYPER) & GITS_TYPER_PTA) {
>                 /*
> -                * We now have to bind each collection to its target
> +                * This ITS wants the physical address of the
>                  * redistributor.
>                  */
> -               if (gic_read_typer(its->base + GITS_TYPER) & GITS_TYPER_PTA) {
> -                       /*
> -                        * This ITS wants the physical address of the
> -                        * redistributor.
> -                        */
> -                       target = gic_data_rdist()->phys_base;
> -               } else {
> -                       /*
> -                        * This ITS wants a linear CPU number.
> -                        */
> -                       target = gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER);
> -                       target = GICR_TYPER_CPU_NUMBER(target) << 16;
> -               }
> +               target = gic_data_rdist()->phys_base;
> +       } else {
> +               /* This ITS wants a linear CPU number. */
> +               target = gic_read_typer(gic_data_rdist_rd_base() + GICR_TYPER);
> +               target = GICR_TYPER_CPU_NUMBER(target) << 16;
> +       }
>
> -               /* Perform collection mapping */
> -               its->collections[cpu].target_address = target;
> -               its->collections[cpu].col_id = cpu;
> +       /* Perform collection mapping */
> +       its->collections[cpu].target_address = target;
> +       its->collections[cpu].col_id = cpu;
>
> -               its_send_mapc(its, &its->collections[cpu], 1);
> -               its_send_invall(its, &its->collections[cpu]);
> -       }
> +       its_send_mapc(its, &its->collections[cpu], 1);
> +       its_send_invall(its, &its->collections[cpu]);
> +}
> +
> +static void its_cpu_init_collections(void)
> +{
> +       struct its_node *its;
> +
> +       spin_lock(&its_lock);
> +
> +       list_for_each_entry(its, &its_nodes, entry)
> +               its_cpu_init_collection(its);
>
>         spin_unlock(&its_lock);
>  }
> @@ -2997,6 +2999,18 @@ static bool __maybe_unused its_enable_quirk_hip07_161600802(void *data)
>         return true;
>  }
>
> +static bool __maybe_unused its_enable_quirk_gic500_collections(void *data)
> +{
> +       struct its_node *its = data;
> +
> +       if (fwnode_property_present(its->fwnode_handle,
> +                                   "collections-reset-on-suspend")) {
> +               its->flags |= ITS_FLAGS_WORKAROUND_GIC500_MAPC;
> +               return true;
> +       }
> +       return false;
> +}
> +
>  static const struct gic_quirk its_quirks[] = {
>  #ifdef CONFIG_CAVIUM_ERRATUM_22375
>         {
> @@ -3042,6 +3056,14 @@ static const struct gic_quirk its_quirks[] = {
>                 .mask   = 0xffffffff,
>                 .init   = its_enable_quirk_hip07_161600802,
>         },
> +#endif
> +#ifdef CONFIG_ARM_GIC500_COLLECTIONS_RESET
> +       {
> +               .desc   = "ITS: GIC-500 Collections Reset on Resume",
> +               .iidr   = 0x00000000,
> +               .mask   = 0xff000000,
> +               .init   = its_enable_quirk_gic500_collections,
> +       },
>  #endif
>         {
>         }
> @@ -3114,6 +3136,9 @@ static void its_restore_enable(void)
>                         }
>                         writel_relaxed(ctx->ctlr, base + GITS_CTLR);
>                 }

Can anyone from ARM indicate whether we need to wait for the ITS to
exit its Quiescent state before sending commands to it?

> +
> +               if (its->flags & ITS_FLAGS_WORKAROUND_GIC500_MAPC)
> +                       its_cpu_init_collection(its);
>         }
>         spin_unlock(&its_lock);
>  }
> @@ -3380,7 +3405,7 @@ int its_cpu_init(void)
>                         return -ENXIO;
>                 }
>                 its_cpu_init_lpis();
> -               its_cpu_init_collection();
> +               its_cpu_init_collections();
>         }
>
>         return 0;
> --
> 2.16.0.rc1.238.g530d649a79-goog
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v3 2/5] irqchip/gic-v3-its: add ability to save/restore ITS state
  2018-01-30  1:00 ` [PATCH v3 2/5] irqchip/gic-v3-its: add ability to save/restore ITS state Derek Basehore
@ 2018-02-01 22:54   ` dbasehore .
  0 siblings, 0 replies; 8+ messages in thread
From: dbasehore . @ 2018-02-01 22:54 UTC (permalink / raw)
  To: linux-kernel
  Cc: Soby Mathew, Sudeep Holla, devicetree, robh+dt, Mark Rutland,
	Linux-pm mailing list, Wysocki, Rafael J, Thomas Gleixner,
	Brian Norris, Marc Zyngier, Derek Basehore

On Mon, Jan 29, 2018 at 5:00 PM, Derek Basehore <dbasehore@chromium.org> wrote:
> Some platforms power off GIC logic in suspend, so we need to
> save/restore state. The distributor and redistributor registers need
> to be handled in platform code due to access permissions on those
> registers, but the ITS registers can be restored in the kernel.
>
> Signed-off-by: Derek Basehore <dbasehore@chromium.org>
> ---
>  drivers/irqchip/irq-gic-v3-its.c | 86 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 86 insertions(+)
>
> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
> index 06f025fd5726..759ede7048ed 100644
> --- a/drivers/irqchip/irq-gic-v3-its.c
> +++ b/drivers/irqchip/irq-gic-v3-its.c
> @@ -33,6 +33,7 @@
>  #include <linux/of_platform.h>
>  #include <linux/percpu.h>
>  #include <linux/slab.h>
> +#include <linux/syscore_ops.h>
>
>  #include <linux/irqchip.h>
>  #include <linux/irqchip/arm-gic-v3.h>
> @@ -46,6 +47,7 @@
>  #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING          (1ULL << 0)
>  #define ITS_FLAGS_WORKAROUND_CAVIUM_22375      (1ULL << 1)
>  #define ITS_FLAGS_WORKAROUND_CAVIUM_23144      (1ULL << 2)
> +#define ITS_FLAGS_SAVE_SUSPEND_STATE           (1ULL << 3)
>
>  #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING    (1 << 0)
>
> @@ -83,6 +85,15 @@ struct its_baser {
>         u32             psz;
>  };
>
> +/*
> + * Saved ITS state - this is where saved state for the ITS is stored
> + * when it's disabled during system suspend.
> + */
> +struct its_ctx {
> +       u64                     cbaser;
> +       u32                     ctlr;
> +};
> +
>  struct its_device;
>
>  /*
> @@ -101,6 +112,7 @@ struct its_node {
>         struct its_collection   *collections;
>         struct fwnode_handle    *fwnode_handle;
>         u64                     (*get_msi_base)(struct its_device *its_dev);
> +       struct its_ctx          its_ctx;
>         struct list_head        its_device_list;
>         u64                     flags;
>         unsigned long           list_nr;
> @@ -3042,6 +3054,75 @@ static void its_enable_quirks(struct its_node *its)
>         gic_enable_quirks(iidr, its_quirks, its);
>  }
>
> +static int its_save_disable(void)
> +{
> +       struct its_node *its;
> +       int err = 0;
> +
> +       spin_lock(&its_lock);
> +       list_for_each_entry(its, &its_nodes, entry) {
> +               if (its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE) {
> +                       struct its_ctx *ctx = &its->its_ctx;
> +                       void __iomem *base = its->base;
> +
> +                       ctx->ctlr = readl_relaxed(base + GITS_CTLR);
> +                       err = its_force_quiescent(base);
> +                       if (err) {
> +                               pr_err("ITS failed to quiesce\n");
> +                               writel_relaxed(ctx->ctlr, base + GITS_CTLR);
> +                               goto err;
> +                       }
> +
> +                       ctx->cbaser = gits_read_cbaser(base + GITS_CBASER);
> +               }
> +       }
> +
> +err:
> +       if (err) {
> +               list_for_each_entry_continue_reverse(its, &its_nodes, entry) {
> +                       if (its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE) {
> +                               struct its_ctx *ctx = &its->its_ctx;
> +                               void __iomem *base = its->base;
> +
> +                               writel_relaxed(ctx->ctlr, base + GITS_CTLR);
> +                       }
> +               }
> +       }
> +
> +       spin_unlock(&its_lock);
> +
> +       return err;
> +}
> +
> +static void its_restore_enable(void)
> +{
> +       struct its_node *its;
> +
> +       spin_lock(&its_lock);
> +       list_for_each_entry(its, &its_nodes, entry) {
> +               if (its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE) {
> +                       struct its_ctx *ctx = &its->its_ctx;
> +                       void __iomem *base = its->base;
> +                       struct its_baser *baser;
> +                       int i;
> +
> +                       gits_write_cbaser(ctx->cbaser, base + GITS_CBASER);
> +                       /* Restore GITS_BASER from the value cache. */
> +                       for (i = 0; i < GITS_BASER_NR_REGS; i++) {
> +                               baser = &its->tables[i];
> +                               its_write_baser(its, baser, baser->val);
> +                       }

It seems that we need to resolve its->cmd_write with the current state
of GITS_CREADR and GITS_CWRITER. Otherwise, the code that detects the
ITS getting wedged will trigger.

> +                       writel_relaxed(ctx->ctlr, base + GITS_CTLR);
> +               }
> +       }
> +       spin_unlock(&its_lock);
> +}
> +
> +static struct syscore_ops its_syscore_ops = {
> +       .suspend = its_save_disable,
> +       .resume = its_restore_enable,
> +};
> +
>  static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
>  {
>         struct irq_domain *inner_domain;
> @@ -3261,6 +3342,9 @@ static int __init its_probe_one(struct resource *res,
>                 ctlr |= GITS_CTLR_ImDe;
>         writel_relaxed(ctlr, its->base + GITS_CTLR);
>
> +       if (fwnode_property_present(handle, "reset-on-suspend"))
> +               its->flags |= ITS_FLAGS_SAVE_SUSPEND_STATE;
> +
>         err = its_init_domain(handle, its);
>         if (err)
>                 goto out_free_tables;
> @@ -3515,5 +3599,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
>                 }
>         }
>
> +       register_syscore_ops(&its_syscore_ops);
> +
>         return 0;
>  }
> --
> 2.16.0.rc1.238.g530d649a79-goog
>

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

end of thread, other threads:[~2018-02-01 22:54 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-30  1:00 [PATCH v3 0/5] GICv3 Save and Restore Derek Basehore
2018-01-30  1:00 ` [PATCH v3 1/5] cpu_pm: add syscore_suspend error handling Derek Basehore
2018-01-30  1:00 ` [PATCH v3 2/5] irqchip/gic-v3-its: add ability to save/restore ITS state Derek Basehore
2018-02-01 22:54   ` dbasehore .
     [not found] ` <20180130010007.256564-1-dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2018-01-30  1:00   ` [PATCH v3 3/5] DT/arm,gic-v3-its: add reset-on-suspend property Derek Basehore
2018-01-30  1:00 ` [PATCH v3 4/5] irqchip/gic-v3-its: add ability to resend MAPC on resume Derek Basehore
     [not found]   ` <20180130010007.256564-5-dbasehore-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2018-02-01 22:52     ` dbasehore .
2018-01-30  1:00 ` [PATCH v3 5/5] DT/arm,gic-v3: add collections-reset-on-suspend property Derek Basehore

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