dpdk: Add support for Mellanox ConnectX-4 devices
[vpp.git] / g2 / cpel.c
1 /* 
2  *------------------------------------------------------------------
3  * Copyright (c) 2005-2016 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <netinet/in.h>
20 #include <string.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <sys/fcntl.h>
25 #include <sys/mman.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #include <vppinfra/clib.h>
29 #include <vppinfra/vec.h>
30 #include <vppinfra/hash.h>
31 #include <pwd.h>
32 #include <stdarg.h>
33 #include <time.h>
34 #include "cpel.h"
35 #include "g2.h"
36
37 typedef struct bound_event_ {
38     u32 event_code;
39     u8  *event_str;
40     u8  *datum_str;
41 } bound_event_t;
42
43 bound_event_t *bound_events;
44
45 int widest_track_format=8;
46
47 typedef struct bound_track_ {
48     u32 track;
49     u8  *track_str;
50 } bound_track_t;
51
52 bound_track_t *bound_tracks;
53
54 uword *the_strtab_hash; /* (name, base-VA) hash of all string tables */
55 uword *the_evtdef_hash; /* (event-id, event-definition) hash */
56 uword *the_trackdef_hash; /* (track-id, track-definition) hash */
57 u8 *event_strtab;         /* event string-table */
58
59 void fatal(char *s)
60 {
61     fprintf(stderr, "%s", s);
62     exit(1);
63 }
64
65 typedef enum {
66     PASS1=1,
67     PASS2=2,
68 } pass_t;
69
70 typedef struct {
71     int (*pass1)(cpel_section_header_t *, int, FILE *);
72     int (*pass2)(cpel_section_header_t *, int, FILE *);
73 } section_processor_t;
74
75 int bad_section(cpel_section_header_t *sh, int verbose, FILE *ofp)
76 {
77     fprintf(ofp, "Bad (type 0) section, skipped...\n");
78     return(0);
79 }
80
81 int noop_pass(cpel_section_header_t *sh, int verbose, FILE *ofp)
82 {
83     return(0);
84 }
85
86 int strtab_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp)
87 {
88     uword *p;
89     u8 *strtab_data_area = (u8 *)(sh+1);
90     
91     /* Multiple string tables with the same name are Bad... */
92     p = hash_get_mem(the_strtab_hash, strtab_data_area);
93     if (p) {
94         fprintf(ofp, "Duplicate string table name %s", strtab_data_area);
95     }
96     /*
97      * Looks funny, but we really do want key = first string in the
98      * table, value = address(first string in the table) 
99      */
100     hash_set_mem(the_strtab_hash, strtab_data_area, strtab_data_area);
101     if (verbose) {
102         fprintf(ofp, "String Table %s\n", strtab_data_area);
103     }
104     return(0);
105 }
106
107 int evtdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp)
108 {
109     int i, nevents;
110     event_definition_section_header_t *edh;
111     event_definition_t *ep;
112     u8 *this_strtab;
113     u32 event_code;
114     uword *p;
115     bound_event_t *bp;
116
117     edh = (event_definition_section_header_t *)(sh+1);
118     nevents = ntohl(edh->number_of_event_definitions);
119     
120     if (verbose) {
121         fprintf(ofp, "Event Definition Section: %d definitions\n",
122                 nevents);
123     }
124
125     p = hash_get_mem(the_strtab_hash, edh->string_table_name);
126     if (!p) {
127         fprintf(ofp, "Fatal: couldn't find string table\n");
128         return(1);
129     }
130     this_strtab = (u8 *)p[0];
131
132     initialize_events();
133
134     ep = (event_definition_t *)(edh+1);
135     
136     for (i = 0; i < nevents; i++) {
137         event_code = ntohl(ep->event);
138         p = hash_get(the_evtdef_hash, event_code);
139         if (p) {
140             fprintf(ofp, "Event %d redefined, retain first definition\n",
141                     event_code);
142             continue;
143         }
144         vec_add2(bound_events, bp, 1);
145         bp->event_code = event_code;
146         bp->event_str = this_strtab + ntohl(ep->event_format);
147         bp->datum_str = this_strtab + ntohl(ep->datum_format);
148         hash_set(the_evtdef_hash, event_code, bp - bound_events);
149
150         add_event_from_cpel_file(event_code, (char *) bp->event_str, 
151                                  (char *)bp->datum_str);
152
153         ep++;
154     }
155
156     finalize_events();
157     return (0);
158 }
159
160 int trackdef_pass1(cpel_section_header_t *sh, int verbose, FILE *ofp)
161 {
162     int i, nevents;
163     track_definition_section_header_t *tdh;
164     track_definition_t *tp;
165     u8 *this_strtab;
166     u32 track_code;
167     uword *p;
168     bound_track_t *btp;
169     int track_strlen;
170
171     tdh = (track_definition_section_header_t *)(sh+1);
172     nevents = ntohl(tdh->number_of_track_definitions);
173     
174     if (verbose) {
175         fprintf(ofp, "Track Definition Section: %d definitions\n",
176                 nevents);
177     }
178
179     p = hash_get_mem(the_strtab_hash, tdh->string_table_name);
180     if (!p) {
181         fprintf(ofp, "Fatal: couldn't find string table\n");
182         return(1);
183     }
184     this_strtab = (u8 *)p[0];
185
186     tp = (track_definition_t *)(tdh+1);
187     
188     for (i = 0; i < nevents; i++) {
189         track_code = ntohl(tp->track);
190         p = hash_get(the_trackdef_hash, track_code);
191         if (p) {
192             fprintf(ofp, "track %d redefined, retain first definition\n",
193                     track_code);
194             continue;
195         }
196         vec_add2(bound_tracks, btp, 1);
197         btp->track = track_code;
198         btp->track_str = this_strtab + ntohl(tp->track_format);
199         hash_set(the_trackdef_hash, track_code, btp - bound_tracks);
200
201         track_strlen = strlen((char *)btp->track_str);
202         if (track_strlen > widest_track_format)
203             widest_track_format = track_strlen;
204         tp++;
205     }
206     return (0);
207 }
208
209 int unsupported_pass (cpel_section_header_t *sh, int verbose, FILE *ofp)
210 {
211     if (verbose) {
212         fprintf(ofp, "Unsupported type %d section\n",
213                 ntohl(sh->section_type));
214     }
215     return(0);
216 }
217
218 int event_pass2(cpel_section_header_t *sh, int verbose, FILE *ofp)
219 {
220     event_section_header_t *eh;
221     u32 event_code, track_code, datum;
222     u64 starttime = ~0ULL;
223     int nevents;
224     int i;
225     event_entry_t *ep;
226     u64 now;
227     u64 delta;
228     u32 time0, time1;
229     double d;
230     uword *p;
231
232     eh = (event_section_header_t *)(sh+1);
233     nevents = ntohl(eh->number_of_events);
234     ticks_per_ns = ntohl(eh->clock_ticks_per_second)/1e9;
235     ep = (event_entry_t *)(eh+1);
236
237     p = hash_get_mem(the_strtab_hash, eh->string_table_name);
238     if (!p) {
239         fprintf(ofp, "Fatal: couldn't find string table\n");
240         return(1);
241     }
242     event_strtab = (u8 *)p[0];
243
244     cpel_event_init(nevents);
245
246     for (i = 0; i < nevents; i++) {
247         time0 = ntohl (ep->time[0]);
248         time1 = ntohl (ep->time[1]);
249
250         now = (((u64) time0)<<32) | time1;
251         
252         /* Convert from bus ticks to usec */
253         d = now;
254         d /= ticks_per_ns;
255
256         now = d;
257
258         if (starttime == ~0ULL)
259             starttime = now;
260         
261         delta = now - starttime;
262
263         /* Delta = time since first event, in usec */
264         event_code = ntohl(ep->event_code);
265         track_code = ntohl(ep->track);
266         datum = ntohl(ep->event_datum);
267
268         add_cpel_event(delta, track_code, event_code, datum);
269
270         ep++;
271     }
272     cpel_event_finalize();
273     return(0);
274 }
275
276 char *strtab_ref(unsigned long datum)
277 {
278     return ((char *)(event_strtab + datum));
279 }
280
281 /* 
282  * Note: If necessary, add passes / columns to this table to 
283  * handle section order dependencies.
284  */
285
286 section_processor_t processors[CPEL_NUM_SECTION_TYPES+1] =
287 {
288     {bad_section,       noop_pass},             /* type 0 -- f**ked */
289     {strtab_pass1,      noop_pass},             /* type 1 -- STRTAB */
290     {unsupported_pass,  noop_pass},             /* type 2 -- SYMTAB */
291     {evtdef_pass1,      noop_pass},             /* type 3 -- EVTDEF */
292     {trackdef_pass1,    noop_pass},             /* type 4 -- TRACKDEF */
293     {noop_pass,         event_pass2},           /* type 5 -- EVENTS */
294 };
295
296
297 int process_section(cpel_section_header_t *sh, int verbose, FILE *ofp,
298                     pass_t pass)
299 {
300     u32 type;
301     type = ntohl(sh->section_type);
302     int rv;
303     int (*fp)(cpel_section_header_t *, int, FILE *);
304
305     if (type > CPEL_NUM_SECTION_TYPES) {
306         fprintf(stderr, "Unknown section type %d\n", type);
307         return(1);
308     }
309     switch(pass) {
310     case PASS1:
311         fp = processors[type].pass1;
312         break;
313
314     case PASS2:
315         fp = processors[type].pass2;
316         break;
317         
318     default:
319         fprintf(stderr, "Unknown pass %d\n", pass);
320         return(1);
321     }
322
323     rv = (*fp)(sh, verbose, ofp);
324
325     return(rv);
326 }
327
328 int cpel_dump_file_header(cpel_file_header_t *fh, int verbose, FILE *ofp)
329 {
330     time_t file_time;
331
332     if (verbose) {
333         fprintf(ofp, "CPEL file: %s-endian, version %d\n",
334                 ((fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) ? 
335                  "little" : "big"), 
336                 fh->endian_version & CPEL_FILE_VERSION_MASK);
337
338         file_time = ntohl(fh->file_date);
339
340         fprintf(ofp, "File created %s", ctime(&file_time));
341     }
342
343     return(0);
344 }
345
346
347 int cpel_process(u8 *cpel, int verbose, FILE *ofp)
348 {
349     cpel_file_header_t *fh;
350     cpel_section_header_t *sh;
351     u16 nsections;
352     u32 section_size;
353     int i;
354
355     /* First, the file header */
356     fh = (cpel_file_header_t *)cpel;
357     if (fh->endian_version != CPEL_FILE_VERSION) {
358         if (fh->endian_version & CPEL_FILE_LITTLE_ENDIAN) {
359             fprintf(stderr, "Little endian data format not supported\n");
360             return(1);
361         }
362         fprintf(stderr, "Unsupported file version 0x%x\n", 
363                 fh->endian_version);
364         return(1);
365     }
366     cpel_dump_file_header(fh, verbose, ofp);
367     nsections = ntohs(fh->nsections);
368
369     /*
370      * Take two passes through the file. PASS1 builds
371      * data structures, PASS2 actually dumps the file.
372      * Just in case the sections are in an unobvious order.
373      */
374     sh = (cpel_section_header_t *)(fh+1);
375     for (i = 0; i < nsections; i++) {
376         section_size = ntohl(sh->data_length);
377
378         if(verbose) {
379             fprintf(ofp, "Section type %d, size %d\n", ntohl(sh->section_type),
380                     section_size);
381         }
382
383         if(process_section(sh, verbose, ofp, PASS1))
384             return(1);
385
386         sh++;
387         sh = (cpel_section_header_t *)(((u8 *)sh)+section_size);
388     }
389
390     sh = (cpel_section_header_t *)(fh+1);
391     for (i = 0; i < nsections; i++) {
392         if(process_section(sh, verbose, ofp, PASS2))
393             return(1);
394         section_size = ntohl(sh->data_length);
395         sh++;
396         sh = (cpel_section_header_t *)(((u8 *)sh)+section_size);
397     }
398
399
400     return(0);
401 }
402
403 /*
404  * read_cpel_file
405  */
406 int read_cpel_file(char *cpel_file)
407 {
408     int verbose = 0;
409     int rv;
410     static u8 *cpel;
411     static unsigned long size;
412     static FILE *ofp;
413
414     if (cpel) {
415         unmapfile((char *)cpel, size);
416         hash_free(the_strtab_hash);
417         the_strtab_hash = 0;
418         hash_free(the_evtdef_hash);
419         the_evtdef_hash = 0;
420         hash_free(the_trackdef_hash);
421         the_trackdef_hash = 0;
422     }
423
424     cpel = (u8 *)mapfile((char *)cpel_file, &size);
425     if (cpel == 0) {
426         fprintf(stderr, "Couldn't map %s...\n", cpel_file);
427         exit(1);
428     }
429
430     if (ofp == NULL) {
431         ofp = fdopen(2, "w");
432         if (ofp == NULL) {
433             fprintf(stderr, "Couldn't fdopen(2)?\n");
434             exit(1);
435         }
436     }
437
438     the_strtab_hash = hash_create_string (0, sizeof (uword));
439     the_evtdef_hash = hash_create (0, sizeof (uword));
440     the_trackdef_hash = hash_create (0, sizeof (uword));
441
442     rv = cpel_process(cpel, verbose, ofp);
443
444     set_pid_ax_width(8*widest_track_format);
445
446     return(rv);
447 }
448
449 static bound_track_t generic_hex_track = {0, (u8 *) "0x%08x"};
450 static bound_track_t generic_decimal_track = {0, (u8 *) "%8ld"};
451
452 /*
453  * get_track_label
454  */
455 char *get_track_label(unsigned long track)
456 {
457     uword *p;
458     bound_track_t *tp;
459
460     p = hash_get(the_trackdef_hash, track);
461     if (p) {
462         tp = &bound_tracks[p[0]];
463     } else {
464         if (track > 65535) 
465             tp = &generic_hex_track;
466         else
467             tp = &generic_decimal_track;
468     }
469     return((char *)tp->track_str);
470 }