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.
The core layer invokes a high level API coresight_disable_source() to disable a source when hotplug-off a CPU. It disables a tracer and changes the tracer's mode to CS_MODE_DISABLED.
When hotplug-in a CPU, if a activated path is detected - when the activated path pointer is not NULL - in this case, the tracer will be re-enabled.
Signed-off-by: Leo Yan leo.yan@arm.com --- drivers/hwtracing/coresight/coresight-core.c | 61 +++++++++++++++++++++- drivers/hwtracing/coresight/coresight-etm4x-core.c | 37 ------------- include/linux/coresight.h | 17 +++--- 3 files changed, 70 insertions(+), 45 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index ef9dbba285710fe508580ee2726e22bcc654014e..e39d1f835d77c302d475f93e125dd4f19d313864 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1704,6 +1704,52 @@ char *coresight_alloc_device_name(struct coresight_dev_list *dict, } EXPORT_SYMBOL_GPL(coresight_alloc_device_name);
+static int coresight_starting_cpu(unsigned int cpu) +{ + struct coresight_device *source = per_cpu(csdev_source, cpu); + struct coresight_path *path; + + if (!source) + return 0; + + /* Re-enable components on an activated path */ + path = per_cpu(csdev_cpu_path, cpu); + if (!path) + return 0; + + if (path->saved_mode != CS_MODE_SYSFS) + return 0; + + source_ops(source)->enable(source, NULL, path->saved_mode, path); + return 0; +} + +static int coresight_dying_cpu(unsigned int cpu) +{ + struct coresight_device *source = per_cpu(csdev_source, cpu); + struct coresight_path *path; + + if (!source) + return 0; + + /* Don't proceed if no path is activated */ + path = per_cpu(csdev_cpu_path, cpu); + if (!path) + return 0; + + path->saved_mode = coresight_get_mode(source); + + /* + * The perf event layer will disable PMU events in the CPU hotplug. + * CoreSight driver should never handle the CS_MODE_PERF case. + */ + if (WARN_ON(path->saved_mode != CS_MODE_SYSFS)) + return 0; + + source_ops(source)->disable(source, NULL); + return 0; +} + static int coresight_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd, void *v) { @@ -1769,11 +1815,24 @@ static struct notifier_block coresight_cpu_pm_nb = {
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_STARTING, + "arm/coresight-core:starting", + coresight_starting_cpu, 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_STARTING); cpu_pm_unregister_notifier(&coresight_cpu_pm_nb); }
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 920c817de8c33751760a1ed7ab1df8437620bb4e..e865d3fda10e10d7861cdb07ac3606e649b13ace 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -1805,33 +1805,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], true); - 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 bool etm4_need_context_save_restore(struct coresight_device *csdev) { if (pm_save_enable != PARAM_PM_SAVE_SELF_HOSTED) @@ -1926,13 +1899,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); @@ -1943,14 +1909,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/coresight.h b/include/linux/coresight.h index 21bb99f9684747d7a610aa7185e1ba5f987248d9..08a2ea9b843405f179f1748b35827502faba7472 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -330,21 +330,24 @@ static struct coresight_dev_list (var) = { \
#define to_coresight_device(d) container_of(d, struct coresight_device, dev)
+enum cs_mode { + CS_MODE_DISABLED, + CS_MODE_SYSFS, + CS_MODE_PERF, + CS_MODE_DEBUG, +}; + /** * struct coresight_path - data needed by enable/disable path * @path_list: path from source to sink. * @trace_id: trace_id of the whole path. + * @saved_mode: The saved device mode. It stores the source device's mode + * to represent the path mode during CPU hotplug off. */ struct coresight_path { struct list_head path_list; u8 trace_id; -}; - -enum cs_mode { - CS_MODE_DISABLED, - CS_MODE_SYSFS, - CS_MODE_PERF, - CS_MODE_DEBUG, + enum cs_mode saved_mode; };
#define coresight_ops(csdev) csdev->ops