1 // SPDX-License-Identifier: GPL-2.0
3 * HiSilicon PCIe Trace and Tuning (PTT) support
4 * Copyright (c) 2022 HiSilicon Technologies Co., Ltd.
7 #include <linux/kernel.h>
8 #include <linux/types.h>
9 #include <linux/bitops.h>
10 #include <linux/log2.h>
11 #include <linux/zalloc.h>
14 #include <internal/lib.h> // page_size
15 #include "../../../util/auxtrace.h"
16 #include "../../../util/cpumap.h"
17 #include "../../../util/debug.h"
18 #include "../../../util/event.h"
19 #include "../../../util/evlist.h"
20 #include "../../../util/evsel.h"
21 #include "../../../util/hisi-ptt.h"
22 #include "../../../util/pmu.h"
23 #include "../../../util/record.h"
24 #include "../../../util/session.h"
25 #include "../../../util/tsc.h"
27 #define KiB(x) ((x) * 1024)
28 #define MiB(x) ((x) * 1024 * 1024)
30 struct hisi_ptt_recording
{
31 struct auxtrace_record itr
;
32 struct perf_pmu
*hisi_ptt_pmu
;
33 struct evlist
*evlist
;
37 hisi_ptt_info_priv_size(struct auxtrace_record
*itr __maybe_unused
,
38 struct evlist
*evlist __maybe_unused
)
40 return HISI_PTT_AUXTRACE_PRIV_SIZE
;
43 static int hisi_ptt_info_fill(struct auxtrace_record
*itr
,
44 struct perf_session
*session
,
45 struct perf_record_auxtrace_info
*auxtrace_info
,
48 struct hisi_ptt_recording
*pttr
=
49 container_of(itr
, struct hisi_ptt_recording
, itr
);
50 struct perf_pmu
*hisi_ptt_pmu
= pttr
->hisi_ptt_pmu
;
52 if (priv_size
!= HISI_PTT_AUXTRACE_PRIV_SIZE
)
55 if (!session
->evlist
->core
.nr_mmaps
)
58 auxtrace_info
->type
= PERF_AUXTRACE_HISI_PTT
;
59 auxtrace_info
->priv
[0] = hisi_ptt_pmu
->type
;
64 static int hisi_ptt_set_auxtrace_mmap_page(struct record_opts
*opts
)
66 bool privileged
= perf_event_paranoid_check(-1);
68 if (!opts
->full_auxtrace
)
71 if (opts
->full_auxtrace
&& !opts
->auxtrace_mmap_pages
) {
73 opts
->auxtrace_mmap_pages
= MiB(16) / page_size
;
75 opts
->auxtrace_mmap_pages
= KiB(128) / page_size
;
76 if (opts
->mmap_pages
== UINT_MAX
)
77 opts
->mmap_pages
= KiB(256) / page_size
;
81 /* Validate auxtrace_mmap_pages */
82 if (opts
->auxtrace_mmap_pages
) {
83 size_t sz
= opts
->auxtrace_mmap_pages
* (size_t)page_size
;
84 size_t min_sz
= KiB(8);
86 if (sz
< min_sz
|| !is_power_of_2(sz
)) {
87 pr_err("Invalid mmap size for HISI PTT: must be at least %zuKiB and a power of 2\n",
96 static int hisi_ptt_recording_options(struct auxtrace_record
*itr
,
97 struct evlist
*evlist
,
98 struct record_opts
*opts
)
100 struct hisi_ptt_recording
*pttr
=
101 container_of(itr
, struct hisi_ptt_recording
, itr
);
102 struct perf_pmu
*hisi_ptt_pmu
= pttr
->hisi_ptt_pmu
;
103 struct evsel
*evsel
, *hisi_ptt_evsel
= NULL
;
104 struct evsel
*tracking_evsel
;
107 pttr
->evlist
= evlist
;
108 evlist__for_each_entry(evlist
, evsel
) {
109 if (evsel
->core
.attr
.type
== hisi_ptt_pmu
->type
) {
110 if (hisi_ptt_evsel
) {
111 pr_err("There may be only one " HISI_PTT_PMU_NAME
"x event\n");
114 evsel
->core
.attr
.freq
= 0;
115 evsel
->core
.attr
.sample_period
= 1;
116 evsel
->needs_auxtrace_mmap
= true;
117 hisi_ptt_evsel
= evsel
;
118 opts
->full_auxtrace
= true;
122 err
= hisi_ptt_set_auxtrace_mmap_page(opts
);
126 * To obtain the auxtrace buffer file descriptor, the auxtrace event
129 evlist__to_front(evlist
, hisi_ptt_evsel
);
130 evsel__set_sample_bit(hisi_ptt_evsel
, TIME
);
132 /* Add dummy event to keep tracking */
133 err
= parse_event(evlist
, "dummy:u");
137 tracking_evsel
= evlist__last(evlist
);
138 evlist__set_tracking_event(evlist
, tracking_evsel
);
140 tracking_evsel
->core
.attr
.freq
= 0;
141 tracking_evsel
->core
.attr
.sample_period
= 1;
142 evsel__set_sample_bit(tracking_evsel
, TIME
);
147 static u64
hisi_ptt_reference(struct auxtrace_record
*itr __maybe_unused
)
152 static void hisi_ptt_recording_free(struct auxtrace_record
*itr
)
154 struct hisi_ptt_recording
*pttr
=
155 container_of(itr
, struct hisi_ptt_recording
, itr
);
160 struct auxtrace_record
*hisi_ptt_recording_init(int *err
,
161 struct perf_pmu
*hisi_ptt_pmu
)
163 struct hisi_ptt_recording
*pttr
;
170 pttr
= zalloc(sizeof(*pttr
));
176 pttr
->hisi_ptt_pmu
= hisi_ptt_pmu
;
177 pttr
->itr
.recording_options
= hisi_ptt_recording_options
;
178 pttr
->itr
.info_priv_size
= hisi_ptt_info_priv_size
;
179 pttr
->itr
.info_fill
= hisi_ptt_info_fill
;
180 pttr
->itr
.free
= hisi_ptt_recording_free
;
181 pttr
->itr
.reference
= hisi_ptt_reference
;
182 pttr
->itr
.read_finish
= auxtrace_record__read_finish
;
183 pttr
->itr
.alignment
= 0;