1 // SPDX-License-Identifier: GPL-2.0
3 * HiSilicon PCIe Trace and Tuning (PTT) support
4 * Copyright (c) 2022 HiSilicon Technologies Co., Ltd.
11 #include <linux/bitops.h>
12 #include <linux/kernel.h>
13 #include <linux/log2.h>
14 #include <linux/types.h>
15 #include <linux/zalloc.h>
24 #include "hisi-ptt-decoder/hisi-ptt-pkt-decoder.h"
28 #include <internal/lib.h>
31 struct auxtrace auxtrace
;
33 struct perf_session
*session
;
34 struct machine
*machine
;
38 static enum hisi_ptt_pkt_type
hisi_ptt_check_packet_type(unsigned char *buf
)
40 uint32_t head
= *(uint32_t *)buf
;
42 if ((HISI_PTT_8DW_CHECK_MASK
& head
) == HISI_PTT_IS_8DW_PKT
)
43 return HISI_PTT_8DW_PKT
;
45 return HISI_PTT_4DW_PKT
;
48 static void hisi_ptt_dump(struct hisi_ptt
*ptt __maybe_unused
,
49 unsigned char *buf
, size_t len
)
51 const char *color
= PERF_COLOR_BLUE
;
52 enum hisi_ptt_pkt_type type
;
56 type
= hisi_ptt_check_packet_type(buf
);
57 len
= round_down(len
, hisi_ptt_pkt_size
[type
]);
58 color_fprintf(stdout
, color
, ". ... HISI PTT data: size %zu bytes\n",
62 pkt_len
= hisi_ptt_pkt_desc(buf
, pos
, type
);
64 color_fprintf(stdout
, color
, " Bad packet!\n");
71 static void hisi_ptt_dump_event(struct hisi_ptt
*ptt
, unsigned char *buf
,
76 hisi_ptt_dump(ptt
, buf
, len
);
79 static int hisi_ptt_process_event(struct perf_session
*session __maybe_unused
,
80 union perf_event
*event __maybe_unused
,
81 struct perf_sample
*sample __maybe_unused
,
82 const struct perf_tool
*tool __maybe_unused
)
87 static int hisi_ptt_process_auxtrace_event(struct perf_session
*session
,
88 union perf_event
*event
,
89 const struct perf_tool
*tool __maybe_unused
)
91 struct hisi_ptt
*ptt
= container_of(session
->auxtrace
, struct hisi_ptt
,
93 int fd
= perf_data__fd(session
->data
);
94 int size
= event
->auxtrace
.size
;
95 void *data
= malloc(size
);
102 if (perf_data__is_pipe(session
->data
)) {
105 data_offset
= lseek(fd
, 0, SEEK_CUR
);
106 if (data_offset
== -1) {
112 err
= readn(fd
, data
, size
);
113 if (err
!= (ssize_t
)size
) {
119 hisi_ptt_dump_event(ptt
, data
, size
);
125 static int hisi_ptt_flush(struct perf_session
*session __maybe_unused
,
126 const struct perf_tool
*tool __maybe_unused
)
131 static void hisi_ptt_free_events(struct perf_session
*session __maybe_unused
)
135 static void hisi_ptt_free(struct perf_session
*session
)
137 struct hisi_ptt
*ptt
= container_of(session
->auxtrace
, struct hisi_ptt
,
140 session
->auxtrace
= NULL
;
144 static bool hisi_ptt_evsel_is_auxtrace(struct perf_session
*session
,
147 struct hisi_ptt
*ptt
= container_of(session
->auxtrace
, struct hisi_ptt
, auxtrace
);
149 return evsel
->core
.attr
.type
== ptt
->pmu_type
;
152 static void hisi_ptt_print_info(__u64 type
)
157 fprintf(stdout
, " PMU Type %" PRId64
"\n", (s64
) type
);
160 int hisi_ptt_process_auxtrace_info(union perf_event
*event
,
161 struct perf_session
*session
)
163 struct perf_record_auxtrace_info
*auxtrace_info
= &event
->auxtrace_info
;
164 struct hisi_ptt
*ptt
;
166 if (auxtrace_info
->header
.size
< HISI_PTT_AUXTRACE_PRIV_SIZE
+
167 sizeof(struct perf_record_auxtrace_info
))
170 ptt
= zalloc(sizeof(*ptt
));
174 ptt
->session
= session
;
175 ptt
->machine
= &session
->machines
.host
; /* No kvm support */
176 ptt
->auxtrace_type
= auxtrace_info
->type
;
177 ptt
->pmu_type
= auxtrace_info
->priv
[0];
179 ptt
->auxtrace
.process_event
= hisi_ptt_process_event
;
180 ptt
->auxtrace
.process_auxtrace_event
= hisi_ptt_process_auxtrace_event
;
181 ptt
->auxtrace
.flush_events
= hisi_ptt_flush
;
182 ptt
->auxtrace
.free_events
= hisi_ptt_free_events
;
183 ptt
->auxtrace
.free
= hisi_ptt_free
;
184 ptt
->auxtrace
.evsel_is_auxtrace
= hisi_ptt_evsel_is_auxtrace
;
185 session
->auxtrace
= &ptt
->auxtrace
;
187 hisi_ptt_print_info(auxtrace_info
->priv
[0]);