blob: 889630c4f6bd9e5e4dafd6d1e27013c49250b0c9 [file] [log] [blame]
/*
<:copyright-BRCM:2016:DUAL/GPL:standard
Broadcom Proprietary and Confidential.(c) 2016 Broadcom
All Rights Reserved
Unless you and Broadcom execute a separate written software license
agreement governing use of this software, this software is licensed
to you under the terms of the GNU General Public License version 2
(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
with the following added to such license:
As a special exception, the copyright holders of this software give
you permission to link this software with independent modules, and
to copy and distribute the resulting executable under terms of your
choice, provided that you also meet, for each linked independent
module, the terms and conditions of the license of that module.
An independent module is a module which is not derived from this
software. The special exception does not apply to any modifications
of the software.
Not withstanding the above, under no circumstances may you combine
this software in any way with any other Broadcom software provided
under a license other than the GPL, without Broadcom's express prior
written consent.
:>
*/
#include <bcmos_system.h>
#include <bcmtr_debug.h>
#include <bcmcli_session.h>
#include <bcm_api_cli_helpers.h>
#include <bcmolt_math.h>
#ifdef ENABLE_LOG
#include <bcm_dev_log.h>
#endif
#ifdef ENABLE_CLI
#include <bcmtr_debug_cli.h>
#endif
/* Messages are recorded in the following format:
* uint32_t - event type
* uint32_t - timestamp
* uint32_t - message data size
* <message data> - padded to the nearest 4 bytes
* uint32_t - total size - total capture entry size, including control info
*/
/* Overhead size: entry header + uint32_t suffix */
#define BCMTR_CAPTURE_OVERHEAD_SIZE (sizeof(bcmtr_capture_entry) + sizeof(uint32_t))
#define BCMTR_CAPTURE_ENTRY_FIELDS (sizeof(bcmtr_capture_entry) / sizeof(uint32_t))
/* Maximum total number of characters for a message dump */
#define BCMTR_MAX_MSG_DUMP_STR_SIZE 4096
/* Capture control block */
typedef struct
{
bcmtr_capture_parm parm; /* Capture configuration */
bcmos_bool active;
uint8_t *start;
uint8_t *end;
uint8_t *cur;
uint32_t size; /* Buffer size */
uint32_t used; /* Bytes used */
uint32_t wa; /* Number of times buffer wrapped around */
uint32_t events; /* Number of capture events */
} bcmtr_capture_buf;
static bcmtr_capture_buf capture_buf[BCMTR_MAX_OLTS];
/* CLI session where to dump */
static bcmcli_session *bcmtr_cld_session;
#ifdef ENABLE_LOG
/* Logger used for BCMTR_CLD_LOG */
static dev_log_id bcmtr_cld_log_id;
#endif
/* Global variable: per msg_id CLD level */
bcmtr_cld_type bcmtr_cld_active_level[BCMTR_MAX_OLTS][BCMOLT_GROUP_ID__NUM_OF];
/* Create a dummy CLI session so we can print to a buffer internally before printing to the real CLI.
* This way, the output can't be interrupted by another print. */
static char bcmtr_cld_scratch_buf[BCMTR_MAX_MSG_DUMP_STR_SIZE];
static uint32_t bcmtr_cld_scratch_pos = 0;
static bcmcli_session *bcmtr_cld_scratch_session;
/*
* Internal functions
*/
/* CLI session print callback for the scratch buffer */
static int bcmtr_log_cli_print(bcmcli_session *session, const char *buf, uint32_t size)
{
size = MIN(size, BCMTR_MAX_MSG_DUMP_STR_SIZE - bcmtr_cld_scratch_pos);
if (size > 0)
{
memcpy(&bcmtr_cld_scratch_buf[bcmtr_cld_scratch_pos], buf, size);
}
bcmtr_cld_scratch_pos += size;
return size;
}
/* Get message event name */
static inline const char *bcmtr_cld_event_name(bcmtr_cld_event_type ev)
{
static const char *ev_name[] = {
[BCMTR_CLD_EV_SEND] = "tx",
[BCMTR_CLD_EV_RESEND] = "re-tx",
[BCMTR_CLD_EV_RECV] = "rx",
[BCMTR_CLD_EV_RECV_DISCARD] = "rx-discard",
[BCMTR_CLD_EV_TIMEOUT] = "timeout"
};
return ev_name[ev];
}
/* Store data in capture buffer */
static inline void _bcmtr_capture_store(bcmtr_capture_buf *tb, const void *data, uint32_t size)
{
int32_t left = (int32_t)(tb->end - tb->cur);
if (left >= (int32_t)size)
{
memcpy(tb->cur, data, size);
tb->cur += size;
}
else
{
memcpy(tb->cur, data, left);
memcpy(tb->start, (const uint8_t *)data + left, size - left);
tb->cur = tb->start + size - left;
++tb->wa;
}
tb->used += size;
if (tb->used > tb->size)
tb->used = tb->size;
}
/* Get capture entry size and start pointer given pointer right after the entry */
static void _bcmtr_capture_get_prev(bcmtr_capture_buf *tb, uint8_t *ptr, uint32_t *prev_size, uint8_t **prev_ptr)
{
uint32_t size;
uint8_t *prev;
if (ptr == tb->start)
ptr = tb->end;
size = *(((uint32_t *)(long)ptr) - 1);
BUG_ON(!size || size > 0xffff || (size & 0x3));
prev = ptr - size;
if (prev < tb->start)
prev = tb->end - (size - (ptr - tb->start));
*prev_size = size;
*prev_ptr = prev;
}
/* Get number of complete messages stored in capture buffer */
static uint32_t _bcmtr_capture_nmsgs(bcmtr_capture_buf *tb)
{
uint32_t n = 0;
uint32_t prev_length;
uint8_t *prev_start = tb->cur;
if (!tb->used)
return 0;
/* Unwind capture buffer backward */
while (n < tb->events)
{
uint8_t *prev = prev_start;
_bcmtr_capture_get_prev(tb, prev, &prev_length, &prev_start);
if (prev_start >= prev)
break;
++n;
}
/* If buffer has wrapped around - continue unwinding */
if (tb->wa)
{
while (prev_start >= tb->cur)
{
_bcmtr_capture_get_prev(tb, prev_start, &prev_length, &prev_start);
++n;
}
}
return n;
}
static inline void _bcmtr_capture_wrap(uint8_t **cur, bcmtr_capture_buf *tb)
{
if (*cur > tb->end)
{
*cur = tb->start + (*cur - tb->end);
}
}
static void _bcmtr_capture_unwind(bcmtr_capture_buf *tb, uint8_t **start, uint32_t *count)
{
uint32_t prev_length;
uint8_t *prev_start;
uint32_t n = 0;
uint8_t *cur_hdr = NULL;
prev_start = tb->cur;
while (n < tb->events)
{
uint8_t *prev = prev_start;
_bcmtr_capture_get_prev(tb, prev, &prev_length, &prev_start);
if (prev_start >= prev)
break;
++n;
cur_hdr = prev_start;
}
/* If buffer has wrapped around - continue unwinding */
if (tb->wa)
{
while (prev_start >= tb->cur)
{
cur_hdr = prev_start;
_bcmtr_capture_get_prev(tb, prev_start, &prev_length, &prev_start);
++n;
}
}
*start = cur_hdr;
*count = n;
}
static inline uint32_t _bcmtr_capture_msg_size_get(uint8_t *buf)
{
/* WARNING: do NOT access any members of bcmtr_capture_entry other than msg_size (the first member) as they may
have been wrapped to the beginning of the buffer. */
return ((bcmtr_capture_entry *)(long)buf)->msg_size;
}
static void _bcmtr_capture_copy(
bcmtr_capture_buf *tb,
uint8_t **dst,
uint8_t *src,
uint32_t to_copy,
uint32_t *remaining)
{
uint32_t left;
left = tb->end - src;
if (left < to_copy)
{
memcpy(*dst, src, left);
memcpy((*dst) + left, tb->start, to_copy - left);
}
else
{
memcpy(*dst, src, to_copy);
}
(*dst) += to_copy;
(*remaining) -= to_copy;
}
static void _bcmtr_capture_copy_bounded(
bcmtr_capture_buf *tb,
uint8_t **dst,
uint8_t *src,
uint32_t to_copy,
uint32_t *remaining,
uint32_t bound)
{
if (bound < to_copy)
{
src += to_copy - bound;
to_copy = bound;
}
if ((*remaining) < to_copy)
{
to_copy = *remaining;
}
_bcmtr_capture_copy(tb, dst, src, to_copy, remaining);
}
/* Set capture, log, debug for selected messages */
bcmos_errno bcmtr_cld_level_set(bcmolt_devid device, const bcmtr_cld_filter *filter, bcmtr_cld_type cld_level)
{
bcmolt_group_id msg_id;
bcmos_errno rc;
if ((unsigned)device >= BCMTR_MAX_OLTS || !filter)
{
return BCM_ERR_PARM;
}
/* Handle wildcard object */
if (filter->object == BCMOLT_OBJECT_ANY)
{
bcmtr_cld_filter f = *filter;
for (f.object = 0; f.object <= BCMOLT_OBJ_ID__NUM_OF; f.object++)
{
bcmtr_cld_level_set(device, &f, cld_level);
}
return BCM_ERR_OK;
}
/* Handle wildcard group */
if (filter->group == BCMOLT_MGT_GROUP_ANY)
{
bcmtr_cld_filter f = *filter;
f.subgroup = BCMOLT_SUBGROUP_ANY;
for (f.group = BCMOLT_MGT_GROUP_CFG; f.group <= BCMOLT_MGT_GROUP__NUM_OF; f.group++)
{
bcmtr_cld_level_set(device, &f, cld_level);
}
return BCM_ERR_OK;
}
/* Handle wildcard subgroup */
if (filter->group == BCMOLT_MGT_GROUP_ANY || filter->subgroup == BCMOLT_SUBGROUP_ANY)
{
bcmtr_cld_filter f = *filter;
f.subgroup = 0;
for (f.subgroup = 0;
bcmolt_group_id_combine(f.object, f.group, f.subgroup, &msg_id) == BCM_ERR_OK;
f.subgroup++)
{
bcmtr_cld_level_set(device, &f, cld_level);
}
return BCM_ERR_OK;
}
/* If we are here - it is not a wildcard */
rc = bcmolt_group_id_combine(filter->object, filter->group, filter->subgroup, &msg_id);
if (rc)
return rc;
BUG_ON((unsigned)msg_id >= BCMOLT_GROUP_ID__NUM_OF);
bcmtr_cld_active_level[device][msg_id] = cld_level;
return BCM_ERR_OK;
}
/* Get capture, log, debug for selected message */
bcmos_errno bcmtr_cld_level_get(bcmolt_devid device, const bcmtr_cld_filter *filter, bcmtr_cld_type *cld_level)
{
bcmolt_group_id msg_id;
bcmos_errno rc;
if ((unsigned)device >= BCMTR_MAX_OLTS || !filter)
{
return BCM_ERR_PARM;
}
rc = bcmolt_group_id_combine(filter->object, filter->group, filter->subgroup, &msg_id);
if (rc)
return rc;
BUG_ON((unsigned)msg_id >= BCMOLT_GROUP_ID__NUM_OF);
*cld_level = bcmtr_cld_active_level[device][msg_id];
return BCM_ERR_OK;
}
/** Initialize capture */
bcmos_errno bcmtr_capture_init(bcmolt_devid olt, const bcmtr_capture_parm *parm)
{
bcmtr_capture_buf *tb;
if (olt >= BCMTR_MAX_OLTS || !parm)
return BCM_ERR_PARM;
if (capture_buf[olt].start)
{
bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: already initialized\n", olt);
return BCM_ERR_PARM;
}
if (parm->size < BCMTR_CAPTURE_MIN_BUF_SIZE)
{
bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: capture buffer is too small (%u < %d)\n",
olt, parm->size, BCMTR_CAPTURE_MIN_BUF_SIZE);
return BCM_ERR_PARM;
}
tb = &capture_buf[olt];
tb->size = parm->size & ~0x3;
/* User-supplied or dynamically allocated buffer ? */
if (parm->ptr)
tb->start = parm->ptr;
else
{
tb->start = bcmos_alloc(parm->size);
if (!tb->start)
{
bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: can't allocate capture buffer\n", olt);
tb->size = 0;
return BCM_ERR_NOMEM;
}
}
tb->end = (void *)((long)tb->start + parm->size);
tb->cur = tb->start;
tb->used = tb->wa = 0;
tb->active = parm->activate;
tb->parm = *parm;
return BCM_ERR_OK;
}
/** Destroy capture buffer */
void bcmtr_capture_destroy(bcmolt_devid olt)
{
bcmtr_capture_buf *tb;
if (olt >= BCMTR_MAX_OLTS)
return;
tb = &capture_buf[olt];
tb->active = BCMOS_FALSE;
if (tb->start && !tb->parm.ptr)
bcmos_free(tb->start);
memset(tb, 0, sizeof(*tb));
}
/** Get capture recording info */
bcmos_errno bcmtr_capture_info_get(bcmolt_devid olt, bcmtr_capture_info *info)
{
bcmtr_capture_buf *tb;
if (olt >= BCMTR_MAX_OLTS || !info)
return BCM_ERR_PARM;
tb = &capture_buf[olt];
if (tb->active)
{
bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: must stop first\n", olt);
return BCM_ERR_PARM;
}
info->size = tb->size;
info->used = tb->used;
info->wa = tb->wa;
info->msgs = _bcmtr_capture_nmsgs(tb);
info->lost = tb->events - info->msgs;
return BCM_ERR_OK;
}
bcmos_errno bcmtr_capture_size_get(bcmolt_devid olt, uint32_t *size)
{
bcmtr_capture_buf *tb;
uint32_t n = 0;
uint8_t *cur_hdr = NULL;
uint32_t i;
*size = 0;
if (olt >= BCMTR_MAX_OLTS)
{
return BCM_ERR_PARM;
}
tb = &capture_buf[olt];
if (!tb->start)
{
bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: not initialized\n", olt);
return BCM_ERR_PARM;
}
if (tb->active)
{
bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: must stop first\n", olt);
return BCM_ERR_PARM;
}
if (!tb->used)
{
return BCM_ERR_OK;
}
/* Unwind capture buffer backward to get to the 1st recorded message */
_bcmtr_capture_unwind(tb, &cur_hdr, &n);
/* "first" points to the 1st recorded entry and "n" contains number of messages.
* Now go forward and copy to the user buffer
*/
BUG_ON(!cur_hdr);
for (i = 0; i < n; i++)
{
uint32_t msg_size = _bcmtr_capture_msg_size_get(cur_hdr) + sizeof(bcmtr_capture_entry);
uint32_t rounded_size = BCMOS_ROUND_UP(msg_size, sizeof(uint32_t));
(*size) += msg_size;
/* Move to the next entry in capture buffer */
cur_hdr += rounded_size + sizeof(uint32_t);
_bcmtr_capture_wrap(&cur_hdr, tb);
}
return BCM_ERR_OK;
}
bcmos_errno bcmtr_capture_read(bcmolt_devid olt, uint8_t *buf, uint32_t offset, uint32_t *length)
{
bcmtr_capture_buf *tb;
uint32_t n = 0;
uint8_t *cur_hdr = NULL;
uint32_t cur_offset = 0;
uint32_t i;
if (olt >= BCMTR_MAX_OLTS || !buf)
{
return BCM_ERR_PARM;
}
tb = &capture_buf[olt];
if (!tb->start)
{
bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: not initialized\n", olt);
return BCM_ERR_PARM;
}
if (tb->active)
{
bcmcli_session_print(bcmtr_cld_session, "TRACE/%d: must stop first\n", olt);
return BCM_ERR_PARM;
}
if (!tb->used)
{
return BCM_ERR_OK;
}
/* Unwind capture buffer backward to get to the 1st recorded message */
_bcmtr_capture_unwind(tb, &cur_hdr, &n);
/* "first" points to the 1st recorded entry and "n" contains number of messages.
* Now go forward and copy to the user buffer
*/
BUG_ON(!cur_hdr);
for (i = 0; (i < n) && ((*length) > 0); i++)
{
uint32_t msg_size = _bcmtr_capture_msg_size_get(cur_hdr);
uint32_t rounded_size = BCMOS_ROUND_UP(msg_size, sizeof(uint32_t));
cur_offset += sizeof(bcmtr_capture_entry);
if (cur_offset > offset)
{
uint32_t temp[BCMTR_CAPTURE_ENTRY_FIELDS];
uint8_t j;
for (j = 0; j < BCMTR_CAPTURE_ENTRY_FIELDS; j++)
{
temp[j] = BCMOLT_BUF_ENDIAN_CPU_TO_BUF(U32, *((uint32_t*)(long)cur_hdr));
cur_hdr += sizeof(uint32_t);
_bcmtr_capture_wrap(&cur_hdr, tb);
}
_bcmtr_capture_copy_bounded(
tb,
&buf,
(uint8_t*)temp,
sizeof(bcmtr_capture_entry),
length,
cur_offset - offset);
}
else
{
cur_hdr += sizeof(bcmtr_capture_entry);
}
cur_offset += msg_size;
if (cur_offset > offset)
{
_bcmtr_capture_copy_bounded(
tb,
&buf,
cur_hdr,
msg_size,
length,
cur_offset - offset);
}
/* Move to the next entry in capture buffer */
cur_hdr += rounded_size + sizeof(uint32_t);
_bcmtr_capture_wrap(&cur_hdr, tb);
}
return BCM_ERR_OK;
}
bcmos_bool bcmtr_capture_entry_get_next(bcmolt_buf *buf, bcmtr_capture_entry *hdr, uint8_t **msg)
{
bcmos_bool valid;
BUG_ON(buf == NULL);
BUG_ON(hdr == NULL);
valid = bcmtr_capture_entry_unpack(buf, hdr);
if (msg != NULL)
{
*msg = bcmolt_buf_snap_get(buf);
}
return valid && bcmolt_buf_skip(buf, hdr->msg_size);
}
/** Decode and dump capture recording */
bcmos_errno bcmtr_capture_dump(bcmcli_session *session, bcmolt_devid olt, uint32_t *nmsgs)
{
bcmtr_capture_entry hdr;
uint8_t *msg_start;
bcmolt_buf buf;
uint8_t *data;
uint32_t length;
uint32_t remaining;
bcmos_errno rc;
rc = bcmtr_capture_size_get(olt, &length);
BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != rc, rc);
/* Allocate temp buffer and read data into it */
data = bcmos_calloc(length);
if (data == NULL)
{
bcmcli_session_print(session, "TRACE/%d: no memory\n", olt);
return BCM_ERR_NOMEM;
}
remaining = length;
rc = bcmtr_capture_read(olt, data, 0, &remaining);
if (BCM_ERR_OK != rc)
{
bcmos_free(data);
return rc;
}
/* Dump */
bcmolt_buf_init(&buf, length - remaining, data, BCMOLT_BUF_ENDIAN_FIXED);
while (bcmtr_capture_entry_get_next(&buf, &hdr, &msg_start))
{
bcmolt_buf msg_buf;
bcmolt_msg *msg = NULL;
bcmos_errno err;
bcmcli_session_print(session, "\n%08x %s:\n", hdr.timestamp, bcmtr_cld_event_name(hdr.event));
bcmolt_buf_init(&msg_buf, hdr.msg_size, msg_start, BCMOLT_BUF_ENDIAN_FIXED);
err = bcmolt_msg_unpack(&msg_buf, &msg);
if (BCM_ERR_OK == err)
{
(void)apicli_msg_dump(session, msg);
bcmolt_msg_free(msg);
}
else
{
bcmcli_session_hexdump(session, msg_start, 0, hdr.msg_size, NULL);
}
}
bcmos_free(data);
*nmsgs = _bcmtr_capture_nmsgs(&capture_buf[olt]);
return BCM_ERR_OK;
}
/** (Re)start / Suspend capture recording */
bcmos_errno bcmtr_capture_start_stop(bcmolt_devid olt, bcmos_bool start)
{
if (olt >= BCMTR_MAX_OLTS)
return BCM_ERR_PARM;
if (!capture_buf[olt].start && start)
{
bcmcli_session_print(bcmtr_cld_session,
"TRACE/%d: Can't start recording - must initialize first\n", olt);
return BCM_ERR_PARM;
}
capture_buf[olt].active = start;
return BCM_ERR_OK;
}
bcmos_bool bcmtr_capture_is_active(bcmolt_devid olt)
{
return capture_buf[olt].active;
}
bcmos_bool bcmtr_capture_entry_unpack(bcmolt_buf *buf, bcmtr_capture_entry *entry)
{
return
bcmolt_buf_read_u32(buf, &entry->msg_size) &&
bcmolt_buf_read_u32(buf, &entry->event) &&
bcmolt_buf_read_u32(buf, &entry->timestamp);
}
/* Notify message to capture module - called from the transport layer */
static void bcmtr_capture_notify(bcmolt_devid device, const bcmtr_hdr *trhdr,
bcmtr_cld_event_type ev, uint32_t ts,
const void *packed, uint32_t packed_length, bcmolt_msg *msg)
{
bcmtr_capture_buf *tb;
bcmtr_capture_entry hdr;
uint32_t rounded_size;
tb = &capture_buf[device];
/* Sanity */
if (!packed)
return;
hdr.msg_size = packed_length;
/* Enable & overflow checks */
if (!tb->active)
return;
if (tb->parm.stop_on_full && (tb->used + hdr.msg_size + BCMTR_CAPTURE_OVERHEAD_SIZE > tb->size))
return;
hdr.timestamp = ts;
hdr.event = ev;
rounded_size = BCMOS_ROUND_UP(hdr.msg_size, sizeof(uint32_t));
_bcmtr_capture_store(tb, &hdr, sizeof(hdr));
_bcmtr_capture_store(tb, packed, rounded_size); /* overflow by up to 3 bytes; is this safe? */
rounded_size += sizeof(bcmtr_capture_entry) + sizeof(uint32_t);
_bcmtr_capture_store(tb, &rounded_size, sizeof(rounded_size));
++tb->events;
}
/* Notify message to logger */
static void bcmtr_log_notify(bcmolt_devid device, const bcmtr_hdr *hdr,
bcmtr_cld_event_type ev, uint32_t ts,
const void *packed, uint32_t packed_length, bcmolt_msg *msg)
{
#ifdef ENABLE_LOG
bcmos_errno err;
bcmolt_obj_id obj;
bcmolt_mgt_group group;
uint16_t subgroup;
const char *obj_name;
const char *subgroup_name;
const char *dummy_str;
err = bcmolt_group_id_split(hdr->msg_id, &obj, &group, &subgroup);
BCMOS_CHECK_RETURN(err != BCM_ERR_OK, err,);
err = api_cli_object_name(obj, &obj_name, &dummy_str);
BCMOS_CHECK_RETURN(err != BCM_ERR_OK, err,);
err = api_cli_object_subgroup_name(obj, group, subgroup, &subgroup_name, &dummy_str);
BCMOS_CHECK_RETURN(err != BCM_ERR_OK, err,);
/* log with the header but without file/line number (file/line number isn't helpful here). */
bcm_dev_log_log(
bcmtr_cld_log_id,
DEV_LOG_LEVEL_INFO,
BCM_LOG_FLAG_NONE,
"%s %s: corr_tag=%u instance=%d obj=%s group=%s subgrp=%s org_ts=%u err=%s\n",
bcmtr_cld_event_name(ev),
hdr->dir == BCMOLT_MSG_DIR_RESPONSE ? "response" : "request",
hdr->corr_tag,
hdr->instance,
obj_name,
apicli_mgt_group_to_str(group),
subgroup_name,
ts,
msg ? bcmos_strerror(msg->err) : "N/A");
#endif
}
/* Dump message header and/or body */
static void bcmtr_dump_notify(
bcmolt_devid device,
const bcmtr_hdr *hdr,
bcmtr_cld_event_type ev,
uint32_t ts,
const void *packed,
uint32_t packed_length,
bcmolt_msg *msg)
{
bcmos_errno err;
bcmtr_cld_type val = bcmtr_cld_active_level[device][hdr->msg_id];
bcmolt_obj_id obj;
bcmolt_mgt_group group;
uint16_t subgroup;
const char *obj_name;
const char *subgroup_name;
const char *dummy_str;
err = bcmolt_group_id_split(hdr->msg_id, &obj, &group, &subgroup);
BCMOS_CHECK_RETURN(err != BCM_ERR_OK, err,);
err = api_cli_object_name(obj, &obj_name, &dummy_str);
BCMOS_CHECK_RETURN(err != BCM_ERR_OK, err,);
err = api_cli_object_subgroup_name(obj, group, subgroup, &subgroup_name, &dummy_str);
BCMOS_CHECK_RETURN(err != BCM_ERR_OK, err,);
/* always dump the message header to the scratch CLI session */
bcmcli_session_print(
bcmtr_cld_scratch_session,
"[-- CLD: %s %s: corr_tag=%u instance=%d msg_id=%d obj=%s(%d) group=%s(%d) subgrp=%s(%d)",
bcmtr_cld_event_name(ev),
hdr->dir == BCMOLT_MSG_DIR_RESPONSE ? "response" : "request",
hdr->corr_tag,
hdr->instance,
hdr->msg_id,
obj_name, obj,
apicli_mgt_group_to_str(group), group,
subgroup_name, subgroup);
if (hdr->more_fragments || (hdr->frag_number != 0))
{
bcmcli_session_print(
bcmtr_cld_scratch_session,
" more_fragments=%d fragment_number=%u",
hdr->more_fragments,
hdr->frag_number);
}
bcmcli_session_print(bcmtr_cld_scratch_session, " --]\n");
/* if configured for a full message dump, write the message data to the scratch session */
if ((val & BCMTR_CLD_DUMP) == BCMTR_CLD_DUMP)
{
if (msg != NULL)
{
bcmcli_session_print(bcmtr_cld_scratch_session, "[-- CLD Message Dump Start --]\n");
apicli_msg_dump(bcmtr_cld_scratch_session, msg);
}
else
{
bcmcli_session_print(bcmtr_cld_scratch_session, "[-- CLD Message Hex Dump Start --]\n");
bcmcli_session_hexdump(bcmtr_cld_scratch_session, packed, 0, packed_length, NULL);
}
bcmcli_session_print(bcmtr_cld_scratch_session, "[-- CLD Message Dump End --]\n");
}
/* Write the scratch session's buffer to the real CLI and reset it */
bcmcli_session_write(bcmtr_cld_session, bcmtr_cld_scratch_buf, bcmtr_cld_scratch_pos);
bcmtr_cld_scratch_pos = 0;
}
/* Notify capture, log, debug */
void bcmtr_cld_notify(bcmolt_devid device, const bcmtr_hdr *hdr,
bcmtr_cld_event_type ev, uint32_t ts, const uint8_t *packed, uint32_t packed_length,
bcmolt_msg *msg)
{
bcmtr_cld_type val = bcmtr_cld_active_level[device][hdr->msg_id];
if ((val & BCMTR_CLD_CAPTURE))
bcmtr_capture_notify(device, hdr, ev, ts, packed, packed_length, msg);
if ((val & BCMTR_CLD_LOG))
bcmtr_log_notify(device, hdr, ev, ts, packed, packed_length, msg);
if ((val & BCMTR_CLD_DUMP))
bcmtr_dump_notify(device, hdr, ev, ts, packed, packed_length, msg);
}
bcmos_errno bcmtr_cld_init(bcmcli_session *session)
{
bcmos_errno err;
bcmcli_session_parm scratch_session_parm = { .write = bcmtr_log_cli_print };
err = bcmcli_session_open_user(&scratch_session_parm, &bcmtr_cld_scratch_session);
BCMOS_CHECK_RETURN_ERROR(err != BCM_ERR_OK, err);
bcmtr_cld_session = session;
#ifdef ENABLE_LOG
bcmtr_cld_log_id = bcm_dev_log_id_register("cld", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
#endif
#ifdef ENABLE_CLI
err = bcmtr_cld_cli_init();
BCMOS_CHECK_RETURN_ERROR(err != BCM_ERR_OK, err);
#endif
return BCM_ERR_OK;
}
/** Clean up transport capture, log, debug service
*/
void bcmtr_cld_exit(void)
{
#ifdef ENABLE_CLI
bcmtr_cld_cli_exit();
#endif
if (bcmtr_cld_scratch_session)
{
bcmcli_session_close(bcmtr_cld_scratch_session);
bcmtr_cld_scratch_session = NULL;
}
}