[PATCH v11 26/27] coresight: Move CPU hotplug callbacks to core layer

Leo Yan
2026-05-01T16:49:35Z

This commit moves CPU hotplug callbacks from ETMv4 driver to core layer.
The motivation is the core layer can control all components on an
activated path rather but not only managing tracer in ETMv4 driver.

The perf event layer will disable CoreSight PMU event 'cs_etm' when
hotplug off a CPU. That means a perf mode will be always converted to
disabled mode in CPU hotplug. Arm CoreSight CPU hotplug callbacks only
need to handle the Sysfs mode and ignore the perf mode.

Add a 'mode' argument to coresight_pm_get_active_path() so it only
returns active paths for the relevant mode.

Change CPUHP_AP_ARM_CORESIGHT_STARTING to CPUHP_AP_ARM_CORESIGHT_ONLINE
so that the CPU hotplug callback runs in the online state and thread
context, allowing coresight_disable_sysfs() to be called directly to
disable the path.

Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: James Clark <james.clark@linaro.org>
Tested-by: Jie Gan <jie.gan@oss.qualcomm.com>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-core.c | 48 ++++++++++++++++++----
drivers/hwtracing/coresight/coresight-etm3x-core.c | 40 ------------------
drivers/hwtracing/coresight/coresight-etm4x-core.c | 37 -----------------
include/linux/cpuhotplug.h | 2 +-
4 files changed, 40 insertions(+), 87 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index b2301ae0fd358242c59b9f4da99faae0db5ff894..015363da12fa8cb46e265bda9eb86c5e9abf0a63 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -1823,7 +1823,7 @@ static void coresight_release_device_list(void)
}
}

-static struct coresight_path *coresight_cpu_get_active_path(void)
+static struct coresight_path *coresight_cpu_get_active_path(enum cs_mode mode)
{
struct coresight_device *source;
bool is_active = false;
@@ -1832,17 +1832,17 @@ static struct coresight_path *coresight_cpu_get_active_path(void)
if (!source)
return NULL;

- if (coresight_get_mode(source) != CS_MODE_DISABLED)
+ if (coresight_get_mode(source) & mode)
is_active = true;

coresight_put_percpu_source_ref(source);

/*
- * It is expected to run in atomic context, so it cannot be preempted
- * to disable the path. Here returns the active path pointer without
- * concern that its state may change. Since the build path has taken
- * a reference on the component, the path can be safely used by the
- * caller.
+ * It is expected to run in atomic context or with the CPU lock held for
+ * sysfs mode, so it cannot be preempted to disable the path. Here
+ * returns the active path pointer without concern that its state may
+ * change. Since the build path has taken a reference on the component,
+ * the path can be safely used by the caller.
*/
return is_active ? source->path : NULL;
}
@@ -1961,7 +1961,8 @@ static void coresight_pm_restore(struct coresight_path *path)
static int coresight_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
void *v)
{
- struct coresight_path *path = coresight_cpu_get_active_path();
+ struct coresight_path *path =
+ coresight_cpu_get_active_path(CS_MODE_SYSFS | CS_MODE_PERF);
int ret;

ret = coresight_pm_is_needed(path);
@@ -1988,13 +1989,42 @@ static struct notifier_block coresight_cpu_pm_nb = {
.notifier_call = coresight_cpu_pm_notify,
};

+static int coresight_dying_cpu(unsigned int cpu)
+{
+ struct coresight_path *path;
+
+ /*
+ * The perf event layer will disable PMU events in the CPU
+ * hotplug. Here only handles SYSFS case.
+ */
+ path = coresight_cpu_get_active_path(CS_MODE_SYSFS);
+ if (!path)
+ return 0;
+
+ coresight_disable_sysfs(coresight_get_source(path));
+ return 0;
+}
+
static int __init coresight_pm_setup(void)
{
- return cpu_pm_register_notifier(&coresight_cpu_pm_nb);
+ int ret;
+
+ ret = cpu_pm_register_notifier(&coresight_cpu_pm_nb);
+ if (ret)
+ return ret;
+
+ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_ONLINE,
+ "arm/coresight-core:dying",
+ NULL, coresight_dying_cpu);
+ if (ret)
+ cpu_pm_unregister_notifier(&coresight_cpu_pm_nb);
+
+ return ret;
}

static void coresight_pm_cleanup(void)
{
+ cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_ONLINE);
cpu_pm_unregister_notifier(&coresight_cpu_pm_nb);
}

diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index c6fe8b25b855a4119110fee4162f55c0154c3d05..862ad0786699c41433eae8683406b3c1340a6cb6 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -699,35 +699,6 @@ static int etm_online_cpu(unsigned int cpu)
return 0;
}

-static int etm_starting_cpu(unsigned int cpu)
-{
- if (!etmdrvdata[cpu])
- return 0;
-
- spin_lock(&etmdrvdata[cpu]->spinlock);
- if (!etmdrvdata[cpu]->os_unlock) {
- etm_os_unlock(etmdrvdata[cpu]);
- etmdrvdata[cpu]->os_unlock = true;
- }
-
- if (coresight_get_mode(etmdrvdata[cpu]->csdev))
- etm_enable_hw(etmdrvdata[cpu]);
- spin_unlock(&etmdrvdata[cpu]->spinlock);
- return 0;
-}
-
-static int etm_dying_cpu(unsigned int cpu)
-{
- if (!etmdrvdata[cpu])
- return 0;
-
- spin_lock(&etmdrvdata[cpu]->spinlock);
- if (coresight_get_mode(etmdrvdata[cpu]->csdev))
- etm_disable_hw(etmdrvdata[cpu]);
- spin_unlock(&etmdrvdata[cpu]->spinlock);
- return 0;
-}
-
static bool etm_arch_supported(u8 arch)
{
switch (arch) {
@@ -795,13 +766,6 @@ static int __init etm_hp_setup(void)
{
int ret;

- ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING,
- "arm/coresight:starting",
- etm_starting_cpu, etm_dying_cpu);
-
- if (ret)
- return ret;
-
ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
"arm/coresight:online",
etm_online_cpu, NULL);
@@ -812,15 +776,11 @@ static int __init etm_hp_setup(void)
return 0;
}

- /* failed dyn state - remove others */
- cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
-
return ret;
}

static void etm_hp_clear(void)
{
- cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
if (hp_online) {
cpuhp_remove_state_nocalls(hp_online);
hp_online = 0;
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 7c9e0af2f24556e27f6c1bcbb22044c52f13de12..266dec109232ed2e8761485a9ee58b80ba7b5141 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -1829,33 +1829,6 @@ static int etm4_online_cpu(unsigned int cpu)
return 0;
}

-static int etm4_starting_cpu(unsigned int cpu)
-{
- if (!etmdrvdata[cpu])
- return 0;
-
- raw_spin_lock(&etmdrvdata[cpu]->spinlock);
- if (!etmdrvdata[cpu]->os_unlock)
- etm4_os_unlock(etmdrvdata[cpu]);
-
- if (coresight_get_mode(etmdrvdata[cpu]->csdev))
- etm4_enable_hw(etmdrvdata[cpu]);
- raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
- return 0;
-}
-
-static int etm4_dying_cpu(unsigned int cpu)
-{
- if (!etmdrvdata[cpu])
- return 0;
-
- raw_spin_lock(&etmdrvdata[cpu]->spinlock);
- if (coresight_get_mode(etmdrvdata[cpu]->csdev))
- etm4_disable_hw(etmdrvdata[cpu]);
- raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
- return 0;
-}
-
static inline bool etm4_pm_save_needed(struct etmv4_drvdata *drvdata)
{
return !!drvdata->save_state;
@@ -2116,13 +2089,6 @@ static int __init etm4_pm_setup(void)
{
int ret;

- ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING,
- "arm/coresight4:starting",
- etm4_starting_cpu, etm4_dying_cpu);
-
- if (ret)
- return ret;
-
ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
"arm/coresight4:online",
etm4_online_cpu, NULL);
@@ -2133,14 +2099,11 @@ static int __init etm4_pm_setup(void)
return 0;
}

- /* failed dyn state - remove others */
- cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
return ret;
}

static void etm4_pm_clear(void)
{
- cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
if (hp_online) {
cpuhp_remove_state_nocalls(hp_online);
hp_online = 0;
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 62cd7b35a29c94f214fec3b55f9462eceffad694..b9196ef6d83471400bb8bc5a8c4fd486c0acd4cc 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -181,7 +181,6 @@ enum cpuhp_state {
CPUHP_AP_DUMMY_TIMER_STARTING,
CPUHP_AP_ARM_XEN_STARTING,
CPUHP_AP_ARM_XEN_RUNSTATE_STARTING,
- CPUHP_AP_ARM_CORESIGHT_STARTING,
CPUHP_AP_ARM_CORESIGHT_CTI_STARTING,
CPUHP_AP_ARM64_ISNDEP_STARTING,
CPUHP_AP_SMPCFD_DYING,
@@ -201,6 +200,7 @@ enum cpuhp_state {
CPUHP_AP_IRQ_AFFINITY_ONLINE,
CPUHP_AP_BLK_MQ_ONLINE,
CPUHP_AP_ARM_MVEBU_SYNC_CLOCKS,
+ CPUHP_AP_ARM_CORESIGHT_ONLINE,
CPUHP_AP_X86_INTEL_EPB_ONLINE,
CPUHP_AP_PERF_ONLINE,
CPUHP_AP_PERF_X86_ONLINE,

--
2.34.1