| /* |
| <: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 "bcmolt_math.h" |
| #include "bcmtr_debug.h" |
| #include "bcmolt_msg.h" |
| #include "bcmolt_debug_api_common.h" |
| |
| #define API_CFG_PROP_EXISTS(mask, prop) (((mask) & (1ULL << (prop))) != 0) |
| |
| static void bcmolt_debug_api_common_capture_stats_update(bcmolt_devid device, bcmolt_debug_api_db *db) |
| { |
| bcmos_errno err; |
| bcmtr_capture_info info; |
| |
| err = bcmtr_capture_info_get(device, &info); |
| BUG_ON(BCM_ERR_OK != err); |
| |
| db->cfg.api_capture_stats.buffer_used_bytes = info.used; |
| db->cfg.api_capture_stats.events_recorded = info.msgs; |
| db->cfg.api_capture_stats.events_dropped = info.lost; |
| db->cfg.api_capture_stats.buffer_wrap_count = info.wa; |
| |
| err = bcmtr_capture_size_get(device, &db->cfg.api_capture_stats.readable_bytes); |
| BUG_ON(BCM_ERR_OK != err); |
| } |
| |
| static bcmos_errno bcmolt_debug_api_common_capture_init(bcmolt_devid device, bcmolt_debug_api_db *db) |
| { |
| bcmos_errno err; |
| bcmtr_capture_parm cap_parm = {}; |
| |
| cap_parm.size = db->cfg.api_capture_cfg.buffer_size_bytes; |
| cap_parm.ptr = db->capture_buffer; |
| cap_parm.stop_on_full = db->cfg.api_capture_cfg.buffer_mode == BCMOLT_API_CAPTURE_BUFFER_MODE_OVERFLOW; |
| cap_parm.activate = BCMOS_FALSE; |
| |
| err = bcmtr_capture_init(device, &cap_parm); |
| BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err); |
| |
| bcmolt_debug_api_common_capture_stats_update(device, db); |
| return BCM_ERR_OK; |
| } |
| |
| bcmos_errno bcmolt_debug_api_common_get(bcmolt_devid device, bcmolt_msg *msg, bcmolt_debug_api_db *db) |
| { |
| if (API_CFG_PROP_EXISTS(msg->presence_mask, BCMOLT_DEBUG_CFG_ID_API_CAPTURE_BUFFER)) |
| { |
| uint32_t to_read = 0; |
| |
| if (bcmtr_capture_is_active(device)) |
| { |
| return bcmolt_msg_err( |
| msg, |
| DEV_LOG_INVALID_ID, |
| BCM_ERR_STATE, |
| BCMOLT_DEBUG_CFG_ID_API_CAPTURE_BUFFER, |
| "Cannot read capture buffer while capture is in progress"); |
| } |
| |
| if (db->cfg.api_capture_buffer_read.offset < db->cfg.api_capture_stats.readable_bytes) |
| { |
| to_read = MIN( |
| db->cfg.api_capture_buffer.len, |
| db->cfg.api_capture_stats.readable_bytes - db->cfg.api_capture_buffer_read.offset); |
| } |
| if ((db->cfg.api_capture_buffer.val != NULL) && (db->cfg.api_capture_buffer.len > 0)) |
| { |
| bcmtr_capture_read( |
| device, |
| db->cfg.api_capture_buffer.val, |
| db->cfg.api_capture_buffer_read.offset, |
| &to_read); |
| memset(db->cfg.api_capture_buffer.val + (db->cfg.api_capture_buffer.len - to_read), 0, to_read); |
| } |
| } |
| |
| return BCM_ERR_OK; |
| } |
| |
| debug_trans_handle *bcmolt_debug_api_common_cfg_trans_start(bcmolt_debug_api_db *db) |
| { |
| debug_trans_handle *handle = bcmos_calloc(sizeof(*handle)); |
| handle->old_db = *db; |
| handle->new_db = db; |
| return handle; |
| } |
| |
| void bcmolt_debug_api_common_cfg_trans_fail(bcmolt_debug_api_db *db, debug_trans_handle *handle) |
| { |
| if (handle->old_db.capture_buffer != handle->new_db->capture_buffer) |
| { |
| bcmos_free(handle->new_db->capture_buffer); |
| } |
| if (handle->old_db.cfg.api_capture_buffer.val != handle->new_db->cfg.api_capture_buffer.val) |
| { |
| bcmos_free(handle->new_db->cfg.api_capture_buffer.val); |
| } |
| *db = handle->old_db; |
| bcmos_free(handle); |
| } |
| |
| void bcmolt_debug_api_common_cfg_trans_succeed(bcmolt_devid device, debug_trans_handle *handle) |
| { |
| bcmos_errno err; |
| |
| if (handle->old_db.capture_buffer != handle->new_db->capture_buffer) |
| { |
| bcmos_free(handle->old_db.capture_buffer); |
| bcmtr_capture_destroy(device); |
| err = bcmolt_debug_api_common_capture_init(device, handle->new_db); |
| if (BCM_ERR_OK != err) /* cfg_set should have validated that this won't fail */ |
| { |
| BCMOS_TRACE_ERR("Capture init failed (%s)!\n", bcmos_strerror(err)); |
| } |
| } |
| if (handle->old_db.cfg.api_capture_buffer.val != handle->new_db->cfg.api_capture_buffer.val) |
| { |
| bcmos_free(handle->old_db.cfg.api_capture_buffer.val); |
| } |
| bcmos_free(handle); |
| } |
| |
| bcmos_errno bcmolt_debug_api_common_set( |
| bcmolt_devid device, |
| bcmolt_msg *msg, |
| const bcmolt_debug_cfg_data *data, |
| debug_trans_handle *handle, |
| bcmolt_api_capture_location local) |
| { |
| if (API_CFG_PROP_EXISTS(msg->presence_mask, BCMOLT_DEBUG_CFG_ID_API_CAPTURE_CFG)) |
| { |
| if (bcmtr_capture_is_active(device)) |
| { |
| return bcmolt_msg_err( |
| msg, |
| DEV_LOG_INVALID_ID, |
| BCM_ERR_STATE, |
| BCMOLT_DEBUG_CFG_ID_API_CAPTURE_CFG, |
| "Cannot change capture configuration while capture is in progress"); |
| } |
| handle->new_db->cfg.api_capture_cfg = data->api_capture_cfg; |
| } |
| |
| if (API_CFG_PROP_EXISTS(msg->presence_mask, BCMOLT_DEBUG_CFG_ID_API_CAPTURE_BUFFER_READ)) |
| { |
| handle->new_db->cfg.api_capture_buffer_read = data->api_capture_buffer_read; |
| } |
| |
| /* Once all the properties are handled, we need to take care of a few things that could depend on multiple |
| properties */ |
| if ((handle->new_db->cfg.api_capture_cfg.location == local) && |
| /* If we just switched to the device ... */ |
| ((handle->new_db->cfg.api_capture_cfg.location != handle->old_db.cfg.api_capture_cfg.location) || |
| /* ... or either the buffer size ... */ |
| (handle->new_db->cfg.api_capture_cfg.buffer_size_bytes != |
| handle->old_db.cfg.api_capture_cfg.buffer_size_bytes) || |
| /* ... or the buffer mode have changed */ |
| (handle->new_db->cfg.api_capture_cfg.buffer_mode != handle->old_db.cfg.api_capture_cfg.buffer_mode))) |
| { |
| handle->new_db->capture_buffer = bcmos_alloc(handle->new_db->cfg.api_capture_cfg.buffer_size_bytes); |
| if (handle->new_db->capture_buffer == NULL) |
| { |
| return bcmolt_msg_err( |
| msg, |
| DEV_LOG_INVALID_ID, |
| BCM_ERR_NOMEM, |
| BCMOLT_DEBUG_CFG_ID_API_CAPTURE_BUFFER_READ, |
| "Failed to allocate new capture buffer"); |
| } |
| } |
| |
| if ((handle->new_db->cfg.api_capture_cfg.location == local) && |
| /* If we just switched to the device ... */ |
| ((handle->new_db->cfg.api_capture_cfg.location != handle->old_db.cfg.api_capture_cfg.location) || |
| /* ... or the read size has changed */ |
| (handle->old_db.cfg.api_capture_buffer_read.size != handle->new_db->cfg.api_capture_buffer_read.size))) |
| { |
| handle->new_db->cfg.api_capture_buffer.len = handle->new_db->cfg.api_capture_buffer_read.size; |
| if (handle->new_db->cfg.api_capture_buffer.len != 0) |
| { |
| handle->new_db->cfg.api_capture_buffer.val = bcmos_alloc(handle->new_db->cfg.api_capture_buffer_read.size); |
| if (handle->new_db->cfg.api_capture_buffer.val == NULL) |
| { |
| return bcmolt_msg_err( |
| msg, |
| DEV_LOG_INVALID_ID, |
| BCM_ERR_NOMEM, |
| BCMOLT_DEBUG_CFG_ID_API_CAPTURE_BUFFER_READ, |
| "Failed to allocate new read buffer"); |
| } |
| } |
| else |
| { |
| handle->new_db->cfg.api_capture_buffer.val = NULL; |
| } |
| } |
| |
| return BCM_ERR_OK; |
| } |
| |
| bcmos_errno bcmolt_debug_api_common_oper_start_api_capture(bcmolt_devid device, bcmolt_msg *msg) |
| { |
| bcmos_errno err; |
| bcmtr_cld_filter filter; |
| |
| if (bcmtr_capture_is_active(device)) |
| { |
| return bcmolt_msg_err( |
| msg, |
| DEV_LOG_INVALID_ID, |
| BCM_ERR_ALREADY, |
| BCMOLT_ERR_FIELD_NONE, |
| "Capture already in progress"); |
| } |
| |
| /* capture everything */ |
| filter.object = BCMOLT_OBJECT_ANY; |
| filter.group = BCMOLT_MGT_GROUP_ANY; |
| filter.subgroup = BCMOLT_SUBGROUP_ANY; |
| err = bcmtr_cld_level_set(device, &filter, BCMTR_CLD_CAPTURE); |
| BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err); |
| /* for now filter out start/stop operations and keep-alives */ |
| filter.object = BCMOLT_OBJ_ID_DEBUG; |
| filter.group = BCMOLT_MGT_GROUP_OPER; |
| filter.subgroup = BCMOLT_DEBUG_OPER_ID_START_API_CAPTURE; /*lint !e633 */ |
| err = bcmtr_cld_level_set(device, &filter, BCMTR_CLD_NONE); |
| BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err); |
| filter.subgroup = BCMOLT_DEBUG_OPER_ID_STOP_API_CAPTURE; /*lint !e633 */ |
| err = bcmtr_cld_level_set(device, &filter, BCMTR_CLD_NONE); |
| BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err); |
| filter.object = BCMOLT_OBJ_ID_DEVICE; |
| filter.group = BCMOLT_MGT_GROUP_OPER; |
| filter.subgroup = BCMOLT_DEVICE_OPER_ID_HOST_KEEP_ALIVE; /*lint !e633 */ |
| err = bcmtr_cld_level_set(device, &filter, BCMTR_CLD_NONE); |
| BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err); |
| filter.group = BCMOLT_MGT_GROUP_AUTO; |
| filter.subgroup = BCMOLT_DEVICE_AUTO_ID_DEVICE_KEEP_ALIVE; /*lint !e633 */ |
| err = bcmtr_cld_level_set(device, &filter, BCMTR_CLD_NONE); |
| BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err); |
| |
| return bcmtr_capture_start_stop(device, BCMOS_TRUE); |
| } |
| |
| bcmos_errno bcmolt_debug_api_common_oper_stop_api_capture(bcmolt_devid device, bcmolt_msg *msg, bcmolt_debug_api_db *db) |
| { |
| bcmos_errno err; |
| |
| if (!bcmtr_capture_is_active(device)) |
| { |
| return bcmolt_msg_err( |
| msg, |
| DEV_LOG_INVALID_ID, |
| BCM_ERR_ALREADY, |
| BCMOLT_ERR_FIELD_NONE, |
| "No capture in progress"); |
| } |
| |
| err = bcmtr_capture_start_stop(device, BCMOS_FALSE); |
| BCMOS_CHECK_RETURN_ERROR(BCM_ERR_OK != err, err); |
| |
| bcmolt_debug_api_common_capture_stats_update(device, db); |
| |
| return BCM_ERR_OK; |
| } |
| |
| bcmos_errno bcmolt_debug_api_common_oper_reset_api_capture(bcmolt_devid device, bcmolt_msg *msg, bcmolt_debug_api_db *db) |
| { |
| bcmos_errno err; |
| |
| if (bcmtr_capture_is_active(device)) |
| { |
| return bcmolt_msg_err( |
| msg, |
| DEV_LOG_INVALID_ID, |
| BCM_ERR_STATE, |
| BCMOLT_ERR_FIELD_NONE, |
| "Cannot reset capture while capture is running"); |
| } |
| |
| bcmtr_capture_destroy(device); |
| err = bcmolt_debug_api_common_capture_init(device, db); |
| |
| return err; |
| } |
| |
| void bcmolt_debug_api_common_init(bcmolt_devid device, bcmolt_debug_api_db *db) |
| { |
| bcmos_errno err; |
| |
| #if ENABLE_LOG |
| db->log_id = bcm_dev_log_id_register("mh_debug", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH); |
| #endif |
| |
| bcmolt_debug_cfg_data_set_default(&db->cfg, BCMOLT_PRESENCE_MASK_ALL); |
| db->capture_buffer = bcmos_alloc(db->cfg.api_capture_cfg.buffer_size_bytes); |
| err = bcmolt_debug_api_common_capture_init(device, db); |
| BUG_ON(BCM_ERR_OK != err); |
| } |
| |