diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index f70090897fdf19c9777c332401dd01de7b1efc52..f2d01d4d93645a0b029561ba2febf7fed56ec276 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -847,6 +847,14 @@ static int cpu_pmu_init(struct arm_pmu *cpu_pmu) if (!platform_get_irq(cpu_pmu->plat_device, 0)) cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; + /* + * This is a CPU PMU potentially in a heterogeneous configuration (e.g. + * big.LITTLE). This is not an uncore PMU, and we have taken ctx + * sharing into account (e.g. with our pmu::filter_match callback and + * pmu::event_init group validation). + */ + cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_HETEROGENEOUS_CPUS; + return 0; out_unregister: diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index c77e4a159fa2074a82af2ea8c734fe60259cc21c..9e1c3ada91c49b36b643496ffe5fcd37917bb5b8 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -225,6 +225,7 @@ struct perf_event; #define PERF_PMU_CAP_AUX_SW_DOUBLEBUF 0x08 #define PERF_PMU_CAP_EXCLUSIVE 0x10 #define PERF_PMU_CAP_ITRACE 0x20 +#define PERF_PMU_CAP_HETEROGENEOUS_CPUS 0x40 /** * struct pmu - generic performance monitoring unit diff --git a/kernel/events/core.c b/kernel/events/core.c index 63be65437e9eacdfe856e5e346c624eedb8ff24c..fc0290f25482201f1226c5a1cbcc0b7b4f2c160b 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -8443,7 +8443,13 @@ int perf_pmu_register(struct pmu *pmu, const char *name, int type) if (pmu->task_ctx_nr == perf_hw_context) { static int hw_context_taken = 0; - if (WARN_ON_ONCE(hw_context_taken)) + /* + * Other than systems with heterogeneous CPUs, it never makes + * sense for two PMUs to share perf_hw_context. PMUs which are + * uncore must use perf_invalid_context. + */ + if (WARN_ON_ONCE(hw_context_taken && + !(pmu->capabilities & PERF_PMU_CAP_HETEROGENEOUS_CPUS))) pmu->task_ctx_nr = perf_invalid_context; hw_context_taken = 1;