Skip to contentSkip to conversation

Arm CMN-600 PMU driver

PATCH In review Robin Murphy 4 participants 12 messages Sep 18, 2020 – Oct 15, 2020

Subsystems (4)
lore
Share & tools
lore

Robin Murphy

author maintainer
#0 lore raw

v2 cover Arm CMN-600 PMU driver

Hi all,

Here's an update with some very minor cleanup tweaks, plus a proposal for some more in-depth debug information. Given that nobody seems to have any significant complaints about the interface, I assume we're all happy to merge the basic driver as-is and fix anything later if needed.

Robin.

Robin Murphy (3):
perf: Add Arm CMN-600 DT binding
perf: Add Arm CMN-600 PMU driver
perf/arm-cmn: Add debugfs topology info

 Documentation/admin-guide/perf/arm-cmn.rst    |   65 +
 Documentation/admin-guide/perf/index.rst      |    1 +
 .../devicetree/bindings/perf/arm,cmn.yaml     |   57 +
 drivers/perf/Kconfig                          |    7 +
 drivers/perf/Makefile                         |    1 +
 drivers/perf/arm-cmn.c                        | 1790 +++++++++++++++++
 6 files changed, 1921 insertions(+)
 create mode 100644 Documentation/admin-guide/perf/arm-cmn.rst
 create mode 100644 Documentation/devicetree/bindings/perf/arm,cmn.yaml
 create mode 100644 drivers/perf/arm-cmn.c
Signature · 1 line
2.28.0.dirty
author maintainer
#1 lore raw

PATCH v2 1/3 perf: Add Arm CMN-600 DT binding

Document the requirements for the CMN-600 DT binding. The internal topology is almost entirely discoverable by walking a tree of ID registers, but sadly both the starting point for that walk and the exact format of those registers are configuration-dependent and not discoverable from some sane fixed location. Oh well.

---

v2: fix filename, license and whitespace per Rob's comments

 .../devicetree/bindings/perf/arm,cmn.yaml     | 57 +++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/perf/arm,cmn.yaml
Documentation/devicetree/bindings/perf/arm,cmn.yaml new file +57 -0
new file mode 100644
index 000000000000..15689cbf417d
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright 2020 Arm Ltd.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/perf/arm-cmn.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Arm CMN (Coherent Mesh Network) Performance Monitors
+
+maintainers:
+  - Robin Murphy <[email protected]>
+
+properties:
+  compatible:
+    const: arm,cmn-600
+
+  reg:
+    items:
+      - description: Physical address of the base (PERIPHBASE) and
+          size (up to 64MB) of the configuration address space.
+
+  interrupts:
+    minItems: 1
+    maxItems: 4
+    items:
+      - description: Overflow interrupt for DTC0
+      - description: Overflow interrupt for DTC1
+      - description: Overflow interrupt for DTC2
+      - description: Overflow interrupt for DTC3
+    description: One interrupt for each DTC domain implemented must
+      be specified, in order. DTC0 is always present.
+
+  arm,root-node:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Offset from PERIPHBASE of the configuration
+      discovery node (see TRM definition of ROOTNODEBASE).
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - arm,root-node
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    pmu@50000000 {
+        compatible = "arm,cmn-600";
+        reg = <0x50000000 0x4000000>;
+        /* 4x2 mesh with one DTC, and CFG node at 0,1,1,0 */
+        interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+        arm,root-node = <0x104000>;
+    };
+...
Signature · 1 line
2.28.0.dirty
maintainer
#2 lore raw

Re: [PATCH v2 1/3] perf: Add Arm CMN-600 DT binding

Quoted 6 lines · Robin Murphy

Document the requirements for the CMN-600 DT binding. The internal topology is almost entirely discoverable by walking a tree of ID registers, but sadly both the starting point for that walk and the exact format of those registers are configuration-dependent and not discoverable from some sane fixed location. Oh well.

Quoted 9 lines

---

v2: fix filename, license and whitespace per Rob's comments

 .../devicetree/bindings/perf/arm,cmn.yaml     | 57 +++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/perf/arm,cmn.yaml

My bot found errors running 'make dt_binding_check' on your patch:

./Documentation/devicetree/bindings/perf/arm,cmn.yaml: $id: relative path/filename doesn't match actual path or filename
expected: http://devicetree.org/schemas/perf/arm,cmn.yaml#

See https://patchwork.ozlabs.org/patch/1366940

If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure dt-schema is up to date:

pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade

Please check and re-submit.

author maintainer
#3 lore raw

PATCH v2 1/3 perf: Add Arm CMN-600 DT binding

In reply to Robin Murphy

Document the requirements for the CMN-600 DT binding. The internal topology is almost entirely discoverable by walking a tree of ID registers, but sadly both the starting point for that walk and the exact format of those registers are configuration-dependent and not discoverable from some sane fixed location. Oh well.

---

fix up $id as well, oops...

 .../devicetree/bindings/perf/arm,cmn.yaml     | 57 +++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/perf/arm,cmn.yaml
Documentation/devicetree/bindings/perf/arm,cmn.yaml new file +57 -0
new file mode 100644
index 000000000000..e4fcc0de25e2
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright 2020 Arm Ltd.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/perf/arm,cmn.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Arm CMN (Coherent Mesh Network) Performance Monitors
+
+maintainers:
+  - Robin Murphy <[email protected]>
+
+properties:
+  compatible:
+    const: arm,cmn-600
+
+  reg:
+    items:
+      - description: Physical address of the base (PERIPHBASE) and
+          size (up to 64MB) of the configuration address space.
+
+  interrupts:
+    minItems: 1
+    maxItems: 4
+    items:
+      - description: Overflow interrupt for DTC0
+      - description: Overflow interrupt for DTC1
+      - description: Overflow interrupt for DTC2
+      - description: Overflow interrupt for DTC3
+    description: One interrupt for each DTC domain implemented must
+      be specified, in order. DTC0 is always present.
+
+  arm,root-node:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Offset from PERIPHBASE of the configuration
+      discovery node (see TRM definition of ROOTNODEBASE).
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - arm,root-node
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    pmu@50000000 {
+        compatible = "arm,cmn-600";
+        reg = <0x50000000 0x4000000>;
+        /* 4x2 mesh with one DTC, and CFG node at 0,1,1,0 */
+        interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+        arm,root-node = <0x104000>;
+    };
+...

--
2.28.0.dirty

maintainer
#4 lore raw

Re: [PATCH v2.1 1/3] perf: Add Arm CMN-600 DT binding

Quoted 7 lines · Robin Murphy

Document the requirements for the CMN-600 DT binding. The internal topology is almost entirely discoverable by walking a tree of ID registers, but sadly both the starting point for that walk and the exact format of those registers are configuration-dependent and not discoverable from some sane fixed location. Oh well.

Quoted 8 lines

---

fix up $id as well, oops...

 .../devicetree/bindings/perf/arm,cmn.yaml     | 57 +++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/perf/arm,cmn.yaml

Do you expect this to cover more than cmn-600? If not, use the compatible string for the file name.

Quoted 28 lines
Documentation/devicetree/bindings/perf/arm,cmn.yaml new file +21 -0
new file mode 100644
index 000000000000..e4fcc0de25e2
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright 2020 Arm Ltd.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/perf/arm,cmn.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Arm CMN (Coherent Mesh Network) Performance Monitors
+
+maintainers:
+  - Robin Murphy <[email protected]>
+
+properties:
+  compatible:
+    const: arm,cmn-600
+
+  reg:
+    items:
+      - description: Physical address of the base (PERIPHBASE) and
+          size (up to 64MB) of the configuration address space.
+

Documentation/devicetree/bindings/perf/arm,cmn.yaml line 31

Quoted 10 lines
Documentation/devicetree/bindings/perf/arm,cmn.yaml new file +10 -0
+  interrupts:
+    minItems: 1
+    maxItems: 4
+    items:
+      - description: Overflow interrupt for DTC0
+      - description: Overflow interrupt for DTC1
+      - description: Overflow interrupt for DTC2
+      - description: Overflow interrupt for DTC3
+    description: One interrupt for each DTC domain implemented must
+      be specified, in order. DTC0 is always present.

What's DTC?

Documentation/devicetree/bindings/perf/arm,cmn.yaml line 36

Quoted 5 lines
Documentation/devicetree/bindings/perf/arm,cmn.yaml new file +5 -0
+
+  arm,root-node:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Offset from PERIPHBASE of the configuration
+      discovery node (see TRM definition of ROOTNODEBASE).

You can enforce some alignment:

multipleOf: 0x4000

Quoted 23 lines
Documentation/devicetree/bindings/perf/arm,cmn.yaml new file +21 -1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - arm,root-node
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    pmu@50000000 {
+        compatible = "arm,cmn-600";
+        reg = <0x50000000 0x4000000>;
+        /* 4x2 mesh with one DTC, and CFG node at 0,1,1,0 */
+        interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+        arm,root-node = <0x104000>;
+    };
+...
--

2.28.0.dirty

author maintainer
#5 lore raw

Re: [PATCH v2.1 1/3] perf: Add Arm CMN-600 DT binding

Quoted 11 lines · Rob Herring
Quoted 10 lines · Robin Murphy

Document the requirements for the CMN-600 DT binding. The internal topology is almost entirely discoverable by walking a tree of ID registers, but sadly both the starting point for that walk and the exact format of those registers are configuration-dependent and not discoverable from some sane fixed location. Oh well.

---

Quoted 8 lines
Quoted 5 lines

fix up $id as well, oops...

  .../devicetree/bindings/perf/arm,cmn.yaml     | 57 +++++++++++++++++++
  1 file changed, 57 insertions(+)

create mode 100644 Documentation/devicetree/bindings/perf/arm,cmn.yaml

Do you expect this to cover more than cmn-600? If not, use the compatible string for the file name.

As far as I'm aware, future CMN products will maintain the same general PMU design, but with enough subtle differences to deserve their own compatible strings.

Quoted 31 lines
Quoted 31 lines
Documentation/devicetree/bindings/perf/arm,cmn.yaml new file +25 -0
new file mode 100644
index 000000000000..e4fcc0de25e2
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright 2020 Arm Ltd.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/perf/arm,cmn.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Arm CMN (Coherent Mesh Network) Performance Monitors
+
+maintainers:
+  - Robin Murphy <[email protected]>
+
+properties:
+  compatible:
+    const: arm,cmn-600
+
+  reg:
+    items:
+      - description: Physical address of the base (PERIPHBASE) and
+          size (up to 64MB) of the configuration address space.
+
+  interrupts:
+    minItems: 1
+    maxItems: 4
+    items:
Quoted 8 lines

Documentation/devicetree/bindings/perf/arm,cmn.yaml line 31

Quoted 6 lines
Documentation/devicetree/bindings/perf/arm,cmn.yaml new file +6 -0
+      - description: Overflow interrupt for DTC0
+      - description: Overflow interrupt for DTC1
+      - description: Overflow interrupt for DTC2
+      - description: Overflow interrupt for DTC3
+    description: One interrupt for each DTC domain implemented must
+      be specified, in order. DTC0 is always present.

What's DTC?

Debug and Trace Controller. I figure it's one of those situations where if someone knows enough about a CMN configuration to be able to write something to this binding, they're probably going to be familiar with the abbreviation.

In CMN terminology, "DT" is all over the place meaning "Debug and Trace". Only now do I suddenly realise that discussing this in the context of Device Tree is pretty much the worst-case scenario for confusion :)

Quoted 9 lines

Documentation/devicetree/bindings/perf/arm,cmn.yaml line 36

Quoted 5 lines
Documentation/devicetree/bindings/perf/arm,cmn.yaml new file +5 -0
+
+  arm,root-node:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: Offset from PERIPHBASE of the configuration
+      discovery node (see TRM definition of ROOTNODEBASE).

You can enforce some alignment:

multipleOf: 0x4000

That's one of the things that may vary in future, so I'm doubtful if it would really be worth the bother. There's only one correct value for a given configuration, and still hundreds of appropriately-aligned wrong ones, so ultimately either it's right and it works, or it's not and it won't (any sensible driver should do a bit of sanity-checking during discovery anyway).

Robin.

Quoted 23 lines
Quoted 23 lines
Documentation/devicetree/bindings/perf/arm,cmn.yaml new file +21 -1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - arm,root-node
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    pmu@50000000 {
+        compatible = "arm,cmn-600";
+        reg = <0x50000000 0x4000000>;
+        /* 4x2 mesh with one DTC, and CFG node at 0,1,1,0 */
+        interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+        arm,root-node = <0x104000>;
+    };
+...
--

2.28.0.dirty

author maintainer
#6 lore raw

PATCH v2 2/3 perf: Add Arm CMN-600 PMU driver

In reply to Robin Murphy

Initial driver for PMU event counting on the Arm CMN-600 interconnect. CMN sports an obnoxiously complex distributed PMU system as part of its debug and trace features, which can do all manner of things like sampling, cross-triggering and generating CoreSight trace. This driver covers the PMU functionality, plus the relevant aspects of watchpoints for simply counting matching flits.

---

v2:
- fix non-atomic use of atomic ID counter
- slightly refactor DTM initialisation to be more sensible
- remove left-over root node probing hack

 Documentation/admin-guide/perf/arm-cmn.rst |   65 +
 Documentation/admin-guide/perf/index.rst   |    1 +
 drivers/perf/Kconfig                       |    7 +
 drivers/perf/Makefile                      |    1 +
 drivers/perf/arm-cmn.c                     | 1641 ++++++++++++++++++++
 5 files changed, 1715 insertions(+)
 create mode 100644 Documentation/admin-guide/perf/arm-cmn.rst
 create mode 100644 drivers/perf/arm-cmn.c
Documentation/admin-guide/perf/arm-cmn.rst new file +65 -0
new file mode 100644
index 000000000000..0e4809346014
@@ -0,0 +1,65 @@
+=============================
+Arm Coherent Mesh Network PMU
+=============================
+
+CMN-600 is a configurable mesh interconnect consisting of a rectangular
+grid of crosspoints (XPs), with each crosspoint supporting up to two
+device ports to which various AMBA CHI agents are attached.
+
+CMN implements a distributed PMU design as part of its debug and trace
+functionality. This consists of a local monitor (DTM) at every XP, which
+counts up to 4 event signals from the connected device nodes and/or the
+XP itself. Overflow from these local counters is accumulated in up to 8
+global counters implemented by the main controller (DTC), which provides
+overall PMU control and interrupts for global counter overflow.
+
+PMU events
+----------
+
+The PMU driver registers a single PMU device for the whole interconnect,
+see /sys/bus/event_source/devices/arm_cmn. Multi-chip systems may link
+more than one CMN together via external CCIX links - in this situation,
+each mesh counts its own events entirely independently, and additional
+PMU devices will be named arm_cmn_{1..n}.
+
+Most events are specified in a format based directly on the TRM
+definitions - "type" selects the respective node type, and "eventid" the
+event number. Some events require an additional occupancy ID, which is
+specified by "occupid".
+
+* Since RN-D nodes do not have any distinct events from RN-I nodes, they
+  are treated as the same type (0xa), and the common event templates are
+  named "rnid_*".
+
+* The cycle counter is treated as a synthetic event belonging to the DTC
+  node ("type" == 0x3, "eventid" is ignored).
+
+* XP events also encode the port and channel in the "eventid" field, to
+  match the underlying pmu_event0_id encoding for the pmu_event_sel
+  register. The event templates are named with prefixes to cover all
+  permutations.
+
+By default each event provides an aggregate count over all nodes of the
+given type. To target a specific node, "bynodeid" must be set to 1 and
+"nodeid" to the appropriate value derived from the CMN configuration
+(as defined in the "Node ID Mapping" section of the TRM).
+
+Watchpoints
+-----------
+
+The PMU can also count watchpoint events to monitor specific flit
+traffic. Watchpoints are treated as a synthetic event type, and like PMU
+events can be global or targeted with a particular XP's "nodeid" value.
+Since the watchpoint direction is otherwise implicit in the underlying
+register selection, separate events are provided for flit uploads and
+downloads.
+
+The flit match value and mask are passed in config1 and config2 ("val"
+and "mask" respectively). "wp_dev_sel", "wp_chn_sel", "wp_grp" and
+"wp_exclusive" are specified per the TRM definitions for dtm_wp_config0.
+Where a watchpoint needs to match fields from both match groups on the
+REQ or SNP channel, it can be specified as two events - one for each
+group - with the same nonzero "combine" value. The count for such a
+pair of combined events will be attributed to the primary match.
+Watchpoint events with a "combine" value of 0 are considered independent
+and will count individually.
Documentation/admin-guide/perf/index.rst +1 -0
index 47c99f40cc16..5a8f2529a033 100644
@@ -12,6 +12,7 @@ Performance monitor support
    qcom_l2_pmu
    qcom_l3_pmu
    arm-ccn
+   arm-cmn
    xgene-pmu
    arm_dsu_pmu
    thunderx2-pmu
drivers/perf/Kconfig +7 -0
index 7305d57d1890..130327ff0b0e 100644
@@ -41,6 +41,13 @@ config ARM_CCN
 	  PMU (perf) driver supporting the ARM CCN (Cache Coherent Network)
 	  interconnect.
 
+config ARM_CMN
+	tristate "Arm CMN-600 PMU support"
+	depends on ARM64 || (COMPILE_TEST && 64BIT)
+	help
+	  Support for PMU events monitoring on the Arm CMN-600 Coherent Mesh
+	  Network interconnect.
+
 config ARM_PMU
 	depends on ARM || ARM64
 	bool "ARM PMU framework"
drivers/perf/Makefile +1 -0
index 2ebb4de17815..5365fd56f88f 100644
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_ARM_CCI_PMU) += arm-cci.o
 obj-$(CONFIG_ARM_CCN) += arm-ccn.o
+obj-$(CONFIG_ARM_CMN) += arm-cmn.o
 obj-$(CONFIG_ARM_DSU_PMU) += arm_dsu_pmu.o
 obj-$(CONFIG_ARM_PMU) += arm_pmu.o arm_pmu_platform.o
 obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_acpi.o
drivers/perf/arm-cmn.c new file +1641 -0

1,641 lines not on this page · raw message

Signature · 1 line
2.28.0.dirty
author maintainer
#7 lore raw

RFC v2 3/3 perf/arm-cmn: Add debugfs topology info

In reply to Robin Murphy

In general, detailed performance analysis will require knoweldge of the the SoC beyond the CMN itself - e.g. which actual CPUs/peripherals/etc. are connected to each node. However for certain development and bringup tasks it can be useful to have a quick overview of the CMN internal topology to hand too. Add a debugfs file to map this out.

---
 drivers/perf/arm-cmn.c | 161 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 155 insertions(+), 6 deletions(-)
drivers/perf/arm-cmn.c +155 -6
index e824b5b83ea2..629373d7deb1 100644
@@ -5,6 +5,7 @@
 #include <linux/acpi.h>
 #include <linux/bitfield.h>
 #include <linux/bitops.h>
+#include <linux/debugfs.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -47,6 +48,10 @@
 #define CMN_CFGM_PERIPH_ID_2		0x0010
 #define CMN_CFGM_PID2_REVISION		GENMASK(7, 4)
 
+/* XPs have some extra topology info which isn't directly relevant to the PMU */
+#define CMN_MXP__CONNECT_INFO_P0	0x0008
+#define CMN_MXP__CONNECT_INFO_P1	0x0010
+
 /* PMU registers occupy the 3rd 4KB page of each node's 16KB space */
 #define CMN_PMU_OFFSET			0x2000
 
@@ -248,11 +253,151 @@ struct arm_cmn {
 
 	unsigned int state;
 	struct pmu pmu;
+	struct dentry *debug;
 };
 
 #define to_cmn(p)	container_of(p, struct arm_cmn, pmu)
 
+static int arm_cmn_xyidbits(const struct arm_cmn *cmn)
+{
+	return cmn->mesh_x > 4 || cmn->mesh_y > 4 ? 3 : 2;
+}
+
 static int arm_cmn_hp_state;
+struct dentry *arm_cmn_debugfs;
+
+#ifdef CONFIG_DEBUG_FS
+static const char *arm_cmn_device_type(u8 type)
+{
+	switch(type) {
+		case 0x01: return "  RN-I  |";
+		case 0x02: return "  RN-D  |";
+		case 0x04: return " RN-F_B |";
+		case 0x05: return "RN-F_B_E|";
+		case 0x06: return " RN-F_A |";
+		case 0x07: return "RN-F_A_E|";
+		case 0x08: return "  HN-T  |";
+		case 0x09: return "  HN-I  |";
+		case 0x0a: return "  HN-D  |";
+		case 0x0c: return "  SN-F  |";
+		case 0x0d: return "  SBSX  |";
+		case 0x0e: return "  HN-F  |";
+		case 0x11: return "  CXHA  |";
+		case 0x12: return "  CXRA  |";
+		case 0x13: return "  CXRH  |";
+		default:   return "        |";
+	}
+}
+
+static void arm_cmn_show_logid(struct seq_file *s, int x, int y, int p, int d)
+{
+	struct arm_cmn *cmn = s->private;
+	int i, bits = arm_cmn_xyidbits(cmn);
+
+	for (i = 0; i < cmn->num_dns; i++) {
+		enum cmn_node_type type = cmn->dns[i].type;
+		u16 id = cmn->dns[i].id;
+
+		if (type == CMN_TYPE_XP)
+			continue;
+		/* Ignore the extra components that will overlap on some ports */
+		if (type < CMN_TYPE_HNI)
+			continue;
+
+		if (CMN_NODEID_X(id, bits) != x || CMN_NODEID_Y(id, bits) != y ||
+		    CMN_NODEID_PID(id) != p || CMN_NODEID_DEVID(id) != d)
+			continue;
+
+		seq_printf(s, "   #%-2d  |", cmn->dns[i].logid);
+		return;
+	}
+	seq_puts(s, "        |");
+}
+
+static int arm_cmn_map_show(struct seq_file *s, void *data)
+{
+	struct arm_cmn *cmn = s->private;
+	int x, y;
+
+	seq_puts(s, "     X");
+	for (x = 0; x < cmn->mesh_x; x++)
+		seq_printf(s, "    %d    ", x);
+	seq_puts(s, "\nY P D+");
+	y = cmn->mesh_y;
+	while (y--) {
+		int xp_base = cmn->mesh_x * y;
+		u8 port[2][8] = {};
+
+		for (x = 0; x < cmn->mesh_x; x++)
+			seq_puts(s, "--------+");
+
+		seq_printf(s, "\n%d    |", y);
+		for (x = 0; x < cmn->mesh_x; x++) {
+			struct arm_cmn_node *xp = cmn->xps + xp_base + x;
+			void __iomem *base = xp->pmu_base - CMN_PMU_OFFSET;
+
+			port[0][x] = readl_relaxed(base + CMN_MXP__CONNECT_INFO_P0);
+			port[1][x] = readl_relaxed(base + CMN_MXP__CONNECT_INFO_P1);
+			seq_printf(s, " XP #%-2d |", xp_base + x);
+		}
+
+		seq_puts(s, "\n     |");
+		for (x = 0; x < cmn->mesh_x; x++) {
+			int dtc = cmn->xps[xp_base + x].dtc;
+
+			if (dtc < 0)
+				seq_puts(s, " DTC ?? |");
+			else
+				seq_printf(s, " DTC %d  |", dtc);
+		}
+		seq_puts(s, "\n     |");
+		for (x = 0; x < cmn->mesh_x; x++)
+			seq_puts(s, "........|");
+
+		seq_puts(s, "\n  0  |");
+		for (x = 0; x < cmn->mesh_x; x++)
+			seq_puts(s, arm_cmn_device_type(port[0][x]));
+		seq_puts(s, "\n    0|");
+		for (x = 0; x < cmn->mesh_x; x++)
+			arm_cmn_show_logid(s, x, y, 0, 0);
+		seq_puts(s, "\n    1|");
+		for (x = 0; x < cmn->mesh_x; x++)
+			arm_cmn_show_logid(s, x, y, 0, 1);
+
+		seq_puts(s, "\n  1  |");
+		for (x = 0; x < cmn->mesh_x; x++)
+			seq_puts(s, arm_cmn_device_type(port[1][x]));
+		seq_puts(s, "\n    0|");
+		for (x = 0; x < cmn->mesh_x; x++)
+			arm_cmn_show_logid(s, x, y, 1, 0);
+		seq_puts(s, "\n    1|");
+		for (x = 0; x < cmn->mesh_x; x++)
+			arm_cmn_show_logid(s, x, y, 1, 1);
+
+		seq_puts(s, "\n-----+");
+	}
+	for (x = 0; x < cmn->mesh_x; x++)
+		seq_puts(s, "--------+");
+	seq_puts(s, "\n");
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(arm_cmn_map);
+
+static void arm_cmn_debugfs_init(struct arm_cmn *cmn, int id)
+{
+	const char *name  = "map";
+
+	if (id > 0)
+		name = devm_kasprintf(cmn->dev, GFP_KERNEL, "map_%d", id);
+	if (!name)
+		return;
+
+	cmn->debug = debugfs_create_file(name, 0444, arm_cmn_debugfs, cmn, &arm_cmn_map_fops);
+}
+#else
+static void arm_cmn_debugfs_init(struct arm_cmn *cmn, int id) {}
+#endif
+
 
 struct arm_cmn_hw_event {
 	struct arm_cmn_node *dn;
@@ -294,11 +439,6 @@ struct arm_cmn_format_attr {
 	int config;
 };
 
-static int arm_cmn_xyidbits(const struct arm_cmn *cmn)
-{
-	return cmn->mesh_x > 4 || cmn->mesh_y > 4 ? 3 : 2;
-}
-
 static void arm_cmn_init_node_to_xp(const struct arm_cmn *cmn,
 				    struct arm_cmn_node *dn)
 {
@@ -1565,6 +1705,9 @@ static int arm_cmn_probe(struct platform_device *pdev)
 	err = perf_pmu_register(&cmn->pmu, name, -1);
 	if (err)
 		cpuhp_state_remove_instance(arm_cmn_hp_state, &cmn->cpuhp_node);
+	else
+		arm_cmn_debugfs_init(cmn, this_id);
+
 	return err;
 }
 
@@ -1581,6 +1724,7 @@ static int arm_cmn_remove(struct platform_device *pdev)
 	for (i = 0; i < cmn->num_dtcs; i++)
 		irq_set_affinity_hint(cmn->dtc[i].irq, NULL);
 
+	debugfs_remove(cmn->debug);
 	return 0;
 }
 
@@ -1621,9 +1765,13 @@ static int __init arm_cmn_init(void)
 		return ret;
 
 	arm_cmn_hp_state = ret;
+	arm_cmn_debugfs = debugfs_create_dir("arm-cmn", NULL);
+
 	ret = platform_driver_register(&arm_cmn_driver);
-	if (ret)
+	if (ret) {
 		cpuhp_remove_multi_state(arm_cmn_hp_state);
+		debugfs_remove(arm_cmn_debugfs);
+	}
 	return ret;
 }
 
@@ -1631,6 +1779,7 @@ static void __exit arm_cmn_exit(void)
 {
 	platform_driver_unregister(&arm_cmn_driver);
 	cpuhp_remove_multi_state(arm_cmn_hp_state);
+	debugfs_remove(arm_cmn_debugfs);
 }
 
 module_init(arm_cmn_init);
Signature · 1 line
2.28.0.dirty
Tested-by on the v2 series
#8 lore raw
In reply to Robin Murphy
Quoted 6 lines · Robin Murphy

Here's an update with some very minor cleanup tweaks, plus a proposal for some more in-depth debug information. Given that nobody seems to have any significant complaints about the interface, I assume we're all happy to merge the basic driver as-is and fix anything later if needed.

Robin.

Agree with merging the driver as-is.
Tested both the updated driver and the debugfs on Graviton2 (ACPI). Both map and initial numbers seem right.

May I offer a small addition to the documentation? Something along these lines:

Documentation/admin-guide/perf/arm-cmn.rst +8 -2
@@ -41,8 +41,14 @@ specified by "occupid".
 
 By default each event provides an aggregate count over all nodes of the
 given type. To target a specific node, "bynodeid" must be set to 1 and
-"nodeid" to the appropriate value derived from the CMN configuration
-(as defined in the "Node ID Mapping" section of the TRM).
+"nodeid" to the appropriate value derived from the CMN configuration.
+
+The CMN map is available in /sys/kernel/debug/arm-cmn/map.
+A nodeid could be calculated with this formulae:
+  node-id = d | (p << 2) | (y << 3) | (x << (3 + xybits))
+where:
+  x,y,p,d are node location as can be seen in the map
+  xybits is 2 for meshes <= 2*2, and 3 otherwise.
 
 Watchpoints
 -----------
maintainer
#9 lore raw
Quoted 25 lines · Tsahi
Quoted 6 lines · Robin Murphy

Here's an update with some very minor cleanup tweaks, plus a proposal for some more in-depth debug information. Given that nobody seems to have any significant complaints about the interface, I assume we're all happy to merge the basic driver as-is and fix anything later if needed.

Robin.

Agree with merging the driver as-is.
Tested both the updated driver and the debugfs on Graviton2 (ACPI). Both map and initial numbers seem right.

May I offer a small addition to the documentation? Something along these lines:

Documentation/admin-guide/perf/arm-cmn.rst +0 -0
@@ -41,8 +41,14 @@ specified by "occupid".
 
 By default each event provides an aggregate count over all nodes of the
 given type. To target a specific node, "bynodeid" must be set to 1 and

Documentation/admin-guide/perf/arm-cmn.rst specified by "occupid". · line 51

Quoted 10 lines
Documentation/admin-guide/perf/arm-cmn.rst +8 -2
-"nodeid" to the appropriate value derived from the CMN configuration
-(as defined in the "Node ID Mapping" section of the TRM).
+"nodeid" to the appropriate value derived from the CMN configuration.
+
+The CMN map is available in /sys/kernel/debug/arm-cmn/map.
+A nodeid could be calculated with this formulae:
+  node-id = d | (p << 2) | (y << 3) | (x << (3 + xybits))
+where:
+  x,y,p,d are node location as can be seen in the map
+  xybits is 2 for meshes <= 2*2, and 3 otherwise.

I already queued the driver, but if you send this as a stand-alone patch (on top of the arm64 for-next/perf branch) then I'm happy to take it.

Thanks,

Will

Quoted 3 lines
Documentation/admin-guide/perf/arm-cmn.rst +0 -0
 Watchpoints
 -----------
 
author maintainer
#10 lore raw
Quoted 24 lines · Will Deacon
Quoted 23 lines · Tsahi

On 18/09/2020, 16:29, "Robin Murphy" <[email protected]> wrote:
> Here's an update with some very minor cleanup tweaks, plus a proposal > for some more in-depth debug information. Given that nobody seems to > have any significant complaints about the interface, I assume we're all > happy to merge the basic driver as-is and fix anything later if needed. >
> Robin.

Agree with merging the driver as-is.
Tested both the updated driver and the debugfs on Graviton2 (ACPI). Both map and initial numbers seem right.

May I offer a small addition to the documentation? Something along these lines:

Documentation/admin-guide/perf/arm-cmn.rst +0 -0
@@ -41,8 +41,14 @@ specified by "occupid".
 
Quoted 12 lines

Documentation/admin-guide/perf/arm-cmn.rst specified by "occupid". · line 51

Quoted 12 lines
Documentation/admin-guide/perf/arm-cmn.rst +8 -2
  By default each event provides an aggregate count over all nodes of the
  given type. To target a specific node, "bynodeid" must be set to 1 and
-"nodeid" to the appropriate value derived from the CMN configuration
-(as defined in the "Node ID Mapping" section of the TRM).
+"nodeid" to the appropriate value derived from the CMN configuration.
+
+The CMN map is available in /sys/kernel/debug/arm-cmn/map.
+A nodeid could be calculated with this formulae:
+  node-id = d | (p << 2) | (y << 3) | (x << (3 + xybits))
+where:
+  x,y,p,d are node location as can be seen in the map
+  xybits is 2 for meshes <= 2*2, and 3 otherwise.

Note that I disagree strongly with removing the reference to the documentation that canonically defines the node ID format, especially when the proposal is to replace it with a harder-to-read definition that is also wrong ;)

If there's actually interest in using the coordinate format rather than just whole ID values, then we should generate format attributes that overlay the appropriate sections of the nodeid field. I haven't tried to implement that so far since it's not entirely trivial and I wasn't sure if anyone would care.

Quoted 2 lines

I already queued the driver, but if you send this as a stand-alone patch (on top of the arm64 for-next/perf branch) then I'm happy to take it.

Ha, so much for taking my holiday after -rc6 and expecting to come back to chasing this up at -rc1... cheers Will, that was a very nice surprise to return to!

Robin.

#11 lore raw
Quoted 10 lines · Robin Murphy
Quoted 9 lines · Tsahi

By default each event provides an aggregate count over all nodes of the given type. To target a specific node, "bynodeid" must be set to 1 and
-"nodeid" to the appropriate value derived from the CMN configuration

Documentation/admin-guide/perf/arm-cmn.rst +5 -1
-(as defined in the "Node ID Mapping" section of the TRM).
+"nodeid" to the appropriate value derived from the CMN configuration.
+
+The CMN map is available in /sys/kernel/debug/arm-cmn/map.
+A nodeid could be calculated with this formulae:
+  node-id = d | (p << 2) | (y << 3) | (x << (3 + xybits))
Quoted 8 lines

Documentation/admin-guide/perf/arm-cmn.rst specified by "occupid". · line 51

Quoted 3 lines
Documentation/admin-guide/perf/arm-cmn.rst +3 -0
+where:
+  x,y,p,d are node location as can be seen in the map
+  xybits is 2 for meshes <= 2*2, and 3 otherwise.

Note that I disagree strongly with removing the reference to the documentation that canonically defines the node ID format, especially when the proposal is to replace it with a harder-to-read definition that is also wrong ;)

Would be happy to be corrected :)

Quoted 5 lines

If there's actually interest in using the coordinate format rather than just whole ID values, then we should generate format attributes that overlay the appropriate sections of the nodeid field. I haven't tried to implement that so far since it's not entirely trivial and I wasn't sure if anyone would care.

I agree that over 90% of the work with the counters should be with aggregate values that the driver already handles well by default.
At the next level, there might be a lot to gain from just understanding if the counter in question is going up across the board, or just for a specific node. Are there a lot of HNF cache misses in the system, or from one specific HNF? To answer that question, the developer doesn't need to hold the SOC SPEC, just to have the list of relevant node-ids per type/counter.
I really like the arm-cmn/map you created. There is still a small missing link between that map to relevant node-ids for the above. In my opinion, looking at specific node-ids would be a rare enough task, requiring enough expertise, that I am comfortable putting a formulae in documentation without actually modifying API, at least at this stage.

Thank you!
Tsahi.