--- /dev/null
+From 79932d161fda7f2d18761ace5f25445f7b525741 Mon Sep 17 00:00:00 2001
+From: Ian Rogers <irogers@google.com>
+Date: Fri, 6 May 2022 22:34:08 -0700
+Subject: perf evsel: Add tool event helpers
+
+From: Ian Rogers <irogers@google.com>
+
+commit 79932d161fda7f2d18761ace5f25445f7b525741 upstream.
+
+Convert to and from a string. Fix evsel__tool_name() as array is
+off-by-1. Support more than just duration_time as a metric-id.
+
+Fixes: 75eafc970bd9d36d ("perf list: Print all available tool events")
+Signed-off-by: Ian Rogers <irogers@google.com>
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
+Cc: Andi Kleen <ak@linux.intel.com>
+Cc: Florian Fischer <florian.fischer@muhq.space>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: James Clark <james.clark@arm.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: John Garry <john.garry@huawei.com>
+Cc: Kim Phillips <kim.phillips@amd.com>
+Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Riccardo Mancini <rickyman7@gmail.com>
+Cc: Shunsuke Nakamura <nakamura.shun@fujitsu.com>
+Cc: Stephane Eranian <eranian@google.com>
+Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
+Link: https://lore.kernel.org/r/20220507053410.3798748-4-irogers@google.com
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/perf/util/evsel.c | 41 +++++++++++++++++++++++++++++++----------
+ tools/perf/util/evsel.h | 11 +++++++++++
+ 2 files changed, 42 insertions(+), 10 deletions(-)
+
+--- a/tools/perf/util/evsel.c
++++ b/tools/perf/util/evsel.c
+@@ -59,6 +59,33 @@ struct perf_missing_features perf_missin
+
+ static clockid_t clockid;
+
++static const char *const perf_tool_event__tool_names[PERF_TOOL_MAX] = {
++ NULL,
++ "duration_time",
++ "user_time",
++ "system_time",
++};
++
++const char *perf_tool_event__to_str(enum perf_tool_event ev)
++{
++ if (ev > PERF_TOOL_NONE && ev < PERF_TOOL_MAX)
++ return perf_tool_event__tool_names[ev];
++
++ return NULL;
++}
++
++enum perf_tool_event perf_tool_event__from_str(const char *str)
++{
++ int i;
++
++ perf_tool_event__for_each_event(i) {
++ if (!strcmp(str, perf_tool_event__tool_names[i]))
++ return i;
++ }
++ return PERF_TOOL_NONE;
++}
++
++
+ static int evsel__no_extra_init(struct evsel *evsel __maybe_unused)
+ {
+ return 0;
+@@ -600,15 +627,9 @@ static int evsel__sw_name(struct evsel *
+ return r + evsel__add_modifiers(evsel, bf + r, size - r);
+ }
+
+-const char *evsel__tool_names[PERF_TOOL_MAX] = {
+- "duration_time",
+- "user_time",
+- "system_time",
+-};
+-
+ static int evsel__tool_name(enum perf_tool_event ev, char *bf, size_t size)
+ {
+- return scnprintf(bf, size, "%s", evsel__tool_names[ev]);
++ return scnprintf(bf, size, "%s", perf_tool_event__to_str(ev));
+ }
+
+ static int __evsel__bp_name(char *bf, size_t size, u64 addr, u64 type)
+@@ -761,7 +782,7 @@ const char *evsel__name(struct evsel *ev
+ break;
+
+ case PERF_TYPE_SOFTWARE:
+- if (evsel->tool_event)
++ if (evsel__is_tool(evsel))
+ evsel__tool_name(evsel->tool_event, bf, sizeof(bf));
+ else
+ evsel__sw_name(evsel, bf, sizeof(bf));
+@@ -794,8 +815,8 @@ const char *evsel__metric_id(const struc
+ if (evsel->metric_id)
+ return evsel->metric_id;
+
+- if (evsel->core.attr.type == PERF_TYPE_SOFTWARE && evsel->tool_event)
+- return "duration_time";
++ if (evsel__is_tool(evsel))
++ return perf_tool_event__to_str(evsel->tool_event);
+
+ return "unknown";
+ }
+--- a/tools/perf/util/evsel.h
++++ b/tools/perf/util/evsel.h
+@@ -30,6 +30,12 @@ enum perf_tool_event {
+ PERF_TOOL_DURATION_TIME = 1,
+ };
+
++const char *perf_tool_event__to_str(enum perf_tool_event ev);
++enum perf_tool_event perf_tool_event__from_str(const char *str);
++
++#define perf_tool_event__for_each_event(ev) \
++ for ((ev) = PERF_TOOL_DURATION_TIME; (ev) < PERF_TOOL_MAX; ev++)
++
+ /** struct evsel - event selector
+ *
+ * @evlist - evlist this evsel is in, if it is in one.
+@@ -265,6 +271,11 @@ int __evsel__hw_cache_type_op_res_name(u
+ const char *evsel__name(struct evsel *evsel);
+ const char *evsel__metric_id(const struct evsel *evsel);
+
++static inline bool evsel__is_tool(const struct evsel *evsel)
++{
++ return evsel->tool_event != PERF_TOOL_NONE;
++}
++
+ const char *evsel__group_name(struct evsel *evsel);
+ int evsel__group_desc(struct evsel *evsel, char *buf, size_t size);
+
--- /dev/null
+From e0257a01d6689c273a019756ed5e13911cc1bfed Mon Sep 17 00:00:00 2001
+From: John Garry <john.garry@huawei.com>
+Date: Wed, 22 Dec 2021 00:11:30 +0800
+Subject: perf pmu: Fix alias events list
+
+From: John Garry <john.garry@huawei.com>
+
+commit e0257a01d6689c273a019756ed5e13911cc1bfed upstream.
+
+Commit 0e0ae8742207c3b4 ("perf list: Display hybrid PMU events with cpu
+type") changes the event list for uncore PMUs or arm64 heterogeneous CPU
+systems, such that duplicate aliases are incorrectly listed per PMU
+(which they should not be), like:
+
+ # perf list
+ ...
+ unc_cbo_cache_lookup.any_es
+ [Unit: uncore_cbox L3 Lookup any request that access cache and found
+ line in E or S-state]
+ unc_cbo_cache_lookup.any_es
+ [Unit: uncore_cbox L3 Lookup any request that access cache and found
+ line in E or S-state]
+ unc_cbo_cache_lookup.any_i
+ [Unit: uncore_cbox L3 Lookup any request that access cache and found
+ line in I-state]
+ unc_cbo_cache_lookup.any_i
+ [Unit: uncore_cbox L3 Lookup any request that access cache and found
+ line in I-state]
+ ...
+
+Notice how the events are listed twice.
+
+The named commit changed how we remove duplicate events, in that events
+for different PMUs are not treated as duplicates. I suppose this is to
+handle how "Each hybrid pmu event has been assigned with a pmu name".
+
+Fix PMU alias listing by restoring behaviour to remove duplicates for
+non-hybrid PMUs.
+
+Fixes: 0e0ae8742207c3b4 ("perf list: Display hybrid PMU events with cpu type")
+Signed-off-by: John Garry <john.garry@huawei.com>
+Tested-by: Zhengjun Xing <zhengjun.xing@linux.intel.com>
+Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
+Cc: Ian Rogers <irogers@google.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Jiri Olsa <jolsa@redhat.com>
+Cc: Kan Liang <kan.liang@linux.intel.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Link: https://lore.kernel.org/r/1640103090-140490-1-git-send-email-john.garry@huawei.com
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/perf/util/pmu.c | 23 +++++++++++++++++------
+ 1 file changed, 17 insertions(+), 6 deletions(-)
+
+--- a/tools/perf/util/pmu.c
++++ b/tools/perf/util/pmu.c
+@@ -1659,6 +1659,21 @@ bool is_pmu_core(const char *name)
+ return !strcmp(name, "cpu") || is_arm_pmu_core(name);
+ }
+
++static bool pmu_alias_is_duplicate(struct sevent *alias_a,
++ struct sevent *alias_b)
++{
++ /* Different names -> never duplicates */
++ if (strcmp(alias_a->name, alias_b->name))
++ return false;
++
++ /* Don't remove duplicates for hybrid PMUs */
++ if (perf_pmu__is_hybrid(alias_a->pmu) &&
++ perf_pmu__is_hybrid(alias_b->pmu))
++ return false;
++
++ return true;
++}
++
+ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
+ bool long_desc, bool details_flag, bool deprecated,
+ const char *pmu_name)
+@@ -1744,12 +1759,8 @@ void print_pmu_events(const char *event_
+ qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
+ for (j = 0; j < len; j++) {
+ /* Skip duplicates */
+- if (j > 0 && !strcmp(aliases[j].name, aliases[j - 1].name)) {
+- if (!aliases[j].pmu || !aliases[j - 1].pmu ||
+- !strcmp(aliases[j].pmu, aliases[j - 1].pmu)) {
+- continue;
+- }
+- }
++ if (j > 0 && pmu_alias_is_duplicate(&aliases[j], &aliases[j - 1]))
++ continue;
+
+ if (name_only) {
+ printf("%s ", aliases[j].name);