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 int cs_etm_set_context_id(struct auxtrace_record *itr,
-                                struct evsel *evsel, int cpu)
+static int cs_etm_validate_context_id(struct auxtrace_record *itr,
+                                     struct evsel *evsel, int cpu)
 {
-       struct cs_etm_recording *ptr;
-       struct perf_pmu *cs_etm_pmu;
+       struct cs_etm_recording *ptr =
+               container_of(itr, struct cs_etm_recording, itr);
+       struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
        char path[PATH_MAX];
-       int err = -EINVAL;
+       int err;
        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);
-       cs_etm_pmu = ptr->cs_etm_pmu;
+       if (!contextid)
+               return 0;
 
-       if (!cs_etm_is_etmv4(itr, cpu))
-               goto out;
+       /* Not supported in etmv3 */
+       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 */
        snprintf(path, PATH_MAX, "cpu%d/%s",
 
        /* There was a problem reading the file, bailing out */
        if (err != 1) {
-               pr_err("%s: can't read file %s\n",
-                      CORESIGHT_ETM_PMU_NAME, path);
-               goto out;
+               pr_err("%s: can't read file %s\n", CORESIGHT_ETM_PMU_NAME,
+                      path);
+               return err;
        }
 
-       /* User has configured for PID tracing, respects it. */
-       contextid = evsel->core.attr.config &
-                       (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)) {
+       if (contextid &
+           perf_pmu__format_bits(&cs_etm_pmu->format, "contextid1")) {
                /*
                 * TRCIDR2.CIDSIZE, bit [9-5], indicates whether contextID
                 * tracing is supported:
                 */
                val = BMVAL(val, 5, 9);
                if (!val || val != 0x4) {
-                       pr_err("%s: CONTEXTIDR_EL1 isn't supported\n",
-                              CORESIGHT_ETM_PMU_NAME);
-                       err = -EINVAL;
-                       goto out;
+                       pr_err("%s: CONTEXTIDR_EL1 isn't supported, disable with %s/contextid1=0/\n",
+                              CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
+                       return -EINVAL;
                }
        }
 
-       if (contextid & BIT(ETM_OPT_CTXTID2)) {
+       if (contextid &
+           perf_pmu__format_bits(&cs_etm_pmu->format, "contextid2")) {
                /*
                 * TRCIDR2.VMIDOPT[30:29] != 0 and
                 * TRCIDR2.VMIDSIZE[14:10] == 0b00100 (32bit virtual contextid)
                 * Any value of VMIDSIZE >= 4 (i.e, > 32bit) is fine for us.
                 */
                if (!BMVAL(val, 29, 30) || BMVAL(val, 10, 14) < 4) {
-                       pr_err("%s: CONTEXTIDR_EL2 isn't supported\n",
-                              CORESIGHT_ETM_PMU_NAME);
-                       err = -EINVAL;
-                       goto out;
+                       pr_err("%s: CONTEXTIDR_EL2 isn't supported, disable with %s/contextid2=0/\n",
+                              CORESIGHT_ETM_PMU_NAME, CORESIGHT_ETM_PMU_NAME);
+                       return -EINVAL;
                }
        }
 
-       /* All good, let the kernel know */
-       evsel->core.attr.config |= contextid;
-       err = 0;
-
-out:
-       return err;
+       return 0;
 }
 
-static int cs_etm_set_timestamp(struct auxtrace_record *itr,
-                               struct evsel *evsel, int cpu)
+static int cs_etm_validate_timestamp(struct auxtrace_record *itr,
+                                    struct evsel *evsel, int cpu)
 {
-       struct cs_etm_recording *ptr;
-       struct perf_pmu *cs_etm_pmu;
+       struct cs_etm_recording *ptr =
+               container_of(itr, struct cs_etm_recording, itr);
+       struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
        char path[PATH_MAX];
-       int err = -EINVAL;
+       int err;
        u32 val;
 
-       ptr = container_of(itr, struct cs_etm_recording, itr);
-       cs_etm_pmu = ptr->cs_etm_pmu;
+       if (!(evsel->core.attr.config &
+             perf_pmu__format_bits(&cs_etm_pmu->format, "timestamp")))
+               return 0;
 
-       if (!cs_etm_is_etmv4(itr, cpu))
-               goto out;
+       if (!cs_etm_is_etmv4(itr, cpu)) {
+               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 */
        snprintf(path, PATH_MAX, "cpu%d/%s",
        if (err != 1) {
                pr_err("%s: can't read file %s\n",
                       CORESIGHT_ETM_PMU_NAME, path);
-               goto out;
+               return err;
        }
 
        /*
         */
        val &= GENMASK(28, 24);
        if (!val) {
-               err = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
-       /* All good, let the kernel know */
-       evsel->core.attr.config |= (1 << ETM_OPT_TS);
-       err = 0;
-
-out:
-       return err;
+       return 0;
 }
 
-#define ETM_SET_OPT_CTXTID     (1 << 0)
-#define ETM_SET_OPT_TS         (1 << 1)
-#define ETM_SET_OPT_MASK       (ETM_SET_OPT_CTXTID | ETM_SET_OPT_TS)
-
-static int cs_etm_set_option(struct auxtrace_record *itr,
-                            struct evsel *evsel, u32 option)
+/*
+ * Check whether the requested timestamp and contextid options should be
+ * 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
+ * first is better. In theory the kernel could still disable the option for
+ * 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;
        struct perf_cpu_map *event_cpus = evsel->evlist->core.user_requested_cpus;
                    !perf_cpu_map__has(online_cpus, cpu))
                        continue;
 
-               if (option & BIT(ETM_OPT_CTXTID)) {
-                       err = cs_etm_set_context_id(itr, evsel, i);
-                       if (err)
-                               goto out;
-               }
-               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 */
+               err = cs_etm_validate_context_id(itr, evsel, i);
+               if (err)
+                       goto out;
+               err = cs_etm_validate_timestamp(itr, evsel, i);
+               if (err)
                        goto out;
        }
 
         * when a context switch happened.
         */
        if (!perf_cpu_map__empty(cpus)) {
-               err = cs_etm_set_option(itr, cs_etm_evsel,
-                                       BIT(ETM_OPT_CTXTID) | BIT(ETM_OPT_TS));
-               if (err)
-                       goto out;
+               cs_etm_evsel->core.attr.config |=
+                       perf_pmu__format_bits(&cs_etm_pmu->format, "timestamp");
+               cs_etm_evsel->core.attr.config |=
+                       perf_pmu__format_bits(&cs_etm_pmu->format, "contextid");
        }
 
        /* Add dummy event to keep tracking */
        if (!perf_cpu_map__empty(cpus))
                evsel__set_sample_bit(evsel, TIME);
 
+       err = cs_etm_validate_config(itr, cs_etm_evsel);
 out:
        return err;
 }