Commit 35c51f83 authored by James Clark's avatar James Clark Committed by Arnaldo Carvalho de Melo

perf cs-etm: Validate options after applying them

Currently the cs_etm_set_option() function both validates and applies
the config options. Because it's only called when they are added
automatically, there are some paths where the user can apply the option
on the command line and skip the validation. By moving it to the end it
covers both cases.

Also, options don't need to be re-applied anyway, Perf handles parsing
and applying the config terms automatically.
Signed-off-by: default avatarJames Clark <james.clark@arm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Denis Nikitin <denik@google.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Mike Leach <mike.leach@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Yang Shi <shy828301@gmail.com>
Cc: coresight@lists.linaro.org
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20230424134748.228137-5-james.clark@arm.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 3963d84b
...@@ -69,21 +69,29 @@ static const char * const metadata_ete_ro[] = { ...@@ -69,21 +69,29 @@ static const char * const metadata_ete_ro[] = {
static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu); static bool cs_etm_is_etmv4(struct auxtrace_record *itr, int cpu);
static bool cs_etm_is_ete(struct auxtrace_record *itr, int cpu); static bool cs_etm_is_ete(struct auxtrace_record *itr, int cpu);
static int cs_etm_set_context_id(struct auxtrace_record *itr, static int cs_etm_validate_context_id(struct auxtrace_record *itr,
struct evsel *evsel, int cpu) struct evsel *evsel, int cpu)
{ {
struct cs_etm_recording *ptr; struct cs_etm_recording *ptr =
struct perf_pmu *cs_etm_pmu; container_of(itr, struct cs_etm_recording, itr);
struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
char path[PATH_MAX]; char path[PATH_MAX];
int err = -EINVAL; int err;
u32 val; u32 val;
u64 contextid; u64 contextid =
evsel->core.attr.config &
(perf_pmu__format_bits(&cs_etm_pmu->format, "contextid1") |
perf_pmu__format_bits(&cs_etm_pmu->format, "contextid2"));
ptr = container_of(itr, struct cs_etm_recording, itr); if (!contextid)
cs_etm_pmu = ptr->cs_etm_pmu; return 0;
if (!cs_etm_is_etmv4(itr, cpu)) /* Not supported in etmv3 */
goto out; if (!cs_etm_is_etmv4(itr, cpu)) {
pr_err("%s: contextid not supported in ETMv3, disable with %s/contextid=0/\n",
CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
return -EINVAL;
}
/* Get a handle on TRCIDR2 */ /* Get a handle on TRCIDR2 */
snprintf(path, PATH_MAX, "cpu%d/%s", snprintf(path, PATH_MAX, "cpu%d/%s",
...@@ -92,27 +100,13 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr, ...@@ -92,27 +100,13 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr,
/* There was a problem reading the file, bailing out */ /* There was a problem reading the file, bailing out */
if (err != 1) { if (err != 1) {
pr_err("%s: can't read file %s\n", pr_err("%s: can't read file %s\n", CORESIGHT_ETM_PMU_NAME,
CORESIGHT_ETM_PMU_NAME, path); path);
goto out; return err;
} }
/* User has configured for PID tracing, respects it. */ if (contextid &
contextid = evsel->core.attr.config & perf_pmu__format_bits(&cs_etm_pmu->format, "contextid1")) {
(BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_CTXTID2));
/*
* If user doesn't configure the contextid format, parse PMU format and
* enable PID tracing according to the "contextid" format bits:
*
* If bit ETM_OPT_CTXTID is set, trace CONTEXTIDR_EL1;
* If bit ETM_OPT_CTXTID2 is set, trace CONTEXTIDR_EL2.
*/
if (!contextid)
contextid = perf_pmu__format_bits(&cs_etm_pmu->format,
"contextid");
if (contextid & BIT(ETM_OPT_CTXTID)) {
/* /*
* TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID
* tracing is supported: * tracing is supported:
...@@ -122,14 +116,14 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr, ...@@ -122,14 +116,14 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr,
*/ */
val = BMVAL(val, 5, 9); val = BMVAL(val, 5, 9);
if (!val || val != 0x4) { if (!val || val != 0x4) {
pr_err("%s: CONTEXTIDR_EL1 isn't supported\n", pr_err("%s: CONTEXTIDR_EL1 isn't supported, disable with %s/contextid1=0/\n",
CORESIGHT_ETM_PMU_NAME); CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
err = -EINVAL; return -EINVAL;
goto out;
} }
} }
if (contextid & BIT(ETM_OPT_CTXTID2)) { if (contextid &
perf_pmu__format_bits(&cs_etm_pmu->format, "contextid2")) {
/* /*
* TRCIDR2.VMIDOPT[30:29] != 0 and * TRCIDR2.VMIDOPT[30:29] != 0 and
* TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid) * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid)
...@@ -138,35 +132,34 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr, ...@@ -138,35 +132,34 @@ static int cs_etm_set_context_id(struct auxtrace_record *itr,
* Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us. * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us.
*/ */
if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) { if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) {
pr_err("%s: CONTEXTIDR_EL2 isn't supported\n", pr_err("%s: CONTEXTIDR_EL2 isn't supported, disable with %s/contextid2=0/\n",
CORESIGHT_ETM_PMU_NAME); CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
err = -EINVAL; return -EINVAL;
goto out;
} }
} }
/* All good, let the kernel know */ return 0;
evsel->core.attr.config |= contextid;
err = 0;
out:
return err;
} }
static int cs_etm_set_timestamp(struct auxtrace_record *itr, static int cs_etm_validate_timestamp(struct auxtrace_record *itr,
struct evsel *evsel, int cpu) struct evsel *evsel, int cpu)
{ {
struct cs_etm_recording *ptr; struct cs_etm_recording *ptr =
struct perf_pmu *cs_etm_pmu; container_of(itr, struct cs_etm_recording, itr);
struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
char path[PATH_MAX]; char path[PATH_MAX];
int err = -EINVAL; int err;
u32 val; u32 val;
ptr = container_of(itr, struct cs_etm_recording, itr); if (!(evsel->core.attr.config &
cs_etm_pmu = ptr->cs_etm_pmu; perf_pmu__format_bits(&cs_etm_pmu->format, "timestamp")))
return 0;
if (!cs_etm_is_etmv4(itr, cpu)) if (!cs_etm_is_etmv4(itr, cpu)) {
goto out; pr_err("%s: timestamp not supported in ETMv3, disable with %s/timestamp=0/\n",
CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
return -EINVAL;
}
/* Get a handle on TRCIRD0 */ /* Get a handle on TRCIRD0 */
snprintf(path, PATH_MAX, "cpu%d/%s", snprintf(path, PATH_MAX, "cpu%d/%s",
...@@ -177,7 +170,7 @@ static int cs_etm_set_timestamp(struct auxtrace_record *itr, ...@@ -177,7 +170,7 @@ static int cs_etm_set_timestamp(struct auxtrace_record *itr,
if (err != 1) { if (err != 1) {
pr_err("%s: can't read file %s\n", pr_err("%s: can't read file %s\n",
CORESIGHT_ETM_PMU_NAME, path); CORESIGHT_ETM_PMU_NAME, path);
goto out; return err;
} }
/* /*
...@@ -189,24 +182,21 @@ static int cs_etm_set_timestamp(struct auxtrace_record *itr, ...@@ -189,24 +182,21 @@ static int cs_etm_set_timestamp(struct auxtrace_record *itr,
*/ */
val &= GENMASK(28, 24); val &= GENMASK(28, 24);
if (!val) { if (!val) {
err = -EINVAL; return -EINVAL;
goto out;
} }
/* All good, let the kernel know */ return 0;
evsel->core.attr.config |= (1 << ETM_OPT_TS);
err = 0;
out:
return err;
} }
#define ETM_SET_OPT_CTXTID (1 << 0) /*
#define ETM_SET_OPT_TS (1 << 1) * Check whether the requested timestamp and contextid options should be
#define ETM_SET_OPT_MASK (ETM_SET_OPT_CTXTID | ETM_SET_OPT_TS) * available on all requested CPUs and if not, tell the user how to override.
* The kernel will silently disable any unavailable options so a warning here
static int cs_etm_set_option(struct auxtrace_record *itr, * first is better. In theory the kernel could still disable the option for
struct evsel *evsel, u32 option) * some other reason so this is best effort only.
*/
static int cs_etm_validate_config(struct auxtrace_record *itr,
struct evsel *evsel)
{ {
int i, err = -EINVAL; int i, err = -EINVAL;
struct perf_cpu_map *event_cpus = evsel->evlist->core.user_requested_cpus; struct perf_cpu_map *event_cpus = evsel->evlist->core.user_requested_cpus;
...@@ -220,18 +210,11 @@ static int cs_etm_set_option(struct auxtrace_record *itr, ...@@ -220,18 +210,11 @@ static int cs_etm_set_option(struct auxtrace_record *itr,
!perf_cpu_map__has(online_cpus, cpu)) !perf_cpu_map__has(online_cpus, cpu))
continue; continue;
if (option & BIT(ETM_OPT_CTXTID)) { err = cs_etm_validate_context_id(itr, evsel, i);
err = cs_etm_set_context_id(itr, evsel, i); if (err)
if (err) goto out;
goto out; err = cs_etm_validate_timestamp(itr, evsel, i);
} if (err)
if (option & BIT(ETM_OPT_TS)) {
err = cs_etm_set_timestamp(itr, evsel, i);
if (err)
goto out;
}
if (option & ~(BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_TS)))
/* Nothing else is currently supported */
goto out; goto out;
} }
...@@ -447,10 +430,10 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, ...@@ -447,10 +430,10 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
* when a context switch happened. * when a context switch happened.
*/ */
if (!perf_cpu_map__empty(cpus)) { if (!perf_cpu_map__empty(cpus)) {
err = cs_etm_set_option(itr, cs_etm_evsel, cs_etm_evsel->core.attr.config |=
BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_TS)); perf_pmu__format_bits(&cs_etm_pmu->format, "timestamp");
if (err) cs_etm_evsel->core.attr.config |=
goto out; perf_pmu__format_bits(&cs_etm_pmu->format, "contextid");
} }
/* Add dummy event to keep tracking */ /* Add dummy event to keep tracking */
...@@ -466,6 +449,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, ...@@ -466,6 +449,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
if (!perf_cpu_map__empty(cpus)) if (!perf_cpu_map__empty(cpus))
evsel__set_sample_bit(evsel, TIME); evsel__set_sample_bit(evsel, TIME);
err = cs_etm_validate_config(itr, cs_etm_evsel);
out: out:
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment