Skip to contentSkip to conversation

arm: l2x0: add PMU support

PATCH Superseded Mark Rutland 3 participants 4 messages Aug 19, 2016 – Aug 22, 2016

Subsystems (2)

v2 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 arm: l2x0: add PMU support

The L2C-220 (AKA L220) and L2C-310 (AKA PL310) cache controllers feature a Performance Monitoring Unit (PMU), which can be useful for tuning and/or debugging. This hardware is always present and the relevant registers are accessible to non-secure accesses. Thus, no special firmware interface is necessary.

This patch adds support for the PMU, plugging into the usual perf infrastructure. The overflow interrupt is not always available (e.g. on RealView PBX A9 it is not wired up at all), and the hardware counters saturate, so the driver does not make use of this. Instead, the driver periodically polls and reset counters as required to avoid losing events due to saturation.

---
 arch/arm/include/asm/hardware/cache-l2x0.h |   9 +
 arch/arm/mm/Kconfig                        |   7 +
 arch/arm/mm/cache-l2x0.c                   | 554 +++++++++++++++++++++++++++++
 include/linux/cpuhotplug.h                 |   1 +
 4 files changed, 571 insertions(+)

Since v1 [1]
* Use relaxed IO accessors, per Russell's comment. From testing, this can save 3% overhead in an extreme case (idle system and trivial workload).
* Add Kim's Tested-by.

Mark.

[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2016-August/449622.html

arch/arm/include/asm/hardware/cache-l2x0.h +9 -0
index 3a5ec1c..e476350 100644
@@ -87,6 +87,15 @@
 #define L310_CACHE_ID_RTL_R3P2		0x08
 #define L310_CACHE_ID_RTL_R3P3		0x09
 
+#define L2X0_EVENT_CNT_CTRL_ENABLE	BIT(0)
+
+#define L2X0_EVENT_CNT_CFG_SRC_SHIFT	2
+#define L2X0_EVENT_CNT_CFG_SRC_MASK	0xf
+#define L2X0_EVENT_CNT_CFG_SRC_DISABLED	0
+#define L2X0_EVENT_CNT_CFG_INT_DISABLED	0
+#define L2X0_EVENT_CNT_CFG_INT_INCR	1
+#define L2X0_EVENT_CNT_CFG_INT_OVERFLOW	2
+
 /* L2C auxiliary control register - bits common to L2C-210/220/310 */
 #define L2C_AUX_CTRL_WAY_SIZE_SHIFT		17
 #define L2C_AUX_CTRL_WAY_SIZE_MASK		(7 << 17)
arch/arm/mm/Kconfig +7 -0
index d15a7fe..0e8cbac 100644
@@ -916,6 +916,13 @@ config CACHE_L2X0
 	help
 	  This option enables the L2x0 PrimeCell.
 
+config CACHE_L2X0_PMU
+	bool "L2x0 performance monitor support" if CACHE_L2X0
+	depends on PERF_EVENTS
+	help
+	  This option enables support for the performance monitoring features
+	  of the L220 and PL310 outer cache controllers.
+
 if CACHE_L2X0
 
 config PL310_ERRATA_588369
arch/arm/mm/cache-l2x0.c +554 -0

584 lines not on this page · raw message

include/linux/cpuhotplug.h +1 -0
index 242bf53..7e1ba14 100644
@@ -86,6 +86,7 @@ enum cpuhp_state {
 	CPUHP_AP_PERF_S390_SF_ONLINE,
 	CPUHP_AP_PERF_ARM_CCI_ONLINE,
 	CPUHP_AP_PERF_ARM_CCN_ONLINE,
+	CPUHP_AP_PERF_ARM_L2X0_ONLINE,
 	CPUHP_AP_WORKQUEUE_ONLINE,
 	CPUHP_AP_RCUTREE_ONLINE,
 	CPUHP_AP_NOTIFY_ONLINE,
Signature · 1 line
1.9.1
#1 lore raw

PATCH v2 1/1 arm: l2x0: add PMU support

Quoted 24 lines · Mark Rutland

The L2C-220 (AKA L220) and L2C-310 (AKA PL310) cache controllers feature a Performance Monitoring Unit (PMU), which can be useful for tuning and/or debugging. This hardware is always present and the relevant registers are accessible to non-secure accesses. Thus, no special firmware interface is necessary.

This patch adds support for the PMU, plugging into the usual perf infrastructure. The overflow interrupt is not always available (e.g. on RealView PBX A9 it is not wired up at all), and the hardware counters saturate, so the driver does not make use of this. Instead, the driver periodically polls and reset counters as required to avoid losing events due to saturation.

---
 arch/arm/include/asm/hardware/cache-l2x0.h |   9 +
 arch/arm/mm/Kconfig                        |   7 +
 arch/arm/mm/cache-l2x0.c                   | 554 +++++++++++++++++++++++++++++
 include/linux/cpuhotplug.h                 |   1 +
 4 files changed, 571 insertions(+)

[...]

Quoted 131 lines

Since v1 [1]
* Use relaxed IO accessors, per Russell's comment. From testing, this can save 3% overhead in an extreme case (idle system and trivial workload).
* Add Kim's Tested-by.

Mark.

[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2016-August/449622.html

arch/arm/include/asm/hardware/cache-l2x0.h +9 -0
index 3a5ec1c..e476350 100644
@@ -87,6 +87,15 @@
 #define L310_CACHE_ID_RTL_R3P2		0x08
 #define L310_CACHE_ID_RTL_R3P3		0x09
 
+#define L2X0_EVENT_CNT_CTRL_ENABLE	BIT(0)
+
+#define L2X0_EVENT_CNT_CFG_SRC_SHIFT	2
+#define L2X0_EVENT_CNT_CFG_SRC_MASK	0xf
+#define L2X0_EVENT_CNT_CFG_SRC_DISABLED	0
+#define L2X0_EVENT_CNT_CFG_INT_DISABLED	0
+#define L2X0_EVENT_CNT_CFG_INT_INCR	1
+#define L2X0_EVENT_CNT_CFG_INT_OVERFLOW	2
+
 /* L2C auxiliary control register - bits common to L2C-210/220/310 */
 #define L2C_AUX_CTRL_WAY_SIZE_SHIFT		17
 #define L2C_AUX_CTRL_WAY_SIZE_MASK		(7 << 17)
arch/arm/mm/Kconfig +7 -0
index d15a7fe..0e8cbac 100644
@@ -916,6 +916,13 @@ config CACHE_L2X0
 	help
 	  This option enables the L2x0 PrimeCell.
 
+config CACHE_L2X0_PMU
+	bool "L2x0 performance monitor support" if CACHE_L2X0
+	depends on PERF_EVENTS
+	help
+	  This option enables support for the performance monitoring features
+	  of the L220 and PL310 outer cache controllers.
+
 if CACHE_L2X0
 
 config PL310_ERRATA_588369
arch/arm/mm/cache-l2x0.c +45 -0
index cc12905..8e1f008 100644
@@ -18,9 +18,17 @@
  */
 #include <linux/cpu.h>
 #include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/hrtimer.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/perf_event.h>
+#include <linux/printk.h>
 #include <linux/smp.h>
 #include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/types.h>
 #include <linux/log2.h>
 #include <linux/io.h>
 #include <linux/of.h>
@@ -57,6 +65,14 @@ static unsigned long sync_reg_offset = L2X0_CACHE_SYNC;
 
 struct l2x0_regs l2x0_saved_regs;
 
+#ifdef CONFIG_CACHE_L2X0_PMU
+static void l2x0_pmu_suspend(void);
+static void l2x0_pmu_resume(void);
+#else
+static inline void l2x0_pmu_suspend(void) { }
+static inline void l2x0_pmu_resume(void) { }
+#endif
+
 /*
  * Common code for all cache controllers.
  */
@@ -142,6 +158,8 @@ static void l2c_disable(void)
 {
 	void __iomem *base = l2x0_base;
 
+	l2x0_pmu_suspend();
+
 	outer_cache.flush_all();
 	l2c_write_sec(0, base, L2X0_CTRL);
 	dsb(st);
@@ -159,6 +177,8 @@ static void l2c_resume(void)
 	/* Do not touch the controller if already enabled. */
 	if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN))
 		l2c_enable(base, l2x0_data->num_lock);
+
+	l2x0_pmu_resume();
 }
 
 /*
@@ -1801,3 +1821,537 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 	return __l2c_init(data, aux_val, aux_mask, cache_id, nosync);
 }
 #endif
+
+#ifdef CONFIG_CACHE_L2X0_PMU
+#define PMU_NR_COUNTERS 2
+
+static struct pmu *l2x0_pmu;
+static cpumask_t pmu_cpu;
+
+static ktime_t l2x0_pmu_poll_period;
+static struct hrtimer l2x0_pmu_hrtimer;
+
+/*
+ * The L220/PL310 PMU has two equivalent counters, Counter1 and Counter0.
+ * Registers controlling these are laid out in pairs, in descending order, i.e.
+ * the register for Counter1 comes first, followed by the register for
+ * Counter0.
+ * We ensure that idx 0 -> Counter0, and idx1 -> Counter1.
+ */
+static struct perf_event *events[PMU_NR_COUNTERS];
+
+/* Find an unused counter */
+static int l2x0_pmu_find_idx(void)
+{
+	int i;
+
+	for (i = 0; i < PMU_NR_COUNTERS; i++) {

arch/arm/mm/cache-l2x0.c int __init l2x0_of_init(u32 aux_val, u32 aux_mask) · line 1858

Quoted 10 lines
arch/arm/mm/cache-l2x0.c +10 -0
+		if (!events[i])
+			return i;
+	}
+
+	return -1;
+}
+
+/* How many counters are allocated? */
+static bool l2x0_pmu_num_active_counters(void)
+{

I know you only have two counters, but using a bool here is perverse!

Quoted 9 lines
arch/arm/mm/cache-l2x0.c +9 -0
+	int i, cnt = 0;
+
+	for (i = 0; i < PMU_NR_COUNTERS; i++) {
+		if (events[i])
+			cnt++;
+	}
+
+	return cnt;
+}

[...]

Quoted 5 lines
arch/arm/mm/cache-l2x0.c +5 -0
+static __init int l2x0_pmu_register(void)
+{
+	int ret;
+	const char *name;
+

arch/arm/mm/cache-l2x0.c int __init l2x0_of_init(u32 aux_val, u32 aux_mask) · line 2301

Quoted 10 lines
arch/arm/mm/cache-l2x0.c +10 -0
+	if (!l2x0_base)
+		return 0;
+
+	/* Only L220 and PL310 have a PMU */
+	if (strcmp("L2C-220", l2x0_data->type) == 0)
+		name = "l2c_220";
+	if (strcmp("L2C-310", l2x0_data->type) == 0)
+		name = "l2c_310";
+	else
+		return 0;

Turns out that the L210 *does* have a PMU, but it's quite different and I don't think we should bother supporting it for now. Worth updating the comment, though.

Will

#2 lore raw

PATCH v2 1/1 arm: l2x0: add PMU support

Quoted 7 lines · Will Deacon

arch/arm/mm/cache-l2x0.c int __init l2x0_of_init(u32 aux_val, u32 aux_mask) · line 1858

Quoted 3 lines · Mark Rutland
arch/arm/mm/cache-l2x0.c +3 -0
+/* How many counters are allocated? */
+static bool l2x0_pmu_num_active_counters(void)
+{

I know you only have two counters, but using a bool here is perverse!

Quoted 9 lines

arch/arm/mm/cache-l2x0.c int __init l2x0_of_init(u32 aux_val, u32 aux_mask) · line 1867

Quoted 9 lines
arch/arm/mm/cache-l2x0.c +9 -0
+	int i, cnt = 0;
+
+	for (i = 0; i < PMU_NR_COUNTERS; i++) {
+		if (events[i])
+			cnt++;
+	}
+
+	return cnt;
+}

Whoops. That's a hold-over from development when this was called something like l2x0_pmu_has_active_counters().

I've fixed this to return an int.

Luckily the callsites all compare against zero, so there shouldn't be a functional problem.

Quoted 11 lines
Quoted 11 lines
arch/arm/mm/cache-l2x0.c +11 -0
+static __init int l2x0_pmu_register(void)
+{
+	int ret;
+	const char *name;
+
+	if (!l2x0_base)
+		return 0;
+
+	/* Only L220 and PL310 have a PMU */
+	if (strcmp("L2C-220", l2x0_data->type) == 0)
+		name = "l2c_220";
Quoted 8 lines

arch/arm/mm/cache-l2x0.c int __init l2x0_of_init(u32 aux_val, u32 aux_mask) · line 2301

Quoted 4 lines
arch/arm/mm/cache-l2x0.c +4 -0
+	if (strcmp("L2C-310", l2x0_data->type) == 0)
+		name = "l2c_310";
+	else
+		return 0;

Turns out that the L210 *does* have a PMU, but it's quite different and I don't think we should bother supporting it for now. Worth updating the comment, though.

Indeed. I've rewritten the above to mention how the name is used by the sysfs code, mentioning that we do not support the L210 PMU.

Thanks,
Mark.

#3 lore raw

PATCH v2 1/1 arm: l2x0: add PMU support

In reply to Mark Rutland
Quoted 16 lines · Mark Rutland

The L2C-220 (AKA L220) and L2C-310 (AKA PL310) cache controllers feature
a Performance Monitoring Unit (PMU), which can be useful for tuning and/or debugging. This hardware is always present and the relevant registers are accessible to non-secure accesses. Thus, no special firmware interface is necessary.

This patch adds support for the PMU, plugging into the usual perf infrastructure. The overflow interrupt is not always available (e.g. on
RealView PBX A9 it is not wired up at all), and the hardware counters saturate, so the driver does not make use of this. Instead, the driver
periodically polls and reset counters as required to avoid losing events due to saturation.

Quoted 5 lines

For what it's worth, it's enthusiastically

Thanks!

Pawel