Skip to contentSkip to conversation

ARM: mvebu: Hardware coherency support for Armada 375 and 38x

PATCH New Thomas Petazzoni 3 participants 16 messages Mar 6, 2014 – Mar 25, 2014

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

cover ARM: mvebu: Hardware coherency support for Armada 375 and 38x

Jason, Gregory, Andrew, Sebastian,

This set of patches add hardware coherency support for the new Armada 375 and Armada 38x SoCs. The patch set can be divided in three sections:

* Patches 1, 2, 3 and 4 prepare the introduction of the support for new SoC in the existing coherency code.

The main change is that the mvebu-mbus driver no longer pokes into the Device Tree to find whether hardware I/O coherency is available or not: this information is passed as argument to the mvebu-mbus initialization function. This avoids changing the mvebu-mbus driver to add the compatible strings of all possible coherency fabrics, and also avoids encoding specific conditions in the mvebu-mbus
driver: on Armada 375 and 38x, the hardware I/O coherency can only be enabled in SMP mode.

These preparation patches had already been sent in the past
(http://permalink.gmane.org/gmane.linux.ports.arm.kernel/290780). This round has taken into account the comments I had received on this early version.

* Patches 5, 6, 7 and 8 add the coherency support itself. Patch 4 enables the SCU, patch 5 adds I/O coherency support for 375, patch 6 adds a major workaround to make coherency support actually work on early 375 SOCs and patch 7 adds I/O coherency support for 38x.

* Patches 9 and 10 add the necessary Device Tree informations to enable the coherency.

Best regards,

Thomas

Thomas Petazzoni (10):
ARM: mvebu: prepare coherency code to support more SOCs
ARM: mvebu: add a coherency_available() call
bus: mvebu: pass the coherency availability information at init time
ARM: mvebu: ARM: mvebu: use of_find_matching_node_and_match() in
coherency.c
ARM: mvebu: enable the ARM SCU on Armada 375 and Armada 38x
ARM: mvebu: add Armada 375 support to the coherency code
ARM: mvebu: implement Armada 375 coherency workaround
ARM: mvebu: add Armada 38x support to the coherency code
ARM: mvebu: enable the coherency fabric on Armada 375
ARM: mvebu: enable the coherency fabric on Armada 38x

 .../devicetree/bindings/arm/coherency-fabric.txt   |  32 ++-
 arch/arm/boot/dts/armada-375.dtsi                  |  10 +
 arch/arm/boot/dts/armada-38x.dtsi                  |  10 +
 arch/arm/mach-kirkwood/board-dt.c                  |   2 +-
 arch/arm/mach-mvebu/Kconfig                        |   2 +
 arch/arm/mach-mvebu/board-v7.c                     |  21 +-
 arch/arm/mach-mvebu/coherency.c                    | 251 +++++++++++++++++++--
 arch/arm/mach-mvebu/coherency.h                    |   1 +
 drivers/bus/mvebu-mbus.c                           |  11 +-
 include/linux/mbus.h                               |   2 +-
 10 files changed, 305 insertions(+), 37 deletions(-)
Signature · 1 line
1.8.3.2
#1 lore raw

PATCH 1/10 ARM: mvebu: prepare coherency code to support more SOCs

The code that handles the coherency fabric of Armada 370 and Armada XP in arch/arm/mach-mvebu/coherency.c made the assumption that there was only one type of coherency fabric. Unfortunately, it turns out that upcoming SoCs have a slightly different coherency unit.

In preparation to the introduction of the coherency support for more SoCs, this commit:

* Introduces a data associated to the compatible string in the compatible string match table, so that the code can differantiate the variant of coherency unit being used.

* Separates the coherency unit initialization code into its own function.

---
 .../devicetree/bindings/arm/coherency-fabric.txt   |  5 ++-
 arch/arm/mach-mvebu/coherency.c                    | 46 +++++++++++++++-------
 2 files changed, 36 insertions(+), 15 deletions(-)
Documentation/devicetree/bindings/arm/coherency-fabric.txt +4 -1
index 17d8cd1..f0bfa37 100644
@@ -4,7 +4,10 @@ Available on Marvell SOCs: Armada 370 and Armada XP
 
 Required properties:
 
-- compatible: "marvell,coherency-fabric"
+- compatible: the possible values are:
+
+ * "marvell,coherency-fabric", to be used for the coherency fabric of
+   the Armada 370 and Armada XP.
 
 - reg: Should contain coherency fabric registers location and
   length. First pair for the coherency fabric registers, second pair
arch/arm/mach-mvebu/coherency.c +32 -14

66 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#2 lore raw

PATCH 2/10 ARM: mvebu: add a coherency_available() call

In reply to Thomas Petazzoni

This commit extends the coherency fabric code to provide a coherency_available()function that the SoC code can call to be told whether coherency support is available or not. On Armada 370/XP, coherency support is available as soon as the relevant DT node is present. On some upcoming SoCs, the DT node needs to be present *and* the system running with CONFIG_SMP enabled.

---
 arch/arm/mach-mvebu/coherency.c | 30 +++++++++++++++++++++++-------
 arch/arm/mach-mvebu/coherency.h |  1 +
 2 files changed, 24 insertions(+), 7 deletions(-)
arch/arm/mach-mvebu/coherency.c +23 -7
index 72d8d75..0c440c3 100644
@@ -39,6 +39,7 @@ static void __iomem *coherency_cpu_base;
 #define IO_SYNC_BARRIER_CTL_OFFSET		   0x0
 
 enum {
+	COHERENCY_FABRIC_TYPE_NONE,
 	COHERENCY_FABRIC_TYPE_ARMADA_370_XP,
 };
 
@@ -143,7 +144,7 @@ static void __init armada_370_coherency_init(struct device_node *np)
 	set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
 }
 
-int __init coherency_init(void)
+static int coherency_type(void)
 {
 	struct device_node *np;
 
@@ -154,27 +155,42 @@ int __init coherency_init(void)
 		int type;
 
 		type = (int) match->data;
+
 		pr_info("Initializing Coherency fabric\n");
 
+		/* Armada 370/XP coherency works in both UP and SMP */
 		if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP)
-			armada_370_coherency_init(np);
+			return type;
 
 		of_node_put(np);
 	}
 
-	return 0;
+	return COHERENCY_FABRIC_TYPE_NONE;
 }
 
-static int __init coherency_late_init(void)
+int coherency_available(void)
 {
+	return coherency_type() != COHERENCY_FABRIC_TYPE_NONE;
+}
+
+int __init coherency_init(void)
+{
+	int type = coherency_type();
 	struct device_node *np;
 
 	np = of_find_matching_node(NULL, of_coherency_table);
-	if (np) {
+
+	if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP)
+		armada_370_coherency_init(np);
+
+	return 0;
+}
+
+static int __init coherency_late_init(void)
+{
+	if (coherency_available())
 		bus_register_notifier(&platform_bus_type,
 				      &mvebu_hwcc_platform_nb);
-		of_node_put(np);
-	}
 	return 0;
 }
 
arch/arm/mach-mvebu/coherency.h +1 -0
index 760226c..02f7ec3 100644
@@ -18,5 +18,6 @@ extern unsigned long coherency_phys_base;
 
 int set_cpu_coherent(unsigned int cpu_id, int smp_group_id);
 int coherency_init(void);
+int coherency_available(void);
 
 #endif	/* __MACH_370_XP_COHERENCY_H */
Signature · 1 line
1.8.3.2
#3 lore raw

PATCH 3/10 bus: mvebu: pass the coherency availability information at init time

In reply to Thomas Petazzoni

Until now, the mvebu-mbus was guessing by itself whether hardware I/O coherency was available or not by poking into the Device Tree to see if the coherency fabric Device Tree node was present or not.

However, on some upcoming SoCs, the presence or absence of the coherency fabric DT node isn't sufficient: in CONFIG_SMP, the coherency can be enabled, but not in !CONFIG_SMP.

In order to clean this up, the mvebu_mbus_dt_init() function is extended to get a boolean argument telling whether coherency is enabled or not. Therefore, the logic to decide whether coherency is available or not now belongs to the core SoC code instead of the mvebu-mbus driver itself, which is much better.

---
 arch/arm/mach-kirkwood/board-dt.c |  2 +-
 arch/arm/mach-mvebu/board-v7.c    |  2 +-
 drivers/bus/mvebu-mbus.c          | 11 +++--------
 include/linux/mbus.h              |  2 +-
 4 files changed, 6 insertions(+), 11 deletions(-)
arch/arm/mach-kirkwood/board-dt.c +1 -1
index 7818815..79e629d 100644
@@ -116,7 +116,7 @@ static void __init kirkwood_dt_init(void)
 	 */
 	writel(readl(CPU_CONFIG) & ~CPU_CONFIG_ERROR_PROP, CPU_CONFIG);
 
-	BUG_ON(mvebu_mbus_dt_init());
+	BUG_ON(mvebu_mbus_dt_init(false));
 
 	kirkwood_l2_init();
 
arch/arm/mach-mvebu/board-v7.c +1 -1
index 95ca216..e5d4f69 100644
@@ -62,7 +62,7 @@ static void __init mvebu_timer_and_clk_init(void)
 	of_clk_init(NULL);
 	clocksource_of_init();
 	coherency_init();
-	BUG_ON(mvebu_mbus_dt_init());
+	BUG_ON(mvebu_mbus_dt_init(coherency_available()));
 #ifdef CONFIG_CACHE_L2X0
 	l2x0_of_init(0, ~0UL);
 #endif
drivers/bus/mvebu-mbus.c +3 -8
index 725c461..67710b8 100644
@@ -694,7 +694,6 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
 					 phys_addr_t sdramwins_phys_base,
 					 size_t sdramwins_size)
 {
-	struct device_node *np;
 	int win;
 
 	mbus->mbuswins_base = ioremap(mbuswins_phys_base, mbuswins_size);
@@ -707,12 +706,6 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
 		return -ENOMEM;
 	}
 
-	np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
-	if (np) {
-		mbus->hw_io_coherency = 1;
-		of_node_put(np);
-	}
-
 	for (win = 0; win < mbus->soc->num_wins; win++)
 		mvebu_mbus_disable_window(mbus, win);
 
@@ -882,7 +875,7 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np,
 	}
 }
 
-int __init mvebu_mbus_dt_init(void)
+int __init mvebu_mbus_dt_init(bool is_coherent)
 {
 	struct resource mbuswins_res, sdramwins_res;
 	struct device_node *np, *controller;
@@ -921,6 +914,8 @@ int __init mvebu_mbus_dt_init(void)
 		return -EINVAL;
 	}
 
+	mbus_state.hw_io_coherency = is_coherent;
+
 	/* Get optional pcie-{mem,io}-aperture properties */
 	mvebu_mbus_get_pcie_resources(np, &mbus_state.pcie_mem_aperture,
 					  &mbus_state.pcie_io_aperture);
include/linux/mbus.h +1 -1
index 345b8c5..550c88f 100644
@@ -73,6 +73,6 @@ int mvebu_mbus_del_window(phys_addr_t base, size_t size);
 int mvebu_mbus_init(const char *soc, phys_addr_t mbus_phys_base,
 		    size_t mbus_size, phys_addr_t sdram_phys_base,
 		    size_t sdram_size);
-int mvebu_mbus_dt_init(void);
+int mvebu_mbus_dt_init(bool is_coherent);
 
 #endif /* __LINUX_MBUS_H */
Signature · 1 line
1.8.3.2
#4 lore raw

PATCH 4/10 ARM: mvebu: ARM: mvebu: use of_find_matching_node_and_match() in coherency.c

In reply to Thomas Petazzoni

In the mach-mvebu coherency code, instead of using of_find_matching_node() and then of_match_node(), directly use the of_find_matching_node_and_match() which does both at once.

We take this opportunity to also simplify the initialization of the "type" variable.

---
 arch/arm/mach-mvebu/coherency.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
arch/arm/mach-mvebu/coherency.c +3 -6
index 0c440c3..15b769d 100644
@@ -147,14 +147,11 @@ static void __init armada_370_coherency_init(struct device_node *np)
 static int coherency_type(void)
 {
 	struct device_node *np;
+	const struct of_device_id *match;
 
-	np = of_find_matching_node(NULL, of_coherency_table);
+	np = of_find_matching_node_and_match(NULL, of_coherency_table, &match);
 	if (np) {
-                const struct of_device_id *match =
-                    of_match_node(of_coherency_table, np);
-		int type;
-
-		type = (int) match->data;
+		int type = (int) match->data;
 
 		pr_info("Initializing Coherency fabric\n");
 
Signature · 1 line
1.8.3.2
#5 lore raw

PATCH 5/10 ARM: mvebu: enable the ARM SCU on Armada 375 and Armada 38x

In reply to Thomas Petazzoni

Contrary to the Armada 370 and XP that used the PJ4B Marvell cores, the Armada 375 and Armada 38x use the ARM Cortex-A9. A consequence of this is that the unit responsible for the coherency between CPUs is now the ARM SCU, and not the Marvell coherency unit (which is still present to do coherency with I/O devices).

Therefore this commit:

* Ensures that the selection of the Armada 375 or Armada 38x SoC support enables the ARM SCU support in the kernel.

* Make sure to initialize the SCU at boot time.

---
 arch/arm/mach-mvebu/Kconfig    |  2 ++
 arch/arm/mach-mvebu/board-v7.c | 19 +++++++++++++++++++
 2 files changed, 21 insertions(+)
arch/arm/mach-mvebu/Kconfig +2 -0
index 884b275a..8634222 100644
@@ -44,6 +44,7 @@ config MACH_ARMADA_375
 	select ARM_GIC
 	select ARMADA_375_CLK
 	select CPU_V7
+	select HAVE_ARM_SCU
 	select MACH_MVEBU_V7
 	select NEON
 	select PINCTRL_ARMADA_375
@@ -58,6 +59,7 @@ config MACH_ARMADA_38X
 	select ARM_GIC
 	select ARMADA_38X_CLK
 	select CPU_V7
+	select HAVE_ARM_SCU
 	select MACH_MVEBU_V7
 	select NEON
 	select PINCTRL_ARMADA_38X
arch/arm/mach-mvebu/board-v7.c +19 -0
index e5d4f69..256e6f6 100644
@@ -26,6 +26,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
+#include <asm/smp_scu.h>
 #include "armada-370-xp.h"
 #include "common.h"
 #include "coherency.h"
@@ -37,6 +38,23 @@ static void __init mvebu_map_io(void)
 }
 
 /*
+ * Enables the SCU when available. Obviously, this is only useful on
+ * Cortex-A based SOCs, not on PJ4B based ones.
+ */
+static void __init mvebu_scu_enable(void)
+{
+	void __iomem *scu_base;
+
+	struct device_node *np =
+		of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
+	if (np) {
+		scu_base = of_iomap(np, 0);
+		scu_enable(scu_base);
+		of_node_put(np);
+	}
+}
+
+/*
  * Early versions of Armada 375 SoC have a bug where the BootROM
  * leaves an external data abort pending. The kernel is hit by this
  * data abort as soon as it enters userspace, because it unmasks the
@@ -61,6 +79,7 @@ static void __init mvebu_timer_and_clk_init(void)
 {
 	of_clk_init(NULL);
 	clocksource_of_init();
+	mvebu_scu_enable();
 	coherency_init();
 	BUG_ON(mvebu_mbus_dt_init(coherency_available()));
 #ifdef CONFIG_CACHE_L2X0
Signature · 1 line
1.8.3.2
#6 lore raw

PATCH 6/10 ARM: mvebu: add Armada 375 support to the coherency code

In reply to Thomas Petazzoni

The Armada 375, like the Armada 370 and Armada XP, has a coherency unit. However, unlike the coherency unit of 370/XP which does both CPU and I/O coherency, the one on Armada 735 only does I/O coherency. Therefore, instead of having two sets of registers (the first one being used mainly to register each CPU in the coherency fabric, the second one being used for the I/O coherency barrier), it has only one set of register (for the I/O coherency barrier).

This commit adds a new "marvell,armada-375-coherency-fabric" compatible string for this variant of the coherency fabric. The custom DMA operations, and the way of triggering an I/O barrier is the same as Armada 370/XP, so the code changes are minimal. However, the set_cpu_coherent() function is not needed on Armada 375 and will not work.

---
 .../devicetree/bindings/arm/coherency-fabric.txt   | 22 ++++++++++++++++++----
 arch/arm/mach-mvebu/coherency.c                    | 14 ++++++++++++++
 2 files changed, 32 insertions(+), 4 deletions(-)
Documentation/devicetree/bindings/arm/coherency-fabric.txt +18 -4
index f0bfa37..dcd80d6 100644
@@ -1,6 +1,6 @@
 Coherency fabric
 ----------------
-Available on Marvell SOCs: Armada 370 and Armada XP
+Available on Marvell SOCs: Armada 370, Armada 375 and Armada XP
 
 Required properties:
 
@@ -9,11 +9,20 @@ Required properties:
  * "marvell,coherency-fabric", to be used for the coherency fabric of
    the Armada 370 and Armada XP.
 
+ * "marvell,armada-375-coherency-fabric", for the Armada 375 coherency
+   fabric.
+
 - reg: Should contain coherency fabric registers location and
-  length. First pair for the coherency fabric registers, second pair
-  for the per-CPU fabric registers registers.
+  length.
+
+ * For "marvell,coherency-fabric", the first pair for the coherency
+   fabric registers, second pair for the per-CPU fabric registers.
+
+ * For "marvell,armada-375-coherency-fabric", only one pair is needed
+   for the per-CPU fabric registers.
 
-Example:
+
+Examples:
 
 coherency-fabric at d0020200 {
 	compatible = "marvell,coherency-fabric";
@@ -22,3 +31,8 @@ coherency-fabric at d0020200 {
 
 };
 
+coherency-fabric at 21810 {
+	compatible = "marvell,armada-375-coherency-fabric";
+	reg = <0x21810 0x1c>;
+};
+
arch/arm/mach-mvebu/coherency.c +14 -0
index 15b769d..f63c868 100644
@@ -41,11 +41,14 @@ static void __iomem *coherency_cpu_base;
 enum {
 	COHERENCY_FABRIC_TYPE_NONE,
 	COHERENCY_FABRIC_TYPE_ARMADA_370_XP,
+	COHERENCY_FABRIC_TYPE_ARMADA_375,
 };
 
 static struct of_device_id of_coherency_table[] = {
 	{.compatible = "marvell,coherency-fabric",
 	 .data = (void*) COHERENCY_FABRIC_TYPE_ARMADA_370_XP },
+	{.compatible = "marvell,armada-375-coherency-fabric",
+	 .data = (void*) COHERENCY_FABRIC_TYPE_ARMADA_375 },
 	{ /* end of list */ },
 };
 
@@ -144,6 +147,11 @@ static void __init armada_370_coherency_init(struct device_node *np)
 	set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
 }
 
+static void __init armada_375_coherency_init(struct device_node *np)
+{
+	coherency_cpu_base = of_iomap(np, 0);
+}
+
 static int coherency_type(void)
 {
 	struct device_node *np;
@@ -159,6 +167,10 @@ static int coherency_type(void)
 		if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP)
 			return type;
 
+		/* Armada 375 coherency works only on SMP */
+		else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp())
+			return type;
+
 		of_node_put(np);
 	}
 
@@ -179,6 +191,8 @@ int __init coherency_init(void)
 
 	if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP)
 		armada_370_coherency_init(np);
+	else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375)
+		armada_375_coherency_init(np);
 
 	return 0;
 }
Signature · 1 line
1.8.3.2
#7 lore raw

PATCH 7/10 ARM: mvebu: implement Armada 375 coherency workaround

In reply to Thomas Petazzoni

The early revisions of Armada 375 SOCs (Z1 stepping) have a bug in the I/O coherency unit that prevents using the normal method for the I/O coherency barrier. The recommended workaround is to use a XOR memset transfer to act as the I/O coherency barrier.

This involves "borrowing" a XOR engine, which gets disabled in the Device Tree so the normal XOR driver doesn't use it. Note also that the mvebu-mbus driver must be initialized prior to the coherency unit, because the DRAM windows of the XOR engine must be configured during the coherency unit initialization, due to this workaround.

---
 arch/arm/mach-mvebu/board-v7.c  |   2 +-
 arch/arm/mach-mvebu/coherency.c | 150 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 151 insertions(+), 1 deletion(-)
arch/arm/mach-mvebu/board-v7.c +1 -1
index 256e6f6..6260cb8 100644
@@ -80,8 +80,8 @@ static void __init mvebu_timer_and_clk_init(void)
 	of_clk_init(NULL);
 	clocksource_of_init();
 	mvebu_scu_enable();
-	coherency_init();
 	BUG_ON(mvebu_mbus_dt_init(coherency_available()));
+	coherency_init();
 #ifdef CONFIG_CACHE_L2X0
 	l2x0_of_init(0, ~0UL);
 #endif
arch/arm/mach-mvebu/coherency.c +150 -0

170 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#8 lore raw

PATCH 7/10 ARM: mvebu: implement Armada 375 coherency workaround

Thomas,

Quoted 1 line · Thomas Petazzoni

The early revisions of Armada 375 SOCs (Z1 stepping) have a bug in the

Do we have a way to determine that we are on a Z1 at runtime? It seems like we're consuming an XOR engine unconditionally. I presume that Marvell is going to fix this with the next stepping?

thx,

Jason.

Quoted 210 lines

I/O coherency unit that prevents using the normal method for the I/O coherency barrier. The recommended workaround is to use a XOR memset transfer to act as the I/O coherency barrier.

This involves "borrowing" a XOR engine, which gets disabled in the Device Tree so the normal XOR driver doesn't use it. Note also that the mvebu-mbus driver must be initialized prior to the coherency unit, because the DRAM windows of the XOR engine must be configured during the coherency unit initialization, due to this workaround.

---
 arch/arm/mach-mvebu/board-v7.c  |   2 +-
 arch/arm/mach-mvebu/coherency.c | 150 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 151 insertions(+), 1 deletion(-)
arch/arm/mach-mvebu/board-v7.c +1 -1
index 256e6f6..6260cb8 100644
@@ -80,8 +80,8 @@ static void __init mvebu_timer_and_clk_init(void)
 	of_clk_init(NULL);
 	clocksource_of_init();
 	mvebu_scu_enable();
-	coherency_init();
 	BUG_ON(mvebu_mbus_dt_init(coherency_available()));
+	coherency_init();
 #ifdef CONFIG_CACHE_L2X0
 	l2x0_of_init(0, ~0UL);
 #endif
arch/arm/mach-mvebu/coherency.c +150 -0
index f63c868..73d56f2 100644
@@ -24,6 +24,9 @@
 #include <linux/smp.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mbus.h>
+#include <linux/clk.h>
 #include <asm/smp_plat.h>
 #include <asm/cacheflush.h>
 #include "armada-370-xp.h"
@@ -66,8 +69,154 @@ int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id)
 	return ll_set_cpu_coherent(coherency_base, hw_cpu_id);
 }
 
+/*
+ * The below code implements the I/O coherency workaround on Armada
+ * 375. This workaround consists in using the two channels of the
+ * first XOR engine to trigger a XOR transaction that serves as the
+ * I/O coherency barrier.
+ */
+
+static void __iomem *xor_base, *xor_high_base;
+static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS];
+static void *coherency_wa_buf[CONFIG_NR_CPUS];
+static bool coherency_wa_enabled;
+
+#define XOR_CONFIG(chan)            (0x10 + (chan * 4))
+#define XOR_ACTIVATION(chan)        (0x20 + (chan * 4))
+#define WINDOW_BAR_ENABLE(chan)     (0x240 + ((chan) << 2))
+#define WINDOW_BASE(w)              (0x250 + ((w) << 2))
+#define WINDOW_SIZE(w)              (0x270 + ((w) << 2))
+#define WINDOW_REMAP_HIGH(w)        (0x290 + ((w) << 2))
+#define WINDOW_OVERRIDE_CTRL(chan)  (0x2A0 + ((chan) << 2))
+#define XOR_DEST_POINTER(chan)      (0x2B0 + (chan * 4))
+#define XOR_BLOCK_SIZE(chan)        (0x2C0 + (chan * 4))
+#define XOR_INIT_VALUE_LOW           0x2E0
+#define XOR_INIT_VALUE_HIGH          0x2E4
+
+static inline void mvebu_hwcc_armada375_sync_io_barrier_wa(void)
+{
+	int idx = smp_processor_id();
+
+	/* Write '1' to the first word of the buffer */
+	writel(0x1, coherency_wa_buf[idx]);
+
+	/* Wait until the engine is idle */
+	while ((readl(xor_base + XOR_ACTIVATION(idx)) >> 4) & 0x3)
+		;
+
+	dmb();
+
+	/* Trigger channel */
+	writel(0x1, xor_base + XOR_ACTIVATION(idx));
+
+	/* Poll the data until it is cleared by the XOR transaction */
+	while (readl(coherency_wa_buf[idx]))
+		;
+}
+
+static void __init armada_375_coherency_init_wa(void)
+{
+	const struct mbus_dram_target_info *dram;
+	struct device_node *xor_node;
+	struct property *xor_status;
+	struct clk *xor_clk;
+	u32 win_enable = 0;
+	int i;
+
+	/*
+	 * Since the workaround uses one XOR engine, we grab a
+	 * reference to its Device Tree node first.
+	 */
+	xor_node = of_find_compatible_node(NULL, NULL, "marvell,orion-xor");
+	BUG_ON(!xor_node);
+
+	/*
+	 * Then we mark it as disabled so that the real XOR driver
+	 * will not use it.
+	 */
+	xor_status = kzalloc(sizeof(struct property), GFP_KERNEL);
+	BUG_ON(!xor_status);
+
+	xor_status->value = kstrdup("disabled", GFP_KERNEL);
+	BUG_ON(!xor_status->value);
+
+	xor_status->length = 8;
+	xor_status->name = kstrdup("status", GFP_KERNEL);
+	BUG_ON(!xor_status->name);
+
+	of_update_property(xor_node, xor_status);
+
+	/*
+	 * And we remap the registers, get the clock, and do the
+	 * initial configuration of the XOR engine.
+	 */
+	xor_base = of_iomap(xor_node, 0);
+	xor_high_base = of_iomap(xor_node, 1);
+
+	xor_clk = of_clk_get_by_name(xor_node, NULL);
+	BUG_ON(!xor_clk);
+
+	clk_prepare_enable(xor_clk);
+
+	dram = mv_mbus_dram_info();
+
+	for (i = 0; i < 8; i++) {
+		writel(0, xor_base + WINDOW_BASE(i));
+		writel(0, xor_base + WINDOW_SIZE(i));
+		if (i < 4)
+			writel(0, xor_base + WINDOW_REMAP_HIGH(i));
+	}
+
+	for (i = 0; i < dram->num_cs; i++) {
+		const struct mbus_dram_window *cs = dram->cs + i;
+		writel((cs->base & 0xffff0000) |
+		       (cs->mbus_attr << 8) |
+		       dram->mbus_dram_target_id, xor_base + WINDOW_BASE(i));
+		writel((cs->size - 1) & 0xffff0000, xor_base + WINDOW_SIZE(i));
+
+		win_enable |= (1 << i);
+		win_enable |= 3 << (16 + (2 * i));
+	}
+
+	writel(win_enable, xor_base + WINDOW_BAR_ENABLE(0));
+	writel(win_enable, xor_base + WINDOW_BAR_ENABLE(1));
+	writel(0, xor_base + WINDOW_OVERRIDE_CTRL(0));
+	writel(0, xor_base + WINDOW_OVERRIDE_CTRL(1));
+
+	for (i = 0; i < CONFIG_NR_CPUS; i++) {
+		coherency_wa_buf[i] = kzalloc(PAGE_SIZE, GFP_KERNEL);
+		BUG_ON(!coherency_wa_buf[i]);
+
+		/*
+		 * We can't use the DMA mapping API, since we don't
+		 * have a valid 'struct device' pointer
+		 */
+		coherency_wa_buf_phys[i] =
+			virt_to_phys(coherency_wa_buf[i]);
+		BUG_ON(!coherency_wa_buf_phys[i]);
+
+		/*
+		 * Configure the XOR engine for memset operation, with
+		 * a 128 bytes block size
+		 */
+		writel(0x444, xor_base + XOR_CONFIG(i));
+		writel(128, xor_base + XOR_BLOCK_SIZE(i));
+		writel(coherency_wa_buf_phys[i], xor_base + XOR_DEST_POINTER(i));
+	}
+
+	writel(0x0, xor_base + XOR_INIT_VALUE_LOW);
+	writel(0x0, xor_base + XOR_INIT_VALUE_HIGH);
+
+	coherency_wa_enabled = true;
+}
+
 static inline void mvebu_hwcc_sync_io_barrier(void)
 {
+	if (coherency_wa_enabled) {
+		mvebu_hwcc_armada375_sync_io_barrier_wa();
+		return;
+	}
+
 	writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
 	while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
 }
@@ -150,6 +299,7 @@ static void __init armada_370_coherency_init(struct device_node *np)
 static void __init armada_375_coherency_init(struct device_node *np)
 {
 	coherency_cpu_base = of_iomap(np, 0);
+	armada_375_coherency_init_wa();
 }
 
 static int coherency_type(void)
Signature · 1 line
1.8.3.2
#9 lore raw

PATCH 7/10 ARM: mvebu: implement Armada 375 coherency workaround

Dear Jason Cooper,

Quoted 6 lines · Jason Cooper
Quoted 1 line · Thomas Petazzoni

The early revisions of Armada 375 SOCs (Z1 stepping) have a bug in the

Do we have a way to determine that we are on a Z1 at runtime? It seems like we're consuming an XOR engine unconditionally. I presume that Marvell is going to fix this with the next stepping?

Yes, we believe there will be a way to differentiate the Z1 stepping for the later steppings, using the mvebu-soc-id. However, since those later steppings are not available yet, we haven't been able to test this. Our plan is that as soon as we have newer steppings, we will improve this code to only apply the XOR workaround on the steppings for which it is needed. It is not clear at this point which stepping exactly will fix the problem, so we've written the code with the information that we have today.

Thanks for the feedback!

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
#10 lore raw

PATCH 8/10 ARM: mvebu: add Armada 38x support to the coherency code

In reply to Thomas Petazzoni

The Armada 38x has a coherency unit that is similar to the one of the Armada 375 SoC, except that it does not have the bug of the Armada 375 coherency unit that requires the XOR based workaround.

This commit therefore extends the Marvell EBU coherency code with a new compatible string to support the Armada 38x coherency unit.

---
 Documentation/devicetree/bindings/arm/coherency-fabric.txt |  7 ++++++-
 arch/arm/mach-mvebu/coherency.c                            | 14 ++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/arm/coherency-fabric.txt +6 -1
index dcd80d6..8dd4661 100644
@@ -1,6 +1,6 @@
 Coherency fabric
 ----------------
-Available on Marvell SOCs: Armada 370, Armada 375 and Armada XP
+Available on Marvell SOCs: Armada 370, Armada 375, Armada 38x and Armada XP
 
 Required properties:
 
@@ -12,6 +12,9 @@ Required properties:
  * "marvell,armada-375-coherency-fabric", for the Armada 375 coherency
    fabric.
 
+ * "marvell,armada-380-coherency-fabric", for the Armada 38x coherency
+   fabric.
+
 - reg: Should contain coherency fabric registers location and
   length.
 
@@ -21,6 +24,8 @@ Required properties:
  * For "marvell,armada-375-coherency-fabric", only one pair is needed
    for the per-CPU fabric registers.
 
+ * For "marvell,armada-380-coherency-fabric", only one pair is needed
+   for the per-CPU fabric registers.
 
 Examples:
 
arch/arm/mach-mvebu/coherency.c +14 -0
index 73d56f2..1a54907 100644
@@ -45,6 +45,7 @@ enum {
 	COHERENCY_FABRIC_TYPE_NONE,
 	COHERENCY_FABRIC_TYPE_ARMADA_370_XP,
 	COHERENCY_FABRIC_TYPE_ARMADA_375,
+	COHERENCY_FABRIC_TYPE_ARMADA_380,
 };
 
 static struct of_device_id of_coherency_table[] = {
@@ -52,6 +53,8 @@ static struct of_device_id of_coherency_table[] = {
 	 .data = (void*) COHERENCY_FABRIC_TYPE_ARMADA_370_XP },
 	{.compatible = "marvell,armada-375-coherency-fabric",
 	 .data = (void*) COHERENCY_FABRIC_TYPE_ARMADA_375 },
+	{.compatible = "marvell,armada-380-coherency-fabric",
+	 .data = (void*) COHERENCY_FABRIC_TYPE_ARMADA_380 },
 	{ /* end of list */ },
 };
 
@@ -302,6 +305,11 @@ static void __init armada_375_coherency_init(struct device_node *np)
 	armada_375_coherency_init_wa();
 }
 
+static void __init armada_380_coherency_init(struct device_node *np)
+{
+	coherency_cpu_base = of_iomap(np, 0);
+}
+
 static int coherency_type(void)
 {
 	struct device_node *np;
@@ -321,6 +329,10 @@ static int coherency_type(void)
 		else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp())
 			return type;
 
+		/* Armada 380 coherency works only on SMP */
+		else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380 && is_smp())
+			return type;
+
 		of_node_put(np);
 	}
 
@@ -343,6 +355,8 @@ int __init coherency_init(void)
 		armada_370_coherency_init(np);
 	else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375)
 		armada_375_coherency_init(np);
+	else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380)
+		armada_380_coherency_init(np);
 
 	return 0;
 }
Signature · 1 line
1.8.3.2
#11 lore raw

PATCH 9/10 ARM: mvebu: enable the coherency fabric on Armada 375

In reply to Thomas Petazzoni

This commit adds the necessary Device Tree information to enable the coherency fabric on Armada 375.

---
 arch/arm/boot/dts/armada-375.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)
arch/arm/boot/dts/armada-375.dtsi +10 -0
index 3877693..eceab89 100644
@@ -128,6 +128,11 @@
 				cache-level = <2>;
 			};
 
+			scu at c000 {
+				compatible = "arm,cortex-a9-scu";
+				reg = <0xc000 0x58>;
+			};
+
 			timer at c600 {
 				compatible = "arm,cortex-a9-twd-timer";
 				reg = <0xc600 0x20>;
@@ -320,6 +325,11 @@
 				clocks = <&coreclk 0>;
 			};
 
+			coherency-fabric at 21010 {
+				compatible = "marvell,armada-375-coherency-fabric";
+				reg = <0x21010 0x1c>;
+			};
+
 			xor at 60800 {
 				compatible = "marvell,orion-xor";
 				reg = <0x60800 0x100
Signature · 1 line
1.8.3.2
#12 lore raw

PATCH 10/10 ARM: mvebu: enable the coherency fabric on Armada 38x

In reply to Thomas Petazzoni

This commit adds the necessary Device Tree information to enable the coherency fabric on Armada 38x.

---
 arch/arm/boot/dts/armada-38x.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)
arch/arm/boot/dts/armada-38x.dtsi +10 -0
index 812ce28..2332b20 100644
@@ -108,6 +108,11 @@
 				cache-level = <2>;
 			};
 
+			scu at c000 {
+				compatible = "arm,cortex-a9-scu";
+				reg = <0xc000 0x58>;
+			};
+
 			timer at c600 {
 				compatible = "arm,cortex-a9-twd-timer";
 				reg = <0xc600 0x20>;
@@ -267,6 +272,11 @@
 				clock-names = "nbclk", "fixed";
 			};
 
+			coherency-fabric at 21010 {
+				compatible = "marvell,armada-380-coherency-fabric";
+				reg = <0x21010 0x1c>;
+			};
+
 			eth1: ethernet at 30000 {
 				compatible = "marvell,armada-370-neta";
 				reg = <0x30000 0x4000>;
Signature · 1 line
1.8.3.2
#13 lore raw

cover ARM: mvebu: Hardware coherency support for Armada 375 and 38x

In reply to Thomas Petazzoni

Jason, Gregory, Andrew, Sebastian,

Any news about this patch set? It is not aimed at 3.15 as was discussed already with Jason, but since I'd still like to have some early comments about this patch series for 3.16, since we would also like to land the Armada 375/38x SMP support in 3.16, which will sit on top of this series.

So far, Jason made one comment about runtime detecting the need for the Armada 375 coherency workaround, to which I already replied. No other comments have been made, unless I missed them, of course.

Thanks a lot!

Thomas

Quoted 60 lines · Thomas Petazzoni

Jason, Gregory, Andrew, Sebastian,

This set of patches add hardware coherency support for the new Armada 375 and Armada 38x SoCs. The patch set can be divided in three sections:

* Patches 1, 2, 3 and 4 prepare the introduction of the support for new SoC in the existing coherency code.

The main change is that the mvebu-mbus driver no longer pokes into the Device Tree to find whether hardware I/O coherency is available or not: this information is passed as argument to the mvebu-mbus initialization function. This avoids changing the mvebu-mbus driver to add the compatible strings of all possible coherency fabrics, and also avoids encoding specific conditions in the mvebu-mbus
driver: on Armada 375 and 38x, the hardware I/O coherency can only be enabled in SMP mode.

These preparation patches had already been sent in the past
(http://permalink.gmane.org/gmane.linux.ports.arm.kernel/290780). This round has taken into account the comments I had received on this early version.

* Patches 5, 6, 7 and 8 add the coherency support itself. Patch 4 enables the SCU, patch 5 adds I/O coherency support for 375, patch 6 adds a major workaround to make coherency support actually work on early 375 SOCs and patch 7 adds I/O coherency support for 38x.

* Patches 9 and 10 add the necessary Device Tree informations to enable the coherency.

Best regards,

Thomas

Thomas Petazzoni (10):
ARM: mvebu: prepare coherency code to support more SOCs
ARM: mvebu: add a coherency_available() call
bus: mvebu: pass the coherency availability information at init time
ARM: mvebu: ARM: mvebu: use of_find_matching_node_and_match() in
coherency.c
ARM: mvebu: enable the ARM SCU on Armada 375 and Armada 38x
ARM: mvebu: add Armada 375 support to the coherency code
ARM: mvebu: implement Armada 375 coherency workaround
ARM: mvebu: add Armada 38x support to the coherency code
ARM: mvebu: enable the coherency fabric on Armada 375
ARM: mvebu: enable the coherency fabric on Armada 38x

 .../devicetree/bindings/arm/coherency-fabric.txt   |  32 ++-
 arch/arm/boot/dts/armada-375.dtsi                  |  10 +
 arch/arm/boot/dts/armada-38x.dtsi                  |  10 +
 arch/arm/mach-kirkwood/board-dt.c                  |   2 +-
 arch/arm/mach-mvebu/Kconfig                        |   2 +
 arch/arm/mach-mvebu/board-v7.c                     |  21 +-
 arch/arm/mach-mvebu/coherency.c                    | 251 +++++++++++++++++++--
 arch/arm/mach-mvebu/coherency.h                    |   1 +
 drivers/bus/mvebu-mbus.c                           |  11 +-
 include/linux/mbus.h                               |   2 +-
 10 files changed, 305 insertions(+), 37 deletions(-)
Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
maintainer
#14 lore raw

cover ARM: mvebu: Hardware coherency support for Armada 375 and 38x

Quoted 7 lines · Thomas Petazzoni

Jason, Gregory, Andrew, Sebastian,

Any news about this patch set? It is not aimed at 3.15 as was discussed already with Jason, but since I'd still like to have some early comments about this patch series for 3.16, since we would also like to land the Armada 375/38x SMP support in 3.16, which will sit on top of this series.

Hi Thomas

I took a look at them. The XOR code is interesting. I guess it is not good for performance. A loud debug message would be useful to know when the workaround has been turned on.

Once you send a rebase on 3.15 i can send an ACK.

Andrew

#15 lore raw

cover ARM: mvebu: Hardware coherency support for Armada 375 and 38x

Dear Andrew Lunn,

Quoted 3 lines · Andrew Lunn

I took a look at them. The XOR code is interesting. I guess it is not good for performance. A loud debug message would be useful to know when the workaround has been turned on.

I haven't measured the performance impact, but indeed I suspect there is one. I'm fine with printing a warning.

Quoted 1 line

Once you send a rebase on 3.15 i can send an ACK.

Great, thanks!

Thomas

Signature · 3 lines
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com