aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/kernel/perf_event_cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/perf_event_cpu.c')
-rw-r--r--arch/arm/kernel/perf_event_cpu.c71
1 files changed, 70 insertions, 1 deletions
diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c
index b2f202be922..e9d1995b002 100644
--- a/arch/arm/kernel/perf_event_cpu.c
+++ b/arch/arm/kernel/perf_event_cpu.c
@@ -30,9 +30,12 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <asm/bL_switcher.h>
#include <asm/cputype.h>
#include <asm/irq_regs.h>
#include <asm/pmu.h>
+#include <asm/smp_plat.h>
+#include <asm/topology.h>
static LIST_HEAD(cpu_pmus_list);
@@ -319,6 +322,33 @@ static void cpu_pmu_free(struct arm_pmu *pmu)
kfree(pmu);
}
+/*
+ * HACK: Find a b.L switcher partner for CPU cpu on the specified cluster
+ * This information should be obtained from an interface provided by the
+ * Switcher itself, if possible.
+ */
+#ifdef CONFIG_BL_SWITCHER
+static int bL_get_partner(int cpu, int cluster)
+{
+ unsigned int i;
+
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_topology[i].thread_id == cpu_topology[cpu].thread_id &&
+ cpu_topology[i].core_id == cpu_topology[cpu].core_id &&
+ cpu_topology[i].socket_id == cluster)
+ return i;
+ }
+
+ return -1; /* no partner found */
+}
+#else
+static int bL_get_partner(int __always_unused cpu, int __always_unused cluster)
+{
+ return -1;
+}
+#endif
+
static int cpu_pmu_device_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id;
@@ -340,6 +370,7 @@ static int cpu_pmu_device_probe(struct platform_device *pdev)
struct device_node *ncluster;
int cluster = -1;
cpumask_t sibling_mask;
+ unsigned int i;
ncluster = of_parse_phandle(node, "cluster", 0);
if (ncluster) {
@@ -350,12 +381,50 @@ static int cpu_pmu_device_probe(struct platform_device *pdev)
cluster = be32_to_cpup(hwid);
}
/* set sibling mask to all cpu mask if socket is not specified */
- if (cluster == -1 ||
+ /*
+ * In a switcher kernel, we affine all PMUs to CPUs and
+ * abstract the runtime presence/absence of PMUs at a lower
+ * level.
+ */
+ if (cluster == -1 || IS_ENABLED(CONFIG_BL_SWITCHER) ||
cluster_to_logical_mask(cluster, &sibling_mask))
cpumask_copy(&sibling_mask, cpu_possible_mask);
+ if (bL_switcher_get_enabled())
+ /*
+ * The switcher initialises late now, so it should not
+ * have initialised yet:
+ */
+ BUG();
+
+ /*
+ * HACK: Deduce how the switcher will modify the topology
+ * in order to fill in PMU<->CPU combinations which don't
+ * make sense when the switcher is disabled. Ideally, this
+ * knowledge should come from the swithcer somehow.
+ */
+ for (i = 0; i < NR_CPUS; i++) {
+ int cpu = i;
+
+ if (cpu_topology[i].socket_id != cluster) {
+ int partner = bL_get_partner(i, cluster);
+
+ if (partner != -1)
+ cpu = partner;
+ }
+
+ per_cpu_ptr(cpu_pmus, i)->mpidr =
+ cpu_logical_map(cpu);
+ }
+
+ /*
+ * This relies on an MP view of the system to choose the right
+ * CPU to run init_fn:
+ */
smp_call_function_any(&sibling_mask, init_fn, pmu, 1);
+ bL_switcher_put_enabled();
+
/* now set the valid_cpus after init */
cpumask_copy(&pmu->valid_cpus, &sibling_mask);
} else {