On Wed, May 01, 2019 at 09:49:39AM +0100, Mike Leach wrote:
Notification mechanism for CPU power events such as CPU hotplug added as general notification mechnism in CoreSight common code to be used by all CPU bound CS devices.
Provides a per-device registration mechanism with callback fn and event type notifier. Core code now manages the CPU hotplug registrations and calls back any registered device when events occur.
Added registration call from CTI devices.
From what I understand Andrew Murray is currently working on something like
that. Have you guys had a chance to talk about this and compare strategies?
Signed-off-by: Mike Leach mike.leach@linaro.org
drivers/hwtracing/coresight/coresight-cti.c | 54 +++++++- drivers/hwtracing/coresight/coresight-priv.h | 25 ++++ drivers/hwtracing/coresight/coresight.c | 138 +++++++++++++++++++ 3 files changed, 213 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index e0192fd50804..faae7db44bd6 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -587,6 +587,38 @@ const struct coresight_ops cti_ops = { .ect_ops = &cti_ops_ect, }; +/* pm event notifiers */ +int cti_cs_cpupm_event(struct coresight_device *csdev, unsigned int cpuid,
enum cs_cpu_pm_events event)
+{
- struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
- switch (event) {
/* called on the device cpu during registration */
- case CS_CPUPM_SMP_ON_REG_CPU:
drvdata->config.hw_powered = true;
break;
/* cpu hotplug start */
- case CS_CPUPM_CPUHP_START:
spin_lock(&drvdata->spinlock);
drvdata->config.hw_powered = true;
spin_unlock(&drvdata->spinlock);
if (atomic_read(&drvdata->config.enable_req_count))
cti_enable_hw(drvdata);
break;
/* cpu hotplug stop */
- case CS_CPUPM_CPUHP_STOP:
cti_disable_hw(drvdata);
spin_lock(&drvdata->spinlock);
drvdata->config.hw_powered = false;
spin_unlock(&drvdata->spinlock);
break;
- }
- return 0;
+}
static int cti_probe(struct amba_device *adev, const struct amba_id *id) { int ret = 0; @@ -668,9 +700,6 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) /* initialise default driver values */ cti_set_default_config(&drvdata->config);
- /* setup cpu related CTI devices, otherwise assume powered */
- drvdata->config.hw_powered = true;
- /* create dynamic attributes for connections */ ret = cti_create_cons_sysfs(drvdata); if (ret) {
@@ -693,6 +722,19 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) goto err_out; }
- /* setup cpu related CTI PM, otherwise assume powered */
- if (drvdata->ctidev.cpu >= 0) {
drvdata->config.hw_powered = false;
ret = coresight_cpupm_register(drvdata->csdev,
drvdata->ctidev.cpu,
cti_cs_cpupm_event);
if (ret) {
pr_err("%s: CS cpu pm register failed\n", pdata->name);
goto err_out;
}
- } else
drvdata->config.hw_powered = true;
- /* add to list of CTI devices */ mutex_lock(&ect_mutex); ect_nd->cti_drv = drvdata;
@@ -719,6 +761,8 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) return 0; err_out:
- if (drvdata->csdev && (drvdata->ctidev.cpu >= 0))
kfree(drvdata); kfree(ect_nd); return ret;coresight_cpupm_unregister(drvdata->csdev, drvdata->ctidev.cpu);
@@ -751,8 +795,10 @@ void cti_device_release(struct device *dev) struct ect_node *ect_item, *ect_tmp; /* free up resources associated with the cti connections */
- if (drvdata->ctidev.cpu >= 0)
- if (drvdata->ctidev.cpu >= 0) { cti_cpu_drv[drvdata->ctidev.cpu] = 0;
coresight_cpupm_unregister(drvdata->csdev, drvdata->ctidev.cpu);
- }
/* clear the dynamic sysfs associate with connections */ cti_destroy_cons_sysfs(&drvdata->ctidev); diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index b1fca5c4bdb2..716669b2a40a 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -212,4 +212,29 @@ static inline void *coresight_get_uci_data(const struct amba_id *id) return 0; } +/*
- cpu power management - allow any CPU bound Coresight device
- to use a common registration infrastructure for notifications.
- */
+/* cpu pm event types */ +enum cs_cpu_pm_events {
- CS_CPUPM_SMP_ON_REG_CPU,/* smp call on cpu at registration */
- CS_CPUPM_CPUHP_START, /* hotplug starting CPU */
- CS_CPUPM_CPUHP_STOP, /* hotplug stopping CPU */
+};
+/* callback function type */ +typedef int (*p_cs_cpu_pm_event)(struct coresight_device *csdev,
unsigned int cpuid,
enum cs_cpu_pm_events event);
+/* registration functions */ +int coresight_cpupm_register(struct coresight_device *csdev,
unsigned int cpuid,
p_cs_cpu_pm_event callback);
+void coresight_cpupm_unregister(struct coresight_device *csdev,
unsigned int cpuid);
#endif diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 9d56b3b32172..afcc330e61eb 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -1295,3 +1295,141 @@ void coresight_unregister(struct coresight_device *csdev) device_unregister(&csdev->dev); } EXPORT_SYMBOL_GPL(coresight_unregister);
+/* cs general CPU bound device pm notification */ +struct coresight_cpupm_item {
- struct coresight_device *csdev;
- p_cs_cpu_pm_event callback;
- struct list_head node;
+};
+/* CS cpu pm notifier lists per cpu */ +static DEFINE_PER_CPU(struct list_head *, cs_cpupm_notifier);
+static enum cpuhp_state cscpu_hp_online; +static int cscpu_dev_reg_cnt;
+static int coresight_iterate_cpu_event_list(unsigned int cpu,
enum cs_cpu_pm_events event)
+{
- struct list_head *cpu_list;
- struct coresight_cpupm_item *item;
- mutex_lock(&coresight_mutex);
- cpu_list = per_cpu(cs_cpupm_notifier, cpu);
- if (!list_empty(cpu_list)) {
list_for_each_entry(item, cpu_list, node) {
item->callback(item->csdev, cpu, event);
}
- }
- mutex_unlock(&coresight_mutex);
- return 0;
+}
+static int coresight_hp_starting_cpu(unsigned int cpu) +{
- return coresight_iterate_cpu_event_list(cpu, CS_CPUPM_CPUHP_START);
+}
+static int coresight_hp_stopping_cpu(unsigned int cpu) +{
- return coresight_iterate_cpu_event_list(cpu, CS_CPUPM_CPUHP_STOP);
+}
+struct cs_smp_reg_cb_info {
- unsigned int cpu;
- struct coresight_cpupm_item *item;
+};
+static void coresight_smp_onreg_callback(void *info) +{
- struct cs_smp_reg_cb_info *cb_info = info;
- cb_info->item->callback(cb_info->item->csdev, cb_info->cpu,
CS_CPUPM_SMP_ON_REG_CPU);
+}
+int coresight_cpupm_register(struct coresight_device *csdev,
unsigned int cpuid,
p_cs_cpu_pm_event callback)
+{
- struct list_head *cpu_list;
- struct coresight_cpupm_item *item;
- int err = 0;
- struct cs_smp_reg_cb_info on_reg_cb_info;
- mutex_lock(&coresight_mutex);
- cpu_list = per_cpu(cs_cpupm_notifier, cpuid);
- /* init list if no head yet */
- if (!cpu_list) {
cpu_list = kzalloc(sizeof(struct list_head), GFP_KERNEL);
if (!cpu_list)
goto cpupm_reg_done;
else
INIT_LIST_HEAD(cpu_list);
- }
- /* create a list item */
- item = kzalloc(sizeof(struct coresight_cpupm_item), GFP_KERNEL);
- if (!item) {
err = -ENOMEM;
goto cpupm_reg_done;
- }
- item->csdev = csdev;
- item->callback = callback;
- /* init the cpu hotplug notification */
- cpus_read_lock();
- if (!cscpu_dev_reg_cnt) {
cscpu_hp_online = cpuhp_setup_state_nocalls_cpuslocked(
CPUHP_AP_ONLINE_DYN, "arm/coresightcpu:online",
coresight_hp_starting_cpu,
coresight_hp_stopping_cpu);
if (cscpu_hp_online < 0) {
err = cscpu_hp_online;
kfree(item);
goto cpupm_hp_done;
}
- }
- cscpu_dev_reg_cnt++;
- list_add(&item->node, cpu_list);
- /* smp callback on dev cpu @ registration */
- on_reg_cb_info.item = item;
- on_reg_cb_info.cpu = cpuid;
- smp_call_function_single(cpuid, coresight_smp_onreg_callback,
&on_reg_cb_info, 1);
+cpupm_hp_done:
- cpus_read_unlock();
+cpupm_reg_done:
- mutex_unlock(&coresight_mutex);
- return err;
+} +EXPORT_SYMBOL_GPL(coresight_cpupm_register);
+void coresight_cpupm_unregister(struct coresight_device *csdev,
unsigned int cpuid)
+{
- struct list_head *cpu_list;
- struct coresight_cpupm_item *item, *tmp;
- mutex_lock(&coresight_mutex);
- cpu_list = per_cpu(cs_cpupm_notifier, cpuid);
- if (!list_empty(cpu_list)) {
list_for_each_entry_safe(item, tmp, cpu_list, node) {
if (item->csdev == csdev) {
list_del(&item->node);
kfree(item);
goto cs_cpupm_item_removed;
}
}
- }
+cs_cpupm_item_removed:
- mutex_unlock(&coresight_mutex);
+}
+EXPORT_SYMBOL_GPL(coresight_cpupm_unregister);
2.20.1