Skip to contentSkip to conversation

arm64:numa: Add numa support for arm64 platforms.

RFC PATCH Superseded Ganapatrao Kulkarni 5 participants 23 messages Sep 25, 2014 – Oct 29, 2014

Subsystems (2)

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

cover arm64:numa: Add numa support for arm64 platforms.

This is initial patch set to support numa on arm64 based platforms. Tested these patches on cavium's multinode(2 node topology) simulator. Tried all test-cases present in numactl-2.0.9 package.

In this patchset, defined dt bindings for numa mapping for memory nodes. The cpu to node mapping is derived from the existing cpu-map mapping as defined in topology binding.

thanks,
Ganapat

Ganapatrao Kulkarni (4):
arm64: defconfig: increase NR_CPUS range to 2-128 arm/arm64:dt:numa: adding numa node mapping for memory nodes. arm64:thunder: Add initial dts for Cavium Thunder SoC in 2 Node topology. arm64:numa: adding numa support for arm64 platforms.

 Documentation/devicetree/bindings/arm/numa.txt |  60 ++
 arch/arm64/Kconfig                             |  37 +-
 arch/arm64/boot/dts/thunder-88xx-2n.dts        |  76 ++
 arch/arm64/boot/dts/thunder-88xx-2n.dtsi       | 990 +++++++++++++++++++++++++
 arch/arm64/include/asm/mmzone.h                |  32 +
 arch/arm64/include/asm/numa.h                  |  41 +
 arch/arm64/kernel/setup.c                      |   8 +
 arch/arm64/kernel/smp.c                        |   2 +
 arch/arm64/mm/Makefile                         |   1 +
 arch/arm64/mm/init.c                           |  33 +-
 arch/arm64/mm/numa.c                           | 471 ++++++++++++
 11 files changed, 1745 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/numa.txt
 create mode 100644 arch/arm64/boot/dts/thunder-88xx-2n.dts
 create mode 100644 arch/arm64/boot/dts/thunder-88xx-2n.dtsi
 create mode 100644 arch/arm64/include/asm/mmzone.h
 create mode 100644 arch/arm64/include/asm/numa.h
 create mode 100644 arch/arm64/mm/numa.c
Signature · 1 line
1.8.1.4
#1 lore raw

RFC PATCH 1/4 arm64: defconfig: increase NR_CPUS range to 2-128

Raising the maximum limit to 128. This is needed for Cavium's Thunder systems that will have 96 cores on Multi-node system.

---
 arch/arm64/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/Kconfig +2 -2
index 4d42453..a409105 100644
@@ -296,8 +296,8 @@ config SCHED_SMT
 	  places. If unsure say N here.
 
 config NR_CPUS
-	int "Maximum number of CPUs (2-64)"
-	range 2 64
+	int "Maximum number of CPUs (2-128)"
+	range 2 128
 	depends on SMP
 	# These have to remain sorted largest to smallest
 	default "64"
Signature · 1 line
1.8.1.4
reviewer
#2 lore raw

RFC PATCH 1/4 arm64: defconfig: increase NR_CPUS range to 2-128

Quoted 2 lines · Ganapatrao Kulkarni

Raising the maximum limit to 128. This is needed for Cavium's Thunder systems that will have 96 cores on Multi-node system.

Has this been tested on any such systems?

Mark.

Quoted 29 lines
---
 arch/arm64/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/Kconfig +2 -2
index 4d42453..a409105 100644
@@ -296,8 +296,8 @@ config SCHED_SMT
 	  places. If unsure say N here.
 
 config NR_CPUS
-	int "Maximum number of CPUs (2-64)"
-	range 2 64
+	int "Maximum number of CPUs (2-128)"
+	range 2 128
 	depends on SMP
 	# These have to remain sorted largest to smallest
 	default "64"
Signature · 6 lines
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#3 lore raw

RFC PATCH 1/4 arm64: defconfig: increase NR_CPUS range to 2-128

Quoted 5 lines · Mark Rutland
Quoted 2 lines · Ganapatrao Kulkarni

Raising the maximum limit to 128. This is needed for Cavium's Thunder systems that will have 96 cores on Multi-node system.

Has this been tested on any such systems?

This is tested on Cavium's Thunder 2 Node Simulator with kernel 3.17-rc5. please let us know, if any specific configurations needs to be tested with the change.

Quoted 27 lines

Mark.

Quoted 24 lines
---
 arch/arm64/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/Kconfig +2 -3
index 4d42453..a409105 100644
@@ -296,8 +296,8 @@ config SCHED_SMT
        places. If unsure say N here.
 
 config NR_CPUS
-     int "Maximum number of CPUs (2-64)"
-     range 2 64
+     int "Maximum number of CPUs (2-128)"
+     range 2 128
      depends on SMP
      # These have to remain sorted largest to smallest
      default "64"
--

1.8.1.4

Quoted 5 lines
Quoted 5 lines

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

thanks
ganapat

#4 lore raw

RFC PATCH 2/4 arm/arm64:dt:numa: adding numa node mapping for memory nodes.

In reply to Ganapatrao Kulkarni

Adding Documentation for dt binding for memory to numa node mapping.

---
 Documentation/devicetree/bindings/arm/numa.txt | 60 ++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/numa.txt
Documentation/devicetree/bindings/arm/numa.txt new file +60 -0
new file mode 100644
index 0000000..1cdc6d3
@@ -0,0 +1,60 @@
+========================================================
+ARM numa id binding description
+========================================================
+
+========================================================
+1 - Introduction
+========================================================
+
+The device node  property nid (numa node id) can be added
+to memory device node to map the range of memory addresses
+as defined in property reg. The property nid maps the memory
+range to the numa node id, which is used to find the local
+and remote pages on numa aware systems.
+
+========================================================
+2 - nid property
+========================================================
+nid is required property of memory device node for
+numa enabled platforms.
+
+|------------------------------------------------------|
+|Property Type  | Usage | Value Type | Definition      |
+|------------------------------------------------------|
+|  nid          |  R    |    <u32>   | Numa Node id    |
+|               |       |            | for this memory |
+|------------------------------------------------------|
+
+========================================================
+4 - Example memory nodes with numa information
+========================================================
+
+Example 1 (2 memory nodes, each mapped to a numa node.):
+
+	memory at 00000000 {
+		device_type = "memory";
+		reg = <0x0 0x00000000 0x0 0x80000000>;
+		nid = <0x0>;
+	};
+
+	memory at 10000000000 {
+		device_type = "memory";
+		reg = <0x100 0x00000000 0x0 0x80000000>;
+		nid = <0x1>;
+	};
+
+Example 2 (multiple memory ranges in each memory node and mapped to numa node):
+
+	memory at 00000000 {
+		device_type = "memory";
+		reg = <0x0 0x00000000 0x0 0x80000000>,
+		      <0x1 0x00000000 0x0 0x80000000>;
+		nid = <0x0>;
+	};
+
+	memory at 10000000000 {
+		device_type = "memory";
+		reg = <0x100 0x00000000 0x0 0x80000000>;
+		reg = <0x100 0x80000000 0x0 0x80000000>;
+		nid = <0x1>;
+	};
Signature · 1 line
1.8.1.4
reviewer
#5 lore raw

RFC PATCH 2/4 arm/arm64:dt:numa: adding numa node mapping for memory nodes.

Quoted 1 line · Ganapatrao Kulkarni

Adding Documentation for dt binding for memory to numa node mapping.

As I previously commented [1], this binding doesn't specify what a nid maps to in terms of the CPU hierarchy, and is thus unusable. The binding absolutely must be explicit about this, and NAK until it is.

Given we're seeing systems with increasing numbers of CPUs and increasingly complex interconnect hierarchies, I would expect at minimum that we would refer to elements in the cpu-map to define the relationship between memory banks and CPUs.

What does the interconnect/memory hierarchy look like in your system?

Mark.

[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-September/288263.html

Quoted 81 lines
---
 Documentation/devicetree/bindings/arm/numa.txt | 60 ++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/numa.txt
Documentation/devicetree/bindings/arm/numa.txt new file +60 -0
new file mode 100644
index 0000000..1cdc6d3
@@ -0,0 +1,60 @@
+========================================================
+ARM numa id binding description
+========================================================
+
+========================================================
+1 - Introduction
+========================================================
+
+The device node  property nid (numa node id) can be added
+to memory device node to map the range of memory addresses
+as defined in property reg. The property nid maps the memory
+range to the numa node id, which is used to find the local
+and remote pages on numa aware systems.
+
+========================================================
+2 - nid property
+========================================================
+nid is required property of memory device node for
+numa enabled platforms.
+
+|------------------------------------------------------|
+|Property Type  | Usage | Value Type | Definition      |
+|------------------------------------------------------|
+|  nid          |  R    |    <u32>   | Numa Node id    |
+|               |       |            | for this memory |
+|------------------------------------------------------|
+
+========================================================
+4 - Example memory nodes with numa information
+========================================================
+
+Example 1 (2 memory nodes, each mapped to a numa node.):
+
+	memory at 00000000 {
+		device_type = "memory";
+		reg = <0x0 0x00000000 0x0 0x80000000>;
+		nid = <0x0>;
+	};
+
+	memory at 10000000000 {
+		device_type = "memory";
+		reg = <0x100 0x00000000 0x0 0x80000000>;
+		nid = <0x1>;
+	};
+
+Example 2 (multiple memory ranges in each memory node and mapped to numa node):
+
+	memory at 00000000 {
+		device_type = "memory";
+		reg = <0x0 0x00000000 0x0 0x80000000>,
+		      <0x1 0x00000000 0x0 0x80000000>;
+		nid = <0x0>;
+	};
+
+	memory at 10000000000 {
+		device_type = "memory";
+		reg = <0x100 0x00000000 0x0 0x80000000>;
+		reg = <0x100 0x80000000 0x0 0x80000000>;
+		nid = <0x1>;
+	};
Signature · 6 lines
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#6 lore raw

RFC PATCH 2/4 arm/arm64:dt:numa: adding numa node mapping for memory nodes.

Hi Mark,

Quoted 6 lines · Mark Rutland
Quoted 1 line · Ganapatrao Kulkarni

Adding Documentation for dt binding for memory to numa node mapping.

As I previously commented [1], this binding doesn't specify what a nid maps to in terms of the CPU hierarchy, and is thus unusable. The binding absolutely must be explicit about this, and NAK until it is.

The nid/numa node id is to map the each memory range/bank to numa node. IIUC, the numa manages the resources based on which node they are tide to. with nid, i am trying to map the memory range to a node.
Same follows for the all IO peripherals and for CPUs.
for cpus, i am using cluster-id as a node id to map all cpus to node. thunder has 2 nodes, in this patch, i have grouped all cpus which belongs to each node under cluster-id(cluster0, cluster1).

Quoted 7 lines

Given we're seeing systems with increasing numbers of CPUs and increasingly complex interconnect hierarchies, I would expect at minimum that we would refer to elements in the cpu-map to define the relationship between memory banks and CPUs.

What does the interconnect/memory hierarchy look like in your system?

In tunder, 2 SoCs (each has 48 cores and ram controllers and IOs) can be connected to form 2 node NUMA system.
in a SoC(within node) there is no hierarchy with respect to memory or IO access. However w.r.t GICv3,
48 cores are in each SoC/node are split in to 3 clusters each of 16 cores.

the MPIDR mapping for this topology is,
Aff0 is mapped to 16 cores within a cluster. Valid range is 0 to 0xf Aff1 is mapped to cluster number, valid values are 0,1 and 2. Aff2 is mapped to Socket-id/node id/SoC number. Valid values are 0 and 1.

Quoted 81 lines

Mark.

[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2014-September/288263.html

Quoted 76 lines
---
 Documentation/devicetree/bindings/arm/numa.txt | 60 ++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/numa.txt
Documentation/devicetree/bindings/arm/numa.txt new file +60 -1
new file mode 100644
index 0000000..1cdc6d3
@@ -0,0 +1,60 @@
+========================================================
+ARM numa id binding description
+========================================================
+
+========================================================
+1 - Introduction
+========================================================
+
+The device node  property nid (numa node id) can be added
+to memory device node to map the range of memory addresses
+as defined in property reg. The property nid maps the memory
+range to the numa node id, which is used to find the local
+and remote pages on numa aware systems.
+
+========================================================
+2 - nid property
+========================================================
+nid is required property of memory device node for
+numa enabled platforms.
+
+|------------------------------------------------------|
+|Property Type  | Usage | Value Type | Definition      |
+|------------------------------------------------------|
+|  nid          |  R    |    <u32>   | Numa Node id    |
+|               |       |            | for this memory |
+|------------------------------------------------------|
+
+========================================================
+4 - Example memory nodes with numa information
+========================================================
+
+Example 1 (2 memory nodes, each mapped to a numa node.):
+
+     memory at 00000000 {
+             device_type = "memory";
+             reg = <0x0 0x00000000 0x0 0x80000000>;
+             nid = <0x0>;
+     };
+
+     memory at 10000000000 {
+             device_type = "memory";
+             reg = <0x100 0x00000000 0x0 0x80000000>;
+             nid = <0x1>;
+     };
+
+Example 2 (multiple memory ranges in each memory node and mapped to numa node):
+
+     memory at 00000000 {
+             device_type = "memory";
+             reg = <0x0 0x00000000 0x0 0x80000000>,
+                   <0x1 0x00000000 0x0 0x80000000>;
+             nid = <0x0>;
+     };
+
+     memory at 10000000000 {
+             device_type = "memory";
+             reg = <0x100 0x00000000 0x0 0x80000000>;
+             reg = <0x100 0x80000000 0x0 0x80000000>;
+             nid = <0x1>;
+     };
--

1.8.1.4

Quoted 5 lines
Quoted 5 lines

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

thanks
ganapat

reviewer
#7 lore raw

RFC PATCH 2/4 arm/arm64:dt:numa: adding numa node mapping for memory nodes.

Quoted 10 lines · Ganapatrao Kulkarni

Hi Mark,

Quoted 6 lines · Mark Rutland
Quoted 1 line · Ganapatrao Kulkarni

Adding Documentation for dt binding for memory to numa node mapping.

As I previously commented [1], this binding doesn't specify what a nid maps to in terms of the CPU hierarchy, and is thus unusable. The binding absolutely must be explicit about this, and NAK until it is.

The nid/numa node id is to map the each memory range/bank to numa node.

The issue is what constitutes a "numa node" is not defined. Hence the mapping a memory banks to a "nid" is just a mapping to an arbitrary number -- the mapping of this number to CPUs isn't defined.

Quoted 4 lines

IIUC, the numa manages the resources based on which node they are tide to. with nid, i am trying to map the memory range to a node.
Same follows for the all IO peripherals and for CPUs.
for cpus, i am using cluster-id as a node id to map all cpus to node.

I strongly suspect that this is not going to work for very long. I don't think relying on a mapping of nid to a top-level cluster-id is a good idea, especially given we have the facility to be more explicit through use of the cpu-map.

We don't need to handle all the possible cases from the start, but I'd rather we consistently used the cou-map to explicitly define the relationship between CPUs and memory.

Quoted 16 lines

thunder has 2 nodes, in this patch, i have grouped all cpus which belongs to each node under cluster-id(cluster0, cluster1).

Quoted 6 lines

Given we're seeing systems with increasing numbers of CPUs and increasingly complex interconnect hierarchies, I would expect at minimum that we would refer to elements in the cpu-map to define the relationship between memory banks and CPUs.

What does the interconnect/memory hierarchy look like in your system?

In tunder, 2 SoCs (each has 48 cores and ram controllers and IOs) can be connected to form 2 node NUMA system.
in a SoC(within node) there is no hierarchy with respect to memory or IO access. However w.r.t GICv3,
48 cores are in each SoC/node are split in to 3 clusters each of 16 cores.

Quoted 4 lines

the MPIDR mapping for this topology is,
Aff0 is mapped to 16 cores within a cluster. Valid range is 0 to 0xf Aff1 is mapped to cluster number, valid values are 0,1 and 2. Aff2 is mapped to Socket-id/node id/SoC number. Valid values are 0 and 1.

Thanks for the information.

Mark.

#8 lore raw

RFC PATCH 2/4 arm/arm64:dt:numa: adding numa node mapping for memory nodes.

Quoted 21 lines · Mark Rutland
Quoted 10 lines · Ganapatrao Kulkarni

Hi Mark,

Quoted 6 lines · Mark Rutland
Quoted 1 line · Ganapatrao Kulkarni

Adding Documentation for dt binding for memory to numa node mapping.

As I previously commented [1], this binding doesn't specify what a nid maps to in terms of the CPU hierarchy, and is thus unusable. The binding absolutely must be explicit about this, and NAK until it is.

The nid/numa node id is to map the each memory range/bank to numa node.

The issue is what constitutes a "numa node" is not defined. Hence the mapping a memory banks to a "nid" is just a mapping to an arbitrary number -- the mapping of this number to CPUs isn't defined.

Quoted 4 lines

IIUC, the numa manages the resources based on which node they are tide to. with nid, i am trying to map the memory range to a node.
Same follows for the all IO peripherals and for CPUs.
for cpus, i am using cluster-id as a node id to map all cpus to node.

Quoted 8 lines

I strongly suspect that this is not going to work for very long. I don't think relying on a mapping of nid to a top-level cluster-id is a good idea, especially given we have the facility to be more explicit through use of the cpu-map.

We don't need to handle all the possible cases from the start, but I'd rather we consistently used the cou-map to explicitly define the relationship between CPUs and memory.

agreed, will implement nid mapping in cpu-map in v2 patchset.

Quoted 25 lines
Quoted 17 lines

thunder has 2 nodes, in this patch, i have grouped all cpus which belongs to each node under cluster-id(cluster0, cluster1).

Quoted 6 lines

Given we're seeing systems with increasing numbers of CPUs and increasingly complex interconnect hierarchies, I would expect at minimum that we would refer to elements in the cpu-map to define the relationship between memory banks and CPUs.

What does the interconnect/memory hierarchy look like in your system?

In tunder, 2 SoCs (each has 48 cores and ram controllers and IOs) can be connected to form 2 node NUMA system.
in a SoC(within node) there is no hierarchy with respect to memory or IO access. However w.r.t GICv3,
48 cores are in each SoC/node are split in to 3 clusters each of 16 cores.

Quoted 4 lines

the MPIDR mapping for this topology is,
Aff0 is mapped to 16 cores within a cluster. Valid range is 0 to 0xf Aff1 is mapped to cluster number, valid values are 0,1 and 2. Aff2 is mapped to Socket-id/node id/SoC number. Valid values are 0 and 1.

Thanks for the information.

Mark.

#9 lore raw

RFC PATCH 3/4 arm64:thunder: Add initial dts for Cavium Thunder SoC in 2 Node topology.

In reply to Ganapatrao Kulkarni

adding devicetree definition for thunder's 2 node topology. Defined cpu-map for all 96 cores of 2 node system.

---
 arch/arm64/boot/dts/thunder-88xx-2n.dts  |  76 +++
 arch/arm64/boot/dts/thunder-88xx-2n.dtsi | 990 +++++++++++++++++++++++++++++++
 2 files changed, 1066 insertions(+)
 create mode 100644 arch/arm64/boot/dts/thunder-88xx-2n.dts
 create mode 100644 arch/arm64/boot/dts/thunder-88xx-2n.dtsi
arch/arm64/boot/dts/thunder-88xx-2n.dts new file +76 -0
new file mode 100644
index 0000000..b2e70e1
@@ -0,0 +1,76 @@
+/*
+ * Cavium Thunder DTS file - Thunder board description
+ *
+ * Copyright (C) 2014, Cavium Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ *  b) Permission is hereby granted, free of charge, to any person
+ *     obtaining a copy of this software and associated documentation
+ *     files (the "Software"), to deal in the Software without
+ *     restriction, including without limitation the rights to use,
+ *     copy, modify, merge, publish, distribute, sublicense, and/or
+ *     sell copies of the Software, and to permit persons to whom the
+ *     Software is furnished to do so, subject to the following
+ *     conditions:
+ *
+ *     The above copyright notice and this permission notice shall be
+ *     included in all copies or substantial portions of the Software.
+ *
+ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *     OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+/include/ "thunder-88xx-2n.dtsi"
+
+/ {
+	model = "Cavium ThunderX CN88XX board";
+	compatible = "cavium,thunder-88xx";
+
+	aliases {
+		serial0 = &uaa0;
+		serial1 = &uaa1;
+	};
+
+	memory at 00000000 {
+		device_type = "memory";
+		reg = <0x0 0x00000000 0x0 0x80000000>,
+		      <0x1 0x00000000 0x0 0x80000000>;
+		nid = <0x0>;
+	};
+
+	memory at 10000000000 {
+		device_type = "memory";
+		reg = <0x100 0x00000000 0x0 0x80000000>;
+		nid = <0x1>;
+	};
+
+};
arch/arm64/boot/dts/thunder-88xx-2n.dtsi new file +990 -0

990 lines not on this page · raw message

Signature · 1 line
1.8.1.4
reviewer
#10 lore raw

RFC PATCH 3/4 arm64:thunder: Add initial dts for Cavium Thunder SoC in 2 Node topology.

Quoted 2 lines · Ganapatrao Kulkarni

adding devicetree definition for thunder's 2 node topology. Defined cpu-map for all 96 cores of 2 node system.

[...]

Review

Quoted 12 lines
(quoted diff) +12 -0
+               CPU0: cpu at 000 {
+                       device_type = "cpu";
+                       compatible = "cavium,thunder", "arm,armv8";
+                       reg = <0x0 0x000>;
+                       enable-method = "psci";
+               };
+               CPU1: cpu at 001 {
+                       device_type = "cpu";
+                       compatible = "cavium,thunder", "arm,armv8";
+                       reg = <0x0 0x001>;
+                       enable-method = "psci";
+               };

This is going to take up an awful lot of space. Perhaps we should follwo ePAPR and allow for common properties to go in /cpus (as I believe we do for arm). We might not be able to do that for device_type given how we detect CPU nodes at present, but we could certainly do it for the enable-method:

---->8----

arch/arm64/kernel/cpu_ops.c +12 -1
index cce9524..733b3ed 100644
@@ -54,7 +54,18 @@ static const struct cpu_operations * __init cpu_get_ops(const char *name)
  */
 int __init cpu_read_ops(struct device_node *dn, int cpu)
 {
-       const char *enable_method = of_get_property(dn, "enable-method", NULL);
+       const char *enable_method = NULL;
+       of_property_read_string(dn, "enable-method", &enable_method);
+
+       if (!enable_method) {
+               /*
+                * Perhaps we have a common /cpus/enable-method
+                */
+               struct device_node *cpus = of_get_parent(dn);
+               of_property_read_string(cpus, "enable-method", &enable_method);
+               of_node_put(cpus);
+       }
+
        if (!enable_method) {
                /*
                 * The boot CPU may not have an enable method (e.g. when

---->8----

I don't believe we check the compatible string at the moment, so that should be safe to make common too.

Mark.

#11 lore raw

RFC PATCH 4/4 arm64:numa: adding numa support for arm64 platforms.

In reply to Ganapatrao Kulkarni

Adding numa support for arm64 based platforms.
This version creates numa mapping by parsing the dt table. cpu to node id mapping is derived from cluster_id as defined in cpu-map. memory to node id mapping is derived from nid property of memory node.

---
 arch/arm64/Kconfig              |  33 +++
 arch/arm64/include/asm/mmzone.h |  32 +++
 arch/arm64/include/asm/numa.h   |  41 ++++
 arch/arm64/kernel/setup.c       |   8 +
 arch/arm64/kernel/smp.c         |   2 +
 arch/arm64/mm/Makefile          |   1 +
 arch/arm64/mm/init.c            |  33 ++-
 arch/arm64/mm/numa.c            | 471 ++++++++++++++++++++++++++++++++++++++++
 8 files changed, 617 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/include/asm/mmzone.h
 create mode 100644 arch/arm64/include/asm/numa.h
 create mode 100644 arch/arm64/mm/numa.c
arch/arm64/Kconfig +33 -0
index a409105..415ee53 100644
@@ -142,6 +142,7 @@ config ARCH_THUNDER
 	select NET_VENDOR_CAVIUM
 	select SATA_AHCI
 	select SATA_AHCI_PLATFORM
+	select HAVE_MEMBLOCK_NODE_MAP if NUMA
 
 config ARCH_VEXPRESS
 	bool "ARMv8 software model (Versatile Express)"
@@ -309,6 +310,38 @@ config HOTPLUG_CPU
 	  Say Y here to experiment with turning CPUs off and on.  CPUs
 	  can be controlled through /sys/devices/system/cpu.
 
+# Common NUMA Features
+config NUMA
+	bool "Numa Memory Allocation and Scheduler Support"
+	depends on SMP
+	---help---
+	  Enable NUMA (Non Uniform Memory Access) support.
+
+	  The kernel will try to allocate memory used by a CPU on the
+	  local memory controller of the CPU and add some more
+	  NUMA awareness to the kernel.
+
+config ARM64_DT_NUMA
+	def_bool y
+	prompt "DT NUMA detection"
+	depends on ARM64 && NUMA && DTC
+	---help---
+	  Enable DT based numa.
+
+config NODES_SHIFT
+	int "Maximum NUMA Nodes (as a power of 2)"
+	range 1 10
+	default "2"
+	depends on NEED_MULTIPLE_NODES
+	---help---
+	  Specify the maximum number of NUMA Nodes available on the target
+	  system.  Increases memory reserved to accommodate various tables.
+
+config USE_PERCPU_NUMA_NODE_ID
+	def_bool y
+	depends on NUMA
+
+
 source kernel/Kconfig.preempt
 
 config HZ
arch/arm64/include/asm/mmzone.h new file +32 -0
new file mode 100644
index 0000000..d27ee66
@@ -0,0 +1,32 @@
+#ifndef __ASM_ARM64_MMZONE_H_
+#define __ASM_ARM64_MMZONE_H_
+
+#ifdef CONFIG_NUMA
+
+#include <linux/mmdebug.h>
+#include <asm/smp.h>
+#include <linux/types.h>
+#include <asm/numa.h>
+
+extern struct pglist_data *node_data[];
+
+#define NODE_DATA(nid)		(node_data[nid])
+
+
+struct numa_memblk {
+	u64			start;
+	u64			end;
+	int			nid;
+};
+
+struct numa_meminfo {
+	int			nr_blks;
+	struct numa_memblk	blk[NR_NODE_MEMBLKS];
+};
+
+void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi);
+int __init numa_cleanup_meminfo(struct numa_meminfo *mi);
+void __init numa_reset_distance(void);
+
+#endif /* CONFIG_NUMA */
+#endif /* __ASM_ARM64_MMZONE_H_ */
arch/arm64/include/asm/numa.h new file +41 -0

41 lines not on this page · raw message

arch/arm64/kernel/setup.c +8 -0
index edb146d..436b78d 100644
@@ -424,6 +424,9 @@ static int __init topology_init(void)
 {
 	int i;
 
+	for_each_online_node(i)
+		register_one_node(i);
+
 	for_each_possible_cpu(i) {
 		struct cpu *cpu = &per_cpu(cpu_data.cpu, i);
 		cpu->hotpluggable = 1;
@@ -460,7 +463,12 @@ static int c_show(struct seq_file *m, void *v)
 		 * "processor".  Give glibc what it expects.
 		 */
 #ifdef CONFIG_SMP
+	if (IS_ENABLED(CONFIG_NUMA)) {
+		seq_printf(m, "processor\t: %d", i);
+		seq_printf(m, " [nid: %d]\n", cpu_to_node(i));
+	} else {
 		seq_printf(m, "processor\t: %d\n", i);
+	}
 #endif
 	}
 
arch/arm64/kernel/smp.c +2 -0
index 4743397..60120db 100644
@@ -50,6 +50,7 @@
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
 #include <asm/ptrace.h>
+#include <asm/numa.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/ipi.h>
@@ -123,6 +124,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
 static void smp_store_cpu_info(unsigned int cpuid)
 {
 	store_cpu_topology(cpuid);
+	numa_store_cpu_info(cpuid);
 }
 
 /*
arch/arm64/mm/Makefile +1 -0
index 3ecb56c..4dda3d0 100644
@@ -3,3 +3,4 @@ obj-y				:= dma-mapping.o extable.o fault.o init.o \
 				   ioremap.o mmap.o pgd.o mmu.o \
 				   context.o proc.o
 obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
+obj-$(CONFIG_NUMA)		+= numa.o
arch/arm64/mm/init.c +29 -4
index 271e654..4b2bbb4 100644
@@ -39,6 +39,7 @@
 #include <asm/setup.h>
 #include <asm/sizes.h>
 #include <asm/tlb.h>
+#include <asm/numa.h>
 
 #include "mm.h"
 
@@ -73,6 +74,20 @@ static phys_addr_t max_zone_dma_phys(void)
 	return min(offset + (1ULL << 32), memblock_end_of_DRAM());
 }
 
+#ifdef CONFIG_NUMA
+static void __init zone_sizes_init(unsigned long min, unsigned long max)
+{
+	unsigned long max_zone_pfns[MAX_NR_ZONES];
+
+	memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+	if (IS_ENABLED(CONFIG_ZONE_DMA))
+		max_zone_pfns[ZONE_DMA] = PFN_DOWN(max_zone_dma_phys());
+	max_zone_pfns[ZONE_NORMAL] = max;
+
+	free_area_init_nodes(max_zone_pfns);
+}
+
+#else
 static void __init zone_sizes_init(unsigned long min, unsigned long max)
 {
 	struct memblock_region *reg;
@@ -111,6 +126,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
 
 	free_area_init_node(0, zone_size, min, zhole_size);
 }
+#endif /* CONFIG_NUMA */
 
 #ifdef CONFIG_HAVE_ARCH_PFN_VALID
 int pfn_valid(unsigned long pfn)
@@ -129,9 +145,16 @@ static void arm64_memory_present(void)
 {
 	struct memblock_region *reg;
 
-	for_each_memblock(memory, reg)
+	for_each_memblock(memory, reg) {
+#ifdef CONFIG_NUMA
+		memory_present(reg->nid,
+				memblock_region_memory_base_pfn(reg),
+				memblock_region_memory_end_pfn(reg));
+#else
 		memory_present(0, memblock_region_memory_base_pfn(reg),
 			       memblock_region_memory_end_pfn(reg));
+#endif
+	}
 }
 #endif
 
@@ -168,6 +191,11 @@ void __init bootmem_init(void)
 	min = PFN_UP(memblock_start_of_DRAM());
 	max = PFN_DOWN(memblock_end_of_DRAM());
 
+	high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
+	max_pfn = max_low_pfn = max;
+
+	if (IS_ENABLED(CONFIG_NUMA))
+		arm64_numa_init();
 	/*
 	 * Sparsemem tries to allocate bootmem in memory_present(), so must be
 	 * done after the fixed reservations.
@@ -176,9 +204,6 @@ void __init bootmem_init(void)
 
 	sparse_init();
 	zone_sizes_init(min, max);
-
-	high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
-	max_pfn = max_low_pfn = max;
 }
 
 #ifndef CONFIG_SPARSEMEM_VMEMMAP
arch/arm64/mm/numa.c new file +469 -0

469 lines not on this page · raw message

Signature · 1 line
1.8.1.4
reviewer
#12 lore raw

RFC PATCH 4/4 arm64:numa: adding numa support for arm64 platforms.

Quoted 4 lines · Ganapatrao Kulkarni

Adding numa support for arm64 based platforms.
This version creates numa mapping by parsing the dt table. cpu to node id mapping is derived from cluster_id as defined in cpu-map. memory to node id mapping is derived from nid property of memory node.

[...]

arch/arm64/include/asm/numa.h line 17

Quoted 6 lines
arch/arm64/include/asm/numa.h new file +6 -0
+/*
+ * Too small node sizes may confuse the VM badly. Usually they
+ * result from BIOS bugs. So dont recognize nodes as standalone
+ * NUMA entities that have less than this amount of RAM listed:
+ */
+#define NODE_MIN_SIZE (4*1024*1024)

Why do these confuse the VM? what does BIOS have to do with arm64?

Review

Quoted 2 lines
(quoted diff) +2 -0
+
+#define parent_node(node)      (node)

Huh?

[...]

arch/arm64/mm/init.c void __init bootmem_init(void) · line 198

Quoted 9 lines
arch/arm64/mm/init.c +5 -0
@@ -168,6 +191,11 @@ void __init bootmem_init(void)
        min = PFN_UP(memblock_start_of_DRAM());
        max = PFN_DOWN(memblock_end_of_DRAM());
 
+       high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
+       max_pfn = max_low_pfn = max;
+
+       if (IS_ENABLED(CONFIG_NUMA))
+               arm64_numa_init();

Is this function defined if !CONFIG_NUMA? Surely it must do nothing in that case anyway?

[...]

arch/arm64/mm/numa.c line 117

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+/*
+ *  Set the cpu to node and mem mapping
+ */
+void numa_store_cpu_info(cpu)
+{
+       cpu_to_node_map[cpu] = cpu_topology[cpu].cluster_id;
+       cpumask_set_cpu(cpu, node_to_cpumask_map[cpu_to_node_map[cpu]]);
+       set_numa_node(cpu_to_node_map[cpu]);
+       set_numa_mem(local_memory_node(cpu_to_node_map[cpu]));
+}

I don't like this. I think we need to be more explicit in the DT w.r.t. the relationship between memory and the CPU hierarchy.

I can imagine that we might end up with systems with multiple levels of NUMA hierarchy (using MPIDR_EL1.Aff{3,2}), and I'd rather that we were explcit as possible from the start w.r.t. the relationship between memory and groups of CPUs such that we don't end up with multiple ways of specifying said relationship, and horrible edge cases around implicit definitions (e.g. the nid to cluster mapping).

arch/arm64/mm/numa.c line 386

Quoted 13 lines
arch/arm64/mm/numa.c new file +13 -0
+/**
+ * dummy_numa_init - Fallback dummy NUMA init
+ *
+ * Used if there's no underlying NUMA architecture, NUMA initialization
+ * fails, or NUMA is disabled on the command line.
+ *
+ * Must online at least one node and add memory blocks that cover all
+ * allowed memory.  This function must not fail.
+ */
+static int __init dummy_numa_init(void)
+{
+       pr_info("%s\n",
+              numa_off ? "NUMA turned off" : "No NUMA configuration found");

Why not print "NUMA turned off" in numa_setup?

Quoted 17 lines
arch/arm64/mm/numa.c new file +17 -0
+       pr_info("Faking a node at [mem %#018Lx-%#018Lx]\n",
+              0LLU, PFN_PHYS(max_pfn) - 1);
+
+       node_set(0, numa_nodes_parsed);
+       numa_add_memblk(0, 0, PFN_PHYS(max_pfn));
+
+       return 0;
+}
+
+/**
+ * early_init_dt_scan_numa_map - parse memory node and map nid to memory range.
+ */
+int __init early_init_dt_scan_numa_map(unsigned long node, const char *uname,
+                                    int depth, void *data)
+{
+       const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+       const __be32 *reg, *endp, *nid_prop;

arch/arm64/mm/numa.c line 413

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+       int l, nid;
+
+       /* We are scanning "memory" nodes only */
+       if (type == NULL) {
+               /*
+                * The longtrail doesn't have a device_type on the
+                * /memory node, so look for the node called /memory at 0.
+                */
+               if (depth != 1 || strcmp(uname, "memory at 0") != 0)
+                       return 0;

This has no place on arm64.

We limited to longtrail workaround in the core memory parsing to PPC32 only in commit b44aa25d20e2ef6b (of: Handle memory at 0 node on PPC32 only). This code doesn't need it enabled ever.

Are you booting using UEFI? This isn't going to work when the memory map comes from UEFI and we have no memory nodes in the DTB.

Mark.

#13 lore raw

RFC PATCH 4/4 arm64:numa: adding numa support for arm64 platforms.

Hi Mark,

Quoted 8 lines · Mark Rutland
Quoted 4 lines · Ganapatrao Kulkarni

Adding numa support for arm64 based platforms.
This version creates numa mapping by parsing the dt table. cpu to node id mapping is derived from cluster_id as defined in cpu-map. memory to node id mapping is derived from nid property of memory node.

[...]

Quoted 8 lines

arch/arm64/include/asm/numa.h line 17

Quoted 6 lines
arch/arm64/include/asm/numa.h new file +6 -0
+/*
+ * Too small node sizes may confuse the VM badly. Usually they
+ * result from BIOS bugs. So dont recognize nodes as standalone
+ * NUMA entities that have less than this amount of RAM listed:
+ */
+#define NODE_MIN_SIZE (4*1024*1024)

Why do these confuse the VM? what does BIOS have to do with arm64?

sneaked in from x86, will remove this.

Quoted 5 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+
+#define parent_node(node)      (node)

Huh?

for thunder, no hierarchy at numa nodes. shall i put under ifdef or separate header file?

Quoted 7 lines

[...]

Quoted 4 lines
arch/arm64/mm/init.c +0 -0
@@ -168,6 +191,11 @@ void __init bootmem_init(void)
        min = PFN_UP(memblock_start_of_DRAM());
        max = PFN_DOWN(memblock_end_of_DRAM());
 
Quoted 8 lines

arch/arm64/mm/init.c void __init bootmem_init(void) · line 198

Quoted 5 lines
arch/arm64/mm/init.c +5 -0
+       high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
+       max_pfn = max_low_pfn = max;
+
+       if (IS_ENABLED(CONFIG_NUMA))
+               arm64_numa_init();

Is this function defined if !CONFIG_NUMA? Surely it must do nothing in that case anyway?

yes, if is not required, will remove it.

Quoted 17 lines

[...]

arch/arm64/mm/numa.c line 117

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+/*
+ *  Set the cpu to node and mem mapping
+ */
+void numa_store_cpu_info(cpu)
+{
+       cpu_to_node_map[cpu] = cpu_topology[cpu].cluster_id;
+       cpumask_set_cpu(cpu, node_to_cpumask_map[cpu_to_node_map[cpu]]);
+       set_numa_node(cpu_to_node_map[cpu]);
+       set_numa_mem(local_memory_node(cpu_to_node_map[cpu]));
+}

I don't like this. I think we need to be more explicit in the DT w.r.t. the relationship between memory and the CPU hierarchy.

Quoted 6 lines

I can imagine that we might end up with systems with multiple levels of NUMA hierarchy (using MPIDR_EL1.Aff{3,2}), and I'd rather that we were explcit as possible from the start w.r.t. the relationship between memory and groups of CPUs such that we don't end up with multiple ways of specifying said relationship, and horrible edge cases around implicit definitions (e.g. the nid to cluster mapping).

are you recomending to have explicit nid attribute to each cpu device node?

Quoted 16 lines
Quoted 4 lines
arch/arm64/mm/numa.c new file +3 -0
+/**
+ * dummy_numa_init - Fallback dummy NUMA init
+ *

arch/arm64/mm/numa.c line 386

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+ * Used if there's no underlying NUMA architecture, NUMA initialization
+ * fails, or NUMA is disabled on the command line.
+ *
+ * Must online at least one node and add memory blocks that cover all
+ * allowed memory.  This function must not fail.
+ */
+static int __init dummy_numa_init(void)
+{
+       pr_info("%s\n",
+              numa_off ? "NUMA turned off" : "No NUMA configuration found");

Why not print "NUMA turned off" in numa_setup?

enters this function only when, numa is turned off or the DT/ACPI based numa init fails.

Quoted 22 lines
Quoted 22 lines
arch/arm64/mm/numa.c new file +21 -0
+       pr_info("Faking a node at [mem %#018Lx-%#018Lx]\n",
+              0LLU, PFN_PHYS(max_pfn) - 1);
+
+       node_set(0, numa_nodes_parsed);
+       numa_add_memblk(0, 0, PFN_PHYS(max_pfn));
+
+       return 0;
+}
+
+/**
+ * early_init_dt_scan_numa_map - parse memory node and map nid to memory range.
+ */
+int __init early_init_dt_scan_numa_map(unsigned long node, const char *uname,
+                                    int depth, void *data)
+{
+       const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+       const __be32 *reg, *endp, *nid_prop;
+       int l, nid;
+
+       /* We are scanning "memory" nodes only */
+       if (type == NULL) {
Quoted 8 lines

arch/arm64/mm/numa.c line 413

Quoted 6 lines
arch/arm64/mm/numa.c new file +6 -0
+               /*
+                * The longtrail doesn't have a device_type on the
+                * /memory node, so look for the node called /memory at 0.
+                */
+               if (depth != 1 || strcmp(uname, "memory at 0") != 0)
+                       return 0;

This has no place on arm64.

i am not sure that we can move to driver/of, at this moment this is arm64 specific binding.

Quoted 6 lines

We limited to longtrail workaround in the core memory parsing to PPC32 only in commit b44aa25d20e2ef6b (of: Handle memory at 0 node on PPC32 only). This code doesn't need it enabled ever.

Are you booting using UEFI? This isn't going to work when the memory map

tried with bootwrapper, working on to boot from UEFI.

Quoted 1 line

comes from UEFI and we have no memory nodes in the DTB.

yes, there is issue with UEFI boot, since memory node is removed. i request UEFI stub dev-team to suggest the possible ways to address this.

Quoted 2 lines

Mark.

thanks
ganapat

reviewer
#14 lore raw

RFC PATCH 4/4 arm64:numa: adding numa support for arm64 platforms.

Quoted 19 lines · Ganapatrao Kulkarni

Hi Mark,

Quoted 8 lines · Mark Rutland
Quoted 4 lines · Ganapatrao Kulkarni

Adding numa support for arm64 based platforms.
This version creates numa mapping by parsing the dt table. cpu to node id mapping is derived from cluster_id as defined in cpu-map. memory to node id mapping is derived from nid property of memory node.

[...]

Quoted 8 lines

arch/arm64/include/asm/numa.h line 17

Quoted 6 lines
arch/arm64/include/asm/numa.h new file +6 -0
+/*
+ * Too small node sizes may confuse the VM badly. Usually they
+ * result from BIOS bugs. So dont recognize nodes as standalone
+ * NUMA entities that have less than this amount of RAM listed:
+ */
+#define NODE_MIN_SIZE (4*1024*1024)

Why do these confuse the VM? what does BIOS have to do with arm64?

Quoted 8 lines

sneaked in from x86, will remove this.

Quoted 5 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+
+#define parent_node(node)      (node)

Huh?

for thunder, no hierarchy at numa nodes. shall i put under ifdef or separate header file?

I was confused by a node being its own parent, but that seems to be the case elsewhere for parent_node() implementations. Please at least have a comment that we're assuming a flat hierarchy (for now).

Quoted 33 lines
Quoted 7 lines

[...]

Quoted 4 lines
arch/arm64/mm/init.c +0 -0
@@ -168,6 +191,11 @@ void __init bootmem_init(void)
        min = PFN_UP(memblock_start_of_DRAM());
        max = PFN_DOWN(memblock_end_of_DRAM());
 
Quoted 8 lines

arch/arm64/mm/init.c void __init bootmem_init(void) · line 198

Quoted 5 lines
arch/arm64/mm/init.c +5 -0
+       high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
+       max_pfn = max_low_pfn = max;
+
+       if (IS_ENABLED(CONFIG_NUMA))
+               arm64_numa_init();

Is this function defined if !CONFIG_NUMA? Surely it must do nothing in that case anyway?

yes, if is not required, will remove it.

Quoted 17 lines

[...]

arch/arm64/mm/numa.c line 117

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+/*
+ *  Set the cpu to node and mem mapping
+ */
+void numa_store_cpu_info(cpu)
+{
+       cpu_to_node_map[cpu] = cpu_topology[cpu].cluster_id;
+       cpumask_set_cpu(cpu, node_to_cpumask_map[cpu_to_node_map[cpu]]);
+       set_numa_node(cpu_to_node_map[cpu]);
+       set_numa_mem(local_memory_node(cpu_to_node_map[cpu]));
+}

I don't like this. I think we need to be more explicit in the DT w.r.t. the relationship between memory and the CPU hierarchy.

Quoted 7 lines
Quoted 6 lines

I can imagine that we might end up with systems with multiple levels of NUMA hierarchy (using MPIDR_EL1.Aff{3,2}), and I'd rather that we were explcit as possible from the start w.r.t. the relationship between memory and groups of CPUs such that we don't end up with multiple ways of specifying said relationship, and horrible edge cases around implicit definitions (e.g. the nid to cluster mapping).

are you recomending to have explicit nid attribute to each cpu device node?

I am recommending that we make the relationship explicit. If anything, using the cpu-map (with phandles) seems like a better approach.

Quoted 15 lines
Quoted 7 lines
Quoted 7 lines

+/**
+ * dummy_numa_init - Fallback dummy NUMA init
+ *
+ * Used if there's no underlying NUMA architecture, NUMA initialization
+ * fails, or NUMA is disabled on the command line.
+ *
+ * Must online at least one node and add memory blocks that cover all

Quoted 8 lines

arch/arm64/mm/numa.c line 386

Quoted 6 lines

+ * allowed memory. This function must not fail.
+ */

arch/arm64/mm/numa.c new file +4 -0
+static int __init dummy_numa_init(void)
+{
+       pr_info("%s\n",
+              numa_off ? "NUMA turned off" : "No NUMA configuration found");

Why not print "NUMA turned off" in numa_setup?

Quoted 2 lines

enters this function only when, numa is turned off or the DT/ACPI based numa init fails.

Sure. Moving the "NUMA turned off" print into numa_setup would mean you could just print "Using dummy NUMA layout" or something to that effect here -- the function has no need to care about the value of numa_off.

Quoted 30 lines
Quoted 22 lines
Quoted 22 lines
arch/arm64/mm/numa.c new file +21 -0
+       pr_info("Faking a node at [mem %#018Lx-%#018Lx]\n",
+              0LLU, PFN_PHYS(max_pfn) - 1);
+
+       node_set(0, numa_nodes_parsed);
+       numa_add_memblk(0, 0, PFN_PHYS(max_pfn));
+
+       return 0;
+}
+
+/**
+ * early_init_dt_scan_numa_map - parse memory node and map nid to memory range.
+ */
+int __init early_init_dt_scan_numa_map(unsigned long node, const char *uname,
+                                    int depth, void *data)
+{
+       const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+       const __be32 *reg, *endp, *nid_prop;
+       int l, nid;
+
+       /* We are scanning "memory" nodes only */
+       if (type == NULL) {
Quoted 8 lines

arch/arm64/mm/numa.c line 413

Quoted 6 lines
arch/arm64/mm/numa.c new file +6 -0
+               /*
+                * The longtrail doesn't have a device_type on the
+                * /memory node, so look for the node called /memory at 0.
+                */
+               if (depth != 1 || strcmp(uname, "memory at 0") != 0)
+                       return 0;

This has no place on arm64.

Quoted 2 lines

i am not sure that we can move to driver/of, at this moment this is arm64 specific binding.

I meant the longtrail workaround, hence my comments on that below.

Quoted 9 lines
Quoted 5 lines

We limited to longtrail workaround in the core memory parsing to PPC32 only in commit b44aa25d20e2ef6b (of: Handle memory at 0 node on PPC32 only). This code doesn't need it enabled ever.

Are you booting using UEFI? This isn't going to work when the memory map

tried with bootwrapper, working on to boot from UEFI.

Quoted 1 line

comes from UEFI and we have no memory nodes in the DTB.

yes, there is issue with UEFI boot, since memory node is removed. i request UEFI stub dev-team to suggest the possible ways to address this.

I've Cc'd a few people who have worked on the stub and/or EFI memory map stuff. It would be worth keeping them on Cc so as to keep them informed.

I believe that the EFI stub is doing the right thing by ensuring that the EFI memory map is used, so this is just another configuration that your binding has to consider.

Mark.

#15 lore raw

RFC PATCH 4/4 arm64:numa: adding numa support for arm64 platforms.

Quoted 26 lines · Mark Rutland
Quoted 25 lines · Ganapatrao Kulkarni

Hi Mark,

Quoted 8 lines · Mark Rutland
Quoted 4 lines · Ganapatrao Kulkarni

Adding numa support for arm64 based platforms.
This version creates numa mapping by parsing the dt table. cpu to node id mapping is derived from cluster_id as defined in cpu-map. memory to node id mapping is derived from nid property of memory node.

[...]

Quoted 8 lines

arch/arm64/include/asm/numa.h line 17

Quoted 6 lines
arch/arm64/include/asm/numa.h new file +6 -0
+/*
+ * Too small node sizes may confuse the VM badly. Usually they
+ * result from BIOS bugs. So dont recognize nodes as standalone
+ * NUMA entities that have less than this amount of RAM listed:
+ */
+#define NODE_MIN_SIZE (4*1024*1024)

Why do these confuse the VM? what does BIOS have to do with arm64?

sneaked in from x86, will remove this.

Quoted 5 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+
+#define parent_node(node)      (node)

Huh?

Quoted 6 lines
Quoted 2 lines

for thunder, no hierarchy at numa nodes. shall i put under ifdef or separate header file?

I was confused by a node being its own parent, but that seems to be the case elsewhere for parent_node() implementations. Please at least have a comment that we're assuming a flat hierarchy (for now).

sure, will add the required comments.

Quoted 40 lines
Quoted 40 lines
Quoted 8 lines

[...]

Quoted 4 lines
arch/arm64/mm/init.c +0 -0
@@ -168,6 +191,11 @@ void __init bootmem_init(void)
        min = PFN_UP(memblock_start_of_DRAM());
        max = PFN_DOWN(memblock_end_of_DRAM());
 
Quoted 8 lines

arch/arm64/mm/init.c void __init bootmem_init(void) · line 198

Quoted 5 lines
arch/arm64/mm/init.c +5 -0
+       high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
+       max_pfn = max_low_pfn = max;
+
+       if (IS_ENABLED(CONFIG_NUMA))
+               arm64_numa_init();

Is this function defined if !CONFIG_NUMA? Surely it must do nothing in that case anyway?

yes, if is not required, will remove it.

Quoted 23 lines

[...]

arch/arm64/mm/numa.c line 117

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+/*
+ *  Set the cpu to node and mem mapping
+ */
+void numa_store_cpu_info(cpu)
+{
+       cpu_to_node_map[cpu] = cpu_topology[cpu].cluster_id;
+       cpumask_set_cpu(cpu, node_to_cpumask_map[cpu_to_node_map[cpu]]);
+       set_numa_node(cpu_to_node_map[cpu]);
+       set_numa_mem(local_memory_node(cpu_to_node_map[cpu]));
+}

I don't like this. I think we need to be more explicit in the DT w.r.t. the relationship between memory and the CPU hierarchy.

I can imagine that we might end up with systems with multiple levels of NUMA hierarchy (using MPIDR_EL1.Aff{3,2}), and I'd rather that we were explcit as possible from the start w.r.t. the relationship between memory and groups of CPUs such that we don't end up with multiple ways of specifying said relationship, and horrible edge cases around implicit definitions (e.g. the nid to cluster mapping).

Quoted 4 lines
Quoted 1 line

are you recomending to have explicit nid attribute to each cpu device node?

I am recommending that we make the relationship explicit. If anything, using the cpu-map (with phandles) seems like a better approach.

yes, will add the mapping.

Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 4 lines
arch/arm64/mm/numa.c new file +3 -0
+/**
+ * dummy_numa_init - Fallback dummy NUMA init
+ *

arch/arm64/mm/numa.c line 386

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+ * Used if there's no underlying NUMA architecture, NUMA initialization
+ * fails, or NUMA is disabled on the command line.
+ *
+ * Must online at least one node and add memory blocks that cover all
+ * allowed memory.  This function must not fail.
+ */
+static int __init dummy_numa_init(void)
+{
+       pr_info("%s\n",
+              numa_off ? "NUMA turned off" : "No NUMA configuration found");

Why not print "NUMA turned off" in numa_setup?

Quoted 6 lines
Quoted 2 lines

enters this function only when, numa is turned off or the DT/ACPI based numa init fails.

Sure. Moving the "NUMA turned off" print into numa_setup would mean you could just print "Using dummy NUMA layout" or something to that effect here -- the function has no need to care about the value of numa_off.

agreed.

Quoted 31 lines
Quoted 31 lines
Quoted 31 lines
Quoted 19 lines
arch/arm64/mm/numa.c new file +17 -0
+       pr_info("Faking a node at [mem %#018Lx-%#018Lx]\n",
+              0LLU, PFN_PHYS(max_pfn) - 1);
+
+       node_set(0, numa_nodes_parsed);
+       numa_add_memblk(0, 0, PFN_PHYS(max_pfn));
+
+       return 0;
+}
+
+/**
+ * early_init_dt_scan_numa_map - parse memory node and map nid to memory range.
+ */
+int __init early_init_dt_scan_numa_map(unsigned long node, const char *uname,
+                                    int depth, void *data)
+{
+       const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+       const __be32 *reg, *endp, *nid_prop;

arch/arm64/mm/numa.c line 413

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+       int l, nid;
+
+       /* We are scanning "memory" nodes only */
+       if (type == NULL) {
+               /*
+                * The longtrail doesn't have a device_type on the
+                * /memory node, so look for the node called /memory at 0.
+                */
+               if (depth != 1 || strcmp(uname, "memory at 0") != 0)
+                       return 0;

This has no place on arm64.

Quoted 4 lines
Quoted 2 lines

i am not sure that we can move to driver/of, at this moment this is arm64 specific binding.

I meant the longtrail workaround, hence my comments on that below.

oh! thanks, will remove this.

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

We limited to longtrail workaround in the core memory parsing to PPC32 only in commit b44aa25d20e2ef6b (of: Handle memory at 0 node on PPC32 only). This code doesn't need it enabled ever.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

Are you booting using UEFI? This isn't going to work when the memory map

tried with bootwrapper, working on to boot from UEFI.

Quoted 1 line

comes from UEFI and we have no memory nodes in the DTB.

yes, there is issue with UEFI boot, since memory node is removed. i request UEFI stub dev-team to suggest the possible ways to address this.

I've Cc'd a few people who have worked on the stub and/or EFI memory map stuff. It would be worth keeping them on Cc so as to keep them informed.

thanks.

Quoted 4 lines

I believe that the EFI stub is doing the right thing by ensuring that the EFI memory map is used, so this is just another configuration that your binding has to consider.

going through EFI stub, next is to boot numa kernel using UEFI, will include UEFI boot support in v2 patch.

Quoted 2 lines

Mark.

#16 lore raw

RFC PATCH 4/4 arm64:numa: adding numa support for arm64 platforms.

Hi All,

Quoted 151 lines · Ganapatrao Kulkarni
Quoted 26 lines · Mark Rutland
Quoted 25 lines · Ganapatrao Kulkarni

Hi Mark,

Quoted 8 lines · Mark Rutland
Quoted 4 lines · Ganapatrao Kulkarni

Adding numa support for arm64 based platforms.
This version creates numa mapping by parsing the dt table. cpu to node id mapping is derived from cluster_id as defined in cpu-map. memory to node id mapping is derived from nid property of memory node.

[...]

Quoted 8 lines

arch/arm64/include/asm/numa.h line 17

Quoted 6 lines
arch/arm64/include/asm/numa.h new file +6 -0
+/*
+ * Too small node sizes may confuse the VM badly. Usually they
+ * result from BIOS bugs. So dont recognize nodes as standalone
+ * NUMA entities that have less than this amount of RAM listed:
+ */
+#define NODE_MIN_SIZE (4*1024*1024)

Why do these confuse the VM? what does BIOS have to do with arm64?

sneaked in from x86, will remove this.

Quoted 5 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+
+#define parent_node(node)      (node)

Huh?

Quoted 6 lines
Quoted 2 lines

for thunder, no hierarchy at numa nodes. shall i put under ifdef or separate header file?

I was confused by a node being its own parent, but that seems to be the case elsewhere for parent_node() implementations. Please at least have a comment that we're assuming a flat hierarchy (for now).

sure, will add the required comments.

Quoted 40 lines
Quoted 40 lines
Quoted 8 lines

[...]

Quoted 4 lines
arch/arm64/mm/init.c +0 -0
@@ -168,6 +191,11 @@ void __init bootmem_init(void)
        min = PFN_UP(memblock_start_of_DRAM());
        max = PFN_DOWN(memblock_end_of_DRAM());
 
Quoted 8 lines

arch/arm64/mm/init.c void __init bootmem_init(void) · line 198

Quoted 5 lines
arch/arm64/mm/init.c +5 -0
+       high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
+       max_pfn = max_low_pfn = max;
+
+       if (IS_ENABLED(CONFIG_NUMA))
+               arm64_numa_init();

Is this function defined if !CONFIG_NUMA? Surely it must do nothing in that case anyway?

yes, if is not required, will remove it.

Quoted 23 lines

[...]

arch/arm64/mm/numa.c line 117

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+/*
+ *  Set the cpu to node and mem mapping
+ */
+void numa_store_cpu_info(cpu)
+{
+       cpu_to_node_map[cpu] = cpu_topology[cpu].cluster_id;
+       cpumask_set_cpu(cpu, node_to_cpumask_map[cpu_to_node_map[cpu]]);
+       set_numa_node(cpu_to_node_map[cpu]);
+       set_numa_mem(local_memory_node(cpu_to_node_map[cpu]));
+}

I don't like this. I think we need to be more explicit in the DT w.r.t. the relationship between memory and the CPU hierarchy.

I can imagine that we might end up with systems with multiple levels of NUMA hierarchy (using MPIDR_EL1.Aff{3,2}), and I'd rather that we were explcit as possible from the start w.r.t. the relationship between memory and groups of CPUs such that we don't end up with multiple ways of specifying said relationship, and horrible edge cases around implicit definitions (e.g. the nid to cluster mapping).

Quoted 4 lines
Quoted 1 line

are you recomending to have explicit nid attribute to each cpu device node?

I am recommending that we make the relationship explicit. If anything, using the cpu-map (with phandles) seems like a better approach.

yes, will add the mapping.

Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 4 lines
arch/arm64/mm/numa.c new file +3 -0
+/**
+ * dummy_numa_init - Fallback dummy NUMA init
+ *

arch/arm64/mm/numa.c line 386

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+ * Used if there's no underlying NUMA architecture, NUMA initialization
+ * fails, or NUMA is disabled on the command line.
+ *
+ * Must online at least one node and add memory blocks that cover all
+ * allowed memory.  This function must not fail.
+ */
+static int __init dummy_numa_init(void)
+{
+       pr_info("%s\n",
+              numa_off ? "NUMA turned off" : "No NUMA configuration found");

Why not print "NUMA turned off" in numa_setup?

Quoted 6 lines
Quoted 2 lines

enters this function only when, numa is turned off or the DT/ACPI based numa init fails.

Sure. Moving the "NUMA turned off" print into numa_setup would mean you could just print "Using dummy NUMA layout" or something to that effect here -- the function has no need to care about the value of numa_off.

agreed.

Quoted 31 lines
Quoted 31 lines
Quoted 31 lines
Quoted 19 lines
arch/arm64/mm/numa.c new file +17 -0
+       pr_info("Faking a node at [mem %#018Lx-%#018Lx]\n",
+              0LLU, PFN_PHYS(max_pfn) - 1);
+
+       node_set(0, numa_nodes_parsed);
+       numa_add_memblk(0, 0, PFN_PHYS(max_pfn));
+
+       return 0;
+}
+
+/**
+ * early_init_dt_scan_numa_map - parse memory node and map nid to memory range.
+ */
+int __init early_init_dt_scan_numa_map(unsigned long node, const char *uname,
+                                    int depth, void *data)
+{
+       const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+       const __be32 *reg, *endp, *nid_prop;

arch/arm64/mm/numa.c line 413

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+       int l, nid;
+
+       /* We are scanning "memory" nodes only */
+       if (type == NULL) {
+               /*
+                * The longtrail doesn't have a device_type on the
+                * /memory node, so look for the node called /memory at 0.
+                */
+               if (depth != 1 || strcmp(uname, "memory at 0") != 0)
+                       return 0;

This has no place on arm64.

Quoted 4 lines
Quoted 2 lines

i am not sure that we can move to driver/of, at this moment this is arm64 specific binding.

I meant the longtrail workaround, hence my comments on that below.

oh! thanks, will remove this.

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

We limited to longtrail workaround in the core memory parsing to PPC32 only in commit b44aa25d20e2ef6b (of: Handle memory at 0 node on PPC32 only). This code doesn't need it enabled ever.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

Are you booting using UEFI? This isn't going to work when the memory map

tried with bootwrapper, working on to boot from UEFI.

Quoted 1 line

comes from UEFI and we have no memory nodes in the DTB.

yes, there is issue with UEFI boot, since memory node is removed. i request UEFI stub dev-team to suggest the possible ways to address this.

I've Cc'd a few people who have worked on the stub and/or EFI memory map stuff. It would be worth keeping them on Cc so as to keep them informed.

Quoted 9 lines

thanks.

Quoted 4 lines

I believe that the EFI stub is doing the right thing by ensuring that the EFI memory map is used, so this is just another configuration that your binding has to consider.

going through EFI stub, next is to boot numa kernel using UEFI, will include UEFI boot support in v2 patch.

Quoted 2 lines

Mark.

Below is the example for the proposal of numa bindings in DT. This covers cpu to node mapping, memory ranges to node mapping. Also defines proximity distance matrix of nodes to each other. please let me know your comments to go ahead with the implementation.

numa-map{
         /*  Address cells used for memory range base address in mem-map.
             For all others, size-cells is used.
             Node-count tells the number of numa nodes in the system.
         */
         #address-cells = <2>;
         #size-cells = <1>;
         #node-count = <4>;

         /* Memmap for memory ranges on each node>

         mem-map = <0x0   0x00c00000 0>,
           <0x1   0x00000000 1>,
           <0x100 0x00000000 2>,
           <0x200 0x00000000 3>;

         /* CPU to node map for 4 NODE and 16 CPUs system
        < first-cpu last-cpu  node belongs>
         */
         cpu-map = <0 3 0>,
                         <4 7 1>,
                        <8 11 2>,
                        <12 16 3>;

         /*Proximity Distance matrix for 4Node system
                       <from-node to-node distance>
        */
         node-matrix=    <0 0 10>,
                               <0 1 20>,
                               <0 2 30>,
                               <0 3 10>,
                               <1 0 20>,
                                <1 1 10>,
                               <1 2 30>,
                              <1 3 10>,
                              <2 0 30>,
                              <2 1 20>,
                              <2 2 10>,
                             <2 3 10>,
                            <3 0 10>,
                            <3 1 20>,
                            <3 2 30>,
                            <3 3 10>,

}

thanks
Ganapat

#17 lore raw

RFC PATCH 4/4 arm64:numa: adding numa support for arm64 platforms.

Quoted 212 lines · Ganapatrao Kulkarni

Hi All,

Quoted 151 lines · Ganapatrao Kulkarni
Quoted 26 lines · Mark Rutland
Quoted 25 lines · Ganapatrao Kulkarni

Hi Mark,

Quoted 8 lines · Mark Rutland
Quoted 4 lines · Ganapatrao Kulkarni

Adding numa support for arm64 based platforms.
This version creates numa mapping by parsing the dt table. cpu to node id mapping is derived from cluster_id as defined in cpu-map. memory to node id mapping is derived from nid property of memory node.

[...]

Quoted 8 lines

arch/arm64/include/asm/numa.h line 17

Quoted 6 lines
arch/arm64/include/asm/numa.h new file +6 -0
+/*
+ * Too small node sizes may confuse the VM badly. Usually they
+ * result from BIOS bugs. So dont recognize nodes as standalone
+ * NUMA entities that have less than this amount of RAM listed:
+ */
+#define NODE_MIN_SIZE (4*1024*1024)

Why do these confuse the VM? what does BIOS have to do with arm64?

sneaked in from x86, will remove this.

Quoted 5 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+
+#define parent_node(node)      (node)

Huh?

Quoted 6 lines
Quoted 2 lines

for thunder, no hierarchy at numa nodes. shall i put under ifdef or separate header file?

I was confused by a node being its own parent, but that seems to be the case elsewhere for parent_node() implementations. Please at least have a comment that we're assuming a flat hierarchy (for now).

sure, will add the required comments.

Quoted 40 lines
Quoted 40 lines
Quoted 8 lines

[...]

Quoted 4 lines
arch/arm64/mm/init.c +0 -0
@@ -168,6 +191,11 @@ void __init bootmem_init(void)
        min = PFN_UP(memblock_start_of_DRAM());
        max = PFN_DOWN(memblock_end_of_DRAM());
 
Quoted 8 lines

arch/arm64/mm/init.c void __init bootmem_init(void) · line 198

Quoted 5 lines
arch/arm64/mm/init.c +5 -0
+       high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
+       max_pfn = max_low_pfn = max;
+
+       if (IS_ENABLED(CONFIG_NUMA))
+               arm64_numa_init();

Is this function defined if !CONFIG_NUMA? Surely it must do nothing in that case anyway?

yes, if is not required, will remove it.

Quoted 23 lines

[...]

arch/arm64/mm/numa.c line 117

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+/*
+ *  Set the cpu to node and mem mapping
+ */
+void numa_store_cpu_info(cpu)
+{
+       cpu_to_node_map[cpu] = cpu_topology[cpu].cluster_id;
+       cpumask_set_cpu(cpu, node_to_cpumask_map[cpu_to_node_map[cpu]]);
+       set_numa_node(cpu_to_node_map[cpu]);
+       set_numa_mem(local_memory_node(cpu_to_node_map[cpu]));
+}

I don't like this. I think we need to be more explicit in the DT w.r.t. the relationship between memory and the CPU hierarchy.

I can imagine that we might end up with systems with multiple levels of NUMA hierarchy (using MPIDR_EL1.Aff{3,2}), and I'd rather that we were explcit as possible from the start w.r.t. the relationship between memory and groups of CPUs such that we don't end up with multiple ways of specifying said relationship, and horrible edge cases around implicit definitions (e.g. the nid to cluster mapping).

Quoted 4 lines
Quoted 1 line

are you recomending to have explicit nid attribute to each cpu device node?

I am recommending that we make the relationship explicit. If anything, using the cpu-map (with phandles) seems like a better approach.

yes, will add the mapping.

Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 4 lines
arch/arm64/mm/numa.c new file +3 -0
+/**
+ * dummy_numa_init - Fallback dummy NUMA init
+ *

arch/arm64/mm/numa.c line 386

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+ * Used if there's no underlying NUMA architecture, NUMA initialization
+ * fails, or NUMA is disabled on the command line.
+ *
+ * Must online at least one node and add memory blocks that cover all
+ * allowed memory.  This function must not fail.
+ */
+static int __init dummy_numa_init(void)
+{
+       pr_info("%s\n",
+              numa_off ? "NUMA turned off" : "No NUMA configuration found");

Why not print "NUMA turned off" in numa_setup?

Quoted 6 lines
Quoted 2 lines

enters this function only when, numa is turned off or the DT/ACPI based numa init fails.

Sure. Moving the "NUMA turned off" print into numa_setup would mean you could just print "Using dummy NUMA layout" or something to that effect here -- the function has no need to care about the value of numa_off.

agreed.

Quoted 31 lines
Quoted 31 lines
Quoted 31 lines
Quoted 19 lines
arch/arm64/mm/numa.c new file +17 -0
+       pr_info("Faking a node at [mem %#018Lx-%#018Lx]\n",
+              0LLU, PFN_PHYS(max_pfn) - 1);
+
+       node_set(0, numa_nodes_parsed);
+       numa_add_memblk(0, 0, PFN_PHYS(max_pfn));
+
+       return 0;
+}
+
+/**
+ * early_init_dt_scan_numa_map - parse memory node and map nid to memory range.
+ */
+int __init early_init_dt_scan_numa_map(unsigned long node, const char *uname,
+                                    int depth, void *data)
+{
+       const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+       const __be32 *reg, *endp, *nid_prop;

arch/arm64/mm/numa.c line 413

Quoted 10 lines
arch/arm64/mm/numa.c new file +10 -0
+       int l, nid;
+
+       /* We are scanning "memory" nodes only */
+       if (type == NULL) {
+               /*
+                * The longtrail doesn't have a device_type on the
+                * /memory node, so look for the node called /memory at 0.
+                */
+               if (depth != 1 || strcmp(uname, "memory at 0") != 0)
+                       return 0;

This has no place on arm64.

Quoted 4 lines
Quoted 2 lines

i am not sure that we can move to driver/of, at this moment this is arm64 specific binding.

I meant the longtrail workaround, hence my comments on that below.

oh! thanks, will remove this.

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

We limited to longtrail workaround in the core memory parsing to PPC32 only in commit b44aa25d20e2ef6b (of: Handle memory at 0 node on PPC32 only). This code doesn't need it enabled ever.

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

Are you booting using UEFI? This isn't going to work when the memory map

tried with bootwrapper, working on to boot from UEFI.

Quoted 1 line

comes from UEFI and we have no memory nodes in the DTB.

yes, there is issue with UEFI boot, since memory node is removed. i request UEFI stub dev-team to suggest the possible ways to address this.

I've Cc'd a few people who have worked on the stub and/or EFI memory map stuff. It would be worth keeping them on Cc so as to keep them informed.

Quoted 9 lines

thanks.

Quoted 4 lines

I believe that the EFI stub is doing the right thing by ensuring that the EFI memory map is used, so this is just another configuration that your binding has to consider.

going through EFI stub, next is to boot numa kernel using UEFI, will include UEFI boot support in v2 patch.

Quoted 2 lines

Mark.

Below is the example for the proposal of numa bindings in DT. This covers cpu to node mapping, memory ranges to node mapping. Also defines proximity distance matrix of nodes to each other. please let me know your comments to go ahead with the implementation.

numa-map{
         /*  Address cells used for memory range base address in mem-map.
             For all others, size-cells is used.
             Node-count tells the number of numa nodes in the system.
         */
         #address-cells = <2>;
         #size-cells = <1>;
         #node-count = <4>;

         /* Memmap for memory ranges on each node>

         mem-map = <0x0   0x00c00000 0>,
           <0x1   0x00000000 1>,
           <0x100 0x00000000 2>,
           <0x200 0x00000000 3>;

         /* CPU to node map for 4 NODE and 16 CPUs system
        < first-cpu last-cpu  node belongs>
         */
         cpu-map = <0 3 0>,
                         <4 7 1>,
                        <8 11 2>,
                        <12 16 3>;

         /*Proximity Distance matrix for 4Node system
                       <from-node to-node distance>
        */
         node-matrix=    <0 0 10>,
                               <0 1 20>,
                               <0 2 30>,
                               <0 3 10>,
                               <1 0 20>,
                                <1 1 10>,
                               <1 2 30>,
                              <1 3 10>,
                              <2 0 30>,
                              <2 1 20>,
                              <2 2 10>,
                             <2 3 10>,
                            <3 0 10>,
                            <3 1 20>,
                            <3 2 30>,
                            <3 3 10>,
Quoted 1 line

}

Hi Ganapat,
The above caught my attention.

For a 4-node system do we not need 16 distances; the implication of that would be that the distance between node A-B could be different from the distance between B-A? Also the distance from a node to itself could be safely assumed to be zero?

I think we should have a symmetric matrix with zero-diagonals so strictly only seven values would need specifying for a 4-node system.

Cheers,

Signature · 1 line
Steve
#18 lore raw

RFC PATCH 4/4 arm64:numa: adding numa support for arm64 platforms.

Quoted 1 line · Steve Capper

On Fri, Oct 17, 2014 at 10:49:56PM +0530, Ganapatrao Kulkarni wrote:

[...]

Quoted 24 lines
         /*Proximity Distance matrix for 4Node system
Quoted 18 lines
                       <from-node to-node distance>
        */
         node-matrix=    <0 0 10>,
                               <0 1 20>,
                               <0 2 30>,
                               <0 3 10>,
                               <1 0 20>,
                                <1 1 10>,
                               <1 2 30>,
                              <1 3 10>,
                              <2 0 30>,
                              <2 1 20>,
                              <2 2 10>,
                             <2 3 10>,
                            <3 0 10>,
                            <3 1 20>,
                            <3 2 30>,
                            <3 3 10>,
Quoted 1 line

}

Hi Ganapat,
The above caught my attention.

Quoted 7 lines

For a 4-node system do we not need 16 distances; the implication of that would be that the distance between node A-B could be different from the distance between B-A? Also the distance from a node to itself could be safely assumed to be zero?

I think we should have a symmetric matrix with zero-diagonals so strictly only seven values would need specifying for a 4-node system.

s/seven/six/

I really need to learn how to count.... :-/

Quoted 4 lines

Cheers,

Signature · 1 line
Steve
#19 lore raw

RFC PATCH 4/4 arm64:numa: adding numa support for arm64 platforms.

Quoted 29 lines · Steve Capper
Quoted 1 line · Steve Capper

On Fri, Oct 17, 2014 at 10:49:56PM +0530, Ganapatrao Kulkarni wrote:

[...]

Quoted 24 lines
         /*Proximity Distance matrix for 4Node system
Quoted 18 lines
                       <from-node to-node distance>
        */
         node-matrix=    <0 0 10>,
                               <0 1 20>,
                               <0 2 30>,
                               <0 3 10>,
                               <1 0 20>,
                                <1 1 10>,
                               <1 2 30>,
                              <1 3 10>,
                              <2 0 30>,
                              <2 1 20>,
                              <2 2 10>,
                             <2 3 10>,
                            <3 0 10>,
                            <3 1 20>,
                            <3 2 30>,
                            <3 3 10>,
Quoted 1 line

}

Hi Ganapat,
The above caught my attention.

Quoted 7 lines
Quoted 7 lines

For a 4-node system do we not need 16 distances; the implication of that would be that the distance between node A-B could be different from the distance between B-A? Also the distance from a node to itself could be safely assumed to be zero?

I think we should have a symmetric matrix with zero-diagonals so strictly only seven values would need specifying for a 4-node system.

Thanks Stave for the comments.
I too thought initially to take the assumption like distance B-A is same as A-B and A-A is always defined to LOCAL. However this example is an ideal case which will define all 16 distances for 4 node system.
In actual DT, we can skip to provide A-A and B-A, In kernel implementation we will use these common/generic assumptions to derive missing distances.

Quoted 9 lines

s/seven/six/

I really need to learn how to count.... :-/

Quoted 4 lines

Cheers,
--
Steve

thanks
Ganapat

#20 lore raw

RFC PATCH 4/4 arm64:numa: adding numa support for arm64 platforms.

In reply to Ganapatrao Kulkarni

Hi Ganapatrao,

On 2014-10-18 1:19, Ganapatrao Kulkarni wrote:
[...]

Quoted 16 lines

Below is the example for the proposal of numa bindings in DT. This covers cpu to node mapping, memory ranges to node mapping. Also defines proximity distance matrix of nodes to each other. please let me know your comments to go ahead with the implementation.

numa-map{
         /*  Address cells used for memory range base address in mem-map.
             For all others, size-cells is used.
             Node-count tells the number of numa nodes in the system.
         */
         #address-cells = <2>;
         #size-cells = <1>;
         #node-count = <4>;

         /* Memmap for memory ranges on each node>
Quoted 7 lines
         mem-map = <0x0   0x00c00000 0>,
           <0x1   0x00000000 1>,
           <0x100 0x00000000 2>,
           <0x200 0x00000000 3>;

         /* CPU to node map for 4 NODE and 16 CPUs system
        < first-cpu last-cpu  node belongs>

What's the property for the cpu? MPIDR of this CPU?

Quoted 6 lines
         */
         cpu-map = <0 3 0>,
                         <4 7 1>,
                        <8 11 2>,
                        <12 16 3>;

Thanks
Hanjun

#21 lore raw

RFC PATCH 4/4 arm64:numa: adding numa support for arm64 platforms.

Hi Hanjun,

Quoted 25 lines · Hanjun Guo

Hi Ganapatrao,

On 2014-10-18 1:19, Ganapatrao Kulkarni wrote:
[...]

Quoted 21 lines

Below is the example for the proposal of numa bindings in DT. This covers cpu to node mapping, memory ranges to node mapping. Also defines proximity distance matrix of nodes to each other. please let me know your comments to go ahead with the implementation.

numa-map{
         /*  Address cells used for memory range base address in mem-map.
             For all others, size-cells is used.
             Node-count tells the number of numa nodes in the system.
         */
         #address-cells = <2>;
         #size-cells = <1>;
         #node-count = <4>;

         /* Memmap for memory ranges on each node>

         mem-map = <0x0   0x00c00000 0>,
           <0x1   0x00000000 1>,
           <0x100 0x00000000 2>,
           <0x200 0x00000000 3>;
Quoted 4 lines
Quoted 2 lines

/* CPU to node map for 4 NODE and 16 CPUs system
< first-cpu last-cpu node belongs>

What's the property for the cpu? MPIDR of this CPU?

I see in ACPI spec, there is mapping between logical cpu number to physical id(using MPIDR) using GICC Affinity Structure
Here i am defining mapping between the logical CPUs and the node it belongs. SMP initialization uses CPU node property of DT to bring them up. We can get physical id using cpu_logical_map(cpu), which is MPIDR Do you see any need to expand cpu-map here to have the mapping between physical cpu id and logical cpu id?

Quoted 8 lines
Quoted 7 lines
         */
         cpu-map = <0 3 0>,
                         <4 7 1>,
                        <8 11 2>,
                        <12 16 3>;
Quoted 4 lines

Thanks
Hanjun

thanks
ganapat

Quoted 4 lines

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#22 lore raw

RFC PATCH 4/4 arm64:numa: adding numa support for arm64 platforms.

In reply to Ganapatrao Kulkarni

Adding numa support for arm64 based platforms.
This version creates numa mapping by parsing the dt table. cpu to node id mapping is derived from cluster_id as defined in cpu-map. memory to node id mapping is derived from nid property of memory node.

---
 arch/arm64/Kconfig              |  33 +++
 arch/arm64/include/asm/mmzone.h |  32 +++
 arch/arm64/include/asm/numa.h   |  41 ++++
 arch/arm64/kernel/setup.c       |   8 +
 arch/arm64/kernel/smp.c         |   2 +
 arch/arm64/mm/Makefile          |   1 +
 arch/arm64/mm/init.c            |  33 ++-
 arch/arm64/mm/numa.c            | 471 ++++++++++++++++++++++++++++++++++++++++
 8 files changed, 617 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm64/include/asm/mmzone.h
 create mode 100644 arch/arm64/include/asm/numa.h
 create mode 100644 arch/arm64/mm/numa.c
arch/arm64/Kconfig +33 -0
index a409105..415ee53 100644
@@ -142,6 +142,7 @@ config ARCH_THUNDER
 	select NET_VENDOR_CAVIUM
 	select SATA_AHCI
 	select SATA_AHCI_PLATFORM
+	select HAVE_MEMBLOCK_NODE_MAP if NUMA
 
 config ARCH_VEXPRESS
 	bool "ARMv8 software model (Versatile Express)"
@@ -309,6 +310,38 @@ config HOTPLUG_CPU
 	  Say Y here to experiment with turning CPUs off and on.  CPUs
 	  can be controlled through /sys/devices/system/cpu.
 
+# Common NUMA Features
+config NUMA
+	bool "Numa Memory Allocation and Scheduler Support"
+	depends on SMP
+	---help---
+	  Enable NUMA (Non Uniform Memory Access) support.
+
+	  The kernel will try to allocate memory used by a CPU on the
+	  local memory controller of the CPU and add some more
+	  NUMA awareness to the kernel.
+
+config ARM64_DT_NUMA
+	def_bool y
+	prompt "DT NUMA detection"
+	depends on ARM64 && NUMA && DTC
+	---help---
+	  Enable DT based numa.
+
+config NODES_SHIFT
+	int "Maximum NUMA Nodes (as a power of 2)"
+	range 1 10
+	default "2"
+	depends on NEED_MULTIPLE_NODES
+	---help---
+	  Specify the maximum number of NUMA Nodes available on the target
+	  system.  Increases memory reserved to accommodate various tables.
+
+config USE_PERCPU_NUMA_NODE_ID
+	def_bool y
+	depends on NUMA
+
+
 source kernel/Kconfig.preempt
 
 config HZ
arch/arm64/include/asm/mmzone.h new file +32 -0
new file mode 100644
index 0000000..d27ee66
@@ -0,0 +1,32 @@
+#ifndef __ASM_ARM64_MMZONE_H_
+#define __ASM_ARM64_MMZONE_H_
+
+#ifdef CONFIG_NUMA
+
+#include <linux/mmdebug.h>
+#include <asm/smp.h>
+#include <linux/types.h>
+#include <asm/numa.h>
+
+extern struct pglist_data *node_data[];
+
+#define NODE_DATA(nid)		(node_data[nid])
+
+
+struct numa_memblk {
+	u64			start;
+	u64			end;
+	int			nid;
+};
+
+struct numa_meminfo {
+	int			nr_blks;
+	struct numa_memblk	blk[NR_NODE_MEMBLKS];
+};
+
+void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi);
+int __init numa_cleanup_meminfo(struct numa_meminfo *mi);
+void __init numa_reset_distance(void);
+
+#endif /* CONFIG_NUMA */
+#endif /* __ASM_ARM64_MMZONE_H_ */
arch/arm64/include/asm/numa.h new file +41 -0

41 lines not on this page · raw message

arch/arm64/kernel/setup.c +8 -0
index edb146d..436b78d 100644
@@ -424,6 +424,9 @@ static int __init topology_init(void)
 {
 	int i;
 
+	for_each_online_node(i)
+		register_one_node(i);
+
 	for_each_possible_cpu(i) {
 		struct cpu *cpu = &per_cpu(cpu_data.cpu, i);
 		cpu->hotpluggable = 1;
@@ -460,7 +463,12 @@ static int c_show(struct seq_file *m, void *v)
 		 * "processor".  Give glibc what it expects.
 		 */
 #ifdef CONFIG_SMP
+	if (IS_ENABLED(CONFIG_NUMA)) {
+		seq_printf(m, "processor\t: %d", i);
+		seq_printf(m, " [nid: %d]\n", cpu_to_node(i));
+	} else {
 		seq_printf(m, "processor\t: %d\n", i);
+	}
 #endif
 	}
 
arch/arm64/kernel/smp.c +2 -0
index 4743397..60120db 100644
@@ -50,6 +50,7 @@
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
 #include <asm/ptrace.h>
+#include <asm/numa.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/ipi.h>
@@ -123,6 +124,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
 static void smp_store_cpu_info(unsigned int cpuid)
 {
 	store_cpu_topology(cpuid);
+	numa_store_cpu_info(cpuid);
 }
 
 /*
arch/arm64/mm/Makefile +1 -0
index 3ecb56c..4dda3d0 100644
@@ -3,3 +3,4 @@ obj-y				:= dma-mapping.o extable.o fault.o init.o \
 				   ioremap.o mmap.o pgd.o mmu.o \
 				   context.o proc.o
 obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
+obj-$(CONFIG_NUMA)		+= numa.o
arch/arm64/mm/init.c +29 -4
index 271e654..4b2bbb4 100644
@@ -39,6 +39,7 @@
 #include <asm/setup.h>
 #include <asm/sizes.h>
 #include <asm/tlb.h>
+#include <asm/numa.h>
 
 #include "mm.h"
 
@@ -73,6 +74,20 @@ static phys_addr_t max_zone_dma_phys(void)
 	return min(offset + (1ULL << 32), memblock_end_of_DRAM());
 }
 
+#ifdef CONFIG_NUMA
+static void __init zone_sizes_init(unsigned long min, unsigned long max)
+{
+	unsigned long max_zone_pfns[MAX_NR_ZONES];
+
+	memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+	if (IS_ENABLED(CONFIG_ZONE_DMA))
+		max_zone_pfns[ZONE_DMA] = PFN_DOWN(max_zone_dma_phys());
+	max_zone_pfns[ZONE_NORMAL] = max;
+
+	free_area_init_nodes(max_zone_pfns);
+}
+
+#else
 static void __init zone_sizes_init(unsigned long min, unsigned long max)
 {
 	struct memblock_region *reg;
@@ -111,6 +126,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
 
 	free_area_init_node(0, zone_size, min, zhole_size);
 }
+#endif /* CONFIG_NUMA */
 
 #ifdef CONFIG_HAVE_ARCH_PFN_VALID
 int pfn_valid(unsigned long pfn)
@@ -129,9 +145,16 @@ static void arm64_memory_present(void)
 {
 	struct memblock_region *reg;
 
-	for_each_memblock(memory, reg)
+	for_each_memblock(memory, reg) {
+#ifdef CONFIG_NUMA
+		memory_present(reg->nid,
+				memblock_region_memory_base_pfn(reg),
+				memblock_region_memory_end_pfn(reg));
+#else
 		memory_present(0, memblock_region_memory_base_pfn(reg),
 			       memblock_region_memory_end_pfn(reg));
+#endif
+	}
 }
 #endif
 
@@ -168,6 +191,11 @@ void __init bootmem_init(void)
 	min = PFN_UP(memblock_start_of_DRAM());
 	max = PFN_DOWN(memblock_end_of_DRAM());
 
+	high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
+	max_pfn = max_low_pfn = max;
+
+	if (IS_ENABLED(CONFIG_NUMA))
+		arm64_numa_init();
 	/*
 	 * Sparsemem tries to allocate bootmem in memory_present(), so must be
 	 * done after the fixed reservations.
@@ -176,9 +204,6 @@ void __init bootmem_init(void)
 
 	sparse_init();
 	zone_sizes_init(min, max);
-
-	high_memory = __va((max << PAGE_SHIFT) - 1) + 1;
-	max_pfn = max_low_pfn = max;
 }
 
 #ifndef CONFIG_SPARSEMEM_VMEMMAP
arch/arm64/mm/numa.c new file +471 -0

471 lines not on this page · raw message

Signature · 1 line
1.8.1.4