blob: 889630c4f6bd9e5e4dafd6d1e27013c49250b0c9 [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/*
2<:copyright-BRCM:2016:DUAL/GPL:standard
3
4 Broadcom Proprietary and Confidential.(c) 2016 Broadcom
5 All Rights Reserved
6
7Unless you and Broadcom execute a separate written software license
8agreement governing use of this software, this software is licensed
9to you under the terms of the GNU General Public License version 2
10(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11with the following added to such license:
12
13 As a special exception, the copyright holders of this software give
14 you permission to link this software with independent modules, and
15 to copy and distribute the resulting executable under terms of your
16 choice, provided that you also meet, for each linked independent
17 module, the terms and conditions of the license of that module.
18 An independent module is a module which is not derived from this
19 software. The special exception does not apply to any modifications
20 of the software.
21
22Not withstanding the above, under no circumstances may you combine
23this software in any way with any other Broadcom software provided
24under a license other than the GPL, without Broadcom's express prior
25written consent.
26
27:>
28 */
29
30#include <bcmos_system.h>
31#include <bcmtr_debug.h>
32#include <bcmcli_session.h>
33#include <bcm_api_cli_helpers.h>
34#include <bcmolt_math.h>
35
36#ifdef ENABLE_LOG
37#include <bcm_dev_log.h>
38#endif
39
40#ifdef ENABLE_CLI
41#include <bcmtr_debug_cli.h>
42#endif
43
44/* Messages are recorded in the following format:
45 * uint32_t - event type
46 * uint32_t - timestamp
47 * uint32_t - message data size
48 * <message data> - padded to the nearest 4 bytes
49 * uint32_t - total size - total capture entry size, including control info
50 */
51
52/* Overhead size: entry header + uint32_t suffix */
53#define BCMTR_CAPTURE_OVERHEAD_SIZE (sizeof(bcmtr_capture_entry) + sizeof(uint32_t))
54
55#define BCMTR_CAPTURE_ENTRY_FIELDS (sizeof(bcmtr_capture_entry) / sizeof(uint32_t))
56
57/* Maximum total number of characters for a message dump */
58#define BCMTR_MAX_MSG_DUMP_STR_SIZE 4096
59
60/* Capture control block */
61typedef struct
62{
63 bcmtr_capture_parm parm; /* Capture configuration */
64 bcmos_bool active;
65
66 uint8_t *start;
67 uint8_t *end;
68 uint8_t *cur;
69 uint32_t size; /* Buffer size */
70 uint32_t used; /* Bytes used */
71 uint32_t wa; /* Number of times buffer wrapped around */
72 uint32_t events; /* Number of capture events */
73} bcmtr_capture_buf;
74
75static bcmtr_capture_buf capture_buf[BCMTR_MAX_OLTS];
76
77/* CLI session where to dump */
78static bcmcli_session *bcmtr_cld_session;
79
80#ifdef ENABLE_LOG
81/* Logger used for BCMTR_CLD_LOG */
82static dev_log_id bcmtr_cld_log_id;
83#endif
84
85/* Global variable: per msg_id CLD level */
86bcmtr_cld_type bcmtr_cld_active_level[BCMTR_MAX_OLTS][BCMOLT_GROUP_ID__NUM_OF];
87
88/* Create a dummy CLI session so we can print to a buffer internally before printing to the real CLI.
89 * This way, the output can't be interrupted by another print. */
90static char bcmtr_cld_scratch_buf[BCMTR_MAX_MSG_DUMP_STR_SIZE];
91static uint32_t bcmtr_cld_scratch_pos = 0;
92static bcmcli_session *bcmtr_cld_scratch_session;
93
94/*
95 * Internal functions
96 */
97
98/* CLI session print callback for the scratch buffer */
99static int bcmtr_log_cli_print(bcmcli_session *session, const char *buf, uint32_t size)
100{
101 size = MIN(size, BCMTR_MAX_MSG_DUMP_STR_SIZE - bcmtr_cld_scratch_pos);
102 if (size > 0)
103 {
104 memcpy(&bcmtr_cld_scratch_buf[bcmtr_cld_scratch_pos], buf, size);
105 }
106 bcmtr_cld_scratch_pos += size;
107 return size;
108}
109
110/* Get message event name */
111static inline const char *bcmtr_cld_event_name(bcmtr_cld_event_type ev)
112{
113 static const char *ev_name[] = {
114 [BCMTR_CLD_EV_SEND] = "tx",
115 [BCMTR_CLD_EV_RESEND] = "re-tx",
116 [BCMTR_CLD_EV_RECV] = "rx",
117 [BCMTR_CLD_EV_RECV_DISCARD] = "rx-discard",
118 [BCMTR_CLD_EV_TIMEOUT] = "timeout"
119 };
120 return ev_name[ev];
121}
122
123/* Store data in capture buffer */
124static inline void _bcmtr_capture_store(bcmtr_capture_buf *tb, const void *data, uint32_t size)
125{
126 int32_t left = (int32_t)(tb->end - tb->cur);
127 if (left >= (int32_t)size)
128 {
129 memcpy(tb->cur, data, size);
130 tb->cur += size;
131 }
132 else
133 {
134 memcpy(tb->cur, data, left);
135 memcpy(tb->start, (const uint8_t *)data + left, size - left);
136 tb->cur = tb->start + size - left;
137 ++tb->wa;
138 }
139 tb->used += size;
140 if (tb->used > tb->size)
141 tb->used = tb->size;
142}
143
144
145/* Get capture entry size and start pointer given pointer right after the entry */
146static void _bcmtr_capture_get_prev(bcmtr_capture_buf *tb, uint8_t *ptr, uint32_t *prev_size, uint8_t **prev_ptr)
147{
148 uint32_t size;
149 uint8_t *prev;
150
151 if (ptr == tb->start)
152 ptr = tb->end;
153 size = *(((uint32_t *)(long)ptr) - 1);
154 BUG_ON(!size || size > 0xffff || (size & 0x3));
155 prev = ptr - size;
156 if (prev < tb->start)
157 prev = tb->end - (size - (ptr - tb->start));
158 *prev_size = size;
159 *prev_ptr = prev;
160}
161
162/* Get number of complete messages stored in capture buffer */
163static uint32_t _bcmtr_capture_nmsgs(bcmtr_capture_buf *tb)
164{
165 uint32_t n = 0;
166 uint32_t prev_length;
167 uint8_t *prev_start = tb->cur;
168
169 if (!tb->used)
170 return 0;
171
172 /* Unwind capture buffer backward */
173 while (n < tb->events)
174 {
175 uint8_t *prev = prev_start;
176 _bcmtr_capture_get_prev(tb, prev, &prev_length, &prev_start);
177 if (prev_start >= prev)
178 break;
179 ++n;
180 }
181
182 /* If buffer has wrapped around - continue unwinding */
183 if (tb->wa)
184 {
185 while (prev_start >= tb->cur)
186 {
187 _bcmtr_capture_get_prev(tb, prev_start, &prev_length, &prev_start);
188 ++n;
189 }
190 }
191
192 return n;
193}
194
195static inline void _bcmtr_capture_wrap(uint8_t **cur, bcmtr_capture_buf *tb)
196{
197 if (*cur > tb->end)
198 {
199 *cur = tb->start + (*cur - tb->end);
200 }
201}
202static void _bcmtr_capture_unwind(bcmtr_capture_buf *tb, uint8_t **start, uint32_t *count)
203{
204 uint32_t prev_length;
205 uint8_t *prev_start;
206 uint32_t n = 0;
207 uint8_t *cur_hdr = NULL;
208
209 prev_start = tb->cur;
210 while (n < tb->events)
211 {
212 uint8_t *prev = prev_start;
213 _bcmtr_capture_get_prev(tb, prev, &prev_length, &prev_start);
214 if (prev_start >= prev)
215 break;
216 ++n;
217 cur_hdr = prev_start;
218 }
219
220 /* If buffer has wrapped around - continue unwinding */
221 if (tb->wa)
222 {
223 while (prev_start >= tb->cur)
224 {
225 cur_hdr = prev_start;
226 _bcmtr_capture_get_prev(tb, prev_start, &prev_length, &prev_start);
227 ++n;
228 }
229 }
230
231 *start = cur_hdr;
232 *count = n;
233}
234
235static inline uint32_t _bcmtr_capture_msg_size_get(uint8_t *buf)
236{
237 /* WARNING: do NOT access any members of bcmtr_capture_entry other than msg_size (the first member) as they may
238 have been wrapped to the beginning of the buffer. */
239 return ((bcmtr_capture_entry *)(long)buf)->msg_size;
240}
241
242static void _bcmtr_capture_copy(
243 bcmtr_capture_buf *tb,
244 uint8_t **dst,
245 uint8_t *src,
246 uint32_t to_copy,
247 uint32_t *remaining)
248{
249 uint32_t left;
250
251 left = tb->end - src;
252 if (left < to_copy)
253 {
254 memcpy(*dst, src, left);
255 memcpy((*dst) + left, tb->start, to_copy - left);
256 }
257 else
258 {
259 memcpy(*dst, src, to_copy);
260 }
261 (*dst) += to_copy;
262 (*remaining) -= to_copy;
263}
264
265static void _bcmtr_capture_copy_bounded(
266 bcmtr_capture_buf *tb,
267 uint8_t **dst,
268 uint8_t *src,
269 uint32_t to_copy,
270 uint32_t *remaining,
271 uint32_t bound)
272{
273 if (bound < to_copy)
274 {
275 src += to_copy - bound;
276 to_copy = bound;
277 }
278 if ((*remaining) < to_copy)
279 {
280 to_copy = *remaining;
281 }
282 _bcmtr_capture_copy(tb, dst, src, to_copy, remaining);
283}
284
285/* Set capture, log, debug for selected messages */
286bcmos_errno bcmtr_cld_level_set(bcmolt_devid device, const bcmtr_cld_filter *filter, bcmtr_cld_type cld_level)
287{
288 bcmolt_group_id msg_id;
289 bcmos_errno rc;
290
291 if ((unsigned)device >= BCMTR_MAX_OLTS || !filter)
292 {
293 return BCM_ERR_PARM;
294 }
295
296 /* Handle wildcard object */
297 if (filter->object == BCMOLT_OBJECT_ANY)
298 {
299 bcmtr_cld_filter f = *filter;
300
301 for (f.object = 0; f.object <= BCMOLT_OBJ_ID__NUM_OF; f.object++)
302 {
303 bcmtr_cld_level_set(device, &f, cld_level);
304 }
305 return BCM_ERR_OK;
306 }
307
308 /* Handle wildcard group */
309 if (filter->group == BCMOLT_MGT_GROUP_ANY)
310 {
311 bcmtr_cld_filter f = *filter;
312
313 f.subgroup = BCMOLT_SUBGROUP_ANY;
314 for (f.group = BCMOLT_MGT_GROUP_CFG; f.group <= BCMOLT_MGT_GROUP__NUM_OF; f.group++)
315 {
316 bcmtr_cld_level_set(device, &f, cld_level);
317 }
318 return BCM_ERR_OK;
319 }
320
321 /* Handle wildcard subgroup */
322 if (filter->group == BCMOLT_MGT_GROUP_ANY || filter->subgroup == BCMOLT_SUBGROUP_ANY)
323 {
324 bcmtr_cld_filter f = *filter;
325
326 f.subgroup = 0;
327 for (f.subgroup = 0;
328 bcmolt_group_id_combine(f.object, f.group, f.subgroup, &msg_id) == BCM_ERR_OK;
329 f.subgroup++)
330 {
331 bcmtr_cld_level_set(device, &f, cld_level);
332 }
333 return BCM_ERR_OK;
334 }
335
336 /* If we are here - it is not a wildcard */
337 rc = bcmolt_group_id_combine(filter->object, filter->group, filter->subgroup, &msg_id);
338 if (rc)
339 return rc;
340
341 BUG_ON((unsigned)msg_id >= BCMOLT_GROUP_ID__NUM_OF);
342 bcmtr_cld_active_level[device][msg_id] = cld_level;
343 return BCM_ERR_OK;
344}
345
346/* Get capture, log, debug for selected message */
347bcmos_errno bcmtr_cld_level_get(bcmolt_devid device, const bcmtr_cld_filter *filter, bcmtr_cld_type *cld_level)
348{
349 bcmolt_group_id msg_id;
350 bcmos_errno rc;
351 if ((unsigned)device >= BCMTR_MAX_OLTS || !filter)
352 {
353 return BCM_ERR_PARM;
354 }
355 rc = bcmolt_group_id_combine(filter->object, filter->group, filter->subgroup, &msg_id);
356 if (rc)
357 return rc;
358 BUG_ON((unsigned)msg_id >= BCMOLT_GROUP_ID__NUM_OF);
359 *cld_level = bcmtr_cld_active_level[device][msg_id];
360 return BCM_ERR_OK;
361}
362
363/** Initialize capture */
364bcmos_errno bcmtr_capture_init(bcmolt_devid olt, const bcmtr_capture_parm *parm)
365{
366 bcmtr_capture_buf *tb;
367
368 if (olt >= BCMTR_MAX_OLTS || !parm)
369 return BCM_ERR_PARM;
370 if (capture_buf[olt].start)
371 {
372 bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: already initialized\n", olt);
373 return BCM_ERR_PARM;
374 }
375
376 if (parm->size < BCMTR_CAPTURE_MIN_BUF_SIZE)
377 {
378 bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: capture buffer is too small (%u < %d)\n",
379 olt, parm->size, BCMTR_CAPTURE_MIN_BUF_SIZE);
380 return BCM_ERR_PARM;
381 }
382
383 tb = &capture_buf[olt];
384 tb->size = parm->size & ~0x3;
385 /* User-supplied or dynamically allocated buffer ? */
386 if (parm->ptr)
387 tb->start = parm->ptr;
388 else
389 {
390 tb->start = bcmos_alloc(parm->size);
391 if (!tb->start)
392 {
393 bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: can't allocate capture buffer\n", olt);
394 tb->size = 0;
395 return BCM_ERR_NOMEM;
396 }
397 }
398 tb->end = (void *)((long)tb->start + parm->size);
399 tb->cur = tb->start;
400 tb->used = tb->wa = 0;
401 tb->active = parm->activate;
402 tb->parm = *parm;
403
404 return BCM_ERR_OK;
405}
406
407/** Destroy capture buffer */
408void bcmtr_capture_destroy(bcmolt_devid olt)
409{
410 bcmtr_capture_buf *tb;
411
412 if (olt >= BCMTR_MAX_OLTS)
413 return;
414 tb = &capture_buf[olt];
415 tb->active = BCMOS_FALSE;
416 if (tb->start && !tb->parm.ptr)
417 bcmos_free(tb->start);
418 memset(tb, 0, sizeof(*tb));
419}
420
421/** Get capture recording info */
422bcmos_errno bcmtr_capture_info_get(bcmolt_devid olt, bcmtr_capture_info *info)
423{
424 bcmtr_capture_buf *tb;
425
426 if (olt >= BCMTR_MAX_OLTS || !info)
427 return BCM_ERR_PARM;
428 tb = &capture_buf[olt];
429 if (tb->active)
430 {
431 bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: must stop first\n", olt);
432 return BCM_ERR_PARM;
433 }
434 info->size = tb->size;
435 info->used = tb->used;
436 info->wa = tb->wa;
437 info->msgs = _bcmtr_capture_nmsgs(tb);
438 info->lost = tb->events - info->msgs;
439 return BCM_ERR_OK;
440}
441
442bcmos_errno bcmtr_capture_size_get(bcmolt_devid olt, uint32_t *size)
443{
444 bcmtr_capture_buf *tb;
445 uint32_t n = 0;
446 uint8_t *cur_hdr = NULL;
447 uint32_t i;
448
449 *size = 0;
450 if (olt >= BCMTR_MAX_OLTS)
451 {
452 return BCM_ERR_PARM;
453 }
454 tb = &capture_buf[olt];
455 if (!tb->start)
456 {
457 bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: not initialized\n", olt);
458 return BCM_ERR_PARM;
459 }
460 if (tb->active)
461 {
462 bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: must stop first\n", olt);
463 return BCM_ERR_PARM;
464 }
465
466 if (!tb->used)
467 {
468 return BCM_ERR_OK;
469 }
470
471 /* Unwind capture buffer backward to get to the 1st recorded message */
472 _bcmtr_capture_unwind(tb, &cur_hdr, &n);
473
474 /* "first" points to the 1st recorded entry and "n" contains number of messages.
475 * Now go forward and copy to the user buffer
476 */
477 BUG_ON(!cur_hdr);
478 for (i = 0; i < n; i++)
479 {
480 uint32_t msg_size = _bcmtr_capture_msg_size_get(cur_hdr) + sizeof(bcmtr_capture_entry);
481 uint32_t rounded_size = BCMOS_ROUND_UP(msg_size, sizeof(uint32_t));
482
483 (*size) += msg_size;
484
485 /* Move to the next entry in capture buffer */
486 cur_hdr += rounded_size + sizeof(uint32_t);
487 _bcmtr_capture_wrap(&cur_hdr, tb);
488 }
489
490 return BCM_ERR_OK;
491}
492
493bcmos_errno bcmtr_capture_read(bcmolt_devid olt, uint8_t *buf, uint32_t offset, uint32_t *length)
494{
495 bcmtr_capture_buf *tb;
496 uint32_t n = 0;
497 uint8_t *cur_hdr = NULL;
498 uint32_t cur_offset = 0;
499 uint32_t i;
500
501 if (olt >= BCMTR_MAX_OLTS || !buf)
502 {
503 return BCM_ERR_PARM;
504 }
505 tb = &capture_buf[olt];
506 if (!tb->start)
507 {
508 bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: not initialized\n", olt);
509 return BCM_ERR_PARM;
510 }
511 if (tb->active)
512 {
513 bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: must stop first\n", olt);
514 return BCM_ERR_PARM;
515 }
516
517 if (!tb->used)
518 {
519 return BCM_ERR_OK;
520 }
521
522 /* Unwind capture buffer backward to get to the 1st recorded message */
523 _bcmtr_capture_unwind(tb, &cur_hdr, &n);
524
525 /* "first" points to the 1st recorded entry and "n" contains number of messages.
526 * Now go forward and copy to the user buffer
527 */
528 BUG_ON(!cur_hdr);
529 for (i = 0; (i < n) && ((*length) > 0); i++)
530 {
531 uint32_t msg_size = _bcmtr_capture_msg_size_get(cur_hdr);
532 uint32_t rounded_size = BCMOS_ROUND_UP(msg_size, sizeof(uint32_t));
533
534 cur_offset += sizeof(bcmtr_capture_entry);
535 if (cur_offset > offset)
536 {
537 uint32_t temp[BCMTR_CAPTURE_ENTRY_FIELDS];
538 uint8_t j;
539
540 for (j = 0; j < BCMTR_CAPTURE_ENTRY_FIELDS; j++)
541 {
542 temp[j] = BCMOLT_BUF_ENDIAN_CPU_TO_BUF(U32, *((uint32_t*)(long)cur_hdr));
543 cur_hdr += sizeof(uint32_t);
544 _bcmtr_capture_wrap(&cur_hdr, tb);
545 }
546
547 _bcmtr_capture_copy_bounded(
548 tb,
549 &buf,
550 (uint8_t*)temp,
551 sizeof(bcmtr_capture_entry),
552 length,
553 cur_offset - offset);
554 }
555 else
556 {
557 cur_hdr += sizeof(bcmtr_capture_entry);
558 }
559
560 cur_offset += msg_size;
561 if (cur_offset > offset)
562 {
563 _bcmtr_capture_copy_bounded(
564 tb,
565 &buf,
566 cur_hdr,
567 msg_size,
568 length,
569 cur_offset - offset);
570 }
571
572 /* Move to the next entry in capture buffer */
573 cur_hdr += rounded_size + sizeof(uint32_t);
574 _bcmtr_capture_wrap(&cur_hdr, tb);
575 }
576
577 return BCM_ERR_OK;
578}
579
580bcmos_bool bcmtr_capture_entry_get_next(bcmolt_buf *buf, bcmtr_capture_entry *hdr, uint8_t **msg)
581{
582 bcmos_bool valid;
583
584 BUG_ON(buf == NULL);
585 BUG_ON(hdr == NULL);
586
587 valid = bcmtr_capture_entry_unpack(buf, hdr);
588 if (msg != NULL)
589 {
590 *msg = bcmolt_buf_snap_get(buf);
591 }
592 return valid && bcmolt_buf_skip(buf, hdr->msg_size);
593}
594
595/** Decode and dump capture recording */
596bcmos_errno bcmtr_capture_dump(bcmcli_session *session, bcmolt_devid olt, uint32_t *nmsgs)
597{
598 bcmtr_capture_entry hdr;
599 uint8_t *msg_start;
600 bcmolt_buf buf;
601 uint8_t *data;
602 uint32_t length;
603 uint32_t remaining;
604 bcmos_errno rc;
605
606 rc = bcmtr_capture_size_get(olt, &length);
607 BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != rc, rc);
608
609 /* Allocate temp buffer and read data into it */
610 data = bcmos_calloc(length);
611 if (data == NULL)
612 {
613 bcmcli_session_print(session, "TRACE/%d: no memory\n", olt);
614 return BCM_ERR_NOMEM;
615 }
616
617 remaining = length;
618 rc = bcmtr_capture_read(olt, data, 0, &remaining);
619 if (BCM_ERR_OK != rc)
620 {
621 bcmos_free(data);
622 return rc;
623 }
624
625 /* Dump */
626 bcmolt_buf_init(&buf, length - remaining, data, BCMOLT_BUF_ENDIAN_FIXED);
627 while (bcmtr_capture_entry_get_next(&buf, &hdr, &msg_start))
628 {
629 bcmolt_buf msg_buf;
630 bcmolt_msg *msg = NULL;
631 bcmos_errno err;
632
633 bcmcli_session_print(session, "\n%08x %s:\n", hdr.timestamp, bcmtr_cld_event_name(hdr.event));
634 bcmolt_buf_init(&msg_buf, hdr.msg_size, msg_start, BCMOLT_BUF_ENDIAN_FIXED);
635 err = bcmolt_msg_unpack(&msg_buf, &msg);
636 if (BCM_ERR_OK == err)
637 {
638 (void)apicli_msg_dump(session, msg);
639 bcmolt_msg_free(msg);
640 }
641 else
642 {
643 bcmcli_session_hexdump(session, msg_start, 0, hdr.msg_size, NULL);
644 }
645 }
646
647 bcmos_free(data);
648
649 *nmsgs = _bcmtr_capture_nmsgs(&capture_buf[olt]);
650
651 return BCM_ERR_OK;
652}
653
654/** (Re)start / Suspend capture recording */
655bcmos_errno bcmtr_capture_start_stop(bcmolt_devid olt, bcmos_bool start)
656{
657 if (olt >= BCMTR_MAX_OLTS)
658 return BCM_ERR_PARM;
659 if (!capture_buf[olt].start && start)
660 {
661 bcmcli_session_print(bcmtr_cld_session,
662 "TRACE/%d: Can't start recording - must initialize first\n", olt);
663 return BCM_ERR_PARM;
664 }
665 capture_buf[olt].active = start;
666 return BCM_ERR_OK;
667}
668
669bcmos_bool bcmtr_capture_is_active(bcmolt_devid olt)
670{
671 return capture_buf[olt].active;
672}
673
674bcmos_bool bcmtr_capture_entry_unpack(bcmolt_buf *buf, bcmtr_capture_entry *entry)
675{
676 return
677 bcmolt_buf_read_u32(buf, &entry->msg_size) &&
678 bcmolt_buf_read_u32(buf, &entry->event) &&
679 bcmolt_buf_read_u32(buf, &entry->timestamp);
680}
681
682/* Notify message to capture module - called from the transport layer */
683static void bcmtr_capture_notify(bcmolt_devid device, const bcmtr_hdr *trhdr,
684 bcmtr_cld_event_type ev, uint32_t ts,
685 const void *packed, uint32_t packed_length, bcmolt_msg *msg)
686{
687 bcmtr_capture_buf *tb;
688 bcmtr_capture_entry hdr;
689 uint32_t rounded_size;
690
691 tb = &capture_buf[device];
692
693 /* Sanity */
694 if (!packed)
695 return;
696 hdr.msg_size = packed_length;
697 /* Enable & overflow checks */
698 if (!tb->active)
699 return;
700 if (tb->parm.stop_on_full && (tb->used + hdr.msg_size + BCMTR_CAPTURE_OVERHEAD_SIZE > tb->size))
701 return;
702 hdr.timestamp = ts;
703 hdr.event = ev;
704 rounded_size = BCMOS_ROUND_UP(hdr.msg_size, sizeof(uint32_t));
705 _bcmtr_capture_store(tb, &hdr, sizeof(hdr));
706 _bcmtr_capture_store(tb, packed, rounded_size); /* overflow by up to 3 bytes; is this safe? */
707 rounded_size += sizeof(bcmtr_capture_entry) + sizeof(uint32_t);
708 _bcmtr_capture_store(tb, &rounded_size, sizeof(rounded_size));
709 ++tb->events;
710}
711
712/* Notify message to logger */
713static void bcmtr_log_notify(bcmolt_devid device, const bcmtr_hdr *hdr,
714 bcmtr_cld_event_type ev, uint32_t ts,
715 const void *packed, uint32_t packed_length, bcmolt_msg *msg)
716{
717#ifdef ENABLE_LOG
718 bcmos_errno err;
719 bcmolt_obj_id obj;
720 bcmolt_mgt_group group;
721 uint16_t subgroup;
722 const char *obj_name;
723 const char *subgroup_name;
724 const char *dummy_str;
725
726 err = bcmolt_group_id_split(hdr->msg_id, &obj, &group, &subgroup);
727 BCMOS_CHECK_RETURN(err != BCM_ERR_OK, err,);
728
729 err = api_cli_object_name(obj, &obj_name, &dummy_str);
730 BCMOS_CHECK_RETURN(err != BCM_ERR_OK, err,);
731
732 err = api_cli_object_subgroup_name(obj, group, subgroup, &subgroup_name, &dummy_str);
733 BCMOS_CHECK_RETURN(err != BCM_ERR_OK, err,);
734
735 /* log with the header but without file/line number (file/line number isn't helpful here). */
736 bcm_dev_log_log(
737 bcmtr_cld_log_id,
738 DEV_LOG_LEVEL_INFO,
739 BCM_LOG_FLAG_NONE,
740 "%s %s: corr_tag=%u instance=%d obj=%s group=%s subgrp=%s org_ts=%u err=%s\n",
741 bcmtr_cld_event_name(ev),
742 hdr->dir == BCMOLT_MSG_DIR_RESPONSE ? "response" : "request",
743 hdr->corr_tag,
744 hdr->instance,
745 obj_name,
746 apicli_mgt_group_to_str(group),
747 subgroup_name,
748 ts,
749 msg ? bcmos_strerror(msg->err) : "N/A");
750#endif
751}
752
753/* Dump message header and/or body */
754static void bcmtr_dump_notify(
755 bcmolt_devid device,
756 const bcmtr_hdr *hdr,
757 bcmtr_cld_event_type ev,
758 uint32_t ts,
759 const void *packed,
760 uint32_t packed_length,
761 bcmolt_msg *msg)
762{
763 bcmos_errno err;
764 bcmtr_cld_type val = bcmtr_cld_active_level[device][hdr->msg_id];
765 bcmolt_obj_id obj;
766 bcmolt_mgt_group group;
767 uint16_t subgroup;
768 const char *obj_name;
769 const char *subgroup_name;
770 const char *dummy_str;
771
772 err = bcmolt_group_id_split(hdr->msg_id, &obj, &group, &subgroup);
773 BCMOS_CHECK_RETURN(err != BCM_ERR_OK, err,);
774
775 err = api_cli_object_name(obj, &obj_name, &dummy_str);
776 BCMOS_CHECK_RETURN(err != BCM_ERR_OK, err,);
777
778 err = api_cli_object_subgroup_name(obj, group, subgroup, &subgroup_name, &dummy_str);
779 BCMOS_CHECK_RETURN(err != BCM_ERR_OK, err,);
780
781 /* always dump the message header to the scratch CLI session */
782 bcmcli_session_print(
783 bcmtr_cld_scratch_session,
784 "[-- CLD: %s %s: corr_tag=%u instance=%d msg_id=%d obj=%s(%d) group=%s(%d) subgrp=%s(%d)",
785 bcmtr_cld_event_name(ev),
786 hdr->dir == BCMOLT_MSG_DIR_RESPONSE ? "response" : "request",
787 hdr->corr_tag,
788 hdr->instance,
789 hdr->msg_id,
790 obj_name, obj,
791 apicli_mgt_group_to_str(group), group,
792 subgroup_name, subgroup);
793
794 if (hdr->more_fragments || (hdr->frag_number != 0))
795 {
796 bcmcli_session_print(
797 bcmtr_cld_scratch_session,
798 " more_fragments=%d fragment_number=%u",
799 hdr->more_fragments,
800 hdr->frag_number);
801 }
802
803 bcmcli_session_print(bcmtr_cld_scratch_session, " --]\n");
804
805 /* if configured for a full message dump, write the message data to the scratch session */
806 if ((val & BCMTR_CLD_DUMP) == BCMTR_CLD_DUMP)
807 {
808 if (msg != NULL)
809 {
810 bcmcli_session_print(bcmtr_cld_scratch_session, "[-- CLD Message Dump Start --]\n");
811 apicli_msg_dump(bcmtr_cld_scratch_session, msg);
812 }
813 else
814 {
815 bcmcli_session_print(bcmtr_cld_scratch_session, "[-- CLD Message Hex Dump Start --]\n");
816 bcmcli_session_hexdump(bcmtr_cld_scratch_session, packed, 0, packed_length, NULL);
817 }
818 bcmcli_session_print(bcmtr_cld_scratch_session, "[-- CLD Message Dump End --]\n");
819 }
820
821 /* Write the scratch session's buffer to the real CLI and reset it */
822 bcmcli_session_write(bcmtr_cld_session, bcmtr_cld_scratch_buf, bcmtr_cld_scratch_pos);
823 bcmtr_cld_scratch_pos = 0;
824}
825
826/* Notify capture, log, debug */
827void bcmtr_cld_notify(bcmolt_devid device, const bcmtr_hdr *hdr,
828 bcmtr_cld_event_type ev, uint32_t ts, const uint8_t *packed, uint32_t packed_length,
829 bcmolt_msg *msg)
830{
831 bcmtr_cld_type val = bcmtr_cld_active_level[device][hdr->msg_id];
832
833 if ((val & BCMTR_CLD_CAPTURE))
834 bcmtr_capture_notify(device, hdr, ev, ts, packed, packed_length, msg);
835 if ((val & BCMTR_CLD_LOG))
836 bcmtr_log_notify(device, hdr, ev, ts, packed, packed_length, msg);
837 if ((val & BCMTR_CLD_DUMP))
838 bcmtr_dump_notify(device, hdr, ev, ts, packed, packed_length, msg);
839}
840
841
842bcmos_errno bcmtr_cld_init(bcmcli_session *session)
843{
844 bcmos_errno err;
845 bcmcli_session_parm scratch_session_parm = { .write = bcmtr_log_cli_print };
846
847 err = bcmcli_session_open_user(&scratch_session_parm, &bcmtr_cld_scratch_session);
848 BCMOS_CHECK_RETURN_ERROR(err != BCM_ERR_OK, err);
849
850 bcmtr_cld_session = session;
851
852#ifdef ENABLE_LOG
853 bcmtr_cld_log_id = bcm_dev_log_id_register("cld", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
854#endif
855
856#ifdef ENABLE_CLI
857 err = bcmtr_cld_cli_init();
858 BCMOS_CHECK_RETURN_ERROR(err != BCM_ERR_OK, err);
859#endif
860
861 return BCM_ERR_OK;
862}
863
864/** Clean up transport capture, log, debug service
865 */
866void bcmtr_cld_exit(void)
867{
868#ifdef ENABLE_CLI
869 bcmtr_cld_cli_exit();
870#endif
871 if (bcmtr_cld_scratch_session)
872 {
873 bcmcli_session_close(bcmtr_cld_scratch_session);
874 bcmtr_cld_scratch_session = NULL;
875 }
876}