@@ -399,6 +399,27 @@ void hisi_uncore_pmu_disable(struct pmu *pmu)
}
EXPORT_SYMBOL_NS_GPL(hisi_uncore_pmu_disable, HISI_PMU);
+static void hisi_pmu_init_associated_cpus(struct hisi_pmu *hisi_pmu)
+{
+ /*
+ * If the associated_cpus has already been initialized, for example
+ * determined by comparing the sccl_id and ccl_id with the CPU's
+ * mpidr_el1, then do nothing here. Otherwise the PMU has no affinity
+ * and could be opened on any online CPU.
+ */
+ if (!cpumask_empty(&hisi_pmu->associated_cpus))
+ return;
+
+ cpumask_copy(&hisi_pmu->associated_cpus, cpu_online_mask);
+ hisi_pmu->dummy_associated_cpus = true;
+
+ /*
+ * Otherwise the associated CPUs haven't been online yet. Pick a
+ * nearest CPU according to the PMU's numa node instead.
+ */
+ hisi_pmu->on_cpu = cpumask_local_spread(0, dev_to_node(hisi_pmu->dev));
+ WARN_ON(irq_set_affinity(hisi_pmu->irq, cpumask_of(hisi_pmu->on_cpu)));
+}
/*
* The Super CPU Cluster (SCCL) and CPU Cluster (CCL) IDs can be
@@ -446,10 +467,6 @@ static bool hisi_pmu_cpu_is_associated_pmu(struct hisi_pmu *hisi_pmu)
{
int sccl_id, ccl_id;
- /* If SCCL_ID is -1, the PMU is in a SICL and has no CPU affinity */
- if (hisi_pmu->sccl_id == -1)
- return true;
-
if (hisi_pmu->ccl_id == -1) {
/* If CCL_ID is -1, the PMU only shares the same SCCL */
hisi_read_sccl_and_ccl_id(&sccl_id, NULL);
@@ -467,13 +484,29 @@ int hisi_uncore_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
struct hisi_pmu *hisi_pmu = hlist_entry_safe(node, struct hisi_pmu,
node);
- if (!hisi_pmu_cpu_is_associated_pmu(hisi_pmu))
- return 0;
+ /*
+ * If the CPU is not in the associated_cpus, it maybe a new CPU.
+ * Test whether it's associated or not.
+ */
+ if (!cpumask_test_cpu(cpu, &hisi_pmu->associated_cpus)) {
+ if (!hisi_pmu_cpu_is_associated_pmu(hisi_pmu))
+ return 0;
+
+ /*
+ * We found an associated CPU so we don't need to use the dummy
+ * associated CPUs. Update it.
+ */
+ if (hisi_pmu->dummy_associated_cpus) {
+ cpumask_clear(&hisi_pmu->associated_cpus);
+ hisi_pmu->dummy_associated_cpus = false;
+ }
- cpumask_set_cpu(cpu, &hisi_pmu->associated_cpus);
+ cpumask_set_cpu(cpu, &hisi_pmu->associated_cpus);
+ }
- /* If another CPU is already managing this PMU, simply return. */
- if (hisi_pmu->on_cpu != -1)
+ /* If another associated CPU is already managing this PMU, simply return. */
+ if (hisi_pmu->on_cpu != -1 &&
+ cpumask_test_cpu(hisi_pmu->on_cpu, &hisi_pmu->associated_cpus))
return 0;
/* Use this CPU in cpumask for event counting */
@@ -492,9 +525,6 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
node);
unsigned int target;
- if (!cpumask_test_and_clear_cpu(cpu, &hisi_pmu->associated_cpus))
- return 0;
-
/* Nothing to do if this CPU doesn't own the PMU */
if (hisi_pmu->on_cpu != cpu)
return 0;
@@ -521,6 +551,8 @@ void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module)
{
struct pmu *pmu = &hisi_pmu->pmu;
+ hisi_pmu_init_associated_cpus(hisi_pmu);
+
pmu->module = module;
pmu->parent = hisi_pmu->dev;
pmu->task_ctx_nr = perf_invalid_context;
@@ -89,6 +89,11 @@ struct hisi_pmu {
struct hisi_pmu_hwevents pmu_events;
/* associated_cpus: All CPUs associated with the PMU */
cpumask_t associated_cpus;
+ /*
+ * If the real associated CPUs not onlined by the time initializing,
+ * we'll initialize with online CPUs and indicate it.
+ */
+ bool dummy_associated_cpus;
/* CPU used for counting */
int on_cpu;
int irq;