]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
perf tools: Add decoder mechanic to support dumping trace data
[linux.git] / tools / perf / util / cs-etm-decoder / cs-etm-decoder.c
1 /*
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
35 struct 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
48 static 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
66 static 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
74 static int
75 cs_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
112 static void
113 cs_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
139 static void
140 cs_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
147 static 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
164 static int
165 cs_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
187 static 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
203 static int
204 cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params,
205                                    struct cs_etm_trace_params *t_params,
206                                    struct cs_etm_decoder *decoder)
207 {
208         if (d_params->operation == CS_ETM_OPERATION_PRINT)
209                 return cs_etm_decoder__create_etm_packet_printer(t_params,
210                                                                  decoder);
211         return -1;
212 }
213
214 struct cs_etm_decoder *
215 cs_etm_decoder__new(int num_cpu, struct cs_etm_decoder_params *d_params,
216                     struct cs_etm_trace_params t_params[])
217 {
218         struct cs_etm_decoder *decoder;
219         ocsd_dcd_tree_src_t format;
220         u32 flags;
221         int i, ret;
222
223         if ((!t_params) || (!d_params))
224                 return NULL;
225
226         decoder = zalloc(sizeof(*decoder));
227
228         if (!decoder)
229                 return NULL;
230
231         decoder->data = d_params->data;
232         decoder->prev_return = OCSD_RESP_CONT;
233         cs_etm_decoder__clear_buffer(decoder);
234         format = (d_params->formatted ? OCSD_TRC_SRC_FRAME_FORMATTED :
235                                          OCSD_TRC_SRC_SINGLE);
236         flags = 0;
237         flags |= (d_params->fsyncs ? OCSD_DFRMTR_HAS_FSYNCS : 0);
238         flags |= (d_params->hsyncs ? OCSD_DFRMTR_HAS_HSYNCS : 0);
239         flags |= (d_params->frame_aligned ? OCSD_DFRMTR_FRAME_MEM_ALIGN : 0);
240
241         /*
242          * Drivers may add barrier frames when used with perf, set up to
243          * handle this. Barriers const of FSYNC packet repeated 4 times.
244          */
245         flags |= OCSD_DFRMTR_RESET_ON_4X_FSYNC;
246
247         /* Create decode tree for the data source */
248         decoder->dcd_tree = ocsd_create_dcd_tree(format, flags);
249
250         if (decoder->dcd_tree == 0)
251                 goto err_free_decoder;
252
253         /* init library print logging support */
254         ret = cs_etm_decoder__init_def_logger_printing(d_params, decoder);
255         if (ret != 0)
256                 goto err_free_decoder_tree;
257
258         /* init raw frame logging if required */
259         cs_etm_decoder__init_raw_frame_logging(d_params, decoder);
260
261         for (i = 0; i < num_cpu; i++) {
262                 ret = cs_etm_decoder__create_etm_decoder(d_params,
263                                                          &t_params[i],
264                                                          decoder);
265                 if (ret != 0)
266                         goto err_free_decoder_tree;
267         }
268
269         return decoder;
270
271 err_free_decoder_tree:
272         ocsd_destroy_dcd_tree(decoder->dcd_tree);
273 err_free_decoder:
274         free(decoder);
275         return NULL;
276 }
277
278 int cs_etm_decoder__process_data_block(struct cs_etm_decoder *decoder,
279                                        u64 indx, const u8 *buf,
280                                        size_t len, size_t *consumed)
281 {
282         int ret = 0;
283         ocsd_datapath_resp_t cur = OCSD_RESP_CONT;
284         ocsd_datapath_resp_t prev_return = decoder->prev_return;
285         size_t processed = 0;
286         u32 count;
287
288         while (processed < len) {
289                 if (OCSD_DATA_RESP_IS_WAIT(prev_return)) {
290                         cur = ocsd_dt_process_data(decoder->dcd_tree,
291                                                    OCSD_OP_FLUSH,
292                                                    0,
293                                                    0,
294                                                    NULL,
295                                                    NULL);
296                 } else if (OCSD_DATA_RESP_IS_CONT(prev_return)) {
297                         cur = ocsd_dt_process_data(decoder->dcd_tree,
298                                                    OCSD_OP_DATA,
299                                                    indx + processed,
300                                                    len - processed,
301                                                    &buf[processed],
302                                                    &count);
303                         processed += count;
304                 } else {
305                         ret = -EINVAL;
306                         break;
307                 }
308
309                 /*
310                  * Return to the input code if the packet buffer is full.
311                  * Flushing will get done once the packet buffer has been
312                  * processed.
313                  */
314                 if (OCSD_DATA_RESP_IS_WAIT(cur))
315                         break;
316
317                 prev_return = cur;
318         }
319
320         decoder->prev_return = cur;
321         *consumed = processed;
322
323         return ret;
324 }
325
326 void cs_etm_decoder__free(struct cs_etm_decoder *decoder)
327 {
328         if (!decoder)
329                 return;
330
331         ocsd_destroy_dcd_tree(decoder->dcd_tree);
332         decoder->dcd_tree = NULL;
333         free(decoder);
334 }