diff options
Diffstat (limited to 'drivers/hwtracing/coresight/coresight-etm3x-core.c')
-rw-r--r-- | drivers/hwtracing/coresight/coresight-etm3x-core.c | 93 |
1 files changed, 58 insertions, 35 deletions
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index d0ab9933472b..afc57195ee52 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c @@ -32,6 +32,7 @@ #include "coresight-etm.h" #include "coresight-etm-perf.h" +#include "coresight-trace-id.h" /* * Not really modular but using module_param is the easiest way to @@ -454,52 +455,59 @@ static int etm_cpu_id(struct coresight_device *csdev) return drvdata->cpu; } -int etm_get_trace_id(struct etm_drvdata *drvdata) +int etm_read_alloc_trace_id(struct etm_drvdata *drvdata) { - unsigned long flags; - int trace_id = -1; - struct device *etm_dev; + int trace_id; - if (!drvdata) - goto out; - - etm_dev = drvdata->csdev->dev.parent; - if (!local_read(&drvdata->mode)) - return drvdata->traceid; - - pm_runtime_get_sync(etm_dev); - - spin_lock_irqsave(&drvdata->spinlock, flags); - - CS_UNLOCK(drvdata->base); - trace_id = (etm_readl(drvdata, ETMTRACEIDR) & ETM_TRACEID_MASK); - CS_LOCK(drvdata->base); - - spin_unlock_irqrestore(&drvdata->spinlock, flags); - pm_runtime_put(etm_dev); - -out: + /* + * This will allocate a trace ID to the cpu, + * or return the one currently allocated. + * + * trace id function has its own lock + */ + trace_id = coresight_trace_id_get_cpu_id(drvdata->cpu); + if (IS_VALID_CS_TRACE_ID(trace_id)) + drvdata->traceid = (u8)trace_id; + else + dev_err(&drvdata->csdev->dev, + "Failed to allocate trace ID for %s on CPU%d\n", + dev_name(&drvdata->csdev->dev), drvdata->cpu); return trace_id; - } -static int etm_trace_id(struct coresight_device *csdev) +void etm_release_trace_id(struct etm_drvdata *drvdata) { - struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - - return etm_get_trace_id(drvdata); + coresight_trace_id_put_cpu_id(drvdata->cpu); } static int etm_enable_perf(struct coresight_device *csdev, struct perf_event *event) { struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + int trace_id; if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) return -EINVAL; /* Configure the tracer based on the session's specifics */ etm_parse_event_config(drvdata, event); + + /* + * perf allocates cpu ids as part of _setup_aux() - device needs to use + * the allocated ID. This reads the current version without allocation. + * + * This does not use the trace id lock to prevent lock_dep issues + * with perf locks - we know the ID cannot change until perf shuts down + * the session + */ + trace_id = coresight_trace_id_read_cpu_id(drvdata->cpu); + if (!IS_VALID_CS_TRACE_ID(trace_id)) { + dev_err(&drvdata->csdev->dev, "Failed to set trace ID for %s on CPU%d\n", + dev_name(&drvdata->csdev->dev), drvdata->cpu); + return -EINVAL; + } + drvdata->traceid = (u8)trace_id; + /* And enable it */ return etm_enable_hw(drvdata); } @@ -512,6 +520,11 @@ static int etm_enable_sysfs(struct coresight_device *csdev) spin_lock(&drvdata->spinlock); + /* sysfs needs to allocate and set a trace ID */ + ret = etm_read_alloc_trace_id(drvdata); + if (ret < 0) + goto unlock_enable_sysfs; + /* * Configure the ETM only if the CPU is online. If it isn't online * hw configuration will take place on the local CPU during bring up. @@ -528,6 +541,10 @@ static int etm_enable_sysfs(struct coresight_device *csdev) ret = -ENODEV; } + if (ret) + etm_release_trace_id(drvdata); + +unlock_enable_sysfs: spin_unlock(&drvdata->spinlock); if (!ret) @@ -611,6 +628,12 @@ static void etm_disable_perf(struct coresight_device *csdev) coresight_disclaim_device_unlocked(csdev); CS_LOCK(drvdata->base); + + /* + * perf will release trace ids when _free_aux() + * is called at the end of the session + */ + } static void etm_disable_sysfs(struct coresight_device *csdev) @@ -635,6 +658,13 @@ static void etm_disable_sysfs(struct coresight_device *csdev) spin_unlock(&drvdata->spinlock); cpus_read_unlock(); + /* + * we only release trace IDs when resetting sysfs. + * This permits sysfs users to read the trace ID after the trace + * session has completed. This maintains operational behaviour with + * prior trace id allocation method + */ + dev_dbg(&csdev->dev, "ETM tracing disabled\n"); } @@ -671,7 +701,6 @@ static void etm_disable(struct coresight_device *csdev, static const struct coresight_ops_source etm_source_ops = { .cpu_id = etm_cpu_id, - .trace_id = etm_trace_id, .enable = etm_enable, .disable = etm_disable, }; @@ -781,11 +810,6 @@ static void etm_init_arch_data(void *info) CS_LOCK(drvdata->base); } -static void etm_init_trace_id(struct etm_drvdata *drvdata) -{ - drvdata->traceid = coresight_get_trace_id(drvdata->cpu); -} - static int __init etm_hp_setup(void) { int ret; @@ -871,7 +895,6 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id) if (etm_arch_supported(drvdata->arch) == false) return -EINVAL; - etm_init_trace_id(drvdata); etm_set_default(&drvdata->config); pdata = coresight_get_platform_data(dev); |