| /* |
| <: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, ¤t_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(); |
| } |