hc
2024-08-16 a24a44ff9ca902811b99aa9663d697cf452e08ef
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright(C) 2015 Linaro Limited. All rights reserved.
 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
 */
 
#include <stdbool.h>
#include <linux/coresight-pmu.h>
#include <linux/zalloc.h>
 
#include "../../util/auxtrace.h"
#include "../../util/debug.h"
#include "../../util/evlist.h"
#include "../../util/pmu.h"
#include "cs-etm.h"
#include "arm-spe.h"
 
static struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err)
{
   struct perf_pmu **arm_spe_pmus = NULL;
   int ret, i, nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
   /* arm_spe_xxxxxxxxx\0 */
   char arm_spe_pmu_name[sizeof(ARM_SPE_PMU_NAME) + 10];
 
   arm_spe_pmus = zalloc(sizeof(struct perf_pmu *) * nr_cpus);
   if (!arm_spe_pmus) {
       pr_err("spes alloc failed\n");
       *err = -ENOMEM;
       return NULL;
   }
 
   for (i = 0; i < nr_cpus; i++) {
       ret = sprintf(arm_spe_pmu_name, "%s%d", ARM_SPE_PMU_NAME, i);
       if (ret < 0) {
           pr_err("sprintf failed\n");
           *err = -ENOMEM;
           return NULL;
       }
 
       arm_spe_pmus[*nr_spes] = perf_pmu__find(arm_spe_pmu_name);
       if (arm_spe_pmus[*nr_spes]) {
           pr_debug2("%s %d: arm_spe_pmu %d type %d name %s\n",
                __func__, __LINE__, *nr_spes,
                arm_spe_pmus[*nr_spes]->type,
                arm_spe_pmus[*nr_spes]->name);
           (*nr_spes)++;
       }
   }
 
   return arm_spe_pmus;
}
 
struct auxtrace_record
*auxtrace_record__init(struct evlist *evlist, int *err)
{
   struct perf_pmu    *cs_etm_pmu;
   struct evsel *evsel;
   bool found_etm = false;
   struct perf_pmu *found_spe = NULL;
   struct perf_pmu **arm_spe_pmus = NULL;
   int nr_spes = 0;
   int i = 0;
 
   if (!evlist)
       return NULL;
 
   cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
   arm_spe_pmus = find_all_arm_spe_pmus(&nr_spes, err);
 
   evlist__for_each_entry(evlist, evsel) {
       if (cs_etm_pmu &&
           evsel->core.attr.type == cs_etm_pmu->type)
           found_etm = true;
 
       if (!nr_spes || found_spe)
           continue;
 
       for (i = 0; i < nr_spes; i++) {
           if (evsel->core.attr.type == arm_spe_pmus[i]->type) {
               found_spe = arm_spe_pmus[i];
               break;
           }
       }
   }
   free(arm_spe_pmus);
 
   if (found_etm && found_spe) {
       pr_err("Concurrent ARM Coresight ETM and SPE operation not currently supported\n");
       *err = -EOPNOTSUPP;
       return NULL;
   }
 
   if (found_etm)
       return cs_etm_record_init(err);
 
#if defined(__aarch64__)
   if (found_spe)
       return arm_spe_recording_init(err, found_spe);
#endif
 
   /*
    * Clear 'err' even if we haven't found an event - that way perf
    * record can still be used even if tracers aren't present.  The NULL
    * return value will take care of telling the infrastructure HW tracing
    * isn't available.
    */
   *err = 0;
   return NULL;
}