coresight: Register CPU PM notifier in core layer

The current implementation only saves and restores the context for ETM
sources while ignoring the context of links.  However, if funnels or
replicators on a linked path resides in a CPU or cluster power domain,
the hardware context for the link will be lost after resuming from low
power states.

To support context management for links during CPU low power modes, a
better way is to implement CPU PM callbacks in the Arm CoreSight core
layer.  As the core layer has sufficient information for linked paths,
from tracers to links, which can be used for power management.

As a first step, this patch registers CPU PM notifier in the core layer.
If a source device provides callbacks for saving and restoring context,
these callbacks will be invoked in CPU suspend and resume.

Reviewed-by: James Clark <james.clark@linaro.org>
Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Tested-by: Jie Gan <jie.gan@oss.qualcomm.com>
Signed-off-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20260515-arm_coresight_path_power_management_improvement-v14-11-f88c4a3ecfe9@arm.com
This commit is contained in:
Leo Yan
2026-05-15 21:08:18 +01:00
committed by Suzuki K Poulose
parent d79125cc36
commit 4d8dd98ee5
2 changed files with 95 additions and 0 deletions

View File

@@ -6,6 +6,7 @@
#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/build_bug.h>
#include <linux/cpu_pm.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -1741,6 +1742,91 @@ static void coresight_release_device_list(void)
}
}
static struct coresight_device *coresight_cpu_get_active_source(void)
{
struct coresight_device *source;
bool is_active = false;
source = coresight_get_percpu_source_ref(smp_processor_id());
if (!source)
return NULL;
if (coresight_get_mode(source) != CS_MODE_DISABLED)
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 source. Here returns the active source pointer
* without concern that its state may change. Since the build path has
* taken a reference on the component, the source can be safely used
* by the caller.
*/
return is_active ? source : NULL;
}
static int coresight_pm_is_needed(struct coresight_device *csdev)
{
if (!csdev)
return 0;
/* pm_save_disable() and pm_restore_enable() must be paired */
if (coresight_ops(csdev)->pm_save_disable &&
coresight_ops(csdev)->pm_restore_enable)
return 1;
return 0;
}
static int coresight_pm_device_save(struct coresight_device *csdev)
{
return coresight_ops(csdev)->pm_save_disable(csdev);
}
static void coresight_pm_device_restore(struct coresight_device *csdev)
{
coresight_ops(csdev)->pm_restore_enable(csdev);
}
static int coresight_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
void *v)
{
struct coresight_device *csdev = coresight_cpu_get_active_source();
if (!coresight_pm_is_needed(csdev))
return NOTIFY_DONE;
switch (cmd) {
case CPU_PM_ENTER:
if (coresight_pm_device_save(csdev))
return NOTIFY_BAD;
break;
case CPU_PM_EXIT:
case CPU_PM_ENTER_FAILED:
coresight_pm_device_restore(csdev);
break;
default:
return NOTIFY_DONE;
}
return NOTIFY_OK;
}
static struct notifier_block coresight_cpu_pm_nb = {
.notifier_call = coresight_cpu_pm_notify,
};
static int __init coresight_pm_setup(void)
{
return cpu_pm_register_notifier(&coresight_cpu_pm_nb);
}
static void coresight_pm_cleanup(void)
{
cpu_pm_unregister_notifier(&coresight_cpu_pm_nb);
}
const struct bus_type coresight_bustype = {
.name = "coresight",
};
@@ -1795,9 +1881,15 @@ static int __init coresight_init(void)
/* initialise the coresight syscfg API */
ret = cscfg_init();
if (ret)
goto exit_notifier;
ret = coresight_pm_setup();
if (!ret)
return 0;
cscfg_exit();
exit_notifier:
atomic_notifier_chain_unregister(&panic_notifier_list,
&coresight_notifier);
exit_perf:
@@ -1809,6 +1901,7 @@ static int __init coresight_init(void)
static void __exit coresight_exit(void)
{
coresight_pm_cleanup();
cscfg_exit();
atomic_notifier_chain_unregister(&panic_notifier_list,
&coresight_notifier);

View File

@@ -438,6 +438,8 @@ struct coresight_ops_panic {
struct coresight_ops {
int (*trace_id)(struct coresight_device *csdev, enum cs_mode mode,
struct coresight_device *sink);
int (*pm_save_disable)(struct coresight_device *csdev);
void (*pm_restore_enable)(struct coresight_device *csdev);
const struct coresight_ops_sink *sink_ops;
const struct coresight_ops_link *link_ops;
const struct coresight_ops_source *source_ops;