diff options
Diffstat (limited to 'drivers/hwtracing/coresight/coresight-etm4x-core.c')
-rw-r--r-- | drivers/hwtracing/coresight/coresight-etm4x-core.c | 122 |
1 files changed, 61 insertions, 61 deletions
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index 3d98e3371fff..2b8f10463840 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -24,7 +24,6 @@ #include <linux/cpu_pm.h> #include <linux/coresight.h> #include <linux/coresight-pmu.h> -#include <linux/pm_wakeup.h> #include <linux/amba/bus.h> #include <linux/seq_file.h> #include <linux/uaccess.h> @@ -233,25 +232,6 @@ static int etm4_cpu_id(struct coresight_device *csdev) return drvdata->cpu; } -int etm4_read_alloc_trace_id(struct etmv4_drvdata *drvdata) -{ - int trace_id; - - /* - * This will allocate a trace ID to the cpu, - * or return the one currently allocated. - * The 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->trcid = (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; -} - void etm4_release_trace_id(struct etmv4_drvdata *drvdata) { coresight_trace_id_put_cpu_id(drvdata->cpu); @@ -428,6 +408,29 @@ static void etm4_check_arch_features(struct etmv4_drvdata *drvdata, } #endif /* CONFIG_ETM4X_IMPDEF_FEATURE */ +static void etm4x_sys_ins_barrier(struct csdev_access *csa, u32 offset, int pos, int val) +{ + if (!csa->io_mem) + isb(); +} + +/* + * etm4x_wait_status: Poll for TRCSTATR.<pos> == <val>. While using system + * instruction to access the trace unit, each access must be separated by a + * synchronization barrier. See ARM IHI0064H.b section "4.3.7 Synchronization of + * register updates", for system instructions section, in "Notes": + * + * "In particular, whenever disabling or enabling the trace unit, a poll of + * TRCSTATR needs explicit synchronization between each read of TRCSTATR" + */ +static int etm4x_wait_status(struct csdev_access *csa, int pos, int val) +{ + if (!csa->io_mem) + return coresight_timeout_action(csa, TRCSTATR, pos, val, + etm4x_sys_ins_barrier); + return coresight_timeout(csa, TRCSTATR, pos, val); +} + static int etm4_enable_hw(struct etmv4_drvdata *drvdata) { int i, rc; @@ -459,7 +462,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata) isb(); /* wait for TRCSTATR.IDLE to go up */ - if (coresight_timeout(csa, TRCSTATR, TRCSTATR_IDLE_BIT, 1)) + if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 1)) dev_err(etm_dev, "timeout while waiting for Idle Trace Status\n"); if (drvdata->nr_pe) @@ -552,7 +555,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata) isb(); /* wait for TRCSTATR.IDLE to go back down to '0' */ - if (coresight_timeout(csa, TRCSTATR, TRCSTATR_IDLE_BIT, 0)) + if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 0)) dev_err(etm_dev, "timeout while waiting for Idle Trace Status\n"); @@ -788,9 +791,9 @@ out: static int etm4_enable_perf(struct coresight_device *csdev, struct perf_event *event, - struct coresight_trace_id_map *id_map) + struct coresight_path *path) { - int ret = 0, trace_id; + int ret = 0; struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) { @@ -803,22 +806,7 @@ static int etm4_enable_perf(struct coresight_device *csdev, if (ret) goto out; - /* - * 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_map(drvdata->cpu, id_map); - 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); - ret = -EINVAL; - goto out; - } - drvdata->trcid = (u8)trace_id; + drvdata->trcid = path->trace_id; /* And enable it */ ret = etm4_enable_hw(drvdata); @@ -827,7 +815,7 @@ out: return ret; } -static int etm4_enable_sysfs(struct coresight_device *csdev) +static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_path *path) { struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); struct etm4_enable_arg arg = { }; @@ -842,12 +830,9 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) return ret; } - spin_lock(&drvdata->spinlock); + raw_spin_lock(&drvdata->spinlock); - /* sysfs needs to read and allocate a trace ID */ - ret = etm4_read_alloc_trace_id(drvdata); - if (ret < 0) - goto unlock_sysfs_enable; + drvdata->trcid = path->trace_id; /* * Executing etm4_enable_hw on the cpu whose ETM is being enabled @@ -864,8 +849,7 @@ static int etm4_enable_sysfs(struct coresight_device *csdev) if (ret) etm4_release_trace_id(drvdata); -unlock_sysfs_enable: - spin_unlock(&drvdata->spinlock); + raw_spin_unlock(&drvdata->spinlock); if (!ret) dev_dbg(&csdev->dev, "ETM tracing enabled\n"); @@ -873,7 +857,7 @@ unlock_sysfs_enable: } static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, - enum cs_mode mode, struct coresight_trace_id_map *id_map) + enum cs_mode mode, struct coresight_path *path) { int ret; @@ -884,10 +868,10 @@ static int etm4_enable(struct coresight_device *csdev, struct perf_event *event, switch (mode) { case CS_MODE_SYSFS: - ret = etm4_enable_sysfs(csdev); + ret = etm4_enable_sysfs(csdev, path); break; case CS_MODE_PERF: - ret = etm4_enable_perf(csdev, event, id_map); + ret = etm4_enable_perf(csdev, event, path); break; default: ret = -EINVAL; @@ -941,10 +925,25 @@ static void etm4_disable_hw(void *info) tsb_csync(); etm4x_relaxed_write32(csa, control, TRCPRGCTLR); + /* + * As recommended by section 4.3.7 ("Synchronization when using system + * instructions to progrom the trace unit") of ARM IHI 0064H.b, the + * self-hosted trace analyzer must perform a Context synchronization + * event between writing to the TRCPRGCTLR and reading the TRCSTATR. + */ + if (!csa->io_mem) + isb(); + /* wait for TRCSTATR.PMSTABLE to go to '1' */ - if (coresight_timeout(csa, TRCSTATR, TRCSTATR_PMSTABLE_BIT, 1)) + if (etm4x_wait_status(csa, TRCSTATR_PMSTABLE_BIT, 1)) dev_err(etm_dev, "timeout while waiting for PM stable Trace Status\n"); + /* + * As recommended by section 4.3.7 (Synchronization of register updates) + * of ARM IHI 0064H.b. + */ + isb(); + /* read the status of the single shot comparators */ for (i = 0; i < drvdata->nr_ss_cmp; i++) { config->ss_status[i] = @@ -1012,7 +1011,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) * DYING hotplug callback is serviced by the ETM driver. */ cpus_read_lock(); - spin_lock(&drvdata->spinlock); + raw_spin_lock(&drvdata->spinlock); /* * Executing etm4_disable_hw on the cpu whose ETM is being disabled @@ -1020,7 +1019,7 @@ static void etm4_disable_sysfs(struct coresight_device *csdev) */ smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1); - spin_unlock(&drvdata->spinlock); + raw_spin_unlock(&drvdata->spinlock); cpus_read_unlock(); /* @@ -1067,6 +1066,7 @@ static const struct coresight_ops_source etm4_source_ops = { }; static const struct coresight_ops etm4_cs_ops = { + .trace_id = coresight_etm_get_trace_id, .source_ops = &etm4_source_ops, }; @@ -1698,13 +1698,13 @@ static int etm4_starting_cpu(unsigned int cpu) if (!etmdrvdata[cpu]) return 0; - spin_lock(&etmdrvdata[cpu]->spinlock); + raw_spin_lock(&etmdrvdata[cpu]->spinlock); if (!etmdrvdata[cpu]->os_unlock) etm4_os_unlock(etmdrvdata[cpu]); if (coresight_get_mode(etmdrvdata[cpu]->csdev)) etm4_enable_hw(etmdrvdata[cpu]); - spin_unlock(&etmdrvdata[cpu]->spinlock); + raw_spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; } @@ -1713,10 +1713,10 @@ static int etm4_dying_cpu(unsigned int cpu) if (!etmdrvdata[cpu]) return 0; - spin_lock(&etmdrvdata[cpu]->spinlock); + raw_spin_lock(&etmdrvdata[cpu]->spinlock); if (coresight_get_mode(etmdrvdata[cpu]->csdev)) etm4_disable_hw(etmdrvdata[cpu]); - spin_unlock(&etmdrvdata[cpu]->spinlock); + raw_spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; } @@ -1746,7 +1746,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata) etm4_os_lock(drvdata); /* wait for TRCSTATR.PMSTABLE to go up */ - if (coresight_timeout(csa, TRCSTATR, TRCSTATR_PMSTABLE_BIT, 1)) { + if (etm4x_wait_status(csa, TRCSTATR_PMSTABLE_BIT, 1)) { dev_err(etm_dev, "timeout while waiting for PM Stable Status\n"); etm4_os_unlock(drvdata); @@ -1837,7 +1837,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata) state->trcpdcr = etm4x_read32(csa, TRCPDCR); /* wait for TRCSTATR.IDLE to go up */ - if (coresight_timeout(csa, TRCSTATR, TRCSTATR_IDLE_BIT, 1)) { + if (etm4x_wait_status(csa, TRCSTATR_PMSTABLE_BIT, 1)) { dev_err(etm_dev, "timeout while waiting for Idle Trace Status\n"); etm4_os_unlock(drvdata); @@ -2160,7 +2160,7 @@ static int etm4_probe(struct device *dev) return -ENOMEM; } - spin_lock_init(&drvdata->spinlock); + raw_spin_lock_init(&drvdata->spinlock); drvdata->cpu = coresight_get_cpu(dev); if (drvdata->cpu < 0) |