summaryrefslogtreecommitdiff
path: root/drivers/hwtracing/coresight/coresight-etm3x-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwtracing/coresight/coresight-etm3x-core.c')
-rw-r--r--drivers/hwtracing/coresight/coresight-etm3x-core.c93
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);