blob: 57b020b0b36fb94b6d49604c58cf578eb769009c [file] [log] [blame]
Mathieu Poirier68ffe392018-01-17 10:52:13 -07001/*
2 * SPDX-License-Identifier: GPL-2.0
3 *
4 * Copyright(C) 2015-2018 Linaro Limited.
5 *
6 * Author: Tor Jeremiassen <tor@ti.com>
7 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
8 */
9
10#include <linux/err.h>
11#include <linux/list.h>
12#include <stdlib.h>
13#include <opencsd/c_api/opencsd_c_api.h>
14#include <opencsd/etmv4/trc_pkt_types_etmv4.h>
15#include <opencsd/ocsd_if_types.h>
16
17#include "cs-etm.h"
18#include "cs-etm-decoder.h"
19#include "intlist.h"
20#include "util.h"
21
22#define MAX_BUFFER 1024
23
24/* use raw logging */
25#ifdef CS_DEBUG_RAW
26#define CS_LOG_RAW_FRAMES
27#ifdef CS_RAW_PACKED
28#define CS_RAW_DEBUG_FLAGS (OCSD_DFRMTR_UNPACKED_RAW_OUT | \
29 OCSD_DFRMTR_PACKED_RAW_OUT)
30#else
31#define CS_RAW_DEBUG_FLAGS (OCSD_DFRMTR_UNPACKED_RAW_OUT)
32#endif
33#endif
34
35struct cs_etm_decoder {
36 void *data;
37 void (*packet_printer)(const char *msg);
38 bool trace_on;
39 dcd_tree_handle_t dcd_tree;
40 cs_etm_mem_cb_type mem_access;
41 ocsd_datapath_resp_t prev_return;
42 u32 packet_count;
43 u32 head;
44 u32 tail;
45 struct cs_etm_packet packet_buffer[MAX_BUFFER];
46};
47
48static void cs_etm_decoder__gen_etmv4_config(struct cs_etm_trace_params *params,
49 ocsd_etmv4_cfg *config)
50{
51 config->reg_configr = params->etmv4.reg_configr;
52 config->reg_traceidr = params->etmv4.reg_traceidr;
53 config->reg_idr0 = params->etmv4.reg_idr0;
54 config->reg_idr1 = params->etmv4.reg_idr1;
55 config->reg_idr2 = params->etmv4.reg_idr2;
56 config->reg_idr8 = params->etmv4.reg_idr8;
57 config->reg_idr9 = 0;
58 config->reg_idr10 = 0;
59 config->reg_idr11 = 0;
60 config->reg_idr12 = 0;
61 config->reg_idr13 = 0;
62 config->arch_ver = ARCH_V8;
63 config->core_prof = profile_CortexA;
64}
65
66static void cs_etm_decoder__print_str_cb(const void *p_context,
67 const char *msg,
68 const int str_len)
69{
70 if (p_context && str_len)
71 ((struct cs_etm_decoder *)p_context)->packet_printer(msg);
72}
73
74static int
75cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params,
76 struct cs_etm_decoder *decoder)
77{
78 int ret = 0;
79
80 if (d_params->packet_printer == NULL)
81 return -1;
82
83 decoder->packet_printer = d_params->packet_printer;
84
85 /*
86 * Set up a library default logger to process any printers
87 * (packet/raw frame) we add later.
88 */
89 ret = ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1);
90 if (ret != 0)
91 return -1;
92
93 /* no stdout / err / file output */
94 ret = ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL);
95 if (ret != 0)
96 return -1;
97
98 /*
99 * Set the string CB for the default logger, passes strings to
100 * perf print logger.
101 */
102 ret = ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree,
103 (void *)decoder,
104 cs_etm_decoder__print_str_cb);
105 if (ret != 0)
106 ret = -1;
107
108 return 0;
109}
110
111#ifdef CS_LOG_RAW_FRAMES
112static void
113cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params,
114 struct cs_etm_decoder *decoder)
115{
116 /* Only log these during a --dump operation */
117 if (d_params->operation == CS_ETM_OPERATION_PRINT) {
118 /* set up a library default logger to process the
119 * raw frame printer we add later
120 */
121 ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1);
122
123 /* no stdout / err / file output */
124 ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL);
125
126 /* set the string CB for the default logger,
127 * passes strings to perf print logger.
128 */
129 ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree,
130 (void *)decoder,
131 cs_etm_decoder__print_str_cb);
132
133 /* use the built in library printer for the raw frames */
134 ocsd_dt_set_raw_frame_printer(decoder->dcd_tree,
135 CS_RAW_DEBUG_FLAGS);
136 }
137}
138#else
139static void
140cs_etm_decoder__init_raw_frame_logging(
141 struct cs_etm_decoder_params *d_params __maybe_unused,
142 struct cs_etm_decoder *decoder __maybe_unused)
143{
144}
145#endif
146
147static int cs_etm_decoder__create_packet_printer(struct cs_etm_decoder *decoder,
148 const char *decoder_name,
149 void *trace_config)
150{
151 u8 csid;
152
153 if (ocsd_dt_create_decoder(decoder->dcd_tree, decoder_name,
154 OCSD_CREATE_FLG_PACKET_PROC,
155 trace_config, &csid))
156 return -1;
157
158 if (ocsd_dt_set_pkt_protocol_printer(decoder->dcd_tree, csid, 0))
159 return -1;
160
161 return 0;
162}
163
164static int
165cs_etm_decoder__create_etm_packet_printer(struct cs_etm_trace_params *t_params,
166 struct cs_etm_decoder *decoder)
167{
168 const char *decoder_name;
169 ocsd_etmv4_cfg trace_config_etmv4;
170 void *trace_config;
171
172 switch (t_params->protocol) {
173 case CS_ETM_PROTO_ETMV4i:
174 cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4);
175 decoder_name = OCSD_BUILTIN_DCD_ETMV4I;
176 trace_config = &trace_config_etmv4;
177 break;
178 default:
179 return -1;
180 }
181
182 return cs_etm_decoder__create_packet_printer(decoder,
183 decoder_name,
184 trace_config);
185}
186
187static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
188{
189 int i;
190
191 decoder->head = 0;
192 decoder->tail = 0;
193 decoder->packet_count = 0;
194 for (i = 0; i < MAX_BUFFER; i++) {
195 decoder->packet_buffer[i].start_addr = 0xdeadbeefdeadbeefUL;
196 decoder->packet_buffer[i].end_addr = 0xdeadbeefdeadbeefUL;
197 decoder->packet_buffer[i].exc = false;
198 decoder->packet_buffer[i].exc_ret = false;
199 decoder->packet_buffer[i].cpu = INT_MIN;
200 }
201}
202
Mathieu Poirierc9a01a12018-01-17 10:52:14 -0700203static ocsd_datapath_resp_t
204cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
205 const ocsd_generic_trace_elem *elem,
206 const u8 trace_chan_id,
207 enum cs_etm_sample_type sample_type)
208{
209 u32 et = 0;
210 struct int_node *inode = NULL;
211
212 if (decoder->packet_count >= MAX_BUFFER - 1)
213 return OCSD_RESP_FATAL_SYS_ERR;
214
215 /* Search the RB tree for the cpu associated with this traceID */
216 inode = intlist__find(traceid_list, trace_chan_id);
217 if (!inode)
218 return OCSD_RESP_FATAL_SYS_ERR;
219
220 et = decoder->tail;
221 decoder->packet_buffer[et].sample_type = sample_type;
222 decoder->packet_buffer[et].start_addr = elem->st_addr;
223 decoder->packet_buffer[et].end_addr = elem->en_addr;
224 decoder->packet_buffer[et].exc = false;
225 decoder->packet_buffer[et].exc_ret = false;
226 decoder->packet_buffer[et].cpu = *((int *)inode->priv);
227
228 /* Wrap around if need be */
229 et = (et + 1) & (MAX_BUFFER - 1);
230
231 decoder->tail = et;
232 decoder->packet_count++;
233
234 if (decoder->packet_count == MAX_BUFFER - 1)
235 return OCSD_RESP_WAIT;
236
237 return OCSD_RESP_CONT;
238}
239
240static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
241 const void *context,
242 const ocsd_trc_index_t indx __maybe_unused,
243 const u8 trace_chan_id __maybe_unused,
244 const ocsd_generic_trace_elem *elem)
245{
246 ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
247 struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context;
248
249 switch (elem->elem_type) {
250 case OCSD_GEN_TRC_ELEM_UNKNOWN:
251 break;
252 case OCSD_GEN_TRC_ELEM_NO_SYNC:
253 decoder->trace_on = false;
254 break;
255 case OCSD_GEN_TRC_ELEM_TRACE_ON:
256 decoder->trace_on = true;
257 break;
258 case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
259 resp = cs_etm_decoder__buffer_packet(decoder, elem,
260 trace_chan_id,
261 CS_ETM_RANGE);
262 break;
263 case OCSD_GEN_TRC_ELEM_EXCEPTION:
264 decoder->packet_buffer[decoder->tail].exc = true;
265 break;
266 case OCSD_GEN_TRC_ELEM_EXCEPTION_RET:
267 decoder->packet_buffer[decoder->tail].exc_ret = true;
268 break;
269 case OCSD_GEN_TRC_ELEM_PE_CONTEXT:
270 case OCSD_GEN_TRC_ELEM_EO_TRACE:
271 case OCSD_GEN_TRC_ELEM_ADDR_NACC:
272 case OCSD_GEN_TRC_ELEM_TIMESTAMP:
273 case OCSD_GEN_TRC_ELEM_CYCLE_COUNT:
274 case OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN:
275 case OCSD_GEN_TRC_ELEM_EVENT:
276 case OCSD_GEN_TRC_ELEM_SWTRACE:
277 case OCSD_GEN_TRC_ELEM_CUSTOM:
278 default:
279 break;
280 }
281
282 return resp;
283}
284
285static int cs_etm_decoder__create_etm_packet_decoder(
286 struct cs_etm_trace_params *t_params,
287 struct cs_etm_decoder *decoder)
288{
289 const char *decoder_name;
290 ocsd_etmv4_cfg trace_config_etmv4;
291 void *trace_config;
292 u8 csid;
293
294 switch (t_params->protocol) {
295 case CS_ETM_PROTO_ETMV4i:
296 cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4);
297 decoder_name = OCSD_BUILTIN_DCD_ETMV4I;
298 trace_config = &trace_config_etmv4;
299 break;
300 default:
301 return -1;
302 }
303
304 if (ocsd_dt_create_decoder(decoder->dcd_tree,
305 decoder_name,
306 OCSD_CREATE_FLG_FULL_DECODER,
307 trace_config, &csid))
308 return -1;
309
310 if (ocsd_dt_set_gen_elem_outfn(decoder->dcd_tree,
311 cs_etm_decoder__gen_trace_elem_printer,
312 decoder))
313 return -1;
314
315 return 0;
316}
317
Mathieu Poirier68ffe392018-01-17 10:52:13 -0700318static int
319cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params,
320 struct cs_etm_trace_params *t_params,
321 struct cs_etm_decoder *decoder)
322{
323 if (d_params->operation == CS_ETM_OPERATION_PRINT)
324 return cs_etm_decoder__create_etm_packet_printer(t_params,
325 decoder);
Mathieu Poirierc9a01a12018-01-17 10:52:14 -0700326 else if (d_params->operation == CS_ETM_OPERATION_DECODE)
327 return cs_etm_decoder__create_etm_packet_decoder(t_params,
328 decoder);
329
Mathieu Poirier68ffe392018-01-17 10:52:13 -0700330 return -1;
331}
332
333struct cs_etm_decoder *
334cs_etm_decoder__new(int num_cpu, struct cs_etm_decoder_params *d_params,
335 struct cs_etm_trace_params t_params[])
336{
337 struct cs_etm_decoder *decoder;
338 ocsd_dcd_tree_src_t format;
339 u32 flags;
340 int i, ret;
341
342 if ((!t_params) || (!d_params))
343 return NULL;
344
345 decoder = zalloc(sizeof(*decoder));
346
347 if (!decoder)
348 return NULL;
349
350 decoder->data = d_params->data;
351 decoder->prev_return = OCSD_RESP_CONT;
352 cs_etm_decoder__clear_buffer(decoder);
353 format = (d_params->formatted ? OCSD_TRC_SRC_FRAME_FORMATTED :
354 OCSD_TRC_SRC_SINGLE);
355 flags = 0;
356 flags |= (d_params->fsyncs ? OCSD_DFRMTR_HAS_FSYNCS : 0);
357 flags |= (d_params->hsyncs ? OCSD_DFRMTR_HAS_HSYNCS : 0);
358 flags |= (d_params->frame_aligned ? OCSD_DFRMTR_FRAME_MEM_ALIGN : 0);
359
360 /*
361 * Drivers may add barrier frames when used with perf, set up to
362 * handle this. Barriers const of FSYNC packet repeated 4 times.
363 */
364 flags |= OCSD_DFRMTR_RESET_ON_4X_FSYNC;
365
366 /* Create decode tree for the data source */
367 decoder->dcd_tree = ocsd_create_dcd_tree(format, flags);
368
369 if (decoder->dcd_tree == 0)
370 goto err_free_decoder;
371
372 /* init library print logging support */
373 ret = cs_etm_decoder__init_def_logger_printing(d_params, decoder);
374 if (ret != 0)
375 goto err_free_decoder_tree;
376
377 /* init raw frame logging if required */
378 cs_etm_decoder__init_raw_frame_logging(d_params, decoder);
379
380 for (i = 0; i < num_cpu; i++) {
381 ret = cs_etm_decoder__create_etm_decoder(d_params,
382 &t_params[i],
383 decoder);
384 if (ret != 0)
385 goto err_free_decoder_tree;
386 }
387
388 return decoder;
389
390err_free_decoder_tree:
391 ocsd_destroy_dcd_tree(decoder->dcd_tree);
392err_free_decoder:
393 free(decoder);
394 return NULL;
395}
396
397int cs_etm_decoder__process_data_block(struct cs_etm_decoder *decoder,
398 u64 indx, const u8 *buf,
399 size_t len, size_t *consumed)
400{
401 int ret = 0;
402 ocsd_datapath_resp_t cur = OCSD_RESP_CONT;
403 ocsd_datapath_resp_t prev_return = decoder->prev_return;
404 size_t processed = 0;
405 u32 count;
406
407 while (processed < len) {
408 if (OCSD_DATA_RESP_IS_WAIT(prev_return)) {
409 cur = ocsd_dt_process_data(decoder->dcd_tree,
410 OCSD_OP_FLUSH,
411 0,
412 0,
413 NULL,
414 NULL);
415 } else if (OCSD_DATA_RESP_IS_CONT(prev_return)) {
416 cur = ocsd_dt_process_data(decoder->dcd_tree,
417 OCSD_OP_DATA,
418 indx + processed,
419 len - processed,
420 &buf[processed],
421 &count);
422 processed += count;
423 } else {
424 ret = -EINVAL;
425 break;
426 }
427
428 /*
429 * Return to the input code if the packet buffer is full.
430 * Flushing will get done once the packet buffer has been
431 * processed.
432 */
433 if (OCSD_DATA_RESP_IS_WAIT(cur))
434 break;
435
436 prev_return = cur;
437 }
438
439 decoder->prev_return = cur;
440 *consumed = processed;
441
442 return ret;
443}
444
445void cs_etm_decoder__free(struct cs_etm_decoder *decoder)
446{
447 if (!decoder)
448 return;
449
450 ocsd_destroy_dcd_tree(decoder->dcd_tree);
451 decoder->dcd_tree = NULL;
452 free(decoder);
453}