blob: 45764cbe2fed478a34d4127d52a85a62bc6ae887 [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.
:>
*/
#define HOST_API_CAPTURE 0
#include "bcmos_system.h"
#include "bcmolt_api.h"
#include "bcmolt_msg.h"
#include "bcmolt_tr_mux.h"
#if HOST_API_CAPTURE
#include "bcmolt_debug_api_common.h"
#endif
#include "bcmolt_dev_ctrl.h"
#include "bcmolt_debug_ctrl.h"
#define API_CAPTURE_PROP_MASK\
((1ULL << BCMOLT_DEBUG_CFG_ID_API_CAPTURE_CFG) |\
(1ULL << BCMOLT_DEBUG_CFG_ID_API_CAPTURE_STATS) |\
(1ULL << BCMOLT_DEBUG_CFG_ID_API_CAPTURE_BUFFER_READ) |\
(1ULL << BCMOLT_DEBUG_CFG_ID_API_CAPTURE_BUFFER))
typedef struct
{
bcmos_bool waiting_for_ack;
bcmolt_msg *last_message;
bcmos_timer ack_timeout;
#if HOST_API_CAPTURE
bcmolt_debug_api_db db;
debug_trans_handle *handle;
#endif
} debug_ctrl_ctxt;
static debug_ctrl_ctxt debug_ctrl[BCMTR_MAX_OLTS];
static void send_to_host(bcmolt_devid device, bcmolt_msg *msg)
{
msg->dir = BCMOLT_MSG_DIR_RESPONSE;
bcmtrmux_control_to_host(device, msg);
bcmolt_msg_free(msg);
}
static void send_to_device(bcmolt_devid device, bcmolt_msg *msg)
{
debug_ctrl[device].waiting_for_ack = BCMOS_TRUE;
debug_ctrl[device].last_message = msg;
bcmtrmux_control_to_line(device, msg);
bcmos_timer_start(&debug_ctrl[device].ack_timeout, DEVICE_RESPONSE_TIMEOUT_LENGTH);
}
static bcmos_bool bcmolt_debug_ctrl_cfg_requires_connection(bcmolt_msg *msg, const bcmolt_debug_cfg_data *cfg)
{
return (((msg->presence_mask & ~API_CAPTURE_PROP_MASK) != 0) || /* includes non-API capture elements, or ... */
(((msg->presence_mask & API_CAPTURE_PROP_MASK) != 0) && /* includes API captue elements and ... */
(cfg->api_capture_cfg.location == BCMOLT_API_CAPTURE_LOCATION_DEVICE))); /* capture location is device */
}
static void bcmolt_debug_ctrl_send_cfg_get_response(bcmolt_devid device, bcmolt_msg *msg)
{
#if HOST_API_CAPTURE
if (debug_ctrl[device].db.cfg.api_capture_cfg.location == BCMOLT_API_CAPTURE_LOCATION_HOST)
{
bcmolt_debug_api_common_get(device, msg, &debug_ctrl[device].db);
}
#endif
send_to_host(device, msg);
}
static void bcmolt_debug_ctrl_handle_cfg_get(bcmolt_devid device, bcmolt_msg *msg, bcmos_bool connected)
{
#if HOST_API_CAPTURE
if (bcmolt_debug_ctrl_cfg_requires_connection(msg, &debug_ctrl[device].db.cfg))
#endif
{
if (connected)
{
send_to_device(device, msg);
return;
}
bcmolt_msg_err(
msg,
DEV_LOG_INVALID_ID,
BCM_ERR_NOT_CONNECTED,
BCMOLT_ERR_FIELD_NONE,
"Cannot access embedded parameters while disconnected");
}
bcmolt_debug_ctrl_send_cfg_get_response(device, msg);
}
static void bcmolt_debug_ctrl_send_cfg_set_response(bcmolt_devid device, bcmolt_msg *msg)
{
#if HOST_API_CAPTURE
if (msg->err == BCM_ERR_OK)
{
bcmolt_debug_api_common_cfg_trans_succeed(device, debug_ctrl[device].handle);
}
else
{
bcmolt_debug_api_common_cfg_trans_fail(&debug_ctrl[device].db, debug_ctrl[device].handle);
}
#endif
send_to_host(device, msg);
}
static void bcmolt_debug_ctrl_handle_cfg_set(bcmolt_devid device, bcmolt_msg *msg, bcmos_bool connected)
{
bcmolt_debug_cfg *cfg = (bcmolt_debug_cfg*)msg;
bcmolt_debug_cfg_id prop_id;
bcmos_errno err;
if (!bcmolt_debug_cfg_data_bounds_check(&cfg->data, msg->presence_mask, &prop_id))
{
err = BCM_ERR_RANGE;
msg->err_field_idx = (uint16_t)prop_id;
send_to_host(device, msg);
return;
}
#if HOST_API_CAPTURE
debug_ctrl[device].handle = bcmolt_debug_api_common_cfg_trans_start(&debug_ctrl[device].db);
err = bcmolt_debug_api_common_set(device, msg, &cfg->data, debug_ctrl[device].handle, BCMOLT_API_CAPTURE_LOCATION_HOST);
#else
if (BCMOLT_CFG_PROP_IS_SET(cfg, debug, api_capture_cfg) &&
(cfg->data.api_capture_cfg.location == BCMOLT_API_CAPTURE_LOCATION_HOST))
{
err = bcmolt_msg_err(
msg,
DEV_LOG_INVALID_ID,
BCM_ERR_NOT_SUPPORTED,
BCMOLT_ERR_FIELD_NONE,
"Host API capture not supported yet");
}
else
{
err = BCM_ERR_OK;
}
#endif
if (err == BCM_ERR_OK)
{
if (bcmolt_debug_ctrl_cfg_requires_connection(msg, &cfg->data))
{
if (connected)
{
send_to_device(device, msg);
return;
}
bcmolt_msg_err(
msg,
DEV_LOG_INVALID_ID,
BCM_ERR_NOT_CONNECTED,
BCMOLT_ERR_FIELD_NONE,
"Cannot access embedded parameters while disconnected");
}
}
bcmolt_debug_ctrl_send_cfg_set_response(device, msg);
}
static void bcmolt_debug_ctrl_handle_cfg_clear(bcmolt_devid device, bcmolt_msg *msg, bcmos_bool connected)
{
#if HOST_API_CAPTURE
bcmolt_debug_cfg *cfg = (bcmolt_debug_cfg*)msg;
#endif
bcmos_errno err;
if (!connected)
{
bcmolt_msg_err(
msg,
DEV_LOG_INVALID_ID,
BCM_ERR_NOT_CONNECTED,
BCMOLT_ERR_FIELD_NONE,
"Cannot access embedded parameters while disconnected");
send_to_host(device, msg);
return;
}
#if HOST_API_CAPTURE
debug_ctrl[device].handle = bcmolt_debug_api_common_cfg_trans_start(&debug_ctrl[device].db);
bcmolt_debug_cfg_data_set_default(&debug_ctrl[device].db.cfg, BCMOLT_PRESENCE_MASK_ALL);
msg->presence_mask = BCMOLT_PRESENCE_MASK_ALL;
err = bcmolt_debug_api_common_set(device, msg, &cfg->data, debug_ctrl[device].handle, BCMOLT_API_CAPTURE_LOCATION_HOST);
#else
err = BCM_ERR_OK;
#endif
if (err == BCM_ERR_OK)
{
send_to_device(device, msg);
}
else
{
bcmolt_debug_ctrl_send_cfg_set_response(device, msg);
}
}
static void bcmolt_debug_ctrl_handle_cfg(bcmolt_devid device, bcmolt_msg *msg, bcmos_bool connected)
{
switch (msg->type)
{
case BCMOLT_MSG_TYPE_GET:
bcmolt_debug_ctrl_handle_cfg_get(device, msg, connected);
break;
case BCMOLT_MSG_TYPE_SET:
bcmolt_debug_ctrl_handle_cfg_set(device, msg, connected);
break;
case BCMOLT_MSG_TYPE_CLEAR:
bcmolt_debug_ctrl_handle_cfg_clear(device, msg, connected);
break;
default:
bcmolt_msg_err(
msg,
DEV_LOG_INVALID_ID,
BCM_ERR_NOT_SUPPORTED,
BCMOLT_ERR_FIELD_NONE,
"Unsupported message type (%u)",
msg->type);
send_to_host(device, msg);
break;
}
}
static void bcmolt_debug_ctrl_handle_oper(bcmolt_devid device, bcmolt_msg *msg, bcmos_bool connected)
{
#if HOST_API_CAPTURE
bcmos_bool host_api_capture =
(debug_ctrl[device].db.cfg.api_capture_cfg.location == BCMOLT_API_CAPTURE_LOCATION_HOST);
switch (msg->subgroup)
{
case BCMOLT_DEBUG_OPER_ID_START_API_CAPTURE:
if (host_api_capture)
{
msg->err = bcmolt_debug_api_common_oper_start_api_capture(device, msg);
send_to_host(device, msg);
return;
}
break;
case BCMOLT_DEBUG_OPER_ID_STOP_API_CAPTURE:
if (host_api_capture)
{
msg->err = bcmolt_debug_api_common_oper_stop_api_capture(device, msg, &debug_ctrl[device].db);
send_to_host(device, msg);
return;
}
break;
case BCMOLT_DEBUG_OPER_ID_RESET_API_CAPTURE:
if (host_api_capture)
{
msg->err = bcmolt_debug_api_common_oper_reset_api_capture(device, msg, &debug_ctrl[device].db);
send_to_host(device, msg);
return;
}
break;
default:
break;
}
#endif
if (!connected)
{
bcmolt_msg_err(
msg,
DEV_LOG_INVALID_ID,
BCM_ERR_NOT_CONNECTED,
BCMOLT_ERR_FIELD_NONE,
"Cannot perform embedded operations while disconnected");
send_to_host(device, msg);
return;
}
send_to_device(device, msg);
}
static void bcmolt_debug_ctrl_handle_auto_cfg(bcmolt_devid device, bcmolt_msg *msg, bcmos_bool connected)
{
if (!connected)
{
bcmolt_msg_err(
msg,
DEV_LOG_INVALID_ID,
BCM_ERR_NOT_CONNECTED,
BCMOLT_ERR_FIELD_NONE,
"Cannot access embedded parameters while disconnected");
send_to_host(device, msg);
return;
}
send_to_device(device, msg);
}
static void bcmolt_debug_ctrl_handle_request(bcmolt_devid device, bcmolt_msg *msg, bcmos_bool connected)
{
if (debug_ctrl[device].waiting_for_ack)
{
bcmolt_msg_err(
msg,
DEV_LOG_INVALID_ID,
BCM_ERR_TOO_MANY_REQS,
BCMOLT_ERR_FIELD_NONE,
"Transaction in progress on debug object");
send_to_host(device, msg);
return;
}
switch (msg->group)
{
case BCMOLT_MGT_GROUP_CFG:
bcmolt_debug_ctrl_handle_cfg(device, msg, connected);
break;
case BCMOLT_MGT_GROUP_OPER:
bcmolt_debug_ctrl_handle_oper(device, msg, connected);
break;
case BCMOLT_MGT_GROUP_AUTO_CFG:
bcmolt_debug_ctrl_handle_auto_cfg(device, msg, connected);
break;
default:
bcmolt_msg_err(
msg,
DEV_LOG_INVALID_ID,
BCM_ERR_NOT_SUPPORTED,
BCMOLT_ERR_FIELD_NONE,
"Unsupported group (%u)",
msg->group);
send_to_host(device, msg);
break;
}
}
static void bcmolt_debug_ctrl_handle_response(bcmolt_devid device, bcmolt_msg *msg)
{
if (!debug_ctrl[device].waiting_for_ack || (msg->corr_tag != debug_ctrl[device].last_message->corr_tag))
{
msg->subch = BCMTRMUX_CHANNEL_AUTO_PROXY;
send_to_host(device, msg);
return;
}
msg->subch = debug_ctrl[device].last_message->subch;
bcmos_timer_stop(&debug_ctrl[device].ack_timeout);
debug_ctrl[device].waiting_for_ack = BCMOS_FALSE;
bcmolt_msg_free(debug_ctrl[device].last_message);
if (msg->err != BCM_ERR_OK)
{
send_to_host(device, msg);
return;
}
switch (msg->group)
{
case BCMOLT_MGT_GROUP_CFG:
switch (msg->type)
{
case BCMOLT_MSG_TYPE_GET:
bcmolt_debug_ctrl_send_cfg_get_response(device, msg);
break;
case BCMOLT_MSG_TYPE_SET:
bcmolt_debug_ctrl_send_cfg_set_response(device, msg);
break;
case BCMOLT_MSG_TYPE_CLEAR:
bcmolt_debug_ctrl_send_cfg_set_response(device, msg);
break;
default:
BCMOS_TRACE_ERR("Got unexpected response type (%u) from embedded\n", msg->group);
send_to_host(device, msg);
break;
}
break;
case BCMOLT_MGT_GROUP_OPER:
case BCMOLT_MGT_GROUP_AUTO_CFG:
send_to_host(device, msg);
break;
default:
BCMOS_TRACE_ERR("Got unexpected response group (%u) from embedded\n", msg->group);
send_to_host(device, msg);
break;
}
}
static bcmos_timer_rc bcmolt_debug_ctrl_handle_ack_timeout(bcmos_timer *timer, long data)
{
bcmolt_devid device = (bcmolt_devid)data;
if (debug_ctrl[device].last_message == NULL)
{
BCMOS_TRACE_ERR("Waiting with no message!\n");
return BCMOS_TIMER_OK;
}
bcmolt_msg_err(
debug_ctrl[device].last_message,
DEV_LOG_INVALID_ID,
BCM_ERR_INTERNAL,
BCMOLT_ERR_FIELD_NONE,
"Did not receive response from embedded");
send_to_host(device, debug_ctrl [device].last_message);
return BCMOS_TIMER_OK;
}
void bcmolt_debug_ctrl_process_msg(bcmolt_devid device, bcmolt_msg *msg, bcmos_bool connected)
{
switch (msg->dir)
{
case BCMOLT_MSG_DIR_REQUEST:
bcmolt_debug_ctrl_handle_request(device, msg, connected);
break;
case BCMOLT_MSG_DIR_RESPONSE:
bcmolt_debug_ctrl_handle_response(device, msg);
break;
default:
BCMOS_TRACE_ERR("Unsupported direction: %u\n", msg->dir);
bcmolt_msg_free(msg);
break;
}
}
void bcmolt_debug_ctrl_init(void)
{
bcmolt_devid i;
for (i = 0; i < BCMTR_MAX_OLTS; i++)
{
bcmos_timer_parm tp =
{
.name = "debug_ctrl_ack_timeout",
.owner = BCMOS_MODULE_ID_DEV_CTRL_DEV0 + i,
.periodic = BCMOS_FALSE,
.handler = bcmolt_debug_ctrl_handle_ack_timeout,
.data = (long)i,
.flags = BCMOS_TIMER_PARM_FLAGS_URGENT,
};
debug_ctrl[i].waiting_for_ack = BCMOS_FALSE;
bcmos_timer_create(&debug_ctrl[i].ack_timeout, &tp);
#if HOST_API_CAPTURE
bcmolt_debug_api_common_init(i, &debug_ctrl[i].db);
#endif
}
}