CPU bound CTI's require registration with CPU power event handling to ensure we know when device power state changes alongside associated CPU.
Signed-off-by: Mike Leach mike.leach@linaro.org --- drivers/hwtracing/coresight/coresight-cti.c | 59 +++++++++++++++++++++ 1 file changed, 59 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c index 6996b70f99e8..c58173d4b11b 100644 --- a/drivers/hwtracing/coresight/coresight-cti.c +++ b/drivers/hwtracing/coresight/coresight-cti.c @@ -91,6 +91,11 @@ static int cti_enable_hw(struct cti_drvdata *drvdata, bool update_refcount) if (config->hw_enabled || !config->hw_powered) goto cti_not_enabled;
+ /* if not updating refcount and it is 0 then nothing to do */ + if (!update_refcount && + (atomic_read(&drvdata->config.enable_req_count) == 0)) + goto cti_not_enabled; + /* claim the device */ rc = coresight_claim_device(drvdata->base); if (rc) @@ -584,6 +589,40 @@ 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_CS_START: + spin_lock(&drvdata->spinlock); + drvdata->config.hw_powered = true; + spin_unlock(&drvdata->spinlock); + cti_enable_hw(drvdata, false); + break; + + /* cpu hotplug stop */ + case CS_CPUPM_CPUHP_CS_STOP: + cti_disable_hw(drvdata, false); + spin_lock(&drvdata->spinlock); + drvdata->config.hw_powered = false; + spin_unlock(&drvdata->spinlock); + break; + + default: + break; + } + return 0; +} + static int cti_probe(struct amba_device *adev, const struct amba_id *id) { int ret = 0; @@ -594,6 +633,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) struct coresight_platform_data *pdata = NULL; struct resource *res = &adev->res; struct ect_node *ect_nd = NULL; + bool cpupm_registered = false;
/* node to keep track of CTI net */ ect_nd = devm_kzalloc(dev, sizeof(struct ect_node), GFP_KERNEL); @@ -676,6 +716,20 @@ 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 error\n", cti_desc.name); + goto err_out; + } + cpupm_registered = true; + } else + drvdata->config.hw_powered = true; + /* add to list of CTI devices */ mutex_lock(&ect_mutex); ect_nd->cti_drv = drvdata; @@ -696,6 +750,8 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) return 0;
err_out: + if (cpupm_registered && drvdata->csdev && (drvdata->ctidev.cpu >= 0)) + coresight_cpupm_unregister(drvdata->csdev, drvdata->ctidev.cpu); return ret; }
@@ -726,6 +782,9 @@ void cti_device_release(struct device *dev) struct ect_node *ect_item, *ect_tmp;
mutex_lock(&ect_mutex); + /* free up resources associated with the cti connections */ + if (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);