Unlike a system level's sink, the per-CPU sink may lose power during CPU idle states. Currently, this refers specifically to TRBE as the sink. This commit registers save and restore callbacks for the per-CPU sink via the PM notifier.
Signed-off-by: Leo Yan leo.yan@arm.com --- drivers/hwtracing/coresight/coresight-core.c | 53 +++++++++++++++++++++++----- include/linux/coresight.h | 4 +++ 2 files changed, 49 insertions(+), 8 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 73be22c8f315525111f2dafd692e61bc6db85c25..7095f9befa98c7d638f857466351ef7cd960fde7 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -1659,8 +1659,25 @@ static bool coresight_pm_is_needed(struct coresight_device *csdev) return coresight_ops(csdev)->pm_is_needed(csdev); }
+static int coresight_pm_percpu_sink_save(struct coresight_device *sink) +{ + if (!sink || !coresight_ops(sink)->pm_save_disable) + return 0; + + return coresight_ops(sink)->pm_save_disable(sink); +} + +static void coresight_pm_percpu_sink_restore(struct coresight_device *sink) +{ + if (!sink || !coresight_ops(sink)->pm_restore_enable) + return; + + coresight_ops(sink)->pm_restore_enable(sink); +} + static int coresight_pm_save(struct coresight_device *csdev) { + struct coresight_device *sink; int ret;
if (WARN_ON(!csdev->path)) @@ -1670,22 +1687,42 @@ static int coresight_pm_save(struct coresight_device *csdev) if (ret) return ret;
- coresight_disable_helpers(csdev, NULL); - coresight_disable_path_from(csdev->path, NULL, true); + sink = coresight_get_sink(csdev->path); + + if (coresight_is_percpu_sink(sink)) { + ret = coresight_pm_percpu_sink_save(sink); + if (ret) { + coresight_ops(csdev)->pm_restore_enable(csdev); + return ret; + } + } else { + coresight_disable_helpers(csdev, NULL); + coresight_disable_path_from(csdev->path, NULL, true); + } + return 0; }
static void coresight_pm_restore(struct coresight_device *csdev) { + struct coresight_device *sink; + if (WARN_ON(!csdev->path)) return;
- /* - * During CPU idle, the sink device is not accessed, so it is okay to - * pass a NULL pointer for the 'sink_data' parameter. - */ - coresight_enable_path_internal(csdev->path, coresight_get_mode(csdev), - NULL, true); + sink = coresight_get_sink(csdev->path); + + if (coresight_is_percpu_sink(sink)) + coresight_pm_percpu_sink_restore(sink); + else + /* + * During CPU idle, the sink device is not accessed, so it is + * okay to pass a NULL pointer for the 'sink_data' parameter. + */ + coresight_enable_path_internal(csdev->path, + coresight_get_mode(csdev), + NULL, true); + coresight_ops(csdev)->pm_restore_enable(csdev); }
diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 58484c225e58a68dd74739a48c08a409ce9ddd73..d2f02f6322e69bfbda82f5df5d90cb8afeb7d21d 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -364,6 +364,8 @@ enum cs_mode { * @alloc_buffer: initialises perf's ring buffer for trace collection. * @free_buffer: release memory allocated in @get_config. * @update_buffer: update buffer pointers after a trace session. + * @save: save context for a sink. + * @restore: restore context for a sink. */ struct coresight_ops_sink { int (*enable)(struct coresight_device *csdev, enum cs_mode mode, @@ -376,6 +378,8 @@ struct coresight_ops_sink { unsigned long (*update_buffer)(struct coresight_device *csdev, struct perf_output_handle *handle, void *sink_config); + int (*save)(struct coresight_device *csdev); + int (*restore)(struct coresight_device *csdev); };
/**