diff options
Diffstat (limited to 'drivers/hwtracing/coresight/coresight-etm3x-core.c')
| -rw-r--r-- | drivers/hwtracing/coresight/coresight-etm3x-core.c | 207 |
1 files changed, 103 insertions, 104 deletions
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c index cf64ce73a741..a5e809589d3e 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 @@ -85,9 +86,9 @@ static void etm_set_pwrup(struct etm_drvdata *drvdata) { u32 etmpdcr; - etmpdcr = readl_relaxed(drvdata->base + ETMPDCR); + etmpdcr = readl_relaxed(drvdata->csa.base + ETMPDCR); etmpdcr |= ETMPDCR_PWD_UP; - writel_relaxed(etmpdcr, drvdata->base + ETMPDCR); + writel_relaxed(etmpdcr, drvdata->csa.base + ETMPDCR); /* Ensure pwrup completes before subsequent cp14 accesses */ mb(); isb(); @@ -100,9 +101,9 @@ static void etm_clr_pwrup(struct etm_drvdata *drvdata) /* Ensure pending cp14 accesses complete before clearing pwrup */ mb(); isb(); - etmpdcr = readl_relaxed(drvdata->base + ETMPDCR); + etmpdcr = readl_relaxed(drvdata->csa.base + ETMPDCR); etmpdcr &= ~ETMPDCR_PWD_UP; - writel_relaxed(etmpdcr, drvdata->base + ETMPDCR); + writel_relaxed(etmpdcr, drvdata->csa.base + ETMPDCR); } /** @@ -114,7 +115,7 @@ static void etm_clr_pwrup(struct etm_drvdata *drvdata) * * Basically the same as @coresight_timeout except for the register access * method where we have to account for CP14 configurations. - + * * Return: 0 as soon as the bit has taken the desired state or -EAGAIN if * TIMEOUT_US has elapsed, which ever happens first. */ @@ -204,7 +205,7 @@ void etm_set_default(struct etm_config *config) * set all bits in register 0x007, the ETMTECR2, to 0 * set register 0x008, the ETMTEEVR, to 0x6F (TRUE). */ - config->enable_ctrl1 = BIT(24); + config->enable_ctrl1 = ETMTECR1_INC_EXC; config->enable_ctrl2 = 0x0; config->enable_event = ETM_HARD_WIRE_RES_A; @@ -340,6 +341,10 @@ static int etm_parse_event_config(struct etm_drvdata *drvdata, config->ctrl = attr->config; + /* Don't trace contextID when runs in non-root PID namespace */ + if (!task_is_in_init_pid_ns(current)) + config->ctrl &= ~ETMCR_CTXID_SIZE; + /* * Possible to have cores with PTM (supports ret stack) and ETM * (never has ret stack) on the same SoC. So if we have a request @@ -360,7 +365,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata) struct etm_config *config = &drvdata->config; struct coresight_device *csdev = drvdata->csdev; - CS_UNLOCK(drvdata->base); + CS_UNLOCK(drvdata->csa.base); rc = coresight_claim_device_unlocked(csdev); if (rc) @@ -422,7 +427,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata) etm_clr_prog(drvdata); done: - CS_LOCK(drvdata->base); + CS_LOCK(drvdata->csa.base); dev_dbg(&drvdata->csdev->dev, "cpu: %d enable smp call done: %d\n", drvdata->cpu, rc); @@ -434,13 +439,26 @@ struct etm_enable_arg { int rc; }; -static void etm_enable_hw_smp_call(void *info) +static void etm_enable_sysfs_smp_call(void *info) { struct etm_enable_arg *arg = info; + struct coresight_device *csdev; if (WARN_ON(!arg)) return; + + csdev = arg->drvdata->csdev; + if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) { + /* Someone is already using the tracer */ + arg->rc = -EBUSY; + return; + } + arg->rc = etm_enable_hw(arg->drvdata); + + /* The tracer didn't start */ + if (arg->rc) + coresight_set_mode(csdev, CS_MODE_DISABLED); } static int etm_cpu_id(struct coresight_device *csdev) @@ -450,57 +468,39 @@ static int etm_cpu_id(struct coresight_device *csdev) return drvdata->cpu; } -int etm_get_trace_id(struct etm_drvdata *drvdata) +void etm_release_trace_id(struct etm_drvdata *drvdata) { - unsigned long flags; - int trace_id = -1; - struct device *etm_dev; - - 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: - return trace_id; - -} - -static int etm_trace_id(struct coresight_device *csdev) -{ - 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 perf_event *event, + struct coresight_path *path) { struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + int ret; if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) return -EINVAL; + if (!coresight_take_mode(csdev, CS_MODE_PERF)) + return -EBUSY; + /* Configure the tracer based on the session's specifics */ etm_parse_event_config(drvdata, event); + drvdata->traceid = path->trace_id; + /* And enable it */ - return etm_enable_hw(drvdata); + ret = etm_enable_hw(drvdata); + + /* Failed to start tracer; roll back to DISABLED mode */ + if (ret) + coresight_set_mode(csdev, CS_MODE_DISABLED); + + return ret; } -static int etm_enable_sysfs(struct coresight_device *csdev) +static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_path *path) { struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); struct etm_enable_arg arg = { }; @@ -508,6 +508,8 @@ static int etm_enable_sysfs(struct coresight_device *csdev) spin_lock(&drvdata->spinlock); + drvdata->traceid = path->trace_id; + /* * 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. @@ -515,7 +517,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev) if (cpu_online(drvdata->cpu)) { arg.drvdata = drvdata; ret = smp_call_function_single(drvdata->cpu, - etm_enable_hw_smp_call, &arg, 1); + etm_enable_sysfs_smp_call, &arg, 1); if (!ret) ret = arg.rc; if (!ret) @@ -524,6 +526,9 @@ static int etm_enable_sysfs(struct coresight_device *csdev) ret = -ENODEV; } + if (ret) + etm_release_trace_id(drvdata); + spin_unlock(&drvdata->spinlock); if (!ret) @@ -531,45 +536,32 @@ static int etm_enable_sysfs(struct coresight_device *csdev) return ret; } -static int etm_enable(struct coresight_device *csdev, - struct perf_event *event, u32 mode) +static int etm_enable(struct coresight_device *csdev, struct perf_event *event, + enum cs_mode mode, struct coresight_path *path) { int ret; - u32 val; - struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); - - val = local_cmpxchg(&drvdata->mode, CS_MODE_DISABLED, mode); - - /* Someone is already using the tracer */ - if (val) - return -EBUSY; switch (mode) { case CS_MODE_SYSFS: - ret = etm_enable_sysfs(csdev); + ret = etm_enable_sysfs(csdev, path); break; case CS_MODE_PERF: - ret = etm_enable_perf(csdev, event); + ret = etm_enable_perf(csdev, event, path); break; default: ret = -EINVAL; } - /* The tracer didn't start */ - if (ret) - local_set(&drvdata->mode, CS_MODE_DISABLED); - return ret; } -static void etm_disable_hw(void *info) +static void etm_disable_hw(struct etm_drvdata *drvdata) { int i; - struct etm_drvdata *drvdata = info; struct etm_config *config = &drvdata->config; struct coresight_device *csdev = drvdata->csdev; - CS_UNLOCK(drvdata->base); + CS_UNLOCK(drvdata->csa.base); etm_set_prog(drvdata); /* Read back sequencer and counters for post trace analysis */ @@ -581,12 +573,21 @@ static void etm_disable_hw(void *info) etm_set_pwrdwn(drvdata); coresight_disclaim_device_unlocked(csdev); - CS_LOCK(drvdata->base); + CS_LOCK(drvdata->csa.base); dev_dbg(&drvdata->csdev->dev, "cpu: %d disable smp call done\n", drvdata->cpu); } +static void etm_disable_sysfs_smp_call(void *info) +{ + struct etm_drvdata *drvdata = info; + + etm_disable_hw(drvdata); + + coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED); +} + static void etm_disable_perf(struct coresight_device *csdev) { struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); @@ -594,7 +595,7 @@ static void etm_disable_perf(struct coresight_device *csdev) if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) return; - CS_UNLOCK(drvdata->base); + CS_UNLOCK(drvdata->csa.base); /* Setting the prog bit disables tracing immediately */ etm_set_prog(drvdata); @@ -606,7 +607,15 @@ static void etm_disable_perf(struct coresight_device *csdev) etm_set_pwrdwn(drvdata); coresight_disclaim_device_unlocked(csdev); - CS_LOCK(drvdata->base); + CS_LOCK(drvdata->csa.base); + + coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED); + + /* + * 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) @@ -626,26 +635,33 @@ static void etm_disable_sysfs(struct coresight_device *csdev) * Executing etm_disable_hw on the cpu whose ETM is being disabled * ensures that register writes occur when cpu is powered. */ - smp_call_function_single(drvdata->cpu, etm_disable_hw, drvdata, 1); + smp_call_function_single(drvdata->cpu, etm_disable_sysfs_smp_call, + drvdata, 1); 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"); } static void etm_disable(struct coresight_device *csdev, struct perf_event *event) { - u32 mode; - struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + enum cs_mode mode; /* * For as long as the tracer isn't disabled another entity can't * change its status. As such we can read the status here without * fearing it will change under us. */ - mode = local_read(&drvdata->mode); + mode = coresight_get_mode(csdev); switch (mode) { case CS_MODE_DISABLED: @@ -660,19 +676,16 @@ static void etm_disable(struct coresight_device *csdev, WARN_ON_ONCE(mode); return; } - - if (mode) - local_set(&drvdata->mode, CS_MODE_DISABLED); } 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, }; static const struct coresight_ops etm_cs_ops = { + .trace_id = coresight_etm_get_trace_id, .source_ops = &etm_source_ops, }; @@ -682,7 +695,7 @@ static int etm_online_cpu(unsigned int cpu) return 0; if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) - coresight_enable(etmdrvdata[cpu]->csdev); + coresight_enable_sysfs(etmdrvdata[cpu]->csdev); return 0; } @@ -697,7 +710,7 @@ static int etm_starting_cpu(unsigned int cpu) etmdrvdata[cpu]->os_unlock = true; } - if (local_read(&etmdrvdata[cpu]->mode)) + if (coresight_get_mode(etmdrvdata[cpu]->csdev)) etm_enable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; @@ -709,7 +722,7 @@ static int etm_dying_cpu(unsigned int cpu) return 0; spin_lock(&etmdrvdata[cpu]->spinlock); - if (local_read(&etmdrvdata[cpu]->mode)) + if (coresight_get_mode(etmdrvdata[cpu]->csdev)) etm_disable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; @@ -741,7 +754,7 @@ static void etm_init_arch_data(void *info) /* Make sure all registers are accessible */ etm_os_unlock(drvdata); - CS_UNLOCK(drvdata->base); + CS_UNLOCK(drvdata->csa.base); /* First dummy read */ (void)etm_readl(drvdata, ETMPDSR); @@ -772,14 +785,10 @@ static void etm_init_arch_data(void *info) drvdata->nr_ext_out = BMVAL(etmccr, 20, 22); drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25); + coresight_clear_self_claim_tag_unlocked(&drvdata->csa); etm_set_pwrdwn(drvdata); etm_clr_pwrup(drvdata); - CS_LOCK(drvdata->base); -} - -static void etm_init_trace_id(struct etm_drvdata *drvdata) -{ - drvdata->traceid = coresight_get_trace_id(drvdata->cpu); + CS_LOCK(drvdata->csa.base); } static int __init etm_hp_setup(void) @@ -840,17 +849,13 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id) if (IS_ERR(base)) return PTR_ERR(base); - drvdata->base = base; - desc.access = CSDEV_ACCESS_IOMEM(base); + desc.access = drvdata->csa = CSDEV_ACCESS_IOMEM(base); spin_lock_init(&drvdata->spinlock); - drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ - if (!IS_ERR(drvdata->atclk)) { - ret = clk_prepare_enable(drvdata->atclk); - if (ret) - return ret; - } + drvdata->atclk = devm_clk_get_optional_enabled(dev, "atclk"); + if (IS_ERR(drvdata->atclk)) + return PTR_ERR(drvdata->atclk); drvdata->cpu = coresight_get_cpu(dev); if (drvdata->cpu < 0) @@ -867,7 +872,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); @@ -898,7 +902,7 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id) dev_info(&drvdata->csdev->dev, "%s initialized\n", (char *)coresight_get_uci_data(id)); if (boot_enable) { - coresight_enable(drvdata->csdev); + coresight_enable_sysfs(drvdata->csdev); drvdata->boot_enable = true; } @@ -942,8 +946,7 @@ static int etm_runtime_suspend(struct device *dev) { struct etm_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_disable_unprepare(drvdata->atclk); + clk_disable_unprepare(drvdata->atclk); return 0; } @@ -952,10 +955,7 @@ static int etm_runtime_resume(struct device *dev) { struct etm_drvdata *drvdata = dev_get_drvdata(dev); - if (drvdata && !IS_ERR(drvdata->atclk)) - clk_prepare_enable(drvdata->atclk); - - return 0; + return clk_prepare_enable(drvdata->atclk); } #endif @@ -976,7 +976,7 @@ static const struct amba_id etm_ids[] = { CS_AMBA_ID_DATA(0x000bb95f, "PTM 1.1"), /* PTM 1.1 Qualcomm */ CS_AMBA_ID_DATA(0x000b006f, "PTM 1.1"), - { 0, 0}, + { 0, 0, NULL}, }; MODULE_DEVICE_TABLE(amba, etm_ids); @@ -984,7 +984,6 @@ MODULE_DEVICE_TABLE(amba, etm_ids); static struct amba_driver etm_driver = { .drv = { .name = "coresight-etm3x", - .owner = THIS_MODULE, .pm = &etm_dev_pm_ops, .suppress_bind_attrs = true, }, |
