Skip to contentSkip to conversation

arm64/perf: Add ACPI support

RFC Superseded Jeremy Linton 3 participants 8 messages Mar 13, 2016 – Mar 16, 2016

Subsystems (3)

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

v3 cover arm64/perf: Add ACPI support

This patch set expands upon the patches published by Mark Salter to clean up a few of the previous review comments, as well as add support for A72's, and big/little configurations.

I've been testing this patch in concert with the ACPI/PCIe and ACPI/GICv3 patches. It works well on seattle/juno, but there appears to be a problem with at least one platform using PPIs (which is questionable as ACPI defines the pmu interrupt as a GSI). I said a couple weeks ago I would post it, so here it is.

Jeremy Linton (1):
arm64: pmu: add A72 cpu type, support multiple PMU types

Mark Salter (3):
arm: pmu: Fix non-devicetree probing
arm64: pmu: add fallback probe table
arm64: pmu: Add support for probing with ACPI

 arch/arm64/include/asm/cputype.h |   1 +
 arch/arm64/kernel/perf_event.c   |  11 +-
 arch/arm64/kernel/smp.c          |   5 +
 drivers/perf/Kconfig             |   4 +
 drivers/perf/Makefile            |   1 +
 drivers/perf/arm_pmu.c           |  54 ++++++++--
 drivers/perf/arm_pmu_acpi.c      | 212 +++++++++++++++++++++++++++++++++++++++
 include/linux/perf/arm_pmu.h     |  10 ++
 8 files changed, 287 insertions(+), 11 deletions(-)
 create mode 100644 drivers/perf/arm_pmu_acpi.c
Signature · 1 line
2.4.3
#1 lore raw

PATCH v3 1/4 arm: pmu: Fix non-devicetree probing

From: Mark Salter <[email protected]>

There is a problem in the non-devicetree PMU probing where some probe functions may get the number of supported events through smp_call_function_any() using the arm_pmu supported_cpus mask. But at the time the probe function is called, the supported_cpus mask is empty so the call fails. This patch makes sure the mask is set before calling the init function rather than after.

---
 drivers/perf/arm_pmu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/perf/arm_pmu.c +1 -1
index 11bacc7..0f33c96 100644
@@ -997,8 +997,8 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 		if (!ret)
 			ret = init_fn(pmu);
 	} else {
-		ret = probe_current_pmu(pmu, probe_table);
 		cpumask_setall(&pmu->supported_cpus);
+		ret = probe_current_pmu(pmu, probe_table);
 	}
 
 	if (ret) {
Signature · 1 line
2.4.3
#2 lore raw

PATCH v3 2/4 arm64: pmu: add fallback probe table

In reply to Jeremy Linton

From: Mark Salter <[email protected]>

In preparation for ACPI support, add a pmu_probe_info table to the arm_pmu_device_probe() call. This table gets used when probing in the absence of a devicetree node for PMU.

---
 arch/arm64/kernel/perf_event.c | 10 +++++++++-
 include/linux/perf/arm_pmu.h   |  3 +++
 2 files changed, 12 insertions(+), 1 deletion(-)
arch/arm64/kernel/perf_event.c +9 -1
index 767c4f6..03e0957 100644
@@ -901,9 +901,17 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = {
 	{},
 };
 
+static const struct pmu_probe_info armv8_pmu_probe_table[] = {
+	ARMV8_PMU_PART_PROBE(ARM_CPU_PART_CORTEX_A53, armv8_a53_pmu_init),
+	ARMV8_PMU_PART_PROBE(ARM_CPU_PART_CORTEX_A57, armv8_a57_pmu_init),
+	PMU_PROBE(0, 0, armv8_pmuv3_init), /* if all else fails... */
+	{ /* sentinel value */ }
+};
+
 static int armv8_pmu_device_probe(struct platform_device *pdev)
 {
-	return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids, NULL);
+	return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids,
+				    armv8_pmu_probe_table);
 }
 
 static struct platform_driver armv8_pmu_driver = {
include/linux/perf/arm_pmu.h +3 -0
index 4196c90..495332f 100644
@@ -145,6 +145,9 @@ struct pmu_probe_info {
 #define XSCALE_PMU_PROBE(_version, _fn) \
 	PMU_PROBE(ARM_CPU_IMP_INTEL << 24 | _version, ARM_PMU_XSCALE_MASK, _fn)
 
+#define ARMV8_PMU_PART_PROBE(_part, _fn) \
+	PMU_PROBE((_part) << MIDR_PARTNUM_SHIFT, MIDR_PARTNUM_MASK, _fn)
+
 int arm_pmu_device_probe(struct platform_device *pdev,
 			 const struct of_device_id *of_table,
 			 const struct pmu_probe_info *probe_table);
Signature · 1 line
2.4.3
#3 lore raw

PATCH 2/4 arm64: pmu: add fallback probe table

Quoted 52 lines · Jeremy Linton

From: Mark Salter <[email protected]>

In preparation for ACPI support, add a pmu_probe_info table to the arm_pmu_device_probe() call. This table gets used when probing in the absence of a devicetree node for PMU.

---
 arch/arm64/kernel/perf_event.c | 10 +++++++++-
 include/linux/perf/arm_pmu.h   |  3 +++
 2 files changed, 12 insertions(+), 1 deletion(-)
arch/arm64/kernel/perf_event.c +9 -1
index 767c4f6..03e0957 100644
@@ -901,9 +901,17 @@ static const struct of_device_id
 armv8_pmu_of_device_ids[] = {
 	{},
 };
 
+static const struct pmu_probe_info armv8_pmu_probe_table[] = {
+	ARMV8_PMU_PART_PROBE(ARM_CPU_PART_CORTEX_A53, armv8_a53_pmu_init),
+	ARMV8_PMU_PART_PROBE(ARM_CPU_PART_CORTEX_A57, armv8_a57_pmu_init),
+	PMU_PROBE(0, 0, armv8_pmuv3_init), /* if all else fails... */
+	{ /* sentinel value */ }
+};
+
 static int armv8_pmu_device_probe(struct platform_device *pdev)
 {
-	return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids, NULL);
+	return arm_pmu_device_probe(pdev, armv8_pmu_of_device_ids,
+				    armv8_pmu_probe_table);
 }
 

static struct platform_driver armv8_pmu_driver = {

include/linux/perf/arm_pmu.h +3 -0
index 4196c90..495332f 100644
@@ -145,6 +145,9 @@ struct pmu_probe_info {
 #define XSCALE_PMU_PROBE(_version, _fn) \
 	PMU_PROBE(ARM_CPU_IMP_INTEL << 24 | _version, ARM_PMU_XSCALE_MASK, 
 _fn)
 
+#define ARMV8_PMU_PART_PROBE(_part, _fn) \
+	PMU_PROBE((_part) << MIDR_PARTNUM_SHIFT, MIDR_PARTNUM_MASK, _fn)
+
 int arm_pmu_device_probe(struct platform_device *pdev,
 			 const struct of_device_id *of_table,
Quoted 1 line

const struct pmu_probe_info *probe_table);

Hi Jeremy,
Thanks for pulling these patches together.

Just one comment: MIDR part numbers are not guaranteed unique across implementors, so I'd suggest that ARMV8_PMU_PART_PROBE include the MIDR_IMPLEMENTOR in the cpuid and mask.

Otherwise everything looks good - I successfully used this patchset as a base for getting my pmu driver running with ACPI.

-- Neil
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project

#4 lore raw

PATCH v3 3/4 arm64: pmu: Add support for probing with ACPI

In reply to Jeremy Linton

From: Mark Salter <[email protected]>

In the case of ACPI, the PMU IRQ information is contained in the MADT table. Also, since the PMU does not exist as a device in the ACPI DSDT table, it is necessary to create a platform device so that the appropriate driver probing is triggered.

---
 arch/arm64/kernel/smp.c      |   5 ++
 drivers/perf/Kconfig         |   4 ++
 drivers/perf/Makefile        |   1 +
 drivers/perf/arm_pmu_acpi.c  | 125 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/perf/arm_pmu.h |   7 +++
 5 files changed, 142 insertions(+)
 create mode 100644 drivers/perf/arm_pmu_acpi.c
arch/arm64/kernel/smp.c +5 -0
index b2d5f4e..c6f2c53 100644
@@ -37,6 +37,7 @@
 #include <linux/completion.h>
 #include <linux/of.h>
 #include <linux/irq_work.h>
+#include <linux/perf/arm_pmu.h>
 
 #include <asm/alternative.h>
 #include <asm/atomic.h>
@@ -502,6 +503,7 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
 			return;
 		}
 		bootcpu_valid = true;
+		arm_pmu_parse_acpi(0, processor);
 		return;
 	}
 
@@ -522,6 +524,9 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
 	 */
 	acpi_set_mailbox_entry(cpu_count, processor);
 
+	/* get PMU irq info */
+	arm_pmu_parse_acpi(cpu_count, processor);
+
 	cpu_count++;
 }
 
drivers/perf/Kconfig +4 -0
index 04e2653..818fa3b 100644
@@ -12,4 +12,8 @@ config ARM_PMU
 	  Say y if you want to use CPU performance monitors on ARM-based
 	  systems.
 
+config ARM_PMU_ACPI
+	def_bool y
+	depends on ARM_PMU && ACPI
+
 endmenu
drivers/perf/Makefile +1 -0
index acd2397..fd8090d 100644
@@ -1 +1,2 @@
 obj-$(CONFIG_ARM_PMU) += arm_pmu.o
+obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_acpi.o
drivers/perf/arm_pmu_acpi.c new file +125 -0

125 lines not on this page · raw message

include/linux/perf/arm_pmu.h +7 -0
index 495332f..d002269 100644
@@ -154,4 +154,11 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 
 #endif /* CONFIG_ARM_PMU */
 
+#ifdef CONFIG_ARM_PMU_ACPI
+struct acpi_madt_generic_interrupt;
+void arm_pmu_parse_acpi(int cpu, struct acpi_madt_generic_interrupt *gic);
+#else
+#define arm_pmu_parse_acpi(a, b) do { } while (0)
+#endif /* CONFIG_ARM_PMU_ACPI */
+
 #endif /* __ARM_PMU_H__ */
Signature · 1 line
2.4.3
#5 lore raw

PATCH 3/4 arm64: pmu: Add support for probing with ACPI

Quoted 10 lines · Jeremy Linton
drivers/perf/arm_pmu_acpi.c new file +10 -0
+	int i, count, irq;
+
+	if (acpi_disabled)
+		return 0;
+
+	acpi_parse_boot_cpu();
+
+	/* Must have irq for boot boot cpu, at least */
+	if (pirq->gsi == 0)
+		return -EINVAL;

drivers/perf/arm_pmu_acpi.c line 87

Quoted 10 lines
drivers/perf/arm_pmu_acpi.c new file +10 -0
+
+	irq = acpi_register_gsi(NULL, pirq->gsi, pirq->trigger,
+				ACPI_ACTIVE_HIGH);
+
+	if (irq_is_percpu(irq))
+		count = 1;
+	else
+		for (i = 1, count = 1; i < NR_CPUS; i++)
+			if (pmu_irqs[i].gsi)
+				++count;

You could more simply with:

	int count = 1
	...
	if (!irq_is_percpu(irq))
		for (i = 1; i < NR_CPUS; i++)
			if (pmu_irqs[i].gsi)
				++count;
Signature · 3 lines
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the
Code Aurora Forum, hosted by The Linux Foundation.
#6 lore raw

PATCH v3 3/4 arm64: pmu: Add support for probing with ACPI

Quoted 24 lines · Timur Tabi
Quoted 10 lines · Jeremy Linton
drivers/perf/arm_pmu_acpi.c new file +10 -0
+    int i, count, irq;
+
+    if (acpi_disabled)
+        return 0;
+
+    acpi_parse_boot_cpu();
+
+    /* Must have irq for boot boot cpu, at least */
+    if (pirq->gsi == 0)
+        return -EINVAL;

drivers/perf/arm_pmu_acpi.c line 87

Quoted 10 lines
drivers/perf/arm_pmu_acpi.c new file +10 -0
+
+    irq = acpi_register_gsi(NULL, pirq->gsi, pirq->trigger,
+                ACPI_ACTIVE_HIGH);
+
+    if (irq_is_percpu(irq))
+        count = 1;
+    else
+        for (i = 1, count = 1; i < NR_CPUS; i++)
+            if (pmu_irqs[i].gsi)
+                ++count;

You could more simply with:

Quoted 6 lines
     int count = 1
     ...
     if (!irq_is_percpu(irq))
         for (i = 1; i < NR_CPUS; i++)
             if (pmu_irqs[i].gsi)
                 ++count;

I think you will notice that the following patch rewrites a lot of this function.

I kept the original patches from Mark to identify/segment his contribution because they run/bisect by themselves. They should probably be squashed together for review purposes.

#7 lore raw

PATCH v3 4/4 arm64: pmu: add A72 cpu type, support multiple PMU types

In reply to Jeremy Linton

ARM big/little machines can have PMU's with differing PMU counters. ACPI systems should be able to support this as well. Also add support for A72 PMU counters.

---
 arch/arm64/include/asm/cputype.h |   1 +
 arch/arm64/kernel/perf_event.c   |   1 +
 drivers/perf/arm_pmu.c           |  54 +++++++--
 drivers/perf/arm_pmu_acpi.c      | 229 +++++++++++++++++++++++++++------------
 4 files changed, 204 insertions(+), 81 deletions(-)
arch/arm64/include/asm/cputype.h +1 -0
index 87e1985..1e40799 100644
@@ -74,6 +74,7 @@
 
 #define ARM_CPU_PART_AEM_V8		0xD0F
 #define ARM_CPU_PART_FOUNDATION		0xD00
+#define ARM_CPU_PART_CORTEX_A72		0xD08
 #define ARM_CPU_PART_CORTEX_A57		0xD07
 #define ARM_CPU_PART_CORTEX_A53		0xD03
 
arch/arm64/kernel/perf_event.c +1 -0
index 03e0957..b3ea97f 100644
@@ -904,6 +904,7 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = {
 static const struct pmu_probe_info armv8_pmu_probe_table[] = {
 	ARMV8_PMU_PART_PROBE(ARM_CPU_PART_CORTEX_A53, armv8_a53_pmu_init),
 	ARMV8_PMU_PART_PROBE(ARM_CPU_PART_CORTEX_A57, armv8_a57_pmu_init),
+	ARMV8_PMU_PART_PROBE(ARM_CPU_PART_CORTEX_A72, armv8_a72_pmu_init),
 	PMU_PROBE(0, 0, armv8_pmuv3_init), /* if all else fails... */
 	{ /* sentinel value */ }
 };
drivers/perf/arm_pmu.c +44 -10

89 lines not on this page · raw message

drivers/perf/arm_pmu_acpi.c +158 -71

280 lines not on this page · raw message

Signature · 1 line
2.4.3