2 * SPDX-License-Identifier: GPL-2.0
4 * Copyright(C) 2015-2018 Linaro Limited.
6 * Author: Tor Jeremiassen <tor@ti.com>
7 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
10 #include <linux/err.h>
11 #include <linux/list.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>
18 #include "cs-etm-decoder.h"
22 #define MAX_BUFFER 1024
26 #define CS_LOG_RAW_FRAMES
28 #define CS_RAW_DEBUG_FLAGS (OCSD_DFRMTR_UNPACKED_RAW_OUT | \
29 OCSD_DFRMTR_PACKED_RAW_OUT)
31 #define CS_RAW_DEBUG_FLAGS (OCSD_DFRMTR_UNPACKED_RAW_OUT)
35 struct cs_etm_decoder
{
37 void (*packet_printer
)(const char *msg
);
39 dcd_tree_handle_t dcd_tree
;
40 cs_etm_mem_cb_type mem_access
;
41 ocsd_datapath_resp_t prev_return
;
45 struct cs_etm_packet packet_buffer
[MAX_BUFFER
];
49 cs_etm_decoder__mem_access(const void *context
,
50 const ocsd_vaddr_t address
,
51 const ocsd_mem_space_acc_t mem_space __maybe_unused
,
55 struct cs_etm_decoder
*decoder
= (struct cs_etm_decoder
*) context
;
57 return decoder
->mem_access(decoder
->data
,
63 int cs_etm_decoder__add_mem_access_cb(struct cs_etm_decoder
*decoder
,
65 cs_etm_mem_cb_type cb_func
)
67 decoder
->mem_access
= cb_func
;
69 if (ocsd_dt_add_callback_mem_acc(decoder
->dcd_tree
, start
, end
,
71 cs_etm_decoder__mem_access
, decoder
))
77 int cs_etm_decoder__reset(struct cs_etm_decoder
*decoder
)
79 ocsd_datapath_resp_t dp_ret
;
81 dp_ret
= ocsd_dt_process_data(decoder
->dcd_tree
, OCSD_OP_RESET
,
83 if (OCSD_DATA_RESP_IS_FATAL(dp_ret
))
89 int cs_etm_decoder__get_packet(struct cs_etm_decoder
*decoder
,
90 struct cs_etm_packet
*packet
)
92 if (!decoder
|| !packet
)
95 /* Nothing to do, might as well just return */
96 if (decoder
->packet_count
== 0)
99 *packet
= decoder
->packet_buffer
[decoder
->head
];
101 decoder
->head
= (decoder
->head
+ 1) & (MAX_BUFFER
- 1);
103 decoder
->packet_count
--;
108 static void cs_etm_decoder__gen_etmv4_config(struct cs_etm_trace_params
*params
,
109 ocsd_etmv4_cfg
*config
)
111 config
->reg_configr
= params
->etmv4
.reg_configr
;
112 config
->reg_traceidr
= params
->etmv4
.reg_traceidr
;
113 config
->reg_idr0
= params
->etmv4
.reg_idr0
;
114 config
->reg_idr1
= params
->etmv4
.reg_idr1
;
115 config
->reg_idr2
= params
->etmv4
.reg_idr2
;
116 config
->reg_idr8
= params
->etmv4
.reg_idr8
;
117 config
->reg_idr9
= 0;
118 config
->reg_idr10
= 0;
119 config
->reg_idr11
= 0;
120 config
->reg_idr12
= 0;
121 config
->reg_idr13
= 0;
122 config
->arch_ver
= ARCH_V8
;
123 config
->core_prof
= profile_CortexA
;
126 static void cs_etm_decoder__print_str_cb(const void *p_context
,
130 if (p_context
&& str_len
)
131 ((struct cs_etm_decoder
*)p_context
)->packet_printer(msg
);
135 cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params
*d_params
,
136 struct cs_etm_decoder
*decoder
)
140 if (d_params
->packet_printer
== NULL
)
143 decoder
->packet_printer
= d_params
->packet_printer
;
146 * Set up a library default logger to process any printers
147 * (packet/raw frame) we add later.
149 ret
= ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR
, 1);
153 /* no stdout / err / file output */
154 ret
= ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE
, NULL
);
159 * Set the string CB for the default logger, passes strings to
162 ret
= ocsd_def_errlog_set_strprint_cb(decoder
->dcd_tree
,
164 cs_etm_decoder__print_str_cb
);
171 #ifdef CS_LOG_RAW_FRAMES
173 cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params
*d_params
,
174 struct cs_etm_decoder
*decoder
)
176 /* Only log these during a --dump operation */
177 if (d_params
->operation
== CS_ETM_OPERATION_PRINT
) {
178 /* set up a library default logger to process the
179 * raw frame printer we add later
181 ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR
, 1);
183 /* no stdout / err / file output */
184 ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE
, NULL
);
186 /* set the string CB for the default logger,
187 * passes strings to perf print logger.
189 ocsd_def_errlog_set_strprint_cb(decoder
->dcd_tree
,
191 cs_etm_decoder__print_str_cb
);
193 /* use the built in library printer for the raw frames */
194 ocsd_dt_set_raw_frame_printer(decoder
->dcd_tree
,
200 cs_etm_decoder__init_raw_frame_logging(
201 struct cs_etm_decoder_params
*d_params __maybe_unused
,
202 struct cs_etm_decoder
*decoder __maybe_unused
)
207 static int cs_etm_decoder__create_packet_printer(struct cs_etm_decoder
*decoder
,
208 const char *decoder_name
,
213 if (ocsd_dt_create_decoder(decoder
->dcd_tree
, decoder_name
,
214 OCSD_CREATE_FLG_PACKET_PROC
,
215 trace_config
, &csid
))
218 if (ocsd_dt_set_pkt_protocol_printer(decoder
->dcd_tree
, csid
, 0))
225 cs_etm_decoder__create_etm_packet_printer(struct cs_etm_trace_params
*t_params
,
226 struct cs_etm_decoder
*decoder
)
228 const char *decoder_name
;
229 ocsd_etmv4_cfg trace_config_etmv4
;
232 switch (t_params
->protocol
) {
233 case CS_ETM_PROTO_ETMV4i
:
234 cs_etm_decoder__gen_etmv4_config(t_params
, &trace_config_etmv4
);
235 decoder_name
= OCSD_BUILTIN_DCD_ETMV4I
;
236 trace_config
= &trace_config_etmv4
;
242 return cs_etm_decoder__create_packet_printer(decoder
,
247 static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder
*decoder
)
253 decoder
->packet_count
= 0;
254 for (i
= 0; i
< MAX_BUFFER
; i
++) {
255 decoder
->packet_buffer
[i
].start_addr
= 0xdeadbeefdeadbeefUL
;
256 decoder
->packet_buffer
[i
].end_addr
= 0xdeadbeefdeadbeefUL
;
257 decoder
->packet_buffer
[i
].exc
= false;
258 decoder
->packet_buffer
[i
].exc_ret
= false;
259 decoder
->packet_buffer
[i
].cpu
= INT_MIN
;
263 static ocsd_datapath_resp_t
264 cs_etm_decoder__buffer_packet(struct cs_etm_decoder
*decoder
,
265 const ocsd_generic_trace_elem
*elem
,
266 const u8 trace_chan_id
,
267 enum cs_etm_sample_type sample_type
)
270 struct int_node
*inode
= NULL
;
272 if (decoder
->packet_count
>= MAX_BUFFER
- 1)
273 return OCSD_RESP_FATAL_SYS_ERR
;
275 /* Search the RB tree for the cpu associated with this traceID */
276 inode
= intlist__find(traceid_list
, trace_chan_id
);
278 return OCSD_RESP_FATAL_SYS_ERR
;
281 decoder
->packet_buffer
[et
].sample_type
= sample_type
;
282 decoder
->packet_buffer
[et
].start_addr
= elem
->st_addr
;
283 decoder
->packet_buffer
[et
].end_addr
= elem
->en_addr
;
284 decoder
->packet_buffer
[et
].exc
= false;
285 decoder
->packet_buffer
[et
].exc_ret
= false;
286 decoder
->packet_buffer
[et
].cpu
= *((int *)inode
->priv
);
288 /* Wrap around if need be */
289 et
= (et
+ 1) & (MAX_BUFFER
- 1);
292 decoder
->packet_count
++;
294 if (decoder
->packet_count
== MAX_BUFFER
- 1)
295 return OCSD_RESP_WAIT
;
297 return OCSD_RESP_CONT
;
300 static ocsd_datapath_resp_t
cs_etm_decoder__gen_trace_elem_printer(
302 const ocsd_trc_index_t indx __maybe_unused
,
303 const u8 trace_chan_id __maybe_unused
,
304 const ocsd_generic_trace_elem
*elem
)
306 ocsd_datapath_resp_t resp
= OCSD_RESP_CONT
;
307 struct cs_etm_decoder
*decoder
= (struct cs_etm_decoder
*) context
;
309 switch (elem
->elem_type
) {
310 case OCSD_GEN_TRC_ELEM_UNKNOWN
:
312 case OCSD_GEN_TRC_ELEM_NO_SYNC
:
313 decoder
->trace_on
= false;
315 case OCSD_GEN_TRC_ELEM_TRACE_ON
:
316 decoder
->trace_on
= true;
318 case OCSD_GEN_TRC_ELEM_INSTR_RANGE
:
319 resp
= cs_etm_decoder__buffer_packet(decoder
, elem
,
323 case OCSD_GEN_TRC_ELEM_EXCEPTION
:
324 decoder
->packet_buffer
[decoder
->tail
].exc
= true;
326 case OCSD_GEN_TRC_ELEM_EXCEPTION_RET
:
327 decoder
->packet_buffer
[decoder
->tail
].exc_ret
= true;
329 case OCSD_GEN_TRC_ELEM_PE_CONTEXT
:
330 case OCSD_GEN_TRC_ELEM_EO_TRACE
:
331 case OCSD_GEN_TRC_ELEM_ADDR_NACC
:
332 case OCSD_GEN_TRC_ELEM_TIMESTAMP
:
333 case OCSD_GEN_TRC_ELEM_CYCLE_COUNT
:
334 case OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN
:
335 case OCSD_GEN_TRC_ELEM_EVENT
:
336 case OCSD_GEN_TRC_ELEM_SWTRACE
:
337 case OCSD_GEN_TRC_ELEM_CUSTOM
:
345 static int cs_etm_decoder__create_etm_packet_decoder(
346 struct cs_etm_trace_params
*t_params
,
347 struct cs_etm_decoder
*decoder
)
349 const char *decoder_name
;
350 ocsd_etmv4_cfg trace_config_etmv4
;
354 switch (t_params
->protocol
) {
355 case CS_ETM_PROTO_ETMV4i
:
356 cs_etm_decoder__gen_etmv4_config(t_params
, &trace_config_etmv4
);
357 decoder_name
= OCSD_BUILTIN_DCD_ETMV4I
;
358 trace_config
= &trace_config_etmv4
;
364 if (ocsd_dt_create_decoder(decoder
->dcd_tree
,
366 OCSD_CREATE_FLG_FULL_DECODER
,
367 trace_config
, &csid
))
370 if (ocsd_dt_set_gen_elem_outfn(decoder
->dcd_tree
,
371 cs_etm_decoder__gen_trace_elem_printer
,
379 cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params
*d_params
,
380 struct cs_etm_trace_params
*t_params
,
381 struct cs_etm_decoder
*decoder
)
383 if (d_params
->operation
== CS_ETM_OPERATION_PRINT
)
384 return cs_etm_decoder__create_etm_packet_printer(t_params
,
386 else if (d_params
->operation
== CS_ETM_OPERATION_DECODE
)
387 return cs_etm_decoder__create_etm_packet_decoder(t_params
,
393 struct cs_etm_decoder
*
394 cs_etm_decoder__new(int num_cpu
, struct cs_etm_decoder_params
*d_params
,
395 struct cs_etm_trace_params t_params
[])
397 struct cs_etm_decoder
*decoder
;
398 ocsd_dcd_tree_src_t format
;
402 if ((!t_params
) || (!d_params
))
405 decoder
= zalloc(sizeof(*decoder
));
410 decoder
->data
= d_params
->data
;
411 decoder
->prev_return
= OCSD_RESP_CONT
;
412 cs_etm_decoder__clear_buffer(decoder
);
413 format
= (d_params
->formatted
? OCSD_TRC_SRC_FRAME_FORMATTED
:
414 OCSD_TRC_SRC_SINGLE
);
416 flags
|= (d_params
->fsyncs
? OCSD_DFRMTR_HAS_FSYNCS
: 0);
417 flags
|= (d_params
->hsyncs
? OCSD_DFRMTR_HAS_HSYNCS
: 0);
418 flags
|= (d_params
->frame_aligned
? OCSD_DFRMTR_FRAME_MEM_ALIGN
: 0);
421 * Drivers may add barrier frames when used with perf, set up to
422 * handle this. Barriers const of FSYNC packet repeated 4 times.
424 flags
|= OCSD_DFRMTR_RESET_ON_4X_FSYNC
;
426 /* Create decode tree for the data source */
427 decoder
->dcd_tree
= ocsd_create_dcd_tree(format
, flags
);
429 if (decoder
->dcd_tree
== 0)
430 goto err_free_decoder
;
432 /* init library print logging support */
433 ret
= cs_etm_decoder__init_def_logger_printing(d_params
, decoder
);
435 goto err_free_decoder_tree
;
437 /* init raw frame logging if required */
438 cs_etm_decoder__init_raw_frame_logging(d_params
, decoder
);
440 for (i
= 0; i
< num_cpu
; i
++) {
441 ret
= cs_etm_decoder__create_etm_decoder(d_params
,
445 goto err_free_decoder_tree
;
450 err_free_decoder_tree
:
451 ocsd_destroy_dcd_tree(decoder
->dcd_tree
);
457 int cs_etm_decoder__process_data_block(struct cs_etm_decoder
*decoder
,
458 u64 indx
, const u8
*buf
,
459 size_t len
, size_t *consumed
)
462 ocsd_datapath_resp_t cur
= OCSD_RESP_CONT
;
463 ocsd_datapath_resp_t prev_return
= decoder
->prev_return
;
464 size_t processed
= 0;
467 while (processed
< len
) {
468 if (OCSD_DATA_RESP_IS_WAIT(prev_return
)) {
469 cur
= ocsd_dt_process_data(decoder
->dcd_tree
,
475 } else if (OCSD_DATA_RESP_IS_CONT(prev_return
)) {
476 cur
= ocsd_dt_process_data(decoder
->dcd_tree
,
489 * Return to the input code if the packet buffer is full.
490 * Flushing will get done once the packet buffer has been
493 if (OCSD_DATA_RESP_IS_WAIT(cur
))
499 decoder
->prev_return
= cur
;
500 *consumed
= processed
;
505 void cs_etm_decoder__free(struct cs_etm_decoder
*decoder
)
510 ocsd_destroy_dcd_tree(decoder
->dcd_tree
);
511 decoder
->dcd_tree
= NULL
;