blob: 6db7d824fe247f4a34b6caa9e27ad6d34a709553 [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 <bcmtr_debug_cli.h>
#include <bcm_api_cli_helpers.h>
#ifdef BCM_SUBSYSTEM_HOST
#include <bcmolt_dev_selector.h>
#endif
#define BCMTR_CLD_CAST_DISCARD_CONST(p, type) (type)((long)(p))
static bcmcli_entry *cld_cli_dir;
static bcmos_errno _bcmtr_cld_cli_create(void);
static void _bcmtr_cld_cli_destroy(void);
/*
* CLI handlers
*/
static bcmos_errno _bcmtr_cld_cli_setget_level(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
{
bcmcli_number obj = bcmcli_parm_get(session, "object")->value.number;
bcmcli_cmd_parm *grp_parm = bcmcli_parm_get(session, "group");
bcmcli_number group = grp_parm ? grp_parm->value.number : -1;
bcmcli_cmd_parm *subgrp_parm = bcmcli_parm_get(session, "subgroup");
bcmcli_number subgroup = subgrp_parm ? subgrp_parm->value.number : -1;
bcmtr_cld_type level = bcmcli_parm_get(session, "level")->value.number;
bcmtr_cld_filter filter = {};
bcmos_errno rc;
if (obj == -1 || !bcmcli_parm_is_set(session, bcmcli_parm_get(session, "object")))
{
filter.object = BCMOLT_OBJECT_ANY;
}
else
{
filter.object = obj;
}
if (group == -1 || !grp_parm || !bcmcli_parm_is_set(session, grp_parm))
{
filter.group = BCMOLT_MGT_GROUP_ANY;
}
else
{
filter.group = group;
}
if (subgroup == -1 || !subgrp_parm || !bcmcli_parm_is_set(session, subgrp_parm))
{
filter.subgroup = BCMOLT_SUBGROUP_ANY;
}
else
{
filter.subgroup = subgroup;
}
/* Get or set level ? */
if (bcmcli_parm_is_set(session, bcmcli_parm_get(session, "level")))
{
rc = bcmtr_cld_level_set(current_device, &filter, level);
}
else
{
rc = bcmtr_cld_level_get(current_device, &filter, &level);
if (rc == BCM_ERR_OK)
{
bcmcli_session_print(session, "capture:%s log:%s dump:%s\n",
(level & BCMTR_CLD_CAPTURE) ? "on" : "off",
(level & BCMTR_CLD_LOG) ? "on" : "off",
((level & BCMTR_CLD_DUMP) == BCMTR_CLD_DUMP) ? "all" :
(level & BCMTR_CLD_DUMP_HDR) ? "headers" : "off");
}
}
return rc;
}
static bcmos_errno _bcmtr_cld_cli_capture_init(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
{
bcmcli_number size = bcmcli_parm_get(session, "size")->value.number;
bcmos_bool stop_on_full = bcmcli_parm_get(session, "stop_on_full")->value.number;
bcmos_bool autostart = bcmcli_parm_get(session, "autostart")->value.number;
bcmtr_capture_parm p = {};
p.size = size;
p.stop_on_full = stop_on_full;
p.activate = autostart;
return bcmtr_capture_init(current_device, &p);
}
static bcmos_errno _bcmtr_cld_cli_capture_delete(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
{
bcmtr_capture_destroy(current_device);
return BCM_ERR_OK;
}
static bcmos_errno _bcmtr_cld_cli_capture_start(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
{
return bcmtr_capture_start_stop(current_device, BCMOS_TRUE);
}
static bcmos_errno _bcmtr_cld_cli_capture_stop(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
{
return bcmtr_capture_start_stop(current_device, BCMOS_FALSE);
}
static bcmos_errno _bcmtr_cld_cli_capture_dump(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
{
uint32_t nmsgs;
bcmos_errno rc;
rc = bcmtr_capture_dump(session, current_device, &nmsgs);
if (!rc)
{
bcmcli_session_print(session, "Dumped %u messages\n", nmsgs);
}
return BCM_ERR_OK;
}
static bcmos_errno _bcmtr_cld_cli_capture_info(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
{
bcmtr_capture_info info;
bcmos_errno rc;
rc = bcmtr_capture_info_get(current_device, &info);
if (!rc)
{
bcmcli_session_print(session, "Buffer: size=%u used=%u. Events: recorded=%u lost=%d. Wraps around:%u\n",
info.size, info.used, info.msgs, info.lost, info.wa);
}
return BCM_ERR_OK;
}
#ifdef BCM_SUBSYSTEM_HOST
/* Current device change indication */
static void _bcmtr_cld_device_change_ind(bcmcli_session *session, bcmolt_devid dev)
{
bcmcli_entry *cur_dir = bcmcli_dir_get(session);
bcmos_bool is_cld_cur_dir = (cur_dir && cur_dir == cld_cli_dir);
bcmos_errno rc;
/* Destroy and re-create CLD CLI directory */
_bcmtr_cld_cli_destroy();
rc = _bcmtr_cld_cli_create();
/* Restore current CLI directory to CLD */
if (!rc && is_cld_cur_dir)
bcmcli_dir_set(session, cld_cli_dir);
}
#endif
/* allocate memory for name and description and copy to to parm */
static bcmos_errno _bcmtr_cld_copy_parm_name(bcmcli_cmd_parm *parm, const char *name, const char *descr)
{
parm->name = bcmos_alloc(strlen(name) + 1);
parm->description = bcmos_alloc(strlen(descr) + 1);
if ((parm->name == NULL) || (parm->description == NULL))
{
/* Successful allocation if any will be released by common cleanup
* along with the rest of dynamic parameter fields */
return BCM_ERR_NOMEM;
}
strcpy(BCMTR_CLD_CAST_DISCARD_CONST(parm->name, void *), name);
strcpy(BCMTR_CLD_CAST_DISCARD_CONST(parm->description, void *), descr);
return BCM_ERR_OK;
}
/* Free "level" command parameters. both name and description are allocated dynamically */
static void _bcmtr_cld_free_level_parms(bcmcli_cmd_parm *parms)
{
bcmcli_cmd_parm *p = parms;
while (p->name)
{
if (p->type == BCMCLI_PARM_ENUM && p->enum_table)
{
if ((p->flags & BCMCLI_PARM_FLAG_SELECTOR))
{
bcmcli_enum_val *e = p->enum_table;
while(e->name)
{
if (e->parms)
{
_bcmtr_cld_free_level_parms(e->parms);
}
++e;
}
}
bcmos_free(p->enum_table);
}
if (p->description)
bcmos_free(BCMTR_CLD_CAST_DISCARD_CONST(p->description, void *));
if (p->name)
bcmos_free(BCMTR_CLD_CAST_DISCARD_CONST(p->name, void *));
++p;
}
bcmos_free(parms);
}
/* Add "level" command */
static bcmos_errno _bcmtr_cld_add_level_cmd(bcmcli_entry *dir)
{
/* object: *all, object list
* group: selector: *all, group list
* subgroup: *all, subgroup list
* level: bitmask
*/
bcmcli_cmd_extra_parm cmd_extras = { .free_parms = _bcmtr_cld_free_level_parms };
bcmcli_enum_val *obj_selector;
bcmcli_cmd_parm *cmd_parms;
static const char *all_name = "*all";
bcmolt_system_mode current_system_mode;
int n_obj = 0;
bcmolt_obj_id o;
bcmos_errno rc = BCM_ERR_NOMEM;
/* Allocate top level parameters: object selector, level, terminator */
cmd_parms = bcmos_calloc(sizeof(bcmcli_cmd_parm) * 3);
if (!cmd_parms)
{
return BCM_ERR_NOMEM;
}
/* Allocate object enum table. 2 extra entries for *all and terminator */
obj_selector = bcmos_calloc(sizeof(bcmcli_enum_val) * (BCMOLT_OBJ_ID__NUM_OF + 2));
if (!obj_selector)
{
goto cleanup;
}
/* Fill up parameters */
rc = _bcmtr_cld_copy_parm_name(&cmd_parms[0], "object", "Object Name");
cmd_parms[0].type = BCMCLI_PARM_ENUM;
cmd_parms[0].flags = BCMCLI_PARM_FLAG_SELECTOR;
cmd_parms[0].enum_table = obj_selector;
rc = rc ? rc : _bcmtr_cld_copy_parm_name(&cmd_parms[1], "level", "Level bitmask: 1=capture,2=log,4=print hdr,8=print body");
cmd_parms[1].type = BCMCLI_PARM_DECIMAL;
cmd_parms[1].flags = BCMCLI_PARM_FLAG_OPTIONAL;
/* obj_selector[0] is reserved for *all */
obj_selector[0].name = all_name;
obj_selector[0].val = -1;
/* Go over objects */
bcmolt_system_mode_get(current_device, &current_system_mode);
for (o = 0; o < BCMOLT_OBJ_ID__NUM_OF; o++)
{
bcmcli_enum_val *grp_selector;
bcmcli_cmd_parm *grp_parm;
bcmolt_mgt_group g;
int n_grp = 0;
if (!bcmolt_object_is_supported(current_system_mode, o))
continue;
/* Allocate group parameter and selector */
++n_obj;
obj_selector[n_obj].val = o;
rc = api_cli_object_name(o, &obj_selector[n_obj].name, NULL);
if (rc != BCM_ERR_OK)
goto cleanup;
obj_selector[n_obj].parms = grp_parm = bcmos_calloc(sizeof(bcmcli_cmd_parm)*2);
if (!grp_parm)
goto cleanup;
rc = _bcmtr_cld_copy_parm_name(grp_parm, "group", "Message group");
grp_parm->type = BCMCLI_PARM_ENUM;
grp_parm->flags = BCMCLI_PARM_FLAG_SELECTOR;
grp_parm->enum_table = grp_selector = bcmos_calloc(sizeof(bcmcli_enum_val) * (BCMOLT_MGT_GROUP__NUM_OF + 1));
if (!grp_selector)
goto cleanup;
/* Selector 0 is reserved for *all */
grp_selector[0].name = all_name;
grp_selector[0].val = -1;
/* Go over groups */
for (g = 1; g < BCMOLT_MGT_GROUP__NUM_OF; g++)
{
uint16_t subgroup_count = api_cli_get_subgroup_count(o, g);
bcmcli_enum_val *subgrp_table;
bcmcli_cmd_parm *subgrp_parm;
uint16_t s;
int sg_table_idx;
if (subgroup_count == 0)
continue;
++n_grp;
grp_selector[n_grp].name = apicli_mgt_group_to_str(g);
grp_selector[n_grp].val = g;
/* Skip subgroup selector for groups that don't support it */
if (g != BCMOLT_MGT_GROUP_AUTO &&
g != BCMOLT_MGT_GROUP_OPER &&
g != BCMOLT_MGT_GROUP_PROXY &&
g != BCMOLT_MGT_GROUP_PROXY_RX)
{
continue;
}
grp_selector[n_grp].parms = subgrp_parm = bcmos_calloc(sizeof(bcmcli_cmd_parm)*2);
if (!subgrp_parm)
goto cleanup;
rc = rc ? rc : _bcmtr_cld_copy_parm_name(subgrp_parm, "subgroup", "Message sub-group");
subgrp_parm->type = BCMCLI_PARM_ENUM;
subgrp_parm->enum_table = subgrp_table = bcmos_calloc(sizeof(bcmcli_enum_val) * (subgroup_count + 2));
if (!subgrp_table)
goto cleanup;
subgrp_table[0].name = all_name;
subgrp_table[0].val = -1;
sg_table_idx = 1;
for (s = 0; s < subgroup_count; s++)
{
if (api_cli_object_subgroup_name(o, g, s, &subgrp_table[sg_table_idx].name, NULL) == BCM_ERR_OK)
{
subgrp_table[sg_table_idx].val = s;
++sg_table_idx;
}
}
}
}
/* Finally add command */
rc = bcmcli_cmd_add(dir, "level", _bcmtr_cld_cli_setget_level, "Set/get cld level", BCMCLI_ACCESS_ADMIN,
&cmd_extras, cmd_parms);
if (rc)
goto cleanup;
return BCM_ERR_OK;
cleanup:
_bcmtr_cld_free_level_parms(cmd_parms);
return rc;
}
/* Create CLI commands */
static bcmos_errno _bcmtr_cld_cli_create(void)
{
bcmcli_entry *dir;
bcmos_errno err;
dir = bcmcli_dir_add(NULL, "cld", "Transport Capture, Log, Debug", BCMCLI_ACCESS_ADMIN, NULL);
BCMOS_CHECK_RETURN_ERROR(dir == NULL, BCM_ERR_NOMEM);
err = _bcmtr_cld_add_level_cmd(dir);
if (err)
return err;
BCMCLI_MAKE_CMD(dir, "init", "Initialize capture buffer", _bcmtr_cld_cli_capture_init,
BCMCLI_MAKE_PARM("size", "Buffer size (bytes)", BCMCLI_PARM_UDECIMAL, 0),
BCMCLI_MAKE_PARM_ENUM("stop_on_full", "Stop capture when buffer is full (yes) or wrap-around (no)",
bcmcli_enum_bool_table, 0),
BCMCLI_MAKE_PARM_ENUM("autostart", "Autostart", bcmcli_enum_bool_table, 0) );
BCMCLI_MAKE_CMD_NOPARM(dir, "delete", "Destroy buffer", _bcmtr_cld_cli_capture_delete);
BCMCLI_MAKE_CMD_NOPARM(dir, "start", "Start capture", _bcmtr_cld_cli_capture_start);
BCMCLI_MAKE_CMD_NOPARM(dir, "stop", "Stop capture", _bcmtr_cld_cli_capture_stop);
BCMCLI_MAKE_CMD_NOPARM(dir, "dump", "Dump capture buffer", _bcmtr_cld_cli_capture_dump);
BCMCLI_MAKE_CMD_NOPARM(dir, "info", "Capture info", _bcmtr_cld_cli_capture_info);
cld_cli_dir = dir;
return BCM_ERR_OK;
}
/* Destroy CLI commands */
static void _bcmtr_cld_cli_destroy(void)
{
if (cld_cli_dir)
{
bcmcli_token_destroy(cld_cli_dir);
cld_cli_dir = NULL;
}
}
/** Initialize CLD CLI commands
* \returns BCM_ERR_OK (0) if successful
*/
bcmos_errno bcmtr_cld_cli_init(void)
{
bcmos_errno err = BCM_ERR_OK;
#ifdef BCM_SUBSYSTEM_HOST
/* Subscribe for device change indication */
err = bcmolt_dev_sel_ind_register(_bcmtr_cld_device_change_ind);
#endif
err = err ? err : _bcmtr_cld_cli_create();
return err;
}
/** Clean-up CLD CLI commands */
void bcmtr_cld_cli_exit(void)
{
_bcmtr_cld_cli_destroy();
}