coresight: etm4x: Configure tracers to emit timestamps
Configure timestamps to be emitted at regular intervals in the trace stream to temporally correlate instructions executed on different CPUs. Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org> Tested-by: Leo Yan <leo.yan@linaro.org> Tested-by: Robert Walker <robert.walker@arm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
8013f32a1b
commit
a54e14f810
|
@ -204,6 +204,91 @@ static void etm4_enable_hw_smp_call(void *info)
|
|||
arg->rc = etm4_enable_hw(arg->drvdata);
|
||||
}
|
||||
|
||||
/*
|
||||
* The goal of function etm4_config_timestamp_event() is to configure a
|
||||
* counter that will tell the tracer to emit a timestamp packet when it
|
||||
* reaches zero. This is done in order to get a more fine grained idea
|
||||
* of when instructions are executed so that they can be correlated
|
||||
* with execution on other CPUs.
|
||||
*
|
||||
* To do this the counter itself is configured to self reload and
|
||||
* TRCRSCTLR1 (always true) used to get the counter to decrement. From
|
||||
* there a resource selector is configured with the counter and the
|
||||
* timestamp control register to use the resource selector to trigger the
|
||||
* event that will insert a timestamp packet in the stream.
|
||||
*/
|
||||
static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata)
|
||||
{
|
||||
int ctridx, ret = -EINVAL;
|
||||
int counter, rselector;
|
||||
u32 val = 0;
|
||||
struct etmv4_config *config = &drvdata->config;
|
||||
|
||||
/* No point in trying if we don't have at least one counter */
|
||||
if (!drvdata->nr_cntr)
|
||||
goto out;
|
||||
|
||||
/* Find a counter that hasn't been initialised */
|
||||
for (ctridx = 0; ctridx < drvdata->nr_cntr; ctridx++)
|
||||
if (config->cntr_val[ctridx] == 0)
|
||||
break;
|
||||
|
||||
/* All the counters have been configured already, bail out */
|
||||
if (ctridx == drvdata->nr_cntr) {
|
||||
pr_debug("%s: no available counter found\n", __func__);
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Searching for an available resource selector to use, starting at
|
||||
* '2' since every implementation has at least 2 resource selector.
|
||||
* ETMIDR4 gives the number of resource selector _pairs_,
|
||||
* hence multiply by 2.
|
||||
*/
|
||||
for (rselector = 2; rselector < drvdata->nr_resource * 2; rselector++)
|
||||
if (!config->res_ctrl[rselector])
|
||||
break;
|
||||
|
||||
if (rselector == drvdata->nr_resource * 2) {
|
||||
pr_debug("%s: no available resource selector found\n",
|
||||
__func__);
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Remember what counter we used */
|
||||
counter = 1 << ctridx;
|
||||
|
||||
/*
|
||||
* Initialise original and reload counter value to the smallest
|
||||
* possible value in order to get as much precision as we can.
|
||||
*/
|
||||
config->cntr_val[ctridx] = 1;
|
||||
config->cntrldvr[ctridx] = 1;
|
||||
|
||||
/* Set the trace counter control register */
|
||||
val = 0x1 << 16 | /* Bit 16, reload counter automatically */
|
||||
0x0 << 7 | /* Select single resource selector */
|
||||
0x1; /* Resource selector 1, i.e always true */
|
||||
|
||||
config->cntr_ctrl[ctridx] = val;
|
||||
|
||||
val = 0x2 << 16 | /* Group 0b0010 - Counter and sequencers */
|
||||
counter << 0; /* Counter to use */
|
||||
|
||||
config->res_ctrl[rselector] = val;
|
||||
|
||||
val = 0x0 << 7 | /* Select single resource selector */
|
||||
rselector; /* Resource selector */
|
||||
|
||||
config->ts_ctrl = val;
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
|
||||
struct perf_event *event)
|
||||
{
|
||||
|
@ -239,9 +324,24 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
|
|||
/* TRM: Must program this for cycacc to work */
|
||||
config->ccctlr = ETM_CYC_THRESHOLD_DEFAULT;
|
||||
}
|
||||
if (attr->config & BIT(ETM_OPT_TS))
|
||||
if (attr->config & BIT(ETM_OPT_TS)) {
|
||||
/*
|
||||
* Configure timestamps to be emitted at regular intervals in
|
||||
* order to correlate instructions executed on different CPUs
|
||||
* (CPU-wide trace scenarios).
|
||||
*/
|
||||
ret = etm4_config_timestamp_event(drvdata);
|
||||
|
||||
/*
|
||||
* No need to go further if timestamp intervals can't
|
||||
* be configured.
|
||||
*/
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* bit[11], Global timestamp tracing bit */
|
||||
config->cfg |= BIT(11);
|
||||
}
|
||||
|
||||
if (attr->config & BIT(ETM_OPT_CTXTID))
|
||||
/* bit[6], Context ID tracing bit */
|
||||
|
|
Loading…
Reference in New Issue