lkml.org 
[lkml]   [2015]   [Sep]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC PATCH 01/20] coresight: etm3x: splitting 'etm_enable_hw()' operations
    Date
    When dealing with other kernel subsystems or automated tools it
    is desirable to split the current etm_enable_hw() operation
    in three: power up, configuration and enabling of the tracer.

    That way it is possible to have more control on the operations
    done by a tracer.

    Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
    ---
    drivers/hwtracing/coresight/coresight-etm3x.c | 167 +++++++++++++++++++++-----
    include/linux/coresight.h | 10 +-
    2 files changed, 146 insertions(+), 31 deletions(-)

    diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c
    index d630b7ece735..999c62a59c70 100644
    --- a/drivers/hwtracing/coresight/coresight-etm3x.c
    +++ b/drivers/hwtracing/coresight/coresight-etm3x.c
    @@ -247,11 +247,12 @@ static void etm_set_default(struct etm_drvdata *drvdata)
    drvdata->ctxid_mask = 0x0;
    }

    -static void etm_enable_hw(void *info)
    +static void etm_power_up_cpu(void *info)
    {
    - int i;
    - u32 etmcr;
    - struct etm_drvdata *drvdata = info;
    + struct coresight_device *csdev = info;
    + struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
    +
    + WARN_ON(drvdata->cpu != smp_processor_id());

    CS_UNLOCK(drvdata->base);

    @@ -262,10 +263,65 @@ static void etm_enable_hw(void *info)
    /* Make sure all registers are accessible */
    etm_os_unlock(drvdata);

    + CS_LOCK(drvdata->base);
    +}
    +
    +static int etm_power_up(struct coresight_device *csdev)
    +{
    + struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
    +
    + /* tell the core we need this tracer */
    + pm_runtime_get_sync(csdev->dev.parent);
    +
    + return smp_call_function_single(drvdata->cpu,
    + etm_power_up_cpu, csdev, 1);
    +}
    +
    +static void etm_power_down_cpu(void *info)
    +{
    + struct coresight_device *csdev = info;
    + struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
    +
    + WARN_ON(drvdata->cpu != smp_processor_id());
    +
    + CS_UNLOCK(drvdata->base);
    + etm_clr_pwrup(drvdata);
    + etm_set_pwrdwn(drvdata);
    + CS_LOCK(drvdata->base);
    +}
    +
    +static void etm_power_down(struct coresight_device *csdev)
    +{
    + struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
    +
    + smp_call_function_single(drvdata->cpu,
    + etm_power_down_cpu, csdev, 1);
    +
    + /* tell the core this tracer is no longer needed */
    + pm_runtime_put(csdev->dev.parent);
    +}
    +
    +/**
    + * etm_configure_cpu - configure ETM registers
    + * @csdev - the etm that needs to be configure.
    + *
    + * Applies a configuration set to the ETM registers _without_ enabling the
    + * tracer. This function needs to be executed on the CPU who's tracer is
    + * being configured.
    + */
    +static void etm_configure_cpu(void *info)
    +{
    + int i;
    + u32 etmcr;
    + struct coresight_device *csdev = info;
    + struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
    +
    + WARN_ON(drvdata->cpu != smp_processor_id());
    +
    + CS_UNLOCK(drvdata->base);
    etm_set_prog(drvdata);

    etmcr = etm_readl(drvdata, ETMCR);
    - etmcr &= (ETMCR_PWD_DWN | ETMCR_ETM_PRG);
    etmcr |= drvdata->port_size;
    etm_writel(drvdata, drvdata->ctrl | etmcr, ETMCR);
    etm_writel(drvdata, drvdata->trigger_event, ETMTRIGGER);
    @@ -306,13 +362,71 @@ static void etm_enable_hw(void *info)
    /* No VMID comparator value selected */
    etm_writel(drvdata, 0x0, ETMVMIDCVR);

    - /* Ensures trace output is enabled from this ETM */
    - etm_writel(drvdata, drvdata->ctrl | ETMCR_ETM_EN | etmcr, ETMCR);
    + etm_clr_prog(drvdata);
    + CS_LOCK(drvdata->base);
    +}
    +
    +static int etm_configure(struct coresight_device *csdev)
    +{
    + struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
    +
    + return smp_call_function_single(drvdata->cpu,
    + etm_configure_cpu, csdev, 1);
    +}
    +
    +/**
    + * etm_trace_enable - enable ETM tracer
    + * @csdev - the etm that needs to be enabled/disabled.
    + * @enable - whether to enable or disable the tracer.
    + *
    + * Only enables the tracer - register configuration should have been made
    + * prior to calling this function. This should be executed on the CPU who's
    + * tracer is being enabled.
    + */
    +static int etm_trace_enable(struct coresight_device *csdev, bool enable)
    +{
    + u32 etmcr;
    + struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
    +
    + WARN_ON(drvdata->cpu != smp_processor_id());
    +
    + /*
    + * It is assumed that etm_configure_cpu() has been called. As such
    + * the ETM should be turned on, power applied to the trace registers
    + * and all registers accessible.
    + */
    + CS_UNLOCK(drvdata->base);
    + etm_set_prog(drvdata);
    +
    + etmcr = etm_readl(drvdata, ETMCR);
    +
    + enable ? (etmcr |= ETMCR_ETM_EN) :
    + (etmcr &= ~ETMCR_ETM_EN);
    +
    + etm_writel(drvdata, ETMCR_ETM_EN | etmcr, ETMCR);

    etm_clr_prog(drvdata);
    CS_LOCK(drvdata->base);

    + return 0;
    +}
    +
    +static void etm_config_enable(void *info)
    +{
    + struct coresight_device *csdev = info;
    + struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
    +
    + spin_lock(&drvdata->spinlock);
    +
    + etm_power_up_cpu(csdev);
    + etm_configure_cpu(csdev);
    + etm_trace_enable(csdev, true);
    dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu);
    +
    + drvdata->enable = true;
    + drvdata->sticky_enable = true;
    +
    + spin_unlock(&drvdata->spinlock);
    }

    static int etm_trace_id(struct coresight_device *csdev)
    @@ -339,11 +453,8 @@ static int etm_trace_id(struct coresight_device *csdev)

    static int etm_enable(struct coresight_device *csdev)
    {
    - struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
    int ret;
    -
    - pm_runtime_get_sync(csdev->dev.parent);
    - spin_lock(&drvdata->spinlock);
    + struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);

    /*
    * Configure the ETM only if the CPU is online. If it isn't online
    @@ -352,34 +463,28 @@ static int etm_enable(struct coresight_device *csdev)
    */
    if (cpu_online(drvdata->cpu)) {
    ret = smp_call_function_single(drvdata->cpu,
    - etm_enable_hw, drvdata, 1);
    + etm_config_enable, csdev, 1);
    if (ret)
    goto err;
    }

    - drvdata->enable = true;
    - drvdata->sticky_enable = true;
    -
    - spin_unlock(&drvdata->spinlock);
    -
    dev_info(drvdata->dev, "ETM tracing enabled\n");
    return 0;
    err:
    - spin_unlock(&drvdata->spinlock);
    - pm_runtime_put(csdev->dev.parent);
    return ret;
    }

    -static void etm_disable_hw(void *info)
    +static void etm_disable_powerdown(void *info)
    {
    int i;
    struct etm_drvdata *drvdata = info;

    + spin_lock(&drvdata->spinlock);
    CS_UNLOCK(drvdata->base);
    etm_set_prog(drvdata);

    - /* Program trace enable to low by using always false event */
    - etm_writel(drvdata, ETM_HARD_WIRE_RES_A | ETM_EVENT_NOT_A, ETMTEEVR);
    + etm_trace_enable(drvdata->csdev, false);
    + drvdata->enable = false;

    /* Read back sequencer and counters for post trace analysis */
    drvdata->seq_curr_state = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
    @@ -387,8 +492,9 @@ static void etm_disable_hw(void *info)
    for (i = 0; i < drvdata->nr_cntr; i++)
    drvdata->cntr_val[i] = etm_readl(drvdata, ETMCNTVRn(i));

    - etm_set_pwrdwn(drvdata);
    + etm_power_down(drvdata->csdev);
    CS_LOCK(drvdata->base);
    + spin_unlock(&drvdata->spinlock);

    dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
    }
    @@ -404,26 +510,27 @@ static void etm_disable(struct coresight_device *csdev)
    * DYING hotplug callback is serviced by the ETM driver.
    */
    get_online_cpus();
    - spin_lock(&drvdata->spinlock);

    /*
    * 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);
    - drvdata->enable = false;
    + smp_call_function_single(drvdata->cpu,
    + etm_disable_powerdown, drvdata, 1);

    - spin_unlock(&drvdata->spinlock);
    put_online_cpus();
    - pm_runtime_put(csdev->dev.parent);

    dev_info(drvdata->dev, "ETM tracing disabled\n");
    }

    static const struct coresight_ops_source etm_source_ops = {
    .trace_id = etm_trace_id,
    + .configure = etm_configure,
    + .trace_enable = etm_trace_enable,
    .enable = etm_enable,
    .disable = etm_disable,
    + .poweron = etm_power_up,
    + .poweroff = etm_power_down,
    };

    static const struct coresight_ops etm_cs_ops = {
    @@ -1659,7 +1766,7 @@ static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
    }

    if (etmdrvdata[cpu]->enable)
    - etm_enable_hw(etmdrvdata[cpu]);
    + etm_config_enable(etmdrvdata[cpu]->csdev);
    spin_unlock(&etmdrvdata[cpu]->spinlock);
    break;

    @@ -1672,7 +1779,7 @@ static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
    case CPU_DYING:
    spin_lock(&etmdrvdata[cpu]->spinlock);
    if (etmdrvdata[cpu]->enable)
    - etm_disable_hw(etmdrvdata[cpu]);
    + etm_disable_powerdown(etmdrvdata[cpu]->csdev);
    spin_unlock(&etmdrvdata[cpu]->spinlock);
    break;
    }
    diff --git a/include/linux/coresight.h b/include/linux/coresight.h
    index a7cabfa23b55..70f3dafa5194 100644
    --- a/include/linux/coresight.h
    +++ b/include/linux/coresight.h
    @@ -206,14 +206,22 @@ struct coresight_ops_link {
    * struct coresight_ops_source - basic operations for a source
    * Operations available for sources.
    * @trace_id: returns the value of the component's trace ID as known
    - to the HW.
    + * to the HW.
    + * @configure: performs configuration for a source but doesn't enable it.
    + * @trace_enable: enable/disable tracing on a source.
    * @enable: enables tracing for a source.
    * @disable: disables tracing for a source.
    + * @poweron: switch on power to a source.
    + * @poweroff: switch off power to a source.
    */
    struct coresight_ops_source {
    int (*trace_id)(struct coresight_device *csdev);
    + int (*configure)(struct coresight_device *csdev);
    + int (*trace_enable)(struct coresight_device *csdev, bool enable);
    int (*enable)(struct coresight_device *csdev);
    void (*disable)(struct coresight_device *csdev);
    + int (*poweron)(struct coresight_device *csdev);
    + void (*poweroff)(struct coresight_device *csdev);
    };

    struct coresight_ops {
    --
    1.9.1


    \
     
     \ /
      Last update: 2015-09-18 18:41    [W:9.631 / U:0.564 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site