All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v9 00/10] Enable PMUs in ACPI systems
@ 2016-09-14 22:32 ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, will.deacon, punit.agrawal, linux-acpi, mlangsdorf,
	steve.capper

This patch expands and reworks the patches published by Mark Salter
in order to clean up a few of the previous review comments, as well as
add support for newer CPUs and big/little configurations.

v9:
Add/cleanup an additional hotplug patch I've had sitting around. This
patch brings the ACPI PMU mostly on par with the DT functionality with
respect to having CPUs offline during boot. This should help clarify
some of the code structuring.
Cleanup the list of PMU types early if we fail to allocate memory for an
additional pmu type.

v8:
Rebase to 4.8rc4
Assorted minor comment/hunk placement/etc tweaks per Punit Agrawal

v7:
Rebase to 4.8rc3
Remove cpu affinity sysfs entry. While providing a CPU mask for
ARMv8 PMU's is really helpful in big/little environments, reworking
the PMU code to support the cpumask attribute for !arm64 PMUs is out
of the scope of this patch set.
Fix CPU miscount problem where an alloc failure followed by successfully
allocating the structure can result in under counting the CPUs associated
with the PMU. This bug was created in v6 with the conversion to a linked
list.
Remove initial platform device creation code by Mark Salter, and re-squash
multiple platform device creation code together with helper routines.
Other minor tweakage.

v6:
Added cpu affinity sysfs entry
Converted pmu_types array, to linked list
Restrict use of the armv8_pmu_probe_table to ACPI systems
Rename MADT parsing routines in smp.c
Convert sysfs PMU name to use index rather than partnum
Remove pr_devel statements
Other Minor cleanups
Add Partial Ack-by Will Deacon

v5:
Remove list of CPU types for ACPI systems. We now match a generic
event list, and use the PMCIED[01] to select events which exist on
the given PMU. This avoids the need to update the kernel every time
a new CPU is released.
Update the maintainers list to include the new file.

v4:
Correct build issues with ARM (!ARM64) kernels.
Add ThunderX to list of PMU types.

v3:
Enable ARM performance monitoring units on ACPI/arm64 machines.

Jeremy Linton (8):
  arm64: pmu: Probe default hw/cache counters
  arm64: pmu: Hoist pmu platform device name
  arm64: Rename the common MADT parse routine
  arm: arm64: Add routine to determine cpuid of other cpus
  arm: arm64: pmu: Assign platform PMU CPU affinity
  arm64: pmu: Detect and enable multiple PMUs in an ACPI system
  arm: pmu: Add PMU definitions for hot-plugged CPUs
  MAINTAINERS: Tweak ARM PMU maintainers

Mark Salter (2):
  arm64: pmu: add fallback probe table
  arm64: pmu: Cache PMU interrupt numbers from MADT parse

 MAINTAINERS                      |   3 +-
 arch/arm/include/asm/cputype.h   |   2 +
 arch/arm64/include/asm/cputype.h |   3 +
 arch/arm64/kernel/perf_event.c   |  58 ++++++++-
 arch/arm64/kernel/smp.c          |  18 ++-
 drivers/perf/Kconfig             |   4 +
 drivers/perf/Makefile            |   1 +
 drivers/perf/arm_pmu.c           | 110 ++++++++++++++--
 drivers/perf/arm_pmu_acpi.c      | 264 +++++++++++++++++++++++++++++++++++++++
 include/linux/perf/arm_pmu.h     |  13 ++
 10 files changed, 452 insertions(+), 24 deletions(-)
 create mode 100644 drivers/perf/arm_pmu_acpi.c

-- 
2.5.5


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v9 00/10] Enable PMUs in ACPI systems
@ 2016-09-14 22:32 ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel

This patch expands and reworks the patches published by Mark Salter
in order to clean up a few of the previous review comments, as well as
add support for newer CPUs and big/little configurations.

v9:
Add/cleanup an additional hotplug patch I've had sitting around. This
patch brings the ACPI PMU mostly on par with the DT functionality with
respect to having CPUs offline during boot. This should help clarify
some of the code structuring.
Cleanup the list of PMU types early if we fail to allocate memory for an
additional pmu type.

v8:
Rebase to 4.8rc4
Assorted minor comment/hunk placement/etc tweaks per Punit Agrawal

v7:
Rebase to 4.8rc3
Remove cpu affinity sysfs entry. While providing a CPU mask for
ARMv8 PMU's is really helpful in big/little environments, reworking
the PMU code to support the cpumask attribute for !arm64 PMUs is out
of the scope of this patch set.
Fix CPU miscount problem where an alloc failure followed by successfully
allocating the structure can result in under counting the CPUs associated
with the PMU. This bug was created in v6 with the conversion to a linked
list.
Remove initial platform device creation code by Mark Salter, and re-squash
multiple platform device creation code together with helper routines.
Other minor tweakage.

v6:
Added cpu affinity sysfs entry
Converted pmu_types array, to linked list
Restrict use of the armv8_pmu_probe_table to ACPI systems
Rename MADT parsing routines in smp.c
Convert sysfs PMU name to use index rather than partnum
Remove pr_devel statements
Other Minor cleanups
Add Partial Ack-by Will Deacon

v5:
Remove list of CPU types for ACPI systems. We now match a generic
event list, and use the PMCIED[01] to select events which exist on
the given PMU. This avoids the need to update the kernel every time
a new CPU is released.
Update the maintainers list to include the new file.

v4:
Correct build issues with ARM (!ARM64) kernels.
Add ThunderX to list of PMU types.

v3:
Enable ARM performance monitoring units on ACPI/arm64 machines.

Jeremy Linton (8):
  arm64: pmu: Probe default hw/cache counters
  arm64: pmu: Hoist pmu platform device name
  arm64: Rename the common MADT parse routine
  arm: arm64: Add routine to determine cpuid of other cpus
  arm: arm64: pmu: Assign platform PMU CPU affinity
  arm64: pmu: Detect and enable multiple PMUs in an ACPI system
  arm: pmu: Add PMU definitions for hot-plugged CPUs
  MAINTAINERS: Tweak ARM PMU maintainers

Mark Salter (2):
  arm64: pmu: add fallback probe table
  arm64: pmu: Cache PMU interrupt numbers from MADT parse

 MAINTAINERS                      |   3 +-
 arch/arm/include/asm/cputype.h   |   2 +
 arch/arm64/include/asm/cputype.h |   3 +
 arch/arm64/kernel/perf_event.c   |  58 ++++++++-
 arch/arm64/kernel/smp.c          |  18 ++-
 drivers/perf/Kconfig             |   4 +
 drivers/perf/Makefile            |   1 +
 drivers/perf/arm_pmu.c           | 110 ++++++++++++++--
 drivers/perf/arm_pmu_acpi.c      | 264 +++++++++++++++++++++++++++++++++++++++
 include/linux/perf/arm_pmu.h     |  13 ++
 10 files changed, 452 insertions(+), 24 deletions(-)
 create mode 100644 drivers/perf/arm_pmu_acpi.c

-- 
2.5.5

^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v9 01/10] arm64: pmu: add fallback probe table
  2016-09-14 22:32 ` Jeremy Linton
@ 2016-09-14 22:32   ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, will.deacon, punit.agrawal, linux-acpi, mlangsdorf,
	steve.capper

From: Mark Salter <msalter@redhat.com>

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.

Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 arch/arm64/kernel/perf_event.c | 13 ++++++++++++-
 drivers/perf/arm_pmu.c         |  2 +-
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 838ccf1..3aac598 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -24,6 +24,7 @@
 #include <asm/sysreg.h>
 #include <asm/virt.h>
 
+#include <linux/acpi.h>
 #include <linux/of.h>
 #include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
@@ -1044,9 +1045,19 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = {
 	{},
 };
 
+static const struct pmu_probe_info armv8_pmu_probe_table[] = {
+	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);
+	if (acpi_disabled)
+		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 = {
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index f5e1008..58117d7 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -1029,7 +1029,7 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 		ret = of_pmu_irq_cfg(pmu);
 		if (!ret)
 			ret = init_fn(pmu);
-	} else {
+	} else if (probe_table) {
 		cpumask_setall(&pmu->supported_cpus);
 		ret = probe_current_pmu(pmu, probe_table);
 	}
-- 
2.5.5


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 01/10] arm64: pmu: add fallback probe table
@ 2016-09-14 22:32   ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel

From: Mark Salter <msalter@redhat.com>

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.

Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 arch/arm64/kernel/perf_event.c | 13 ++++++++++++-
 drivers/perf/arm_pmu.c         |  2 +-
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 838ccf1..3aac598 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -24,6 +24,7 @@
 #include <asm/sysreg.h>
 #include <asm/virt.h>
 
+#include <linux/acpi.h>
 #include <linux/of.h>
 #include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
@@ -1044,9 +1045,19 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = {
 	{},
 };
 
+static const struct pmu_probe_info armv8_pmu_probe_table[] = {
+	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);
+	if (acpi_disabled)
+		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 = {
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index f5e1008..58117d7 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -1029,7 +1029,7 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 		ret = of_pmu_irq_cfg(pmu);
 		if (!ret)
 			ret = init_fn(pmu);
-	} else {
+	} else if (probe_table) {
 		cpumask_setall(&pmu->supported_cpus);
 		ret = probe_current_pmu(pmu, probe_table);
 	}
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 02/10] arm64: pmu: Probe default hw/cache counters
  2016-09-14 22:32 ` Jeremy Linton
@ 2016-09-14 22:32   ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, will.deacon, punit.agrawal, linux-acpi, mlangsdorf,
	steve.capper

ARMv8 machines can identify the micro/arch defined counters
that are available on a machine. Add all these counters to the
default armv8 perf map. At run-time disable the counters which
are not available on the given PMU.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/kernel/perf_event.c | 45 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 41 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 3aac598..f650548 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -191,13 +191,23 @@
 #define ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_MISS		0xED
 
 /* PMUv3 HW events mapping. */
+
+/*
+ * ARMv8 Architectural defined events, not all of these may
+ * be supported on any given implementation. Undefined events will
+ * be disabled at run-time.
+ */
 static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = {
 	PERF_MAP_ALL_UNSUPPORTED,
 	[PERF_COUNT_HW_CPU_CYCLES]		= ARMV8_PMUV3_PERFCTR_CPU_CYCLES,
 	[PERF_COUNT_HW_INSTRUCTIONS]		= ARMV8_PMUV3_PERFCTR_INST_RETIRED,
 	[PERF_COUNT_HW_CACHE_REFERENCES]	= ARMV8_PMUV3_PERFCTR_L1D_CACHE,
 	[PERF_COUNT_HW_CACHE_MISSES]		= ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= ARMV8_PMUV3_PERFCTR_PC_WRITE_RETIRED,
 	[PERF_COUNT_HW_BRANCH_MISSES]		= ARMV8_PMUV3_PERFCTR_BR_MIS_PRED,
+	[PERF_COUNT_HW_BUS_CYCLES]		= ARMV8_PMUV3_PERFCTR_BUS_CYCLES,
+	[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND]	= ARMV8_PMUV3_PERFCTR_STALL_FRONTEND,
+	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= ARMV8_PMUV3_PERFCTR_STALL_BACKEND,
 };
 
 /* ARM Cortex-A53 HW events mapping. */
@@ -259,6 +269,15 @@ static const unsigned armv8_pmuv3_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 	[C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_L1D_CACHE,
 	[C(L1D)][C(OP_WRITE)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL,
 
+	[C(L1I)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_L1I_CACHE,
+	[C(L1I)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_L1I_CACHE_REFILL,
+
+	[C(DTLB)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_L1D_TLB_REFILL,
+	[C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_L1D_TLB,
+
+	[C(ITLB)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_L1I_TLB_REFILL,
+	[C(ITLB)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_L1I_TLB,
+
 	[C(BPU)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_BR_PRED,
 	[C(BPU)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_BR_MIS_PRED,
 	[C(BPU)][C(OP_WRITE)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_BR_PRED,
@@ -906,9 +925,22 @@ static void armv8pmu_reset(void *info)
 
 static int armv8_pmuv3_map_event(struct perf_event *event)
 {
-	return armpmu_map_event(event, &armv8_pmuv3_perf_map,
-				&armv8_pmuv3_perf_cache_map,
-				ARMV8_PMU_EVTYPE_EVENT);
+	int hw_event_id;
+	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+
+	hw_event_id = armpmu_map_event(event, &armv8_pmuv3_perf_map,
+				       &armv8_pmuv3_perf_cache_map,
+				       ARMV8_PMU_EVTYPE_EVENT);
+	if (hw_event_id < 0)
+		return hw_event_id;
+
+	/* disable micro/arch events not supported by this PMU */
+	if ((hw_event_id < ARMV8_PMUV3_MAX_COMMON_EVENTS) &&
+		!test_bit(hw_event_id, armpmu->pmceid_bitmap)) {
+			return -EOPNOTSUPP;
+	}
+
+	return hw_event_id;
 }
 
 static int armv8_a53_map_event(struct perf_event *event)
@@ -1045,8 +1077,13 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = {
 	{},
 };
 
+/*
+ * Non DT systems have their micro/arch events probed at run-time.
+ * A fairly complete list of generic events are provided and ones that
+ * aren't supported by the current PMU are disabled.
+ */
 static const struct pmu_probe_info armv8_pmu_probe_table[] = {
-	PMU_PROBE(0, 0, armv8_pmuv3_init), /* if all else fails... */
+	PMU_PROBE(0, 0, armv8_pmuv3_init), /* enable all defined counters */
 	{ /* sentinel value */ }
 };
 
-- 
2.5.5


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 02/10] arm64: pmu: Probe default hw/cache counters
@ 2016-09-14 22:32   ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel

ARMv8 machines can identify the micro/arch defined counters
that are available on a machine. Add all these counters to the
default armv8 perf map. At run-time disable the counters which
are not available on the given PMU.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
---
 arch/arm64/kernel/perf_event.c | 45 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 41 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 3aac598..f650548 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -191,13 +191,23 @@
 #define ARMV8_THUNDER_PERFCTR_L1I_CACHE_PREF_MISS		0xED
 
 /* PMUv3 HW events mapping. */
+
+/*
+ * ARMv8 Architectural defined events, not all of these may
+ * be supported on any given implementation. Undefined events will
+ * be disabled at run-time.
+ */
 static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = {
 	PERF_MAP_ALL_UNSUPPORTED,
 	[PERF_COUNT_HW_CPU_CYCLES]		= ARMV8_PMUV3_PERFCTR_CPU_CYCLES,
 	[PERF_COUNT_HW_INSTRUCTIONS]		= ARMV8_PMUV3_PERFCTR_INST_RETIRED,
 	[PERF_COUNT_HW_CACHE_REFERENCES]	= ARMV8_PMUV3_PERFCTR_L1D_CACHE,
 	[PERF_COUNT_HW_CACHE_MISSES]		= ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS]	= ARMV8_PMUV3_PERFCTR_PC_WRITE_RETIRED,
 	[PERF_COUNT_HW_BRANCH_MISSES]		= ARMV8_PMUV3_PERFCTR_BR_MIS_PRED,
+	[PERF_COUNT_HW_BUS_CYCLES]		= ARMV8_PMUV3_PERFCTR_BUS_CYCLES,
+	[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND]	= ARMV8_PMUV3_PERFCTR_STALL_FRONTEND,
+	[PERF_COUNT_HW_STALLED_CYCLES_BACKEND]	= ARMV8_PMUV3_PERFCTR_STALL_BACKEND,
 };
 
 /* ARM Cortex-A53 HW events mapping. */
@@ -259,6 +269,15 @@ static const unsigned armv8_pmuv3_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 	[C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_L1D_CACHE,
 	[C(L1D)][C(OP_WRITE)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL,
 
+	[C(L1I)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_L1I_CACHE,
+	[C(L1I)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_L1I_CACHE_REFILL,
+
+	[C(DTLB)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_L1D_TLB_REFILL,
+	[C(DTLB)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_L1D_TLB,
+
+	[C(ITLB)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_L1I_TLB_REFILL,
+	[C(ITLB)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_L1I_TLB,
+
 	[C(BPU)][C(OP_READ)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_BR_PRED,
 	[C(BPU)][C(OP_READ)][C(RESULT_MISS)]	= ARMV8_PMUV3_PERFCTR_BR_MIS_PRED,
 	[C(BPU)][C(OP_WRITE)][C(RESULT_ACCESS)]	= ARMV8_PMUV3_PERFCTR_BR_PRED,
@@ -906,9 +925,22 @@ static void armv8pmu_reset(void *info)
 
 static int armv8_pmuv3_map_event(struct perf_event *event)
 {
-	return armpmu_map_event(event, &armv8_pmuv3_perf_map,
-				&armv8_pmuv3_perf_cache_map,
-				ARMV8_PMU_EVTYPE_EVENT);
+	int hw_event_id;
+	struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+
+	hw_event_id = armpmu_map_event(event, &armv8_pmuv3_perf_map,
+				       &armv8_pmuv3_perf_cache_map,
+				       ARMV8_PMU_EVTYPE_EVENT);
+	if (hw_event_id < 0)
+		return hw_event_id;
+
+	/* disable micro/arch events not supported by this PMU */
+	if ((hw_event_id < ARMV8_PMUV3_MAX_COMMON_EVENTS) &&
+		!test_bit(hw_event_id, armpmu->pmceid_bitmap)) {
+			return -EOPNOTSUPP;
+	}
+
+	return hw_event_id;
 }
 
 static int armv8_a53_map_event(struct perf_event *event)
@@ -1045,8 +1077,13 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = {
 	{},
 };
 
+/*
+ * Non DT systems have their micro/arch events probed at run-time.
+ * A fairly complete list of generic events are provided and ones that
+ * aren't supported by the current PMU are disabled.
+ */
 static const struct pmu_probe_info armv8_pmu_probe_table[] = {
-	PMU_PROBE(0, 0, armv8_pmuv3_init), /* if all else fails... */
+	PMU_PROBE(0, 0, armv8_pmuv3_init), /* enable all defined counters */
 	{ /* sentinel value */ }
 };
 
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 03/10] arm64: pmu: Hoist pmu platform device name
  2016-09-14 22:32 ` Jeremy Linton
@ 2016-09-14 22:32   ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, will.deacon, punit.agrawal, linux-acpi, mlangsdorf,
	steve.capper

Move the PMU name into a common header file so it may
be referenced by other users.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 arch/arm64/kernel/perf_event.c | 2 +-
 include/linux/perf/arm_pmu.h   | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index f650548..356fa6c 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -1099,7 +1099,7 @@ static int armv8_pmu_device_probe(struct platform_device *pdev)
 
 static struct platform_driver armv8_pmu_driver = {
 	.driver		= {
-		.name	= "armv8-pmu",
+		.name	= ARMV8_PMU_PDEV_NAME,
 		.of_match_table = armv8_pmu_of_device_ids,
 	},
 	.probe		= armv8_pmu_device_probe,
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index e188438..eab9014 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -151,6 +151,8 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 			 const struct of_device_id *of_table,
 			 const struct pmu_probe_info *probe_table);
 
+#define ARMV8_PMU_PDEV_NAME "armv8-pmu"
+
 #endif /* CONFIG_ARM_PMU */
 
 #endif /* __ARM_PMU_H__ */
-- 
2.5.5


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 03/10] arm64: pmu: Hoist pmu platform device name
@ 2016-09-14 22:32   ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel

Move the PMU name into a common header file so it may
be referenced by other users.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 arch/arm64/kernel/perf_event.c | 2 +-
 include/linux/perf/arm_pmu.h   | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index f650548..356fa6c 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -1099,7 +1099,7 @@ static int armv8_pmu_device_probe(struct platform_device *pdev)
 
 static struct platform_driver armv8_pmu_driver = {
 	.driver		= {
-		.name	= "armv8-pmu",
+		.name	= ARMV8_PMU_PDEV_NAME,
 		.of_match_table = armv8_pmu_of_device_ids,
 	},
 	.probe		= armv8_pmu_device_probe,
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index e188438..eab9014 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -151,6 +151,8 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 			 const struct of_device_id *of_table,
 			 const struct pmu_probe_info *probe_table);
 
+#define ARMV8_PMU_PDEV_NAME "armv8-pmu"
+
 #endif /* CONFIG_ARM_PMU */
 
 #endif /* __ARM_PMU_H__ */
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 04/10] arm64: Rename the common MADT parse routine
  2016-09-14 22:32 ` Jeremy Linton
@ 2016-09-14 22:32   ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, will.deacon, punit.agrawal, linux-acpi, mlangsdorf,
	steve.capper

The MADT parser in smp.c is now being used to parse
out NUMA, PMU and ACPI parking protocol information as
well as the GIC information for which it was originally
created. Rename it to avoid a misleading name.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 arch/arm64/kernel/smp.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index d93d433..a6552fe 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -506,13 +506,14 @@ static unsigned int cpu_count = 1;
 
 #ifdef CONFIG_ACPI
 /*
- * acpi_map_gic_cpu_interface - parse processor MADT entry
+ * acpi_verify_and_map_madt - parse processor MADT entry
  *
  * Carry out sanity checks on MADT processor entry and initialize
- * cpu_logical_map on success
+ * cpu_logical_map, the ACPI parking protocol, NUMA mapping
+ * and the PMU interrupts on success
  */
 static void __init
-acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
+acpi_verify_and_map_madt(struct acpi_madt_generic_interrupt *processor)
 {
 	u64 hwid = processor->arm_mpidr;
 
@@ -565,7 +566,7 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
 }
 
 static int __init
-acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
+acpi_parse_madt_common(struct acpi_subtable_header *header,
 			     const unsigned long end)
 {
 	struct acpi_madt_generic_interrupt *processor;
@@ -576,7 +577,7 @@ acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
 
 	acpi_table_print_madt_entry(header);
 
-	acpi_map_gic_cpu_interface(processor);
+	acpi_verify_and_map_madt(processor);
 
 	return 0;
 }
@@ -659,7 +660,7 @@ void __init smp_init_cpus(void)
 		 * we need for SMP init
 		 */
 		acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
-				      acpi_parse_gic_cpu_interface, 0);
+				      acpi_parse_madt_common, 0);
 
 	if (cpu_count > nr_cpu_ids)
 		pr_warn("Number of cores (%d) exceeds configured maximum of %d - clipping\n",
-- 
2.5.5


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 04/10] arm64: Rename the common MADT parse routine
@ 2016-09-14 22:32   ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel

The MADT parser in smp.c is now being used to parse
out NUMA, PMU and ACPI parking protocol information as
well as the GIC information for which it was originally
created. Rename it to avoid a misleading name.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 arch/arm64/kernel/smp.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index d93d433..a6552fe 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -506,13 +506,14 @@ static unsigned int cpu_count = 1;
 
 #ifdef CONFIG_ACPI
 /*
- * acpi_map_gic_cpu_interface - parse processor MADT entry
+ * acpi_verify_and_map_madt - parse processor MADT entry
  *
  * Carry out sanity checks on MADT processor entry and initialize
- * cpu_logical_map on success
+ * cpu_logical_map, the ACPI parking protocol, NUMA mapping
+ * and the PMU interrupts on success
  */
 static void __init
-acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
+acpi_verify_and_map_madt(struct acpi_madt_generic_interrupt *processor)
 {
 	u64 hwid = processor->arm_mpidr;
 
@@ -565,7 +566,7 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor)
 }
 
 static int __init
-acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
+acpi_parse_madt_common(struct acpi_subtable_header *header,
 			     const unsigned long end)
 {
 	struct acpi_madt_generic_interrupt *processor;
@@ -576,7 +577,7 @@ acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
 
 	acpi_table_print_madt_entry(header);
 
-	acpi_map_gic_cpu_interface(processor);
+	acpi_verify_and_map_madt(processor);
 
 	return 0;
 }
@@ -659,7 +660,7 @@ void __init smp_init_cpus(void)
 		 * we need for SMP init
 		 */
 		acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
-				      acpi_parse_gic_cpu_interface, 0);
+				      acpi_parse_madt_common, 0);
 
 	if (cpu_count > nr_cpu_ids)
 		pr_warn("Number of cores (%d) exceeds configured maximum of %d - clipping\n",
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 05/10] arm: arm64: Add routine to determine cpuid of other cpus
  2016-09-14 22:32 ` Jeremy Linton
@ 2016-09-14 22:32   ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, will.deacon, punit.agrawal, linux-acpi, mlangsdorf,
	steve.capper

It is helpful if we can read the cpuid/midr of other CPUs
in the system independent of arm/arm64.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 arch/arm/include/asm/cputype.h   | 2 ++
 arch/arm64/include/asm/cputype.h | 3 +++
 2 files changed, 5 insertions(+)

diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index 1ee94c7..d5900a2 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -208,6 +208,8 @@ static inline unsigned int __attribute_const__ read_cpuid_mpidr(void)
 	return read_cpuid(CPUID_MPIDR);
 }
 
+#define read_specific_cpuid(cpu_num) per_cpu_ptr(&cpu_data, cpu_num)->cpuid
+
 /*
  * Intel's XScale3 core supports some v6 features (supersections, L2)
  * but advertises itself as v5 as it does not support the v6 ISA.  For
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 9d9fd4b..beb95dc 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -128,6 +128,9 @@ static inline u32 __attribute_const__ read_cpuid_cachetype(void)
 {
 	return read_cpuid(CTR_EL0);
 }
+
+#define read_specific_cpuid(cpu_num) per_cpu_ptr(&cpu_data, cpu_num)->reg_midr
+
 #endif /* __ASSEMBLY__ */
 
 #endif
-- 
2.5.5


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 05/10] arm: arm64: Add routine to determine cpuid of other cpus
@ 2016-09-14 22:32   ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel

It is helpful if we can read the cpuid/midr of other CPUs
in the system independent of arm/arm64.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 arch/arm/include/asm/cputype.h   | 2 ++
 arch/arm64/include/asm/cputype.h | 3 +++
 2 files changed, 5 insertions(+)

diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index 1ee94c7..d5900a2 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -208,6 +208,8 @@ static inline unsigned int __attribute_const__ read_cpuid_mpidr(void)
 	return read_cpuid(CPUID_MPIDR);
 }
 
+#define read_specific_cpuid(cpu_num) per_cpu_ptr(&cpu_data, cpu_num)->cpuid
+
 /*
  * Intel's XScale3 core supports some v6 features (supersections, L2)
  * but advertises itself as v5 as it does not support the v6 ISA.  For
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 9d9fd4b..beb95dc 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -128,6 +128,9 @@ static inline u32 __attribute_const__ read_cpuid_cachetype(void)
 {
 	return read_cpuid(CTR_EL0);
 }
+
+#define read_specific_cpuid(cpu_num) per_cpu_ptr(&cpu_data, cpu_num)->reg_midr
+
 #endif /* __ASSEMBLY__ */
 
 #endif
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 06/10] arm64: pmu: Cache PMU interrupt numbers from MADT parse
  2016-09-14 22:32 ` Jeremy Linton
@ 2016-09-14 22:32   ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, will.deacon, punit.agrawal, linux-acpi, mlangsdorf,
	steve.capper

From: Mark Salter <msalter@redhat.com>

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. Since the platform
device creation needs to happen after the CPU's have been started, and
the MADT parsing needs to happen before, we save off the interrupt
numbers discovered during the parsing.

Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 arch/arm64/kernel/smp.c      |  5 +++++
 drivers/perf/Kconfig         |  4 ++++
 drivers/perf/Makefile        |  1 +
 drivers/perf/arm_pmu_acpi.c  | 40 ++++++++++++++++++++++++++++++++++++++++
 include/linux/perf/arm_pmu.h |  7 +++++++
 5 files changed, 57 insertions(+)
 create mode 100644 drivers/perf/arm_pmu_acpi.c

diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index a6552fe..dc333c6 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -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>
@@ -540,6 +541,7 @@ acpi_verify_and_map_madt(struct acpi_madt_generic_interrupt *processor)
 			return;
 		}
 		bootcpu_valid = true;
+		arm_pmu_parse_acpi(0, processor);
 		return;
 	}
 
@@ -560,6 +562,9 @@ acpi_verify_and_map_madt(struct acpi_madt_generic_interrupt *processor)
 	 */
 	acpi_set_mailbox_entry(cpu_count, processor);
 
+	/* get PMU irq info */
+	arm_pmu_parse_acpi(cpu_count, processor);
+
 	early_map_cpu_to_node(cpu_count, acpi_numa_get_nid(cpu_count, hwid));
 
 	cpu_count++;
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 04e2653..818fa3b 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -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
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index acd2397..fd8090d 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_ARM_PMU) += arm_pmu.o
+obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_acpi.o
diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c
new file mode 100644
index 0000000..dbd4e10
--- /dev/null
+++ b/drivers/perf/arm_pmu_acpi.c
@@ -0,0 +1,40 @@
+/*
+ * ARM ACPI PMU support
+ *
+ * Copyright (C) 2015 Red Hat Inc.
+ * Author: Mark Salter <msalter@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <asm/cpu.h>
+#include <linux/acpi.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/list.h>
+#include <linux/perf/arm_pmu.h>
+#include <linux/platform_device.h>
+
+struct pmu_irq {
+	int  gsi;
+	int  trigger;
+	bool registered;
+};
+
+static struct pmu_irq pmu_irqs[NR_CPUS];
+
+/*
+ * Called from acpi_verify_and_map_madt()'s MADT parsing during boot.
+ * This routine saves off the GSI's and their trigger state for use when we are
+ * ready to build the PMU platform device.
+*/
+void __init arm_pmu_parse_acpi(int cpu, struct acpi_madt_generic_interrupt *gic)
+{
+	pmu_irqs[cpu].gsi = gic->performance_interrupt;
+	if (gic->flags & ACPI_MADT_PERFORMANCE_IRQ_MODE)
+		pmu_irqs[cpu].trigger = ACPI_EDGE_SENSITIVE;
+	else
+		pmu_irqs[cpu].trigger = ACPI_LEVEL_SENSITIVE;
+}
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index eab9014..535c9e2 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -155,4 +155,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__ */
-- 
2.5.5


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 06/10] arm64: pmu: Cache PMU interrupt numbers from MADT parse
@ 2016-09-14 22:32   ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel

From: Mark Salter <msalter@redhat.com>

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. Since the platform
device creation needs to happen after the CPU's have been started, and
the MADT parsing needs to happen before, we save off the interrupt
numbers discovered during the parsing.

Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 arch/arm64/kernel/smp.c      |  5 +++++
 drivers/perf/Kconfig         |  4 ++++
 drivers/perf/Makefile        |  1 +
 drivers/perf/arm_pmu_acpi.c  | 40 ++++++++++++++++++++++++++++++++++++++++
 include/linux/perf/arm_pmu.h |  7 +++++++
 5 files changed, 57 insertions(+)
 create mode 100644 drivers/perf/arm_pmu_acpi.c

diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index a6552fe..dc333c6 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -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>
@@ -540,6 +541,7 @@ acpi_verify_and_map_madt(struct acpi_madt_generic_interrupt *processor)
 			return;
 		}
 		bootcpu_valid = true;
+		arm_pmu_parse_acpi(0, processor);
 		return;
 	}
 
@@ -560,6 +562,9 @@ acpi_verify_and_map_madt(struct acpi_madt_generic_interrupt *processor)
 	 */
 	acpi_set_mailbox_entry(cpu_count, processor);
 
+	/* get PMU irq info */
+	arm_pmu_parse_acpi(cpu_count, processor);
+
 	early_map_cpu_to_node(cpu_count, acpi_numa_get_nid(cpu_count, hwid));
 
 	cpu_count++;
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 04e2653..818fa3b 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -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
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index acd2397..fd8090d 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_ARM_PMU) += arm_pmu.o
+obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_acpi.o
diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c
new file mode 100644
index 0000000..dbd4e10
--- /dev/null
+++ b/drivers/perf/arm_pmu_acpi.c
@@ -0,0 +1,40 @@
+/*
+ * ARM ACPI PMU support
+ *
+ * Copyright (C) 2015 Red Hat Inc.
+ * Author: Mark Salter <msalter@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <asm/cpu.h>
+#include <linux/acpi.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/list.h>
+#include <linux/perf/arm_pmu.h>
+#include <linux/platform_device.h>
+
+struct pmu_irq {
+	int  gsi;
+	int  trigger;
+	bool registered;
+};
+
+static struct pmu_irq pmu_irqs[NR_CPUS];
+
+/*
+ * Called from acpi_verify_and_map_madt()'s MADT parsing during boot.
+ * This routine saves off the GSI's and their trigger state for use when we are
+ * ready to build the PMU platform device.
+*/
+void __init arm_pmu_parse_acpi(int cpu, struct acpi_madt_generic_interrupt *gic)
+{
+	pmu_irqs[cpu].gsi = gic->performance_interrupt;
+	if (gic->flags & ACPI_MADT_PERFORMANCE_IRQ_MODE)
+		pmu_irqs[cpu].trigger = ACPI_EDGE_SENSITIVE;
+	else
+		pmu_irqs[cpu].trigger = ACPI_LEVEL_SENSITIVE;
+}
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index eab9014..535c9e2 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -155,4 +155,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__ */
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 07/10] arm: arm64: pmu: Assign platform PMU CPU affinity
  2016-09-14 22:32 ` Jeremy Linton
@ 2016-09-14 22:32   ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, will.deacon, punit.agrawal, linux-acpi, mlangsdorf,
	steve.capper

On systems with multiple PMU types the PMU to CPU affinity
needs to be detected and set. The CPU to interrupt affinity
should also be set.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 drivers/perf/arm_pmu.c | 63 ++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 53 insertions(+), 10 deletions(-)

diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 58117d7..63f16a5 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -11,6 +11,7 @@
  */
 #define pr_fmt(fmt) "hw perfevents: " fmt
 
+#include <linux/acpi.h>
 #include <linux/bitmap.h>
 #include <linux/cpumask.h>
 #include <linux/cpu_pm.h>
@@ -24,6 +25,7 @@
 #include <linux/irq.h>
 #include <linux/irqdesc.h>
 
+#include <asm/cpu.h>
 #include <asm/cputype.h>
 #include <asm/irq_regs.h>
 
@@ -876,25 +878,67 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
 }
 
 /*
- * CPU PMU identification and probing.
+ * CPU PMU identification and probing. Its possible to have
+ * multiple CPU types in an ARM machine. Assure that we are
+ * picking the right PMU types based on the CPU in question
  */
-static int probe_current_pmu(struct arm_pmu *pmu,
-			     const struct pmu_probe_info *info)
+static int probe_plat_pmu(struct arm_pmu *pmu,
+			     const struct pmu_probe_info *info,
+			     unsigned int pmuid)
 {
-	int cpu = get_cpu();
-	unsigned int cpuid = read_cpuid_id();
 	int ret = -ENODEV;
+	int cpu;
+	int aff_ctr = 0;
+	static int duplicate_pmus;
+	struct platform_device *pdev = pmu->plat_device;
+	int irq = platform_get_irq(pdev, 0);
 
-	pr_info("probing PMU on CPU %d\n", cpu);
+	if (irq >= 0 && !irq_is_percpu(irq)) {
+		pmu->irq_affinity = kcalloc(pdev->num_resources, sizeof(int),
+					    GFP_KERNEL);
+		if (!pmu->irq_affinity)
+			return -ENOMEM;
+	}
 
+	for_each_possible_cpu(cpu) {
+		unsigned int cpuid = read_specific_cpuid(cpu);
+
+		if (cpuid == pmuid) {
+			cpumask_set_cpu(cpu, &pmu->supported_cpus);
+			if (pmu->irq_affinity) {
+				pmu->irq_affinity[aff_ctr] = cpu;
+				aff_ctr++;
+			}
+		}
+	}
+
+	/* find the type of PMU given the CPU */
 	for (; info->init != NULL; info++) {
-		if ((cpuid & info->mask) != info->cpuid)
+		if ((pmuid & info->mask) != info->cpuid)
 			continue;
 		ret = info->init(pmu);
+		/*
+		 * if this pmu declaration is unspecified and we have
+		 * previously found a PMU on this platform then append
+		 * a PMU number to the pmu name. This avoids changing
+		 * the names of PMUs that are specific to a class of CPUs.
+		 * The assumption is that if we match a specific PMU in the
+		 * provided pmu_probe_info then it's unique, and another PMU
+		 * in the system will match a different entry rather than
+		 * needing the _number to assure its unique.
+		 */
+		if ((!info->cpuid) && (duplicate_pmus)) {
+			pmu->name = kasprintf(GFP_KERNEL, "%s_%d",
+					    pmu->name, duplicate_pmus);
+			if (!pmu->name) {
+				kfree(pmu->irq_affinity);
+				ret = -ENOMEM;
+			}
+		}
+		duplicate_pmus++;
 		break;
 	}
 
-	put_cpu();
 	return ret;
 }
 
@@ -1030,8 +1074,7 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 		if (!ret)
 			ret = init_fn(pmu);
 	} else if (probe_table) {
-		cpumask_setall(&pmu->supported_cpus);
-		ret = probe_current_pmu(pmu, probe_table);
+		ret = probe_plat_pmu(pmu, probe_table, read_cpuid_id());
 	}
 
 	if (ret) {
-- 
2.5.5


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 07/10] arm: arm64: pmu: Assign platform PMU CPU affinity
@ 2016-09-14 22:32   ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel

On systems with multiple PMU types the PMU to CPU affinity
needs to be detected and set. The CPU to interrupt affinity
should also be set.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 drivers/perf/arm_pmu.c | 63 ++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 53 insertions(+), 10 deletions(-)

diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 58117d7..63f16a5 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -11,6 +11,7 @@
  */
 #define pr_fmt(fmt) "hw perfevents: " fmt
 
+#include <linux/acpi.h>
 #include <linux/bitmap.h>
 #include <linux/cpumask.h>
 #include <linux/cpu_pm.h>
@@ -24,6 +25,7 @@
 #include <linux/irq.h>
 #include <linux/irqdesc.h>
 
+#include <asm/cpu.h>
 #include <asm/cputype.h>
 #include <asm/irq_regs.h>
 
@@ -876,25 +878,67 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
 }
 
 /*
- * CPU PMU identification and probing.
+ * CPU PMU identification and probing. Its possible to have
+ * multiple CPU types in an ARM machine. Assure that we are
+ * picking the right PMU types based on the CPU in question
  */
-static int probe_current_pmu(struct arm_pmu *pmu,
-			     const struct pmu_probe_info *info)
+static int probe_plat_pmu(struct arm_pmu *pmu,
+			     const struct pmu_probe_info *info,
+			     unsigned int pmuid)
 {
-	int cpu = get_cpu();
-	unsigned int cpuid = read_cpuid_id();
 	int ret = -ENODEV;
+	int cpu;
+	int aff_ctr = 0;
+	static int duplicate_pmus;
+	struct platform_device *pdev = pmu->plat_device;
+	int irq = platform_get_irq(pdev, 0);
 
-	pr_info("probing PMU on CPU %d\n", cpu);
+	if (irq >= 0 && !irq_is_percpu(irq)) {
+		pmu->irq_affinity = kcalloc(pdev->num_resources, sizeof(int),
+					    GFP_KERNEL);
+		if (!pmu->irq_affinity)
+			return -ENOMEM;
+	}
 
+	for_each_possible_cpu(cpu) {
+		unsigned int cpuid = read_specific_cpuid(cpu);
+
+		if (cpuid == pmuid) {
+			cpumask_set_cpu(cpu, &pmu->supported_cpus);
+			if (pmu->irq_affinity) {
+				pmu->irq_affinity[aff_ctr] = cpu;
+				aff_ctr++;
+			}
+		}
+	}
+
+	/* find the type of PMU given the CPU */
 	for (; info->init != NULL; info++) {
-		if ((cpuid & info->mask) != info->cpuid)
+		if ((pmuid & info->mask) != info->cpuid)
 			continue;
 		ret = info->init(pmu);
+		/*
+		 * if this pmu declaration is unspecified and we have
+		 * previously found a PMU on this platform then append
+		 * a PMU number to the pmu name. This avoids changing
+		 * the names of PMUs that are specific to a class of CPUs.
+		 * The assumption is that if we match a specific PMU in the
+		 * provided pmu_probe_info then it's unique, and another PMU
+		 * in the system will match a different entry rather than
+		 * needing the _number to assure its unique.
+		 */
+		if ((!info->cpuid) && (duplicate_pmus)) {
+			pmu->name = kasprintf(GFP_KERNEL, "%s_%d",
+					    pmu->name, duplicate_pmus);
+			if (!pmu->name) {
+				kfree(pmu->irq_affinity);
+				ret = -ENOMEM;
+			}
+		}
+		duplicate_pmus++;
 		break;
 	}
 
-	put_cpu();
 	return ret;
 }
 
@@ -1030,8 +1074,7 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 		if (!ret)
 			ret = init_fn(pmu);
 	} else if (probe_table) {
-		cpumask_setall(&pmu->supported_cpus);
-		ret = probe_current_pmu(pmu, probe_table);
+		ret = probe_plat_pmu(pmu, probe_table, read_cpuid_id());
 	}
 
 	if (ret) {
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system
  2016-09-14 22:32 ` Jeremy Linton
@ 2016-09-14 22:32   ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, will.deacon, punit.agrawal, linux-acpi, mlangsdorf,
	steve.capper

Its possible that an ACPI system has multiple CPU types in it
with differing PMU counters. Iterate the CPU's and make a determination
about how many of each type exist in the system. Then take and create
a PMU platform device for each type, and assign it the interrupts parsed
from the MADT. Creating a platform device is necessary because the PMUs
are not described as devices in the DSDT table.

This code is loosely based on earlier work by Mark Salter.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 drivers/perf/arm_pmu.c      |   8 +-
 drivers/perf/arm_pmu_acpi.c | 224 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 231 insertions(+), 1 deletion(-)

diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 63f16a5..47ab4e9 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -1074,7 +1074,13 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 		if (!ret)
 			ret = init_fn(pmu);
 	} else if (probe_table) {
-		ret = probe_plat_pmu(pmu, probe_table, read_cpuid_id());
+		if (acpi_disabled) {
+			/* use the current cpu. */
+			ret = probe_plat_pmu(pmu, probe_table,
+					     read_cpuid_id());
+		} else {
+			ret = probe_plat_pmu(pmu, probe_table, pdev->id);
+		}
 	}
 
 	if (ret) {
diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c
index dbd4e10..7c56ee4 100644
--- a/drivers/perf/arm_pmu_acpi.c
+++ b/drivers/perf/arm_pmu_acpi.c
@@ -2,13 +2,17 @@
  * ARM ACPI PMU support
  *
  * Copyright (C) 2015 Red Hat Inc.
+ * Copyright (C) 2016 ARM Ltd.
  * Author: Mark Salter <msalter@redhat.com>
+ *	   Jeremy Linton <jeremy.linton@arm.com>
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
  */
 
+#define pr_fmt(fmt) "ACPI-PMU: " fmt
+
 #include <asm/cpu.h>
 #include <linux/acpi.h>
 #include <linux/irq.h>
@@ -23,6 +27,12 @@ struct pmu_irq {
 	bool registered;
 };
 
+struct pmu_types {
+	struct list_head list;
+	int		 cpu_type;
+	int		 cpu_count;
+};
+
 static struct pmu_irq pmu_irqs[NR_CPUS];
 
 /*
@@ -38,3 +48,217 @@ void __init arm_pmu_parse_acpi(int cpu, struct acpi_madt_generic_interrupt *gic)
 	else
 		pmu_irqs[cpu].trigger = ACPI_LEVEL_SENSITIVE;
 }
+
+static void __init arm_pmu_acpi_handle_alloc_failure(struct list_head *pmus)
+{
+	struct pmu_types *pmu, *safe_temp;
+
+	list_for_each_entry_safe(pmu, safe_temp, pmus, list) {
+		list_del(&pmu->list);
+		kfree(pmu);
+	}
+}
+
+/* Count number and type of CPU cores in the system. */
+static bool __init arm_pmu_acpi_determine_cpu_types(struct list_head *pmus)
+{
+	int i;
+	bool unused_madt_entries = false;
+
+	for_each_possible_cpu(i) {
+		struct cpuinfo_arm64 *cinfo = per_cpu_ptr(&cpu_data, i);
+		u32 partnum = MIDR_PARTNUM(cinfo->reg_midr);
+		struct pmu_types *pmu;
+
+		if (cinfo->reg_midr == 0) {
+			unused_madt_entries = true;
+			continue;
+		}
+
+		list_for_each_entry(pmu, pmus, list) {
+			if (pmu->cpu_type == partnum) {
+				pmu->cpu_count++;
+				break;
+			}
+		}
+
+		/* we didn't find the CPU type, add an entry to identify it */
+		if (&pmu->list == pmus) {
+			pmu = kzalloc(sizeof(struct pmu_types), GFP_KERNEL);
+			if (!pmu) {
+				pr_err("Unable to allocate pmu_types\n");
+				/*
+				 * Instead of waiting to cleanup possible
+				 * allocation failures in the caller clean
+				 * them up immediately. Functionally this
+				 * doesn't make any difference, except in
+				 * genuine heterogeneous systems where it
+				 * guarantees the whole subsystem is
+				 * disabled rather than running with just
+				 * a single set of homogeneous CPU's PMU
+				 * active. That assumes there aren't
+				 * any further memory allocation failures.
+				 */
+				arm_pmu_acpi_handle_alloc_failure(pmus);
+				break;
+			} else {
+				pmu->cpu_type = partnum;
+				pmu->cpu_count++;
+				list_add_tail(&pmu->list, pmus);
+			}
+		}
+	}
+
+	return unused_madt_entries;
+}
+
+/*
+ * Registers the group of PMU interfaces which correspond to the 'last_cpu_id'.
+ * This group utilizes 'count' resources in the 'res'.
+ */
+static int __init arm_pmu_acpi_register_pmu(int count, struct resource *res,
+					    int last_cpu_id)
+{
+	int i;
+	int err = -ENOMEM;
+	bool free_gsi = false;
+	struct platform_device *pdev;
+
+	if (count) {
+		pdev = platform_device_alloc(ARMV8_PMU_PDEV_NAME, last_cpu_id);
+		if (pdev) {
+			err = platform_device_add_resources(pdev, res, count);
+			if (!err) {
+				err = platform_device_add(pdev);
+				if (err) {
+					pr_warn("Unable to register PMU device\n");
+					free_gsi = true;
+				}
+			} else {
+				pr_warn("Unable to add resources to device\n");
+				free_gsi = true;
+				platform_device_put(pdev);
+			}
+		} else {
+			pr_warn("Unable to allocate platform device\n");
+			free_gsi = true;
+		}
+	}
+
+	/* unmark (and possibly unregister) registered GSIs */
+	for_each_possible_cpu(i) {
+		if (pmu_irqs[i].registered) {
+			if (free_gsi)
+				acpi_unregister_gsi(pmu_irqs[i].gsi);
+			pmu_irqs[i].registered = false;
+		}
+	}
+
+	return err;
+}
+
+int arm_pmu_acpi_retrieve_irq(struct resource *res, int cpu)
+{
+	int irq = -ENODEV;
+
+	if (pmu_irqs[cpu].registered) {
+		pr_info("CPU %d's interrupt is already registered\n", cpu);
+	} else {
+		irq = acpi_register_gsi(NULL, pmu_irqs[cpu].gsi,
+					pmu_irqs[cpu].trigger,
+					ACPI_ACTIVE_HIGH);
+		pmu_irqs[cpu].registered = true;
+		res->start = irq;
+		res->end = irq;
+		res->flags = IORESOURCE_IRQ;
+		if (pmu_irqs[cpu].trigger == ACPI_EDGE_SENSITIVE)
+			res->flags |= IORESOURCE_IRQ_HIGHEDGE;
+		else
+			res->flags |= IORESOURCE_IRQ_HIGHLEVEL;
+	}
+	return irq;
+}
+
+/*
+ * For the given cpu/pmu type, walk all known GSIs, register them, and add
+ * them to the resource structure. Return the number of GSI's contained
+ * in the res structure, and the id of the last CPU/PMU we added.
+ */
+static int __init arm_pmu_acpi_gsi_res(struct pmu_types *pmus,
+				       struct resource *res, int *last_cpu_id)
+{
+	int i, count;
+
+	/* lets group all the PMU's from similar CPU's together */
+	count = 0;
+	for_each_possible_cpu(i) {
+		struct cpuinfo_arm64 *cinfo = per_cpu_ptr(&cpu_data, i);
+
+		if (pmus->cpu_type == MIDR_PARTNUM(cinfo->reg_midr)) {
+			if ((pmu_irqs[i].gsi == 0) && (cinfo->reg_midr != 0)) {
+				pr_info("CPU %d is assigned interrupt 0\n", i);
+				continue;
+			}
+			/* likely not online */
+			if (!cinfo->reg_midr)
+				continue;
+
+			arm_pmu_acpi_retrieve_irq(&res[count], i);
+			count++;
+			(*last_cpu_id) = cinfo->reg_midr;
+		}
+	}
+	return count;
+}
+
+static int __init pmu_acpi_init(void)
+{
+	struct resource	*res;
+	int err = -ENOMEM;
+	int count, cpu_id;
+	struct pmu_types *pmu, *safe_temp;
+	bool unused_madt_entries;
+	LIST_HEAD(pmus);
+
+	if (acpi_disabled)
+		return 0;
+
+	unused_madt_entries = arm_pmu_acpi_determine_cpu_types(&pmus);
+
+	list_for_each_entry_safe(pmu, safe_temp, &pmus, list) {
+		if (unused_madt_entries)
+			pmu->cpu_count = num_possible_cpus();
+
+		res = kcalloc(pmu->cpu_count,
+				  sizeof(struct resource), GFP_KERNEL);
+
+		/* for a given PMU type collect all the GSIs. */
+		if (res) {
+			count = arm_pmu_acpi_gsi_res(pmu, res,
+						     &cpu_id);
+			/*
+			 * register this set of interrupts
+			 * with a new PMU device
+			 */
+			if (count) {
+				if (unused_madt_entries)
+					count = num_possible_cpus();
+				err = arm_pmu_acpi_register_pmu(count, res,
+								cpu_id);
+				if (!err)
+					pr_info("Register %d devices for %X\n",
+						count, pmu->cpu_type);
+				kfree(res);
+			}
+		} else {
+			pr_warn("PMU unable to allocate interrupt resource\n");
+		}
+
+		list_del(&pmu->list);
+		kfree(pmu);
+	}
+
+	return err;
+}
+
+arch_initcall(pmu_acpi_init);
-- 
2.5.5


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system
@ 2016-09-14 22:32   ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel

Its possible that an ACPI system has multiple CPU types in it
with differing PMU counters. Iterate the CPU's and make a determination
about how many of each type exist in the system. Then take and create
a PMU platform device for each type, and assign it the interrupts parsed
from the MADT. Creating a platform device is necessary because the PMUs
are not described as devices in the DSDT table.

This code is loosely based on earlier work by Mark Salter.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 drivers/perf/arm_pmu.c      |   8 +-
 drivers/perf/arm_pmu_acpi.c | 224 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 231 insertions(+), 1 deletion(-)

diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 63f16a5..47ab4e9 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -1074,7 +1074,13 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 		if (!ret)
 			ret = init_fn(pmu);
 	} else if (probe_table) {
-		ret = probe_plat_pmu(pmu, probe_table, read_cpuid_id());
+		if (acpi_disabled) {
+			/* use the current cpu. */
+			ret = probe_plat_pmu(pmu, probe_table,
+					     read_cpuid_id());
+		} else {
+			ret = probe_plat_pmu(pmu, probe_table, pdev->id);
+		}
 	}
 
 	if (ret) {
diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c
index dbd4e10..7c56ee4 100644
--- a/drivers/perf/arm_pmu_acpi.c
+++ b/drivers/perf/arm_pmu_acpi.c
@@ -2,13 +2,17 @@
  * ARM ACPI PMU support
  *
  * Copyright (C) 2015 Red Hat Inc.
+ * Copyright (C) 2016 ARM Ltd.
  * Author: Mark Salter <msalter@redhat.com>
+ *	   Jeremy Linton <jeremy.linton@arm.com>
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
  *
  */
 
+#define pr_fmt(fmt) "ACPI-PMU: " fmt
+
 #include <asm/cpu.h>
 #include <linux/acpi.h>
 #include <linux/irq.h>
@@ -23,6 +27,12 @@ struct pmu_irq {
 	bool registered;
 };
 
+struct pmu_types {
+	struct list_head list;
+	int		 cpu_type;
+	int		 cpu_count;
+};
+
 static struct pmu_irq pmu_irqs[NR_CPUS];
 
 /*
@@ -38,3 +48,217 @@ void __init arm_pmu_parse_acpi(int cpu, struct acpi_madt_generic_interrupt *gic)
 	else
 		pmu_irqs[cpu].trigger = ACPI_LEVEL_SENSITIVE;
 }
+
+static void __init arm_pmu_acpi_handle_alloc_failure(struct list_head *pmus)
+{
+	struct pmu_types *pmu, *safe_temp;
+
+	list_for_each_entry_safe(pmu, safe_temp, pmus, list) {
+		list_del(&pmu->list);
+		kfree(pmu);
+	}
+}
+
+/* Count number and type of CPU cores in the system. */
+static bool __init arm_pmu_acpi_determine_cpu_types(struct list_head *pmus)
+{
+	int i;
+	bool unused_madt_entries = false;
+
+	for_each_possible_cpu(i) {
+		struct cpuinfo_arm64 *cinfo = per_cpu_ptr(&cpu_data, i);
+		u32 partnum = MIDR_PARTNUM(cinfo->reg_midr);
+		struct pmu_types *pmu;
+
+		if (cinfo->reg_midr == 0) {
+			unused_madt_entries = true;
+			continue;
+		}
+
+		list_for_each_entry(pmu, pmus, list) {
+			if (pmu->cpu_type == partnum) {
+				pmu->cpu_count++;
+				break;
+			}
+		}
+
+		/* we didn't find the CPU type, add an entry to identify it */
+		if (&pmu->list == pmus) {
+			pmu = kzalloc(sizeof(struct pmu_types), GFP_KERNEL);
+			if (!pmu) {
+				pr_err("Unable to allocate pmu_types\n");
+				/*
+				 * Instead of waiting to cleanup possible
+				 * allocation failures in the caller clean
+				 * them up immediately. Functionally this
+				 * doesn't make any difference, except in
+				 * genuine heterogeneous systems where it
+				 * guarantees the whole subsystem is
+				 * disabled rather than running with just
+				 * a single set of homogeneous CPU's PMU
+				 * active. That assumes there aren't
+				 * any further memory allocation failures.
+				 */
+				arm_pmu_acpi_handle_alloc_failure(pmus);
+				break;
+			} else {
+				pmu->cpu_type = partnum;
+				pmu->cpu_count++;
+				list_add_tail(&pmu->list, pmus);
+			}
+		}
+	}
+
+	return unused_madt_entries;
+}
+
+/*
+ * Registers the group of PMU interfaces which correspond to the 'last_cpu_id'.
+ * This group utilizes 'count' resources in the 'res'.
+ */
+static int __init arm_pmu_acpi_register_pmu(int count, struct resource *res,
+					    int last_cpu_id)
+{
+	int i;
+	int err = -ENOMEM;
+	bool free_gsi = false;
+	struct platform_device *pdev;
+
+	if (count) {
+		pdev = platform_device_alloc(ARMV8_PMU_PDEV_NAME, last_cpu_id);
+		if (pdev) {
+			err = platform_device_add_resources(pdev, res, count);
+			if (!err) {
+				err = platform_device_add(pdev);
+				if (err) {
+					pr_warn("Unable to register PMU device\n");
+					free_gsi = true;
+				}
+			} else {
+				pr_warn("Unable to add resources to device\n");
+				free_gsi = true;
+				platform_device_put(pdev);
+			}
+		} else {
+			pr_warn("Unable to allocate platform device\n");
+			free_gsi = true;
+		}
+	}
+
+	/* unmark (and possibly unregister) registered GSIs */
+	for_each_possible_cpu(i) {
+		if (pmu_irqs[i].registered) {
+			if (free_gsi)
+				acpi_unregister_gsi(pmu_irqs[i].gsi);
+			pmu_irqs[i].registered = false;
+		}
+	}
+
+	return err;
+}
+
+int arm_pmu_acpi_retrieve_irq(struct resource *res, int cpu)
+{
+	int irq = -ENODEV;
+
+	if (pmu_irqs[cpu].registered) {
+		pr_info("CPU %d's interrupt is already registered\n", cpu);
+	} else {
+		irq = acpi_register_gsi(NULL, pmu_irqs[cpu].gsi,
+					pmu_irqs[cpu].trigger,
+					ACPI_ACTIVE_HIGH);
+		pmu_irqs[cpu].registered = true;
+		res->start = irq;
+		res->end = irq;
+		res->flags = IORESOURCE_IRQ;
+		if (pmu_irqs[cpu].trigger == ACPI_EDGE_SENSITIVE)
+			res->flags |= IORESOURCE_IRQ_HIGHEDGE;
+		else
+			res->flags |= IORESOURCE_IRQ_HIGHLEVEL;
+	}
+	return irq;
+}
+
+/*
+ * For the given cpu/pmu type, walk all known GSIs, register them, and add
+ * them to the resource structure. Return the number of GSI's contained
+ * in the res structure, and the id of the last CPU/PMU we added.
+ */
+static int __init arm_pmu_acpi_gsi_res(struct pmu_types *pmus,
+				       struct resource *res, int *last_cpu_id)
+{
+	int i, count;
+
+	/* lets group all the PMU's from similar CPU's together */
+	count = 0;
+	for_each_possible_cpu(i) {
+		struct cpuinfo_arm64 *cinfo = per_cpu_ptr(&cpu_data, i);
+
+		if (pmus->cpu_type == MIDR_PARTNUM(cinfo->reg_midr)) {
+			if ((pmu_irqs[i].gsi == 0) && (cinfo->reg_midr != 0)) {
+				pr_info("CPU %d is assigned interrupt 0\n", i);
+				continue;
+			}
+			/* likely not online */
+			if (!cinfo->reg_midr)
+				continue;
+
+			arm_pmu_acpi_retrieve_irq(&res[count], i);
+			count++;
+			(*last_cpu_id) = cinfo->reg_midr;
+		}
+	}
+	return count;
+}
+
+static int __init pmu_acpi_init(void)
+{
+	struct resource	*res;
+	int err = -ENOMEM;
+	int count, cpu_id;
+	struct pmu_types *pmu, *safe_temp;
+	bool unused_madt_entries;
+	LIST_HEAD(pmus);
+
+	if (acpi_disabled)
+		return 0;
+
+	unused_madt_entries = arm_pmu_acpi_determine_cpu_types(&pmus);
+
+	list_for_each_entry_safe(pmu, safe_temp, &pmus, list) {
+		if (unused_madt_entries)
+			pmu->cpu_count = num_possible_cpus();
+
+		res = kcalloc(pmu->cpu_count,
+				  sizeof(struct resource), GFP_KERNEL);
+
+		/* for a given PMU type collect all the GSIs. */
+		if (res) {
+			count = arm_pmu_acpi_gsi_res(pmu, res,
+						     &cpu_id);
+			/*
+			 * register this set of interrupts
+			 * with a new PMU device
+			 */
+			if (count) {
+				if (unused_madt_entries)
+					count = num_possible_cpus();
+				err = arm_pmu_acpi_register_pmu(count, res,
+								cpu_id);
+				if (!err)
+					pr_info("Register %d devices for %X\n",
+						count, pmu->cpu_type);
+				kfree(res);
+			}
+		} else {
+			pr_warn("PMU unable to allocate interrupt resource\n");
+		}
+
+		list_del(&pmu->list);
+		kfree(pmu);
+	}
+
+	return err;
+}
+
+arch_initcall(pmu_acpi_init);
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 09/10] arm: pmu: Add PMU definitions for hot-plugged CPUs
  2016-09-14 22:32 ` Jeremy Linton
@ 2016-09-14 22:32   ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, will.deacon, punit.agrawal, linux-acpi, mlangsdorf,
	steve.capper

ACPI CPUs aren't associated with a PMU until they have been put
online. This means that we potentially have to update a PMU
definition the first time a CPU is hot added to the machine.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 drivers/perf/arm_pmu.c       | 39 ++++++++++++++++++++++++++++++++++++++-
 include/linux/perf/arm_pmu.h |  4 ++++
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 47ab4e9..7835602 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -693,6 +693,34 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
 static DEFINE_SPINLOCK(arm_pmu_lock);
 static LIST_HEAD(arm_pmu_list);
 
+static void arm_perf_associate_new_cpu(struct arm_pmu *lpmu, unsigned int cpu)
+{
+	if (lpmu) {
+		struct platform_device *pdev = lpmu->plat_device;
+		struct resource *res;
+		struct pmu_hw_events *events;
+		int num_res;
+
+		for (num_res = 0; num_res < pdev->num_resources; num_res++) {
+			if (!pdev->resource[num_res].flags)
+				break;
+		}
+		res = &pdev->resource[num_res];
+
+		arm_pmu_acpi_retrieve_irq(res, cpu);
+		events = per_cpu_ptr(lpmu->hw_events, cpu);
+		cpumask_set_cpu(cpu, &lpmu->supported_cpus);
+		if (lpmu->irq_affinity)
+			lpmu->irq_affinity[num_res] = cpu;
+		pdev->num_resources++;
+		events->percpu_pmu = lpmu;
+		if (lpmu->reset)
+			lpmu->reset(lpmu);
+	} else {
+		pr_err("ACPI: unknown PMU type, unable to enable\n");
+	}
+}
+
 /*
  * PMU hardware loses all context when a CPU goes offline.
  * When a CPU is hotplugged back in, since some hardware registers are
@@ -702,15 +730,22 @@ static LIST_HEAD(arm_pmu_list);
 static int arm_perf_starting_cpu(unsigned int cpu)
 {
 	struct arm_pmu *pmu;
+	struct arm_pmu *lpmu = NULL;
+	bool found = false;
+	unsigned int cpuid = read_specific_cpuid(cpu);
 
 	spin_lock(&arm_pmu_lock);
 	list_for_each_entry(pmu, &arm_pmu_list, entry) {
-
+		if (cpuid == pmu->id)
+			lpmu = pmu;
 		if (!cpumask_test_cpu(cpu, &pmu->supported_cpus))
 			continue;
+		found = true;
 		if (pmu->reset)
 			pmu->reset(pmu);
 	}
+	if (!(found || acpi_disabled))
+		arm_perf_associate_new_cpu(lpmu, cpu);
 	spin_unlock(&arm_pmu_lock);
 	return 0;
 }
@@ -893,6 +928,8 @@ static int probe_plat_pmu(struct arm_pmu *pmu,
 	struct platform_device *pdev = pmu->plat_device;
 	int irq = platform_get_irq(pdev, 0);
 
+	pmu->id = pmuid;
+
 	if (irq >= 0 && !irq_is_percpu(irq)) {
 		pmu->irq_affinity = kcalloc(pdev->num_resources, sizeof(int),
 					    GFP_KERNEL);
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index 535c9e2..651b7a5 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -105,6 +105,7 @@ struct arm_pmu {
 	struct mutex	reserve_mutex;
 	u64		max_period;
 	bool		secure_access; /* 32-bit ARM only */
+	unsigned int	id;
 #define ARMV8_PMUV3_MAX_COMMON_EVENTS 0x40
 	DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
 	struct platform_device	*plat_device;
@@ -158,8 +159,11 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 #ifdef CONFIG_ARM_PMU_ACPI
 struct acpi_madt_generic_interrupt;
 void arm_pmu_parse_acpi(int cpu, struct acpi_madt_generic_interrupt *gic);
+int arm_pmu_acpi_retrieve_irq(struct resource *pdev, int cpu);
 #else
 #define arm_pmu_parse_acpi(a, b) do { } while (0)
+#define arm_pmu_acpi_retrieve_irq(pdev, cpu) \
+	do { } while (0)
 #endif /* CONFIG_ARM_PMU_ACPI */
 
 #endif /* __ARM_PMU_H__ */
-- 
2.5.5


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 09/10] arm: pmu: Add PMU definitions for hot-plugged CPUs
@ 2016-09-14 22:32   ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel

ACPI CPUs aren't associated with a PMU until they have been put
online. This means that we potentially have to update a PMU
definition the first time a CPU is hot added to the machine.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 drivers/perf/arm_pmu.c       | 39 ++++++++++++++++++++++++++++++++++++++-
 include/linux/perf/arm_pmu.h |  4 ++++
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index 47ab4e9..7835602 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -693,6 +693,34 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
 static DEFINE_SPINLOCK(arm_pmu_lock);
 static LIST_HEAD(arm_pmu_list);
 
+static void arm_perf_associate_new_cpu(struct arm_pmu *lpmu, unsigned int cpu)
+{
+	if (lpmu) {
+		struct platform_device *pdev = lpmu->plat_device;
+		struct resource *res;
+		struct pmu_hw_events *events;
+		int num_res;
+
+		for (num_res = 0; num_res < pdev->num_resources; num_res++) {
+			if (!pdev->resource[num_res].flags)
+				break;
+		}
+		res = &pdev->resource[num_res];
+
+		arm_pmu_acpi_retrieve_irq(res, cpu);
+		events = per_cpu_ptr(lpmu->hw_events, cpu);
+		cpumask_set_cpu(cpu, &lpmu->supported_cpus);
+		if (lpmu->irq_affinity)
+			lpmu->irq_affinity[num_res] = cpu;
+		pdev->num_resources++;
+		events->percpu_pmu = lpmu;
+		if (lpmu->reset)
+			lpmu->reset(lpmu);
+	} else {
+		pr_err("ACPI: unknown PMU type, unable to enable\n");
+	}
+}
+
 /*
  * PMU hardware loses all context when a CPU goes offline.
  * When a CPU is hotplugged back in, since some hardware registers are
@@ -702,15 +730,22 @@ static LIST_HEAD(arm_pmu_list);
 static int arm_perf_starting_cpu(unsigned int cpu)
 {
 	struct arm_pmu *pmu;
+	struct arm_pmu *lpmu = NULL;
+	bool found = false;
+	unsigned int cpuid = read_specific_cpuid(cpu);
 
 	spin_lock(&arm_pmu_lock);
 	list_for_each_entry(pmu, &arm_pmu_list, entry) {
-
+		if (cpuid == pmu->id)
+			lpmu = pmu;
 		if (!cpumask_test_cpu(cpu, &pmu->supported_cpus))
 			continue;
+		found = true;
 		if (pmu->reset)
 			pmu->reset(pmu);
 	}
+	if (!(found || acpi_disabled))
+		arm_perf_associate_new_cpu(lpmu, cpu);
 	spin_unlock(&arm_pmu_lock);
 	return 0;
 }
@@ -893,6 +928,8 @@ static int probe_plat_pmu(struct arm_pmu *pmu,
 	struct platform_device *pdev = pmu->plat_device;
 	int irq = platform_get_irq(pdev, 0);
 
+	pmu->id = pmuid;
+
 	if (irq >= 0 && !irq_is_percpu(irq)) {
 		pmu->irq_affinity = kcalloc(pdev->num_resources, sizeof(int),
 					    GFP_KERNEL);
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index 535c9e2..651b7a5 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -105,6 +105,7 @@ struct arm_pmu {
 	struct mutex	reserve_mutex;
 	u64		max_period;
 	bool		secure_access; /* 32-bit ARM only */
+	unsigned int	id;
 #define ARMV8_PMUV3_MAX_COMMON_EVENTS 0x40
 	DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
 	struct platform_device	*plat_device;
@@ -158,8 +159,11 @@ int arm_pmu_device_probe(struct platform_device *pdev,
 #ifdef CONFIG_ARM_PMU_ACPI
 struct acpi_madt_generic_interrupt;
 void arm_pmu_parse_acpi(int cpu, struct acpi_madt_generic_interrupt *gic);
+int arm_pmu_acpi_retrieve_irq(struct resource *pdev, int cpu);
 #else
 #define arm_pmu_parse_acpi(a, b) do { } while (0)
+#define arm_pmu_acpi_retrieve_irq(pdev, cpu) \
+	do { } while (0)
 #endif /* CONFIG_ARM_PMU_ACPI */
 
 #endif /* __ARM_PMU_H__ */
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 10/10] MAINTAINERS: Tweak ARM PMU maintainers
  2016-09-14 22:32 ` Jeremy Linton
@ 2016-09-14 22:32   ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mark.rutland, will.deacon, punit.agrawal, linux-acpi, mlangsdorf,
	steve.capper

Update the ARM PMU file list, and add the arm mailing list.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 MAINTAINERS | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 1fbd77d..246b427 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -915,12 +915,13 @@ ARM PMU PROFILING AND DEBUGGING
 M:	Will Deacon <will.deacon@arm.com>
 R:	Mark Rutland <mark.rutland@arm.com>
 S:	Maintained
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 F:	arch/arm*/kernel/perf_*
 F:	arch/arm/oprofile/common.c
 F:	arch/arm*/kernel/hw_breakpoint.c
 F:	arch/arm*/include/asm/hw_breakpoint.h
 F:	arch/arm*/include/asm/perf_event.h
-F:	drivers/perf/arm_pmu.c
+F:	drivers/perf/arm_pmu*
 F:	include/linux/perf/arm_pmu.h
 
 ARM PORT
-- 
2.5.5


^ permalink raw reply related	[flat|nested] 42+ messages in thread

* [PATCH v9 10/10] MAINTAINERS: Tweak ARM PMU maintainers
@ 2016-09-14 22:32   ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-14 22:32 UTC (permalink / raw)
  To: linux-arm-kernel

Update the ARM PMU file list, and add the arm mailing list.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
---
 MAINTAINERS | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 1fbd77d..246b427 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -915,12 +915,13 @@ ARM PMU PROFILING AND DEBUGGING
 M:	Will Deacon <will.deacon@arm.com>
 R:	Mark Rutland <mark.rutland@arm.com>
 S:	Maintained
+L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
 F:	arch/arm*/kernel/perf_*
 F:	arch/arm/oprofile/common.c
 F:	arch/arm*/kernel/hw_breakpoint.c
 F:	arch/arm*/include/asm/hw_breakpoint.h
 F:	arch/arm*/include/asm/perf_event.h
-F:	drivers/perf/arm_pmu.c
+F:	drivers/perf/arm_pmu*
 F:	include/linux/perf/arm_pmu.h
 
 ARM PORT
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [PATCH v9 07/10] arm: arm64: pmu: Assign platform PMU CPU affinity
  2016-09-14 22:32   ` Jeremy Linton
@ 2016-09-16 13:29     ` Will Deacon
  -1 siblings, 0 replies; 42+ messages in thread
From: Will Deacon @ 2016-09-16 13:29 UTC (permalink / raw)
  To: Jeremy Linton
  Cc: linux-arm-kernel, mark.rutland, punit.agrawal, linux-acpi,
	mlangsdorf, steve.capper

On Wed, Sep 14, 2016 at 05:32:35PM -0500, Jeremy Linton wrote:
> On systems with multiple PMU types the PMU to CPU affinity
> needs to be detected and set. The CPU to interrupt affinity
> should also be set.
> 
> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
> ---
>  drivers/perf/arm_pmu.c | 63 ++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 53 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
> index 58117d7..63f16a5 100644
> --- a/drivers/perf/arm_pmu.c
> +++ b/drivers/perf/arm_pmu.c
> @@ -11,6 +11,7 @@
>   */
>  #define pr_fmt(fmt) "hw perfevents: " fmt
>  
> +#include <linux/acpi.h>
>  #include <linux/bitmap.h>
>  #include <linux/cpumask.h>
>  #include <linux/cpu_pm.h>
> @@ -24,6 +25,7 @@
>  #include <linux/irq.h>
>  #include <linux/irqdesc.h>
>  
> +#include <asm/cpu.h>
>  #include <asm/cputype.h>
>  #include <asm/irq_regs.h>
>  
> @@ -876,25 +878,67 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
>  }
>  
>  /*
> - * CPU PMU identification and probing.
> + * CPU PMU identification and probing. Its possible to have
> + * multiple CPU types in an ARM machine. Assure that we are
> + * picking the right PMU types based on the CPU in question
>   */
> -static int probe_current_pmu(struct arm_pmu *pmu,
> -			     const struct pmu_probe_info *info)
> +static int probe_plat_pmu(struct arm_pmu *pmu,
> +			     const struct pmu_probe_info *info,
> +			     unsigned int pmuid)
>  {
> -	int cpu = get_cpu();
> -	unsigned int cpuid = read_cpuid_id();
>  	int ret = -ENODEV;
> +	int cpu;
> +	int aff_ctr = 0;
> +	static int duplicate_pmus;
> +	struct platform_device *pdev = pmu->plat_device;
> +	int irq = platform_get_irq(pdev, 0);
>  
> -	pr_info("probing PMU on CPU %d\n", cpu);
> +	if (irq >= 0 && !irq_is_percpu(irq)) {
> +		pmu->irq_affinity = kcalloc(pdev->num_resources, sizeof(int),
> +					    GFP_KERNEL);
> +		if (!pmu->irq_affinity)
> +			return -ENOMEM;
> +	}
>  
> +	for_each_possible_cpu(cpu) {
> +		unsigned int cpuid = read_specific_cpuid(cpu);
> +
> +		if (cpuid == pmuid) {
> +			cpumask_set_cpu(cpu, &pmu->supported_cpus);
> +			if (pmu->irq_affinity) {
> +				pmu->irq_affinity[aff_ctr] = cpu;
> +				aff_ctr++;
> +			}
> +		}
> +	}
> +
> +	/* find the type of PMU given the CPU */
>  	for (; info->init != NULL; info++) {
> -		if ((cpuid & info->mask) != info->cpuid)
> +		if ((pmuid & info->mask) != info->cpuid)
>  			continue;
>  		ret = info->init(pmu);
> +		/*
> +		 * if this pmu declaration is unspecified and we have
> +		 * previously found a PMU on this platform then append
> +		 * a PMU number to the pmu name. This avoids changing
> +		 * the names of PMUs that are specific to a class of CPUs.
> +		 * The assumption is that if we match a specific PMU in the
> +		 * provided pmu_probe_info then it's unique, and another PMU
> +		 * in the system will match a different entry rather than
> +		 * needing the _number to assure its unique.
> +		 */
> +		if ((!info->cpuid) && (duplicate_pmus)) {

Hmm, the duplicate_pmus check looks a little odd here. Doesn't it mean
that you'd end up with things like:

"arm,armv8-pmuv3"
"arm,armv8-pmuv3_1"

which looks needlessly fiddly to parse. Is this intentional?

Will

^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v9 07/10] arm: arm64: pmu: Assign platform PMU CPU affinity
@ 2016-09-16 13:29     ` Will Deacon
  0 siblings, 0 replies; 42+ messages in thread
From: Will Deacon @ 2016-09-16 13:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Sep 14, 2016 at 05:32:35PM -0500, Jeremy Linton wrote:
> On systems with multiple PMU types the PMU to CPU affinity
> needs to be detected and set. The CPU to interrupt affinity
> should also be set.
> 
> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
> ---
>  drivers/perf/arm_pmu.c | 63 ++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 53 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
> index 58117d7..63f16a5 100644
> --- a/drivers/perf/arm_pmu.c
> +++ b/drivers/perf/arm_pmu.c
> @@ -11,6 +11,7 @@
>   */
>  #define pr_fmt(fmt) "hw perfevents: " fmt
>  
> +#include <linux/acpi.h>
>  #include <linux/bitmap.h>
>  #include <linux/cpumask.h>
>  #include <linux/cpu_pm.h>
> @@ -24,6 +25,7 @@
>  #include <linux/irq.h>
>  #include <linux/irqdesc.h>
>  
> +#include <asm/cpu.h>
>  #include <asm/cputype.h>
>  #include <asm/irq_regs.h>
>  
> @@ -876,25 +878,67 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
>  }
>  
>  /*
> - * CPU PMU identification and probing.
> + * CPU PMU identification and probing. Its possible to have
> + * multiple CPU types in an ARM machine. Assure that we are
> + * picking the right PMU types based on the CPU in question
>   */
> -static int probe_current_pmu(struct arm_pmu *pmu,
> -			     const struct pmu_probe_info *info)
> +static int probe_plat_pmu(struct arm_pmu *pmu,
> +			     const struct pmu_probe_info *info,
> +			     unsigned int pmuid)
>  {
> -	int cpu = get_cpu();
> -	unsigned int cpuid = read_cpuid_id();
>  	int ret = -ENODEV;
> +	int cpu;
> +	int aff_ctr = 0;
> +	static int duplicate_pmus;
> +	struct platform_device *pdev = pmu->plat_device;
> +	int irq = platform_get_irq(pdev, 0);
>  
> -	pr_info("probing PMU on CPU %d\n", cpu);
> +	if (irq >= 0 && !irq_is_percpu(irq)) {
> +		pmu->irq_affinity = kcalloc(pdev->num_resources, sizeof(int),
> +					    GFP_KERNEL);
> +		if (!pmu->irq_affinity)
> +			return -ENOMEM;
> +	}
>  
> +	for_each_possible_cpu(cpu) {
> +		unsigned int cpuid = read_specific_cpuid(cpu);
> +
> +		if (cpuid == pmuid) {
> +			cpumask_set_cpu(cpu, &pmu->supported_cpus);
> +			if (pmu->irq_affinity) {
> +				pmu->irq_affinity[aff_ctr] = cpu;
> +				aff_ctr++;
> +			}
> +		}
> +	}
> +
> +	/* find the type of PMU given the CPU */
>  	for (; info->init != NULL; info++) {
> -		if ((cpuid & info->mask) != info->cpuid)
> +		if ((pmuid & info->mask) != info->cpuid)
>  			continue;
>  		ret = info->init(pmu);
> +		/*
> +		 * if this pmu declaration is unspecified and we have
> +		 * previously found a PMU on this platform then append
> +		 * a PMU number to the pmu name. This avoids changing
> +		 * the names of PMUs that are specific to a class of CPUs.
> +		 * The assumption is that if we match a specific PMU in the
> +		 * provided pmu_probe_info then it's unique, and another PMU
> +		 * in the system will match a different entry rather than
> +		 * needing the _number to assure its unique.
> +		 */
> +		if ((!info->cpuid) && (duplicate_pmus)) {

Hmm, the duplicate_pmus check looks a little odd here. Doesn't it mean
that you'd end up with things like:

"arm,armv8-pmuv3"
"arm,armv8-pmuv3_1"

which looks needlessly fiddly to parse. Is this intentional?

Will

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system
  2016-09-14 22:32   ` Jeremy Linton
@ 2016-09-16 13:33     ` Punit Agrawal
  -1 siblings, 0 replies; 42+ messages in thread
From: Punit Agrawal @ 2016-09-16 13:33 UTC (permalink / raw)
  To: Jeremy Linton
  Cc: linux-arm-kernel, mark.rutland, will.deacon, linux-acpi,
	mlangsdorf, steve.capper

Jeremy Linton <jeremy.linton@arm.com> writes:

> Its possible that an ACPI system has multiple CPU types in it
> with differing PMU counters. Iterate the CPU's and make a determination
> about how many of each type exist in the system. Then take and create
> a PMU platform device for each type, and assign it the interrupts parsed
> from the MADT. Creating a platform device is necessary because the PMUs
> are not described as devices in the DSDT table.
>
> This code is loosely based on earlier work by Mark Salter.
>
> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
> ---
>  drivers/perf/arm_pmu.c      |   8 +-
>  drivers/perf/arm_pmu_acpi.c | 224 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 231 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
> index 63f16a5..47ab4e9 100644
> --- a/drivers/perf/arm_pmu.c
> +++ b/drivers/perf/arm_pmu.c
> @@ -1074,7 +1074,13 @@ int arm_pmu_device_probe(struct platform_device *pdev,
>  		if (!ret)
>  			ret = init_fn(pmu);
>  	} else if (probe_table) {
> -		ret = probe_plat_pmu(pmu, probe_table, read_cpuid_id());
> +		if (acpi_disabled) {
> +			/* use the current cpu. */
> +			ret = probe_plat_pmu(pmu, probe_table,
> +					     read_cpuid_id());
> +		} else {
> +			ret = probe_plat_pmu(pmu, probe_table, pdev->id);
> +		}
>  	}
>  
>  	if (ret) {
> diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c
> index dbd4e10..7c56ee4 100644
> --- a/drivers/perf/arm_pmu_acpi.c
> +++ b/drivers/perf/arm_pmu_acpi.c
> @@ -2,13 +2,17 @@
>   * ARM ACPI PMU support
>   *
>   * Copyright (C) 2015 Red Hat Inc.
> + * Copyright (C) 2016 ARM Ltd.
>   * Author: Mark Salter <msalter@redhat.com>
> + *	   Jeremy Linton <jeremy.linton@arm.com>
>   *
>   * This work is licensed under the terms of the GNU GPL, version 2.  See
>   * the COPYING file in the top-level directory.
>   *
>   */
>  
> +#define pr_fmt(fmt) "ACPI-PMU: " fmt
> +
>  #include <asm/cpu.h>
>  #include <linux/acpi.h>
>  #include <linux/irq.h>
> @@ -23,6 +27,12 @@ struct pmu_irq {
>  	bool registered;
>  };
>  
> +struct pmu_types {
> +	struct list_head list;
> +	int		 cpu_type;

Apologies for not noticing this earlier but cpu_type should be u32 to
match partnum (which is derived from reg_midr).

> +	int		 cpu_count;
> +};
> +
>  static struct pmu_irq pmu_irqs[NR_CPUS];
>  
>  /*
> @@ -38,3 +48,217 @@ void __init arm_pmu_parse_acpi(int cpu, struct acpi_madt_generic_interrupt *gic)
>  	else
>  		pmu_irqs[cpu].trigger = ACPI_LEVEL_SENSITIVE;
>  }
> +
> +static void __init arm_pmu_acpi_handle_alloc_failure(struct list_head *pmus)
> +{
> +	struct pmu_types *pmu, *safe_temp;
> +
> +	list_for_each_entry_safe(pmu, safe_temp, pmus, list) {
> +		list_del(&pmu->list);
> +		kfree(pmu);
> +	}
> +}
> +
> +/* Count number and type of CPU cores in the system. */
> +static bool __init arm_pmu_acpi_determine_cpu_types(struct list_head *pmus)
> +{
> +	int i;
> +	bool unused_madt_entries = false;
> +
> +	for_each_possible_cpu(i) {
> +		struct cpuinfo_arm64 *cinfo = per_cpu_ptr(&cpu_data, i);
> +		u32 partnum = MIDR_PARTNUM(cinfo->reg_midr);
> +		struct pmu_types *pmu;
> +
> +		if (cinfo->reg_midr == 0) {

When can the above condition be true? Worth a comment.

> +			unused_madt_entries = true;
> +			continue;
> +		}
> +
> +		list_for_each_entry(pmu, pmus, list) {
> +			if (pmu->cpu_type == partnum) {
> +				pmu->cpu_count++;
> +				break;
> +			}
> +		}
> +
> +		/* we didn't find the CPU type, add an entry to identify it */
> +		if (&pmu->list == pmus) {
> +			pmu = kzalloc(sizeof(struct pmu_types), GFP_KERNEL);
> +			if (!pmu) {
> +				pr_err("Unable to allocate pmu_types\n");
> +				/*
> +				 * Instead of waiting to cleanup possible
> +				 * allocation failures in the caller clean
> +				 * them up immediately. Functionally this
> +				 * doesn't make any difference, except in
> +				 * genuine heterogeneous systems where it
> +				 * guarantees the whole subsystem is
> +				 * disabled rather than running with just
> +				 * a single set of homogeneous CPU's PMU
> +				 * active. That assumes there aren't
> +				 * any further memory allocation failures.
> +				 */
> +				arm_pmu_acpi_handle_alloc_failure(pmus);
> +				break;
> +			} else {
> +				pmu->cpu_type = partnum;
> +				pmu->cpu_count++;
> +				list_add_tail(&pmu->list, pmus);
> +			}
> +		}
> +	}
> +
> +	return unused_madt_entries;
> +}
> +
> +/*
> + * Registers the group of PMU interfaces which correspond to the 'last_cpu_id'.
> + * This group utilizes 'count' resources in the 'res'.
> + */
> +static int __init arm_pmu_acpi_register_pmu(int count, struct resource *res,
> +					    int last_cpu_id)
> +{
> +	int i;
> +	int err = -ENOMEM;
> +	bool free_gsi = false;
> +	struct platform_device *pdev;
> +
> +	if (count) {
> +		pdev = platform_device_alloc(ARMV8_PMU_PDEV_NAME, last_cpu_id);
> +		if (pdev) {
> +			err = platform_device_add_resources(pdev, res, count);
> +			if (!err) {
> +				err = platform_device_add(pdev);
> +				if (err) {
> +					pr_warn("Unable to register PMU device\n");
> +					free_gsi = true;
> +				}
> +			} else {
> +				pr_warn("Unable to add resources to device\n");
> +				free_gsi = true;
> +				platform_device_put(pdev);
> +			}
> +		} else {
> +			pr_warn("Unable to allocate platform device\n");
> +			free_gsi = true;
> +		}
> +	}

The above if block is quite hard to review. I've had the same comment on
previous versions as well.

> +
> +	/* unmark (and possibly unregister) registered GSIs */
> +	for_each_possible_cpu(i) {
> +		if (pmu_irqs[i].registered) {
> +			if (free_gsi)
> +				acpi_unregister_gsi(pmu_irqs[i].gsi);
> +			pmu_irqs[i].registered = false;
> +		}
> +	}
> +
> +	return err;
> +}
> +
> +int arm_pmu_acpi_retrieve_irq(struct resource *res, int cpu)

The return value of this function isn't used anywhere. Any reason it
can't be void?

> +{
> +	int irq = -ENODEV;
> +
> +	if (pmu_irqs[cpu].registered) {
> +		pr_info("CPU %d's interrupt is already registered\n", cpu);
> +	} else {
> +		irq = acpi_register_gsi(NULL, pmu_irqs[cpu].gsi,
> +					pmu_irqs[cpu].trigger,
> +					ACPI_ACTIVE_HIGH);
> +		pmu_irqs[cpu].registered = true;
> +		res->start = irq;
> +		res->end = irq;
> +		res->flags = IORESOURCE_IRQ;
> +		if (pmu_irqs[cpu].trigger == ACPI_EDGE_SENSITIVE)
> +			res->flags |= IORESOURCE_IRQ_HIGHEDGE;
> +		else
> +			res->flags |= IORESOURCE_IRQ_HIGHLEVEL;
> +	}
> +	return irq;
> +}
> +
> +/*
> + * For the given cpu/pmu type, walk all known GSIs, register them, and add
> + * them to the resource structure. Return the number of GSI's contained
> + * in the res structure, and the id of the last CPU/PMU we added.
> + */
> +static int __init arm_pmu_acpi_gsi_res(struct pmu_types *pmus,
> +				       struct resource *res, int *last_cpu_id)
> +{
> +	int i, count;
> +
> +	/* lets group all the PMU's from similar CPU's together */
> +	count = 0;
> +	for_each_possible_cpu(i) {
> +		struct cpuinfo_arm64 *cinfo = per_cpu_ptr(&cpu_data, i);
> +
> +		if (pmus->cpu_type == MIDR_PARTNUM(cinfo->reg_midr)) {
> +			if ((pmu_irqs[i].gsi == 0) && (cinfo->reg_midr != 0)) {
> +				pr_info("CPU %d is assigned interrupt 0\n", i);
> +				continue;
> +			}
> +			/* likely not online */
> +			if (!cinfo->reg_midr)
> +				continue;
> +
> +			arm_pmu_acpi_retrieve_irq(&res[count], i);
> +			count++;
> +			(*last_cpu_id) = cinfo->reg_midr;
> +		}
> +	}
> +	return count;
> +}
> +
> +static int __init pmu_acpi_init(void)
> +{
> +	struct resource	*res;
> +	int err = -ENOMEM;
> +	int count, cpu_id;
> +	struct pmu_types *pmu, *safe_temp;
> +	bool unused_madt_entries;
> +	LIST_HEAD(pmus);
> +
> +	if (acpi_disabled)
> +		return 0;
> +
> +	unused_madt_entries = arm_pmu_acpi_determine_cpu_types(&pmus);
> +
> +	list_for_each_entry_safe(pmu, safe_temp, &pmus, list) {
> +		if (unused_madt_entries)
> +			pmu->cpu_count = num_possible_cpus();

So if there is any unbooted cpu ...

> +
> +		res = kcalloc(pmu->cpu_count,
> +				  sizeof(struct resource), GFP_KERNEL);

... we allocate potentially large number (num_possible_cpus()) of
resources for each PMU.

This is needlessly wasteful. Under what conditions have you found
reg_midr to be 0?

> +
> +		/* for a given PMU type collect all the GSIs. */
> +		if (res) {
> +			count = arm_pmu_acpi_gsi_res(pmu, res,
> +						     &cpu_id);
> +			/*
> +			 * register this set of interrupts
> +			 * with a new PMU device
> +			 */
> +			if (count) {
> +				if (unused_madt_entries)
> +					count = num_possible_cpus();
> +				err = arm_pmu_acpi_register_pmu(count, res,
> +								cpu_id);
> +				if (!err)
> +					pr_info("Register %d devices for %X\n",
> +						count, pmu->cpu_type);
> +				kfree(res);
> +			}
> +		} else {
> +			pr_warn("PMU unable to allocate interrupt resource\n");
> +		}
> +
> +		list_del(&pmu->list);
> +		kfree(pmu);
> +	}
> +
> +	return err;
> +}
> +
> +arch_initcall(pmu_acpi_init);

^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system
@ 2016-09-16 13:33     ` Punit Agrawal
  0 siblings, 0 replies; 42+ messages in thread
From: Punit Agrawal @ 2016-09-16 13:33 UTC (permalink / raw)
  To: linux-arm-kernel

Jeremy Linton <jeremy.linton@arm.com> writes:

> Its possible that an ACPI system has multiple CPU types in it
> with differing PMU counters. Iterate the CPU's and make a determination
> about how many of each type exist in the system. Then take and create
> a PMU platform device for each type, and assign it the interrupts parsed
> from the MADT. Creating a platform device is necessary because the PMUs
> are not described as devices in the DSDT table.
>
> This code is loosely based on earlier work by Mark Salter.
>
> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
> ---
>  drivers/perf/arm_pmu.c      |   8 +-
>  drivers/perf/arm_pmu_acpi.c | 224 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 231 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
> index 63f16a5..47ab4e9 100644
> --- a/drivers/perf/arm_pmu.c
> +++ b/drivers/perf/arm_pmu.c
> @@ -1074,7 +1074,13 @@ int arm_pmu_device_probe(struct platform_device *pdev,
>  		if (!ret)
>  			ret = init_fn(pmu);
>  	} else if (probe_table) {
> -		ret = probe_plat_pmu(pmu, probe_table, read_cpuid_id());
> +		if (acpi_disabled) {
> +			/* use the current cpu. */
> +			ret = probe_plat_pmu(pmu, probe_table,
> +					     read_cpuid_id());
> +		} else {
> +			ret = probe_plat_pmu(pmu, probe_table, pdev->id);
> +		}
>  	}
>  
>  	if (ret) {
> diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c
> index dbd4e10..7c56ee4 100644
> --- a/drivers/perf/arm_pmu_acpi.c
> +++ b/drivers/perf/arm_pmu_acpi.c
> @@ -2,13 +2,17 @@
>   * ARM ACPI PMU support
>   *
>   * Copyright (C) 2015 Red Hat Inc.
> + * Copyright (C) 2016 ARM Ltd.
>   * Author: Mark Salter <msalter@redhat.com>
> + *	   Jeremy Linton <jeremy.linton@arm.com>
>   *
>   * This work is licensed under the terms of the GNU GPL, version 2.  See
>   * the COPYING file in the top-level directory.
>   *
>   */
>  
> +#define pr_fmt(fmt) "ACPI-PMU: " fmt
> +
>  #include <asm/cpu.h>
>  #include <linux/acpi.h>
>  #include <linux/irq.h>
> @@ -23,6 +27,12 @@ struct pmu_irq {
>  	bool registered;
>  };
>  
> +struct pmu_types {
> +	struct list_head list;
> +	int		 cpu_type;

Apologies for not noticing this earlier but cpu_type should be u32 to
match partnum (which is derived from reg_midr).

> +	int		 cpu_count;
> +};
> +
>  static struct pmu_irq pmu_irqs[NR_CPUS];
>  
>  /*
> @@ -38,3 +48,217 @@ void __init arm_pmu_parse_acpi(int cpu, struct acpi_madt_generic_interrupt *gic)
>  	else
>  		pmu_irqs[cpu].trigger = ACPI_LEVEL_SENSITIVE;
>  }
> +
> +static void __init arm_pmu_acpi_handle_alloc_failure(struct list_head *pmus)
> +{
> +	struct pmu_types *pmu, *safe_temp;
> +
> +	list_for_each_entry_safe(pmu, safe_temp, pmus, list) {
> +		list_del(&pmu->list);
> +		kfree(pmu);
> +	}
> +}
> +
> +/* Count number and type of CPU cores in the system. */
> +static bool __init arm_pmu_acpi_determine_cpu_types(struct list_head *pmus)
> +{
> +	int i;
> +	bool unused_madt_entries = false;
> +
> +	for_each_possible_cpu(i) {
> +		struct cpuinfo_arm64 *cinfo = per_cpu_ptr(&cpu_data, i);
> +		u32 partnum = MIDR_PARTNUM(cinfo->reg_midr);
> +		struct pmu_types *pmu;
> +
> +		if (cinfo->reg_midr == 0) {

When can the above condition be true? Worth a comment.

> +			unused_madt_entries = true;
> +			continue;
> +		}
> +
> +		list_for_each_entry(pmu, pmus, list) {
> +			if (pmu->cpu_type == partnum) {
> +				pmu->cpu_count++;
> +				break;
> +			}
> +		}
> +
> +		/* we didn't find the CPU type, add an entry to identify it */
> +		if (&pmu->list == pmus) {
> +			pmu = kzalloc(sizeof(struct pmu_types), GFP_KERNEL);
> +			if (!pmu) {
> +				pr_err("Unable to allocate pmu_types\n");
> +				/*
> +				 * Instead of waiting to cleanup possible
> +				 * allocation failures in the caller clean
> +				 * them up immediately. Functionally this
> +				 * doesn't make any difference, except in
> +				 * genuine heterogeneous systems where it
> +				 * guarantees the whole subsystem is
> +				 * disabled rather than running with just
> +				 * a single set of homogeneous CPU's PMU
> +				 * active. That assumes there aren't
> +				 * any further memory allocation failures.
> +				 */
> +				arm_pmu_acpi_handle_alloc_failure(pmus);
> +				break;
> +			} else {
> +				pmu->cpu_type = partnum;
> +				pmu->cpu_count++;
> +				list_add_tail(&pmu->list, pmus);
> +			}
> +		}
> +	}
> +
> +	return unused_madt_entries;
> +}
> +
> +/*
> + * Registers the group of PMU interfaces which correspond to the 'last_cpu_id'.
> + * This group utilizes 'count' resources in the 'res'.
> + */
> +static int __init arm_pmu_acpi_register_pmu(int count, struct resource *res,
> +					    int last_cpu_id)
> +{
> +	int i;
> +	int err = -ENOMEM;
> +	bool free_gsi = false;
> +	struct platform_device *pdev;
> +
> +	if (count) {
> +		pdev = platform_device_alloc(ARMV8_PMU_PDEV_NAME, last_cpu_id);
> +		if (pdev) {
> +			err = platform_device_add_resources(pdev, res, count);
> +			if (!err) {
> +				err = platform_device_add(pdev);
> +				if (err) {
> +					pr_warn("Unable to register PMU device\n");
> +					free_gsi = true;
> +				}
> +			} else {
> +				pr_warn("Unable to add resources to device\n");
> +				free_gsi = true;
> +				platform_device_put(pdev);
> +			}
> +		} else {
> +			pr_warn("Unable to allocate platform device\n");
> +			free_gsi = true;
> +		}
> +	}

The above if block is quite hard to review. I've had the same comment on
previous versions as well.

> +
> +	/* unmark (and possibly unregister) registered GSIs */
> +	for_each_possible_cpu(i) {
> +		if (pmu_irqs[i].registered) {
> +			if (free_gsi)
> +				acpi_unregister_gsi(pmu_irqs[i].gsi);
> +			pmu_irqs[i].registered = false;
> +		}
> +	}
> +
> +	return err;
> +}
> +
> +int arm_pmu_acpi_retrieve_irq(struct resource *res, int cpu)

The return value of this function isn't used anywhere. Any reason it
can't be void?

> +{
> +	int irq = -ENODEV;
> +
> +	if (pmu_irqs[cpu].registered) {
> +		pr_info("CPU %d's interrupt is already registered\n", cpu);
> +	} else {
> +		irq = acpi_register_gsi(NULL, pmu_irqs[cpu].gsi,
> +					pmu_irqs[cpu].trigger,
> +					ACPI_ACTIVE_HIGH);
> +		pmu_irqs[cpu].registered = true;
> +		res->start = irq;
> +		res->end = irq;
> +		res->flags = IORESOURCE_IRQ;
> +		if (pmu_irqs[cpu].trigger == ACPI_EDGE_SENSITIVE)
> +			res->flags |= IORESOURCE_IRQ_HIGHEDGE;
> +		else
> +			res->flags |= IORESOURCE_IRQ_HIGHLEVEL;
> +	}
> +	return irq;
> +}
> +
> +/*
> + * For the given cpu/pmu type, walk all known GSIs, register them, and add
> + * them to the resource structure. Return the number of GSI's contained
> + * in the res structure, and the id of the last CPU/PMU we added.
> + */
> +static int __init arm_pmu_acpi_gsi_res(struct pmu_types *pmus,
> +				       struct resource *res, int *last_cpu_id)
> +{
> +	int i, count;
> +
> +	/* lets group all the PMU's from similar CPU's together */
> +	count = 0;
> +	for_each_possible_cpu(i) {
> +		struct cpuinfo_arm64 *cinfo = per_cpu_ptr(&cpu_data, i);
> +
> +		if (pmus->cpu_type == MIDR_PARTNUM(cinfo->reg_midr)) {
> +			if ((pmu_irqs[i].gsi == 0) && (cinfo->reg_midr != 0)) {
> +				pr_info("CPU %d is assigned interrupt 0\n", i);
> +				continue;
> +			}
> +			/* likely not online */
> +			if (!cinfo->reg_midr)
> +				continue;
> +
> +			arm_pmu_acpi_retrieve_irq(&res[count], i);
> +			count++;
> +			(*last_cpu_id) = cinfo->reg_midr;
> +		}
> +	}
> +	return count;
> +}
> +
> +static int __init pmu_acpi_init(void)
> +{
> +	struct resource	*res;
> +	int err = -ENOMEM;
> +	int count, cpu_id;
> +	struct pmu_types *pmu, *safe_temp;
> +	bool unused_madt_entries;
> +	LIST_HEAD(pmus);
> +
> +	if (acpi_disabled)
> +		return 0;
> +
> +	unused_madt_entries = arm_pmu_acpi_determine_cpu_types(&pmus);
> +
> +	list_for_each_entry_safe(pmu, safe_temp, &pmus, list) {
> +		if (unused_madt_entries)
> +			pmu->cpu_count = num_possible_cpus();

So if there is any unbooted cpu ...

> +
> +		res = kcalloc(pmu->cpu_count,
> +				  sizeof(struct resource), GFP_KERNEL);

... we allocate potentially large number (num_possible_cpus()) of
resources for each PMU.

This is needlessly wasteful. Under what conditions have you found
reg_midr to be 0?

> +
> +		/* for a given PMU type collect all the GSIs. */
> +		if (res) {
> +			count = arm_pmu_acpi_gsi_res(pmu, res,
> +						     &cpu_id);
> +			/*
> +			 * register this set of interrupts
> +			 * with a new PMU device
> +			 */
> +			if (count) {
> +				if (unused_madt_entries)
> +					count = num_possible_cpus();
> +				err = arm_pmu_acpi_register_pmu(count, res,
> +								cpu_id);
> +				if (!err)
> +					pr_info("Register %d devices for %X\n",
> +						count, pmu->cpu_type);
> +				kfree(res);
> +			}
> +		} else {
> +			pr_warn("PMU unable to allocate interrupt resource\n");
> +		}
> +
> +		list_del(&pmu->list);
> +		kfree(pmu);
> +	}
> +
> +	return err;
> +}
> +
> +arch_initcall(pmu_acpi_init);

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v9 07/10] arm: arm64: pmu: Assign platform PMU CPU affinity
  2016-09-16 13:29     ` Will Deacon
@ 2016-09-16 15:35       ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-16 15:35 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-arm-kernel, mark.rutland, punit.agrawal, linux-acpi,
	mlangsdorf, steve.capper

Hi
	Thanks for taking a look at this..

On 09/16/2016 08:29 AM, Will Deacon wrote:
> On Wed, Sep 14, 2016 at 05:32:35PM -0500, Jeremy Linton wrote:
>> On systems with multiple PMU types the PMU to CPU affinity
>> needs to be detected and set. The CPU to interrupt affinity
>> should also be set.
>>
(trimming)
>>  			continue;
>>  		ret = info->init(pmu);
>> +		/*
>> +		 * if this pmu declaration is unspecified and we have
>> +		 * previously found a PMU on this platform then append
>> +		 * a PMU number to the pmu name. This avoids changing
>> +		 * the names of PMUs that are specific to a class of CPUs.
>> +		 * The assumption is that if we match a specific PMU in the
>> +		 * provided pmu_probe_info then it's unique, and another PMU
>> +		 * in the system will match a different entry rather than
>> +		 * needing the _number to assure its unique.
>> +		 */
>> +		if ((!info->cpuid) && (duplicate_pmus)) {
>
> Hmm, the duplicate_pmus check looks a little odd here. Doesn't it mean
> that you'd end up with things like:
>
> "arm,armv8-pmuv3"
> "arm,armv8-pmuv3_1"
>
> which looks needlessly fiddly to parse. Is this intentional?

Well, IIRC, you recommend that format, or maybe I misunderstood. Anyway, 
per the comment I'm trying to assure that legacy platform devices don't 
accidentally get a "_X" appended to their name and break something.

Further, by itself the name itself doesn't have any meaning/ordering and 
could just as well be a random string. So, I don't think anyone is going 
to try and parse it except to compare it as a whole something like 
"armv8_cortex_a53". Which is why the cpu affinity is required. 
Additionally, doing it this way allows a tiny tweak to the pmu table in 
the future to re-enable meaningful PMU names. Lastly, its big.little 
exclusive, so I would rather apply pain to non-existant big.little 
server machines, than uglify the common case.






^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v9 07/10] arm: arm64: pmu: Assign platform PMU CPU affinity
@ 2016-09-16 15:35       ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-16 15:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi
	Thanks for taking a look at this..

On 09/16/2016 08:29 AM, Will Deacon wrote:
> On Wed, Sep 14, 2016 at 05:32:35PM -0500, Jeremy Linton wrote:
>> On systems with multiple PMU types the PMU to CPU affinity
>> needs to be detected and set. The CPU to interrupt affinity
>> should also be set.
>>
(trimming)
>>  			continue;
>>  		ret = info->init(pmu);
>> +		/*
>> +		 * if this pmu declaration is unspecified and we have
>> +		 * previously found a PMU on this platform then append
>> +		 * a PMU number to the pmu name. This avoids changing
>> +		 * the names of PMUs that are specific to a class of CPUs.
>> +		 * The assumption is that if we match a specific PMU in the
>> +		 * provided pmu_probe_info then it's unique, and another PMU
>> +		 * in the system will match a different entry rather than
>> +		 * needing the _number to assure its unique.
>> +		 */
>> +		if ((!info->cpuid) && (duplicate_pmus)) {
>
> Hmm, the duplicate_pmus check looks a little odd here. Doesn't it mean
> that you'd end up with things like:
>
> "arm,armv8-pmuv3"
> "arm,armv8-pmuv3_1"
>
> which looks needlessly fiddly to parse. Is this intentional?

Well, IIRC, you recommend that format, or maybe I misunderstood. Anyway, 
per the comment I'm trying to assure that legacy platform devices don't 
accidentally get a "_X" appended to their name and break something.

Further, by itself the name itself doesn't have any meaning/ordering and 
could just as well be a random string. So, I don't think anyone is going 
to try and parse it except to compare it as a whole something like 
"armv8_cortex_a53". Which is why the cpu affinity is required. 
Additionally, doing it this way allows a tiny tweak to the pmu table in 
the future to re-enable meaningful PMU names. Lastly, its big.little 
exclusive, so I would rather apply pain to non-existant big.little 
server machines, than uglify the common case.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v9 07/10] arm: arm64: pmu: Assign platform PMU CPU affinity
  2016-09-16 15:35       ` Jeremy Linton
@ 2016-09-16 15:48         ` Will Deacon
  -1 siblings, 0 replies; 42+ messages in thread
From: Will Deacon @ 2016-09-16 15:48 UTC (permalink / raw)
  To: Jeremy Linton
  Cc: linux-arm-kernel, mark.rutland, punit.agrawal, linux-acpi,
	mlangsdorf, steve.capper

On Fri, Sep 16, 2016 at 10:35:32AM -0500, Jeremy Linton wrote:
> On 09/16/2016 08:29 AM, Will Deacon wrote:
> >On Wed, Sep 14, 2016 at 05:32:35PM -0500, Jeremy Linton wrote:
> >>On systems with multiple PMU types the PMU to CPU affinity
> >>needs to be detected and set. The CPU to interrupt affinity
> >>should also be set.
> >>
> (trimming)
> >> 			continue;
> >> 		ret = info->init(pmu);
> >>+		/*
> >>+		 * if this pmu declaration is unspecified and we have
> >>+		 * previously found a PMU on this platform then append
> >>+		 * a PMU number to the pmu name. This avoids changing
> >>+		 * the names of PMUs that are specific to a class of CPUs.
> >>+		 * The assumption is that if we match a specific PMU in the
> >>+		 * provided pmu_probe_info then it's unique, and another PMU
> >>+		 * in the system will match a different entry rather than
> >>+		 * needing the _number to assure its unique.
> >>+		 */
> >>+		if ((!info->cpuid) && (duplicate_pmus)) {
> >
> >Hmm, the duplicate_pmus check looks a little odd here. Doesn't it mean
> >that you'd end up with things like:
> >
> >"arm,armv8-pmuv3"
> >"arm,armv8-pmuv3_1"
> >
> >which looks needlessly fiddly to parse. Is this intentional?
> 
> Well, IIRC, you recommend that format, or maybe I misunderstood. Anyway, per
> the comment I'm trying to assure that legacy platform devices don't
> accidentally get a "_X" appended to their name and break something.

Ah, right, for the old 32-bit platforms that rely on probing, Gotcha.

Will

^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v9 07/10] arm: arm64: pmu: Assign platform PMU CPU affinity
@ 2016-09-16 15:48         ` Will Deacon
  0 siblings, 0 replies; 42+ messages in thread
From: Will Deacon @ 2016-09-16 15:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Sep 16, 2016 at 10:35:32AM -0500, Jeremy Linton wrote:
> On 09/16/2016 08:29 AM, Will Deacon wrote:
> >On Wed, Sep 14, 2016 at 05:32:35PM -0500, Jeremy Linton wrote:
> >>On systems with multiple PMU types the PMU to CPU affinity
> >>needs to be detected and set. The CPU to interrupt affinity
> >>should also be set.
> >>
> (trimming)
> >> 			continue;
> >> 		ret = info->init(pmu);
> >>+		/*
> >>+		 * if this pmu declaration is unspecified and we have
> >>+		 * previously found a PMU on this platform then append
> >>+		 * a PMU number to the pmu name. This avoids changing
> >>+		 * the names of PMUs that are specific to a class of CPUs.
> >>+		 * The assumption is that if we match a specific PMU in the
> >>+		 * provided pmu_probe_info then it's unique, and another PMU
> >>+		 * in the system will match a different entry rather than
> >>+		 * needing the _number to assure its unique.
> >>+		 */
> >>+		if ((!info->cpuid) && (duplicate_pmus)) {
> >
> >Hmm, the duplicate_pmus check looks a little odd here. Doesn't it mean
> >that you'd end up with things like:
> >
> >"arm,armv8-pmuv3"
> >"arm,armv8-pmuv3_1"
> >
> >which looks needlessly fiddly to parse. Is this intentional?
> 
> Well, IIRC, you recommend that format, or maybe I misunderstood. Anyway, per
> the comment I'm trying to assure that legacy platform devices don't
> accidentally get a "_X" appended to their name and break something.

Ah, right, for the old 32-bit platforms that rely on probing, Gotcha.

Will

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system
  2016-09-16 13:33     ` Punit Agrawal
@ 2016-09-16 16:32       ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-16 16:32 UTC (permalink / raw)
  To: Punit Agrawal
  Cc: linux-arm-kernel, mark.rutland, will.deacon, linux-acpi,
	mlangsdorf, steve.capper

Hi,

On 09/16/2016 08:33 AM, Punit Agrawal wrote:
> Jeremy Linton <jeremy.linton@arm.com> writes:
>
>> Its possible that an ACPI system has multiple CPU types in it
>> with differing PMU counters. Iterate the CPU's and make a determination
>> about how many of each type exist in the system. Then take and create
>> a PMU platform device for each type, and assign it the interrupts parsed
>> from the MADT. Creating a platform device is necessary because the PMUs
>> are not described as devices in the DSDT table.
>>
>> This code is loosely based on earlier work by Mark Salter.

(trimming)

>> +
>> +	list_for_each_entry_safe(pmu, safe_temp, &pmus, list) {
>> +		if (unused_madt_entries)
>> +			pmu->cpu_count = num_possible_cpus();
>
> So if there is any unbooted cpu ...
>
>> +
>> +		res = kcalloc(pmu->cpu_count,
>> +				  sizeof(struct resource), GFP_KERNEL);
>
> ... we allocate potentially large number (num_possible_cpus()) of
> resources for each PMU.
>
> This is needlessly wasteful. Under what conditions have you found
> reg_midr to be 0?

Unused MADT entries, in place for potentially unbooted/hotplug CPUs. In 
those cases you don't know for sure which PMU the CPU belongs to until 
it comes online and the MIDR can be read. I'm open to suggestions on how 
to deal with this, outside of pushing my luck and further breaking the 
platform device encapsulation by trying to reallocate the resource 
structure while its active. Besides its only wasteful for 
ACPI+big.little, which at the moment only applies to a development platform.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system
@ 2016-09-16 16:32       ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-16 16:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 09/16/2016 08:33 AM, Punit Agrawal wrote:
> Jeremy Linton <jeremy.linton@arm.com> writes:
>
>> Its possible that an ACPI system has multiple CPU types in it
>> with differing PMU counters. Iterate the CPU's and make a determination
>> about how many of each type exist in the system. Then take and create
>> a PMU platform device for each type, and assign it the interrupts parsed
>> from the MADT. Creating a platform device is necessary because the PMUs
>> are not described as devices in the DSDT table.
>>
>> This code is loosely based on earlier work by Mark Salter.

(trimming)

>> +
>> +	list_for_each_entry_safe(pmu, safe_temp, &pmus, list) {
>> +		if (unused_madt_entries)
>> +			pmu->cpu_count = num_possible_cpus();
>
> So if there is any unbooted cpu ...
>
>> +
>> +		res = kcalloc(pmu->cpu_count,
>> +				  sizeof(struct resource), GFP_KERNEL);
>
> ... we allocate potentially large number (num_possible_cpus()) of
> resources for each PMU.
>
> This is needlessly wasteful. Under what conditions have you found
> reg_midr to be 0?

Unused MADT entries, in place for potentially unbooted/hotplug CPUs. In 
those cases you don't know for sure which PMU the CPU belongs to until 
it comes online and the MIDR can be read. I'm open to suggestions on how 
to deal with this, outside of pushing my luck and further breaking the 
platform device encapsulation by trying to reallocate the resource 
structure while its active. Besides its only wasteful for 
ACPI+big.little, which at the moment only applies to a development platform.

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v9 07/10] arm: arm64: pmu: Assign platform PMU CPU affinity
  2016-09-14 22:32   ` Jeremy Linton
@ 2016-09-16 16:37     ` Punit Agrawal
  -1 siblings, 0 replies; 42+ messages in thread
From: Punit Agrawal @ 2016-09-16 16:37 UTC (permalink / raw)
  To: Jeremy Linton
  Cc: linux-arm-kernel, mark.rutland, will.deacon, linux-acpi,
	mlangsdorf, steve.capper

Hi Jeremy,

One comment below.

Jeremy Linton <jeremy.linton@arm.com> writes:

> On systems with multiple PMU types the PMU to CPU affinity
> needs to be detected and set. The CPU to interrupt affinity
> should also be set.
>
> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
> ---
>  drivers/perf/arm_pmu.c | 63 ++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 53 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
> index 58117d7..63f16a5 100644
> --- a/drivers/perf/arm_pmu.c
> +++ b/drivers/perf/arm_pmu.c
> @@ -11,6 +11,7 @@
>   */
>  #define pr_fmt(fmt) "hw perfevents: " fmt
>  
> +#include <linux/acpi.h>
>  #include <linux/bitmap.h>
>  #include <linux/cpumask.h>
>  #include <linux/cpu_pm.h>
> @@ -24,6 +25,7 @@
>  #include <linux/irq.h>
>  #include <linux/irqdesc.h>
>  
> +#include <asm/cpu.h>
>  #include <asm/cputype.h>
>  #include <asm/irq_regs.h>
>  
> @@ -876,25 +878,67 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
>  }
>  
>  /*
> - * CPU PMU identification and probing.
> + * CPU PMU identification and probing. Its possible to have
> + * multiple CPU types in an ARM machine. Assure that we are
> + * picking the right PMU types based on the CPU in question
>   */
> -static int probe_current_pmu(struct arm_pmu *pmu,
> -			     const struct pmu_probe_info *info)
> +static int probe_plat_pmu(struct arm_pmu *pmu,
> +			     const struct pmu_probe_info *info,
> +			     unsigned int pmuid)
>  {
> -	int cpu = get_cpu();
> -	unsigned int cpuid = read_cpuid_id();
>  	int ret = -ENODEV;
> +	int cpu;
> +	int aff_ctr = 0;
> +	static int duplicate_pmus;
> +	struct platform_device *pdev = pmu->plat_device;
> +	int irq = platform_get_irq(pdev, 0);
>  
> -	pr_info("probing PMU on CPU %d\n", cpu);
> +	if (irq >= 0 && !irq_is_percpu(irq)) {

Marc's got a patch[0] changing all instances of "irq >= 0" in this file to
"irq > 0" on the basis that irq 0 is an error.

If this version doesn't get merged, please drop the "=" for the next
version.

[0] http://marc.info/?l=linux-arm-kernel&m=147318284923863


[...]


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v9 07/10] arm: arm64: pmu: Assign platform PMU CPU affinity
@ 2016-09-16 16:37     ` Punit Agrawal
  0 siblings, 0 replies; 42+ messages in thread
From: Punit Agrawal @ 2016-09-16 16:37 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jeremy,

One comment below.

Jeremy Linton <jeremy.linton@arm.com> writes:

> On systems with multiple PMU types the PMU to CPU affinity
> needs to be detected and set. The CPU to interrupt affinity
> should also be set.
>
> Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
> ---
>  drivers/perf/arm_pmu.c | 63 ++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 53 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
> index 58117d7..63f16a5 100644
> --- a/drivers/perf/arm_pmu.c
> +++ b/drivers/perf/arm_pmu.c
> @@ -11,6 +11,7 @@
>   */
>  #define pr_fmt(fmt) "hw perfevents: " fmt
>  
> +#include <linux/acpi.h>
>  #include <linux/bitmap.h>
>  #include <linux/cpumask.h>
>  #include <linux/cpu_pm.h>
> @@ -24,6 +25,7 @@
>  #include <linux/irq.h>
>  #include <linux/irqdesc.h>
>  
> +#include <asm/cpu.h>
>  #include <asm/cputype.h>
>  #include <asm/irq_regs.h>
>  
> @@ -876,25 +878,67 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
>  }
>  
>  /*
> - * CPU PMU identification and probing.
> + * CPU PMU identification and probing. Its possible to have
> + * multiple CPU types in an ARM machine. Assure that we are
> + * picking the right PMU types based on the CPU in question
>   */
> -static int probe_current_pmu(struct arm_pmu *pmu,
> -			     const struct pmu_probe_info *info)
> +static int probe_plat_pmu(struct arm_pmu *pmu,
> +			     const struct pmu_probe_info *info,
> +			     unsigned int pmuid)
>  {
> -	int cpu = get_cpu();
> -	unsigned int cpuid = read_cpuid_id();
>  	int ret = -ENODEV;
> +	int cpu;
> +	int aff_ctr = 0;
> +	static int duplicate_pmus;
> +	struct platform_device *pdev = pmu->plat_device;
> +	int irq = platform_get_irq(pdev, 0);
>  
> -	pr_info("probing PMU on CPU %d\n", cpu);
> +	if (irq >= 0 && !irq_is_percpu(irq)) {

Marc's got a patch[0] changing all instances of "irq >= 0" in this file to
"irq > 0" on the basis that irq 0 is an error.

If this version doesn't get merged, please drop the "=" for the next
version.

[0] http://marc.info/?l=linux-arm-kernel&m=147318284923863


[...]

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system
  2016-09-16 16:32       ` Jeremy Linton
@ 2016-09-16 17:07         ` Punit Agrawal
  -1 siblings, 0 replies; 42+ messages in thread
From: Punit Agrawal @ 2016-09-16 17:07 UTC (permalink / raw)
  To: Jeremy Linton
  Cc: linux-arm-kernel, mark.rutland, will.deacon, linux-acpi,
	mlangsdorf, steve.capper

Jeremy Linton <jeremy.linton@arm.com> writes:

> Hi,
>
> On 09/16/2016 08:33 AM, Punit Agrawal wrote:
>> Jeremy Linton <jeremy.linton@arm.com> writes:
>>
>>> Its possible that an ACPI system has multiple CPU types in it
>>> with differing PMU counters. Iterate the CPU's and make a determination
>>> about how many of each type exist in the system. Then take and create
>>> a PMU platform device for each type, and assign it the interrupts parsed
>>> from the MADT. Creating a platform device is necessary because the PMUs
>>> are not described as devices in the DSDT table.
>>>
>>> This code is loosely based on earlier work by Mark Salter.
>
> (trimming)
>
>>> +
>>> +	list_for_each_entry_safe(pmu, safe_temp, &pmus, list) {
>>> +		if (unused_madt_entries)
>>> +			pmu->cpu_count = num_possible_cpus();
>>
>> So if there is any unbooted cpu ...
>>
>>> +
>>> +		res = kcalloc(pmu->cpu_count,
>>> +				  sizeof(struct resource), GFP_KERNEL);
>>
>> ... we allocate potentially large number (num_possible_cpus()) of
>> resources for each PMU.
>>
>> This is needlessly wasteful. Under what conditions have you found
>> reg_midr to be 0?
>
> Unused MADT entries, in place for potentially unbooted/hotplug
> CPUs.

Is linux able to deal with booting secondaries that have unused MADT
entries?

> In those cases you don't know for sure which PMU the CPU belongs
> to until it comes online and the MIDR can be read. I'm open to
> suggestions on how to deal with this, outside of pushing my luck and
> further breaking the platform device encapsulation by trying to
> reallocate the resource structure while its active. Besides its only
> wasteful for ACPI+big.little, which at the moment only applies to a
> development platform.

I don't have any ideas to solve this problem, but in the interest of
helping review, please move all the changes arising from hotplug/unused
MADT entries in this patch to the next one.

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

^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system
@ 2016-09-16 17:07         ` Punit Agrawal
  0 siblings, 0 replies; 42+ messages in thread
From: Punit Agrawal @ 2016-09-16 17:07 UTC (permalink / raw)
  To: linux-arm-kernel

Jeremy Linton <jeremy.linton@arm.com> writes:

> Hi,
>
> On 09/16/2016 08:33 AM, Punit Agrawal wrote:
>> Jeremy Linton <jeremy.linton@arm.com> writes:
>>
>>> Its possible that an ACPI system has multiple CPU types in it
>>> with differing PMU counters. Iterate the CPU's and make a determination
>>> about how many of each type exist in the system. Then take and create
>>> a PMU platform device for each type, and assign it the interrupts parsed
>>> from the MADT. Creating a platform device is necessary because the PMUs
>>> are not described as devices in the DSDT table.
>>>
>>> This code is loosely based on earlier work by Mark Salter.
>
> (trimming)
>
>>> +
>>> +	list_for_each_entry_safe(pmu, safe_temp, &pmus, list) {
>>> +		if (unused_madt_entries)
>>> +			pmu->cpu_count = num_possible_cpus();
>>
>> So if there is any unbooted cpu ...
>>
>>> +
>>> +		res = kcalloc(pmu->cpu_count,
>>> +				  sizeof(struct resource), GFP_KERNEL);
>>
>> ... we allocate potentially large number (num_possible_cpus()) of
>> resources for each PMU.
>>
>> This is needlessly wasteful. Under what conditions have you found
>> reg_midr to be 0?
>
> Unused MADT entries, in place for potentially unbooted/hotplug
> CPUs.

Is linux able to deal with booting secondaries that have unused MADT
entries?

> In those cases you don't know for sure which PMU the CPU belongs
> to until it comes online and the MIDR can be read. I'm open to
> suggestions on how to deal with this, outside of pushing my luck and
> further breaking the platform device encapsulation by trying to
> reallocate the resource structure while its active. Besides its only
> wasteful for ACPI+big.little, which at the moment only applies to a
> development platform.

I don't have any ideas to solve this problem, but in the interest of
helping review, please move all the changes arising from hotplug/unused
MADT entries in this patch to the next one.

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

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v9 00/10] Enable PMUs in ACPI systems
  2016-09-14 22:32 ` Jeremy Linton
@ 2016-09-16 17:13   ` Punit Agrawal
  -1 siblings, 0 replies; 42+ messages in thread
From: Punit Agrawal @ 2016-09-16 17:13 UTC (permalink / raw)
  To: Jeremy Linton
  Cc: linux-arm-kernel, mark.rutland, will.deacon, linux-acpi,
	mlangsdorf, steve.capper

Hi Jeremy,

Jeremy Linton <jeremy.linton@arm.com> writes:

> This patch expands and reworks the patches published by Mark Salter
> in order to clean up a few of the previous review comments, as well as
> add support for newer CPUs and big/little configurations.
>
> v9:
> Add/cleanup an additional hotplug patch I've had sitting around. This
> patch brings the ACPI PMU mostly on par with the DT functionality with
> respect to having CPUs offline during boot. This should help clarify
> some of the code structuring.
> Cleanup the list of PMU types early if we fail to allocate memory for an
> additional pmu type.

The earlier patches in the series look OK but there are still
unaddressed comments on Patch 8 from previous versions - coding style,
excessive indentation, complicated logic etc.

Additionally, I'd suggest moving hotplug/unsed MADT related changes out
of Patch 8 to later patches, i.e., add support for hotplug on top.

Thanks,
Punit

>
> v8:
> Rebase to 4.8rc4
> Assorted minor comment/hunk placement/etc tweaks per Punit Agrawal
>
> v7:
> Rebase to 4.8rc3
> Remove cpu affinity sysfs entry. While providing a CPU mask for
> ARMv8 PMU's is really helpful in big/little environments, reworking
> the PMU code to support the cpumask attribute for !arm64 PMUs is out
> of the scope of this patch set.
> Fix CPU miscount problem where an alloc failure followed by successfully
> allocating the structure can result in under counting the CPUs associated
> with the PMU. This bug was created in v6 with the conversion to a linked
> list.
> Remove initial platform device creation code by Mark Salter, and re-squash
> multiple platform device creation code together with helper routines.
> Other minor tweakage.
>
> v6:
> Added cpu affinity sysfs entry
> Converted pmu_types array, to linked list
> Restrict use of the armv8_pmu_probe_table to ACPI systems
> Rename MADT parsing routines in smp.c
> Convert sysfs PMU name to use index rather than partnum
> Remove pr_devel statements
> Other Minor cleanups
> Add Partial Ack-by Will Deacon
>
> v5:
> Remove list of CPU types for ACPI systems. We now match a generic
> event list, and use the PMCIED[01] to select events which exist on
> the given PMU. This avoids the need to update the kernel every time
> a new CPU is released.
> Update the maintainers list to include the new file.
>
> v4:
> Correct build issues with ARM (!ARM64) kernels.
> Add ThunderX to list of PMU types.
>
> v3:
> Enable ARM performance monitoring units on ACPI/arm64 machines.
>
> Jeremy Linton (8):
>   arm64: pmu: Probe default hw/cache counters
>   arm64: pmu: Hoist pmu platform device name
>   arm64: Rename the common MADT parse routine
>   arm: arm64: Add routine to determine cpuid of other cpus
>   arm: arm64: pmu: Assign platform PMU CPU affinity
>   arm64: pmu: Detect and enable multiple PMUs in an ACPI system
>   arm: pmu: Add PMU definitions for hot-plugged CPUs
>   MAINTAINERS: Tweak ARM PMU maintainers
>
> Mark Salter (2):
>   arm64: pmu: add fallback probe table
>   arm64: pmu: Cache PMU interrupt numbers from MADT parse
>
>  MAINTAINERS                      |   3 +-
>  arch/arm/include/asm/cputype.h   |   2 +
>  arch/arm64/include/asm/cputype.h |   3 +
>  arch/arm64/kernel/perf_event.c   |  58 ++++++++-
>  arch/arm64/kernel/smp.c          |  18 ++-
>  drivers/perf/Kconfig             |   4 +
>  drivers/perf/Makefile            |   1 +
>  drivers/perf/arm_pmu.c           | 110 ++++++++++++++--
>  drivers/perf/arm_pmu_acpi.c      | 264 +++++++++++++++++++++++++++++++++++++++
>  include/linux/perf/arm_pmu.h     |  13 ++
>  10 files changed, 452 insertions(+), 24 deletions(-)
>  create mode 100644 drivers/perf/arm_pmu_acpi.c

^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v9 00/10] Enable PMUs in ACPI systems
@ 2016-09-16 17:13   ` Punit Agrawal
  0 siblings, 0 replies; 42+ messages in thread
From: Punit Agrawal @ 2016-09-16 17:13 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jeremy,

Jeremy Linton <jeremy.linton@arm.com> writes:

> This patch expands and reworks the patches published by Mark Salter
> in order to clean up a few of the previous review comments, as well as
> add support for newer CPUs and big/little configurations.
>
> v9:
> Add/cleanup an additional hotplug patch I've had sitting around. This
> patch brings the ACPI PMU mostly on par with the DT functionality with
> respect to having CPUs offline during boot. This should help clarify
> some of the code structuring.
> Cleanup the list of PMU types early if we fail to allocate memory for an
> additional pmu type.

The earlier patches in the series look OK but there are still
unaddressed comments on Patch 8 from previous versions - coding style,
excessive indentation, complicated logic etc.

Additionally, I'd suggest moving hotplug/unsed MADT related changes out
of Patch 8 to later patches, i.e., add support for hotplug on top.

Thanks,
Punit

>
> v8:
> Rebase to 4.8rc4
> Assorted minor comment/hunk placement/etc tweaks per Punit Agrawal
>
> v7:
> Rebase to 4.8rc3
> Remove cpu affinity sysfs entry. While providing a CPU mask for
> ARMv8 PMU's is really helpful in big/little environments, reworking
> the PMU code to support the cpumask attribute for !arm64 PMUs is out
> of the scope of this patch set.
> Fix CPU miscount problem where an alloc failure followed by successfully
> allocating the structure can result in under counting the CPUs associated
> with the PMU. This bug was created in v6 with the conversion to a linked
> list.
> Remove initial platform device creation code by Mark Salter, and re-squash
> multiple platform device creation code together with helper routines.
> Other minor tweakage.
>
> v6:
> Added cpu affinity sysfs entry
> Converted pmu_types array, to linked list
> Restrict use of the armv8_pmu_probe_table to ACPI systems
> Rename MADT parsing routines in smp.c
> Convert sysfs PMU name to use index rather than partnum
> Remove pr_devel statements
> Other Minor cleanups
> Add Partial Ack-by Will Deacon
>
> v5:
> Remove list of CPU types for ACPI systems. We now match a generic
> event list, and use the PMCIED[01] to select events which exist on
> the given PMU. This avoids the need to update the kernel every time
> a new CPU is released.
> Update the maintainers list to include the new file.
>
> v4:
> Correct build issues with ARM (!ARM64) kernels.
> Add ThunderX to list of PMU types.
>
> v3:
> Enable ARM performance monitoring units on ACPI/arm64 machines.
>
> Jeremy Linton (8):
>   arm64: pmu: Probe default hw/cache counters
>   arm64: pmu: Hoist pmu platform device name
>   arm64: Rename the common MADT parse routine
>   arm: arm64: Add routine to determine cpuid of other cpus
>   arm: arm64: pmu: Assign platform PMU CPU affinity
>   arm64: pmu: Detect and enable multiple PMUs in an ACPI system
>   arm: pmu: Add PMU definitions for hot-plugged CPUs
>   MAINTAINERS: Tweak ARM PMU maintainers
>
> Mark Salter (2):
>   arm64: pmu: add fallback probe table
>   arm64: pmu: Cache PMU interrupt numbers from MADT parse
>
>  MAINTAINERS                      |   3 +-
>  arch/arm/include/asm/cputype.h   |   2 +
>  arch/arm64/include/asm/cputype.h |   3 +
>  arch/arm64/kernel/perf_event.c   |  58 ++++++++-
>  arch/arm64/kernel/smp.c          |  18 ++-
>  drivers/perf/Kconfig             |   4 +
>  drivers/perf/Makefile            |   1 +
>  drivers/perf/arm_pmu.c           | 110 ++++++++++++++--
>  drivers/perf/arm_pmu_acpi.c      | 264 +++++++++++++++++++++++++++++++++++++++
>  include/linux/perf/arm_pmu.h     |  13 ++
>  10 files changed, 452 insertions(+), 24 deletions(-)
>  create mode 100644 drivers/perf/arm_pmu_acpi.c

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system
  2016-09-16 17:07         ` Punit Agrawal
@ 2016-09-16 17:57           ` Jeremy Linton
  -1 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-16 17:57 UTC (permalink / raw)
  To: Punit Agrawal
  Cc: linux-arm-kernel, mark.rutland, will.deacon, linux-acpi,
	mlangsdorf, steve.capper

On 09/16/2016 12:07 PM, Punit Agrawal wrote:
> Jeremy Linton <jeremy.linton@arm.com> writes:
>
>> Hi,
>>
>> On 09/16/2016 08:33 AM, Punit Agrawal wrote:
>>> Jeremy Linton <jeremy.linton@arm.com> writes:
>>>
>>>> Its possible that an ACPI system has multiple CPU types in it
>>>> with differing PMU counters. Iterate the CPU's and make a determination
>>>> about how many of each type exist in the system. Then take and create
>>>> a PMU platform device for each type, and assign it the interrupts parsed
>>>> from the MADT. Creating a platform device is necessary because the PMUs
>>>> are not described as devices in the DSDT table.
>>>>
>>>> This code is loosely based on earlier work by Mark Salter.
>>
>> (trimming)
>>
>>>> +
>>>> +	list_for_each_entry_safe(pmu, safe_temp, &pmus, list) {
>>>> +		if (unused_madt_entries)
>>>> +			pmu->cpu_count = num_possible_cpus();
>>>
>>> So if there is any unbooted cpu ...
>>>
>>>> +
>>>> +		res = kcalloc(pmu->cpu_count,
>>>> +				  sizeof(struct resource), GFP_KERNEL);
>>>
>>> ... we allocate potentially large number (num_possible_cpus()) of
>>> resources for each PMU.
>>>
>>> This is needlessly wasteful. Under what conditions have you found
>>> reg_midr to be 0?
>>
>> Unused MADT entries, in place for potentially unbooted/hotplug
>> CPUs.
>
> Is linux able to deal with booting secondaries that have unused MADT
> entries?

Uh, yah I think so, that is how i've been testing it, maybe we are 
saying different things. When i'm talking about "unused" I mean MADT 
entries that don't have started/running cpus. Obviously they stop being 
unused when a cpu is booted.

>
>> In those cases you don't know for sure which PMU the CPU belongs
>> to until it comes online and the MIDR can be read. I'm open to
>> suggestions on how to deal with this, outside of pushing my luck and
>> further breaking the platform device encapsulation by trying to
>> reallocate the resource structure while its active. Besides its only
>> wasteful for ACPI+big.little, which at the moment only applies to a
>> development platform.
>
> I don't have any ideas to solve this problem, but in the interest of
> helping review, please move all the changes arising from hotplug/unused
> MADT entries in this patch to the next one.

Which is sort of the opposite of the last 3 months, of complaints about 
how hard it was to review this module with multiple patches adding 
features to the code...

^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system
@ 2016-09-16 17:57           ` Jeremy Linton
  0 siblings, 0 replies; 42+ messages in thread
From: Jeremy Linton @ 2016-09-16 17:57 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/16/2016 12:07 PM, Punit Agrawal wrote:
> Jeremy Linton <jeremy.linton@arm.com> writes:
>
>> Hi,
>>
>> On 09/16/2016 08:33 AM, Punit Agrawal wrote:
>>> Jeremy Linton <jeremy.linton@arm.com> writes:
>>>
>>>> Its possible that an ACPI system has multiple CPU types in it
>>>> with differing PMU counters. Iterate the CPU's and make a determination
>>>> about how many of each type exist in the system. Then take and create
>>>> a PMU platform device for each type, and assign it the interrupts parsed
>>>> from the MADT. Creating a platform device is necessary because the PMUs
>>>> are not described as devices in the DSDT table.
>>>>
>>>> This code is loosely based on earlier work by Mark Salter.
>>
>> (trimming)
>>
>>>> +
>>>> +	list_for_each_entry_safe(pmu, safe_temp, &pmus, list) {
>>>> +		if (unused_madt_entries)
>>>> +			pmu->cpu_count = num_possible_cpus();
>>>
>>> So if there is any unbooted cpu ...
>>>
>>>> +
>>>> +		res = kcalloc(pmu->cpu_count,
>>>> +				  sizeof(struct resource), GFP_KERNEL);
>>>
>>> ... we allocate potentially large number (num_possible_cpus()) of
>>> resources for each PMU.
>>>
>>> This is needlessly wasteful. Under what conditions have you found
>>> reg_midr to be 0?
>>
>> Unused MADT entries, in place for potentially unbooted/hotplug
>> CPUs.
>
> Is linux able to deal with booting secondaries that have unused MADT
> entries?

Uh, yah I think so, that is how i've been testing it, maybe we are 
saying different things. When i'm talking about "unused" I mean MADT 
entries that don't have started/running cpus. Obviously they stop being 
unused when a cpu is booted.

>
>> In those cases you don't know for sure which PMU the CPU belongs
>> to until it comes online and the MIDR can be read. I'm open to
>> suggestions on how to deal with this, outside of pushing my luck and
>> further breaking the platform device encapsulation by trying to
>> reallocate the resource structure while its active. Besides its only
>> wasteful for ACPI+big.little, which at the moment only applies to a
>> development platform.
>
> I don't have any ideas to solve this problem, but in the interest of
> helping review, please move all the changes arising from hotplug/unused
> MADT entries in this patch to the next one.

Which is sort of the opposite of the last 3 months, of complaints about 
how hard it was to review this module with multiple patches adding 
features to the code...

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system
  2016-09-16 17:57           ` Jeremy Linton
@ 2016-09-20 16:11             ` Punit Agrawal
  -1 siblings, 0 replies; 42+ messages in thread
From: Punit Agrawal @ 2016-09-20 16:11 UTC (permalink / raw)
  To: Jeremy Linton
  Cc: linux-arm-kernel, mark.rutland, will.deacon, linux-acpi,
	mlangsdorf, steve.capper

Jeremy Linton <jeremy.linton@arm.com> writes:

> On 09/16/2016 12:07 PM, Punit Agrawal wrote:
>> Jeremy Linton <jeremy.linton@arm.com> writes:
>>
>>> Hi,
>>>
>>> On 09/16/2016 08:33 AM, Punit Agrawal wrote:
>>>> Jeremy Linton <jeremy.linton@arm.com> writes:
>>>>
>>>>> Its possible that an ACPI system has multiple CPU types in it
>>>>> with differing PMU counters. Iterate the CPU's and make a determination
>>>>> about how many of each type exist in the system. Then take and create
>>>>> a PMU platform device for each type, and assign it the interrupts parsed
>>>>> from the MADT. Creating a platform device is necessary because the PMUs
>>>>> are not described as devices in the DSDT table.
>>>>>
>>>>> This code is loosely based on earlier work by Mark Salter.
>>>
>>> (trimming)
>>>
>>>>> +
>>>>> +	list_for_each_entry_safe(pmu, safe_temp, &pmus, list) {
>>>>> +		if (unused_madt_entries)
>>>>> +			pmu->cpu_count = num_possible_cpus();
>>>>
>>>> So if there is any unbooted cpu ...
>>>>
>>>>> +
>>>>> +		res = kcalloc(pmu->cpu_count,
>>>>> +				  sizeof(struct resource), GFP_KERNEL);
>>>>
>>>> ... we allocate potentially large number (num_possible_cpus()) of
>>>> resources for each PMU.
>>>>
>>>> This is needlessly wasteful. Under what conditions have you found
>>>> reg_midr to be 0?
>>>
>>> Unused MADT entries, in place for potentially unbooted/hotplug
>>> CPUs.
>>
>> Is linux able to deal with booting secondaries that have unused MADT
>> entries?
>
> Uh, yah I think so, that is how i've been testing it, maybe we are
> saying different things. When i'm talking about "unused" I mean MADT
> entries that don't have started/running cpus. Obviously they stop
> being unused when a cpu is booted.
>
>>
>>> In those cases you don't know for sure which PMU the CPU belongs
>>> to until it comes online and the MIDR can be read. I'm open to
>>> suggestions on how to deal with this, outside of pushing my luck and
>>> further breaking the platform device encapsulation by trying to
>>> reallocate the resource structure while its active. Besides its only
>>> wasteful for ACPI+big.little, which at the moment only applies to a
>>> development platform.
>>
>> I don't have any ideas to solve this problem, but in the interest of
>> helping review, please move all the changes arising from hotplug/unused
>> MADT entries in this patch to the next one.
>
> Which is sort of the opposite of the last 3 months, of complaints
> about how hard it was to review this module with multiple patches
> adding features to the code...

My suggestion to move functionality that has concerns and needs rework
to later patch is aimed at helping get stuff that everybody agrees upon
merged. But it's only a suggestion...

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

^ permalink raw reply	[flat|nested] 42+ messages in thread

* [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system
@ 2016-09-20 16:11             ` Punit Agrawal
  0 siblings, 0 replies; 42+ messages in thread
From: Punit Agrawal @ 2016-09-20 16:11 UTC (permalink / raw)
  To: linux-arm-kernel

Jeremy Linton <jeremy.linton@arm.com> writes:

> On 09/16/2016 12:07 PM, Punit Agrawal wrote:
>> Jeremy Linton <jeremy.linton@arm.com> writes:
>>
>>> Hi,
>>>
>>> On 09/16/2016 08:33 AM, Punit Agrawal wrote:
>>>> Jeremy Linton <jeremy.linton@arm.com> writes:
>>>>
>>>>> Its possible that an ACPI system has multiple CPU types in it
>>>>> with differing PMU counters. Iterate the CPU's and make a determination
>>>>> about how many of each type exist in the system. Then take and create
>>>>> a PMU platform device for each type, and assign it the interrupts parsed
>>>>> from the MADT. Creating a platform device is necessary because the PMUs
>>>>> are not described as devices in the DSDT table.
>>>>>
>>>>> This code is loosely based on earlier work by Mark Salter.
>>>
>>> (trimming)
>>>
>>>>> +
>>>>> +	list_for_each_entry_safe(pmu, safe_temp, &pmus, list) {
>>>>> +		if (unused_madt_entries)
>>>>> +			pmu->cpu_count = num_possible_cpus();
>>>>
>>>> So if there is any unbooted cpu ...
>>>>
>>>>> +
>>>>> +		res = kcalloc(pmu->cpu_count,
>>>>> +				  sizeof(struct resource), GFP_KERNEL);
>>>>
>>>> ... we allocate potentially large number (num_possible_cpus()) of
>>>> resources for each PMU.
>>>>
>>>> This is needlessly wasteful. Under what conditions have you found
>>>> reg_midr to be 0?
>>>
>>> Unused MADT entries, in place for potentially unbooted/hotplug
>>> CPUs.
>>
>> Is linux able to deal with booting secondaries that have unused MADT
>> entries?
>
> Uh, yah I think so, that is how i've been testing it, maybe we are
> saying different things. When i'm talking about "unused" I mean MADT
> entries that don't have started/running cpus. Obviously they stop
> being unused when a cpu is booted.
>
>>
>>> In those cases you don't know for sure which PMU the CPU belongs
>>> to until it comes online and the MIDR can be read. I'm open to
>>> suggestions on how to deal with this, outside of pushing my luck and
>>> further breaking the platform device encapsulation by trying to
>>> reallocate the resource structure while its active. Besides its only
>>> wasteful for ACPI+big.little, which at the moment only applies to a
>>> development platform.
>>
>> I don't have any ideas to solve this problem, but in the interest of
>> helping review, please move all the changes arising from hotplug/unused
>> MADT entries in this patch to the next one.
>
> Which is sort of the opposite of the last 3 months, of complaints
> about how hard it was to review this module with multiple patches
> adding features to the code...

My suggestion to move functionality that has concerns and needs rework
to later patch is aimed at helping get stuff that everybody agrees upon
merged. But it's only a suggestion...

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

^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2016-09-20 16:12 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-14 22:32 [PATCH v9 00/10] Enable PMUs in ACPI systems Jeremy Linton
2016-09-14 22:32 ` Jeremy Linton
2016-09-14 22:32 ` [PATCH v9 01/10] arm64: pmu: add fallback probe table Jeremy Linton
2016-09-14 22:32   ` Jeremy Linton
2016-09-14 22:32 ` [PATCH v9 02/10] arm64: pmu: Probe default hw/cache counters Jeremy Linton
2016-09-14 22:32   ` Jeremy Linton
2016-09-14 22:32 ` [PATCH v9 03/10] arm64: pmu: Hoist pmu platform device name Jeremy Linton
2016-09-14 22:32   ` Jeremy Linton
2016-09-14 22:32 ` [PATCH v9 04/10] arm64: Rename the common MADT parse routine Jeremy Linton
2016-09-14 22:32   ` Jeremy Linton
2016-09-14 22:32 ` [PATCH v9 05/10] arm: arm64: Add routine to determine cpuid of other cpus Jeremy Linton
2016-09-14 22:32   ` Jeremy Linton
2016-09-14 22:32 ` [PATCH v9 06/10] arm64: pmu: Cache PMU interrupt numbers from MADT parse Jeremy Linton
2016-09-14 22:32   ` Jeremy Linton
2016-09-14 22:32 ` [PATCH v9 07/10] arm: arm64: pmu: Assign platform PMU CPU affinity Jeremy Linton
2016-09-14 22:32   ` Jeremy Linton
2016-09-16 13:29   ` Will Deacon
2016-09-16 13:29     ` Will Deacon
2016-09-16 15:35     ` Jeremy Linton
2016-09-16 15:35       ` Jeremy Linton
2016-09-16 15:48       ` Will Deacon
2016-09-16 15:48         ` Will Deacon
2016-09-16 16:37   ` Punit Agrawal
2016-09-16 16:37     ` Punit Agrawal
2016-09-14 22:32 ` [PATCH v9 08/10] arm64: pmu: Detect and enable multiple PMUs in an ACPI system Jeremy Linton
2016-09-14 22:32   ` Jeremy Linton
2016-09-16 13:33   ` Punit Agrawal
2016-09-16 13:33     ` Punit Agrawal
2016-09-16 16:32     ` Jeremy Linton
2016-09-16 16:32       ` Jeremy Linton
2016-09-16 17:07       ` Punit Agrawal
2016-09-16 17:07         ` Punit Agrawal
2016-09-16 17:57         ` Jeremy Linton
2016-09-16 17:57           ` Jeremy Linton
2016-09-20 16:11           ` Punit Agrawal
2016-09-20 16:11             ` Punit Agrawal
2016-09-14 22:32 ` [PATCH v9 09/10] arm: pmu: Add PMU definitions for hot-plugged CPUs Jeremy Linton
2016-09-14 22:32   ` Jeremy Linton
2016-09-14 22:32 ` [PATCH v9 10/10] MAINTAINERS: Tweak ARM PMU maintainers Jeremy Linton
2016-09-14 22:32   ` Jeremy Linton
2016-09-16 17:13 ` [PATCH v9 00/10] Enable PMUs in ACPI systems Punit Agrawal
2016-09-16 17:13   ` Punit Agrawal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.