BAL and Maple Release 2.2
Signed-off-by: Shad Ansari <developer@Carbon.local>
diff --git a/bcm68620_release/release/host_driver/dev_ctrl/Makefile b/bcm68620_release/release/host_driver/dev_ctrl/Makefile
new file mode 100644
index 0000000..24f149b
--- /dev/null
+++ b/bcm68620_release/release/host_driver/dev_ctrl/Makefile
@@ -0,0 +1,24 @@
+# Device control driver
+MOD_NAME = dev_ctrl
+MOD_DEPS = trmux keep_alive fld ll_pcie debug_common
+MOD_INC_DIRS = $(SRC_DIR)
+
+ifeq ("$(RELEASE_BUILD)", "y")
+ MOD_INC_DIRS += host_driver/sw_version host_driver/sw_error host_driver/mh_utils
+else
+ MOD_INC_DIRS += host/sw_version $(TOP_DIR)/common/sw_error $(TOP_DIR)/common/mh_utils
+endif
+
+ifeq ("$(OS_KERNEL)", "linux")
+MOD_TYPE = linux_lib
+else
+MOD_TYPE = lib
+endif
+
+srcs = bcmolt_dev_ctrl.c bcmolt_debug_ctrl.c
+
+# If called by linux kernel builder - add include paths manually.
+# It is not elegant, but we'll not have many linux modules
+ifneq ("$(KBUILD_SRC)", "")
+ -include $(OUT_DIR_BASE)/Makefile.config.$(MOD_NAME)
+endif
diff --git a/bcm68620_release/release/host_driver/dev_ctrl/bcmolt_debug_ctrl.c b/bcm68620_release/release/host_driver/dev_ctrl/bcmolt_debug_ctrl.c
new file mode 100644
index 0000000..45764cb
--- /dev/null
+++ b/bcm68620_release/release/host_driver/dev_ctrl/bcmolt_debug_ctrl.c
@@ -0,0 +1,469 @@
+/*
+<: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
+ }
+}
diff --git a/bcm68620_release/release/host_driver/dev_ctrl/bcmolt_debug_ctrl.h b/bcm68620_release/release/host_driver/dev_ctrl/bcmolt_debug_ctrl.h
new file mode 100644
index 0000000..43991e9
--- /dev/null
+++ b/bcm68620_release/release/host_driver/dev_ctrl/bcmolt_debug_ctrl.h
@@ -0,0 +1,41 @@
+/*
+<: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.
+
+:>
+ */
+
+#ifndef _BCMOLT_DEBUG_CTRL_H_
+#define _BCMOLT_DEBUG_CTRL_H_
+
+#include "bcmos_system.h"
+#include "bcmolt_msg.h"
+
+void bcmolt_debug_ctrl_process_msg(bcmolt_devid device, bcmolt_msg *msg, bcmos_bool connected);
+
+void bcmolt_debug_ctrl_init(void);
+
+#endif /* _BCMOLT_DEBUG_CTRL_H_ */
+
diff --git a/bcm68620_release/release/host_driver/dev_ctrl/bcmolt_dev_ctrl.c b/bcm68620_release/release/host_driver/dev_ctrl/bcmolt_dev_ctrl.c
new file mode 100644
index 0000000..2ddfa8d
--- /dev/null
+++ b/bcm68620_release/release/host_driver/dev_ctrl/bcmolt_dev_ctrl.c
@@ -0,0 +1,3158 @@
+/*
+<: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 <bcm_config.h>
+#include <bcmolt_msg.h>
+#include <bcmolt_tr_mux.h>
+#include <bcmolt_api.h>
+#include <bcmolt_model_types.h>
+#include <bcmolt_model_ids.h>
+#include <bcmolt_host_sw_version.h>
+#include <bcmolt_model_revision.h>
+#include "bcmolt_dev_ctrl.h"
+#include "bcmtr_pcie.h"
+#include "bcmolt_llpcie.h"
+#include "bcm_dev_log.h"
+#include "bcmolt_utils.h"
+#include "bcmolt_firmware_envelope.h"
+#include "bcmolt_msg_pack.h"
+#include "bcmolt_mh_utils.h"
+#include "bcmolt_debug_ctrl.h"
+
+static bcmolt_dev_ctrl_params dev_ctrl_params;
+static dev_ctrl_database dev_ctrl_db[BCMTR_MAX_OLTS];
+static uint8_t *image_buf[BCMTR_MAX_OLTS];
+static uint8_t *rd_image_buf[BCMTR_MAX_OLTS];
+
+#define BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, fmt, args...)\
+ do\
+ {\
+ if (BCM_ERR_OK != rc)\
+ {\
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "%s: "fmt, bcmos_strerror(rc), ## args);\
+ return rc;\
+ }\
+ } while (0)
+
+#ifndef IN_BAND
+static bcmos_timer_rc dev_ctrl_boot_seq_timer_handler(bcmos_timer *timer, long data);
+static bcmos_timer_rc dev_ctrl_ddr_test_timer_handler(bcmos_timer *timer, long data);
+#endif
+
+const char *bcm_str_device_state(bcmolt_device_state device_state)
+{
+ static const char *strings[] =
+ {
+ [BCMOLT_DEVICE_STATE_DISCONNECTED] = "DISCONNECTED",
+ [BCMOLT_DEVICE_STATE_CONNECTING] = "CONNECTING",
+ [BCMOLT_DEVICE_STATE_READY] = "READY",
+ [BCMOLT_DEVICE_STATE_WAITING_FOR_DEVICE] = "WAITING_FOR_DEVICE",
+ [BCMOLT_DEVICE_STATE__NUM_OF] = "UNKNOWN"
+ };
+ return strings[device_state > BCMOLT_DEVICE_STATE__NUM_OF ? BCMOLT_DEVICE_STATE__NUM_OF : device_state];
+}
+
+const char *bcm_str_device_event(dev_ctrl_event device_event)
+{
+ static const char *strings[] =
+ {
+ [DEVICE_CONTROL_EVENT_DEVICE_CLEAR] = "DEVICE_CLEAR",
+ [DEVICE_CONTROL_EVENT_DEVICE_CONFIG_SET] = "DEVICE_CONFIG_SET",
+ [DEVICE_CONTROL_EVENT_DEVICE_CONFIG_GET] = "DEVICE_CONFIG_GET",
+ [DEVICE_CONTROL_EVENT_DEVICE_DISCONNECT] = "DEVICE_DISCONNECT",
+ [DEVICE_CONTROL_EVENT_DEVICE_TIMER_TIMEOUT] = "TIMER_TIMEOUT",
+ [DEVICE_CONTROL_EVENT_DEVICE_RECEIVED_ACK] = "RECEIVED_ACK",
+ [DEVICE_CONTROL_EVENT_DEVICE_CONNECT] = "DEVICE_CONNECT",
+ [DEVICE_CONTROL_EVENT_DEVICE_RESET] = "DEVICE_RESET",
+ [DEVICE_CONTROL_EVENT_CONNECTION_FAILURE] = "CONNECTION_FAILURE",
+ [DEVICE_CONTROL_EVENT_CONNECTION_ESTABLISHED] = "CONNECTION_ESTABLISHED",
+ [DEVICE_CONTROL_EVENT_DEVICE_READY] = "DEVICE_READY",
+ [DEVICE_CONTROL_EVENT_RUN_DDR_TEST] = "RUN_DDR_TEST",
+ [DEVICE_CONTROL_EVENT_DDR_TEST_COMPLETED] = "DDR_TEST_COMPLETED",
+ [DEVICE_CONTROL_EVENT_DDR_TEST_TIMEOUT] = "DDR_TEST_TIMEOUT",
+ [DEVICE_CONTROL_EVENT__NUM_OF] = "UNKNOWN"
+ };
+ return strings[device_event > DEVICE_CONTROL_EVENT__NUM_OF ? DEVICE_CONTROL_EVENT__NUM_OF : device_event];
+}
+
+#ifdef ENABLE_LOG
+static const char *bcm_str_auto_id(bcmolt_device_auto_id auto_id)
+{
+ static const char *strings[] =
+ {
+ [BCMOLT_DEVICE_AUTO_ID_DEVICE_READY] = "DEVICE_READY",
+ [BCMOLT_DEVICE_AUTO_ID_CONNECTION_ESTABLISHED] = "CONNECTION_ESTABLISHED",
+ [BCMOLT_DEVICE_AUTO_ID_DEVICE_KEEP_ALIVE] = "DEVICE_KEEP_ALIVE",
+ [BCMOLT_DEVICE_AUTO_ID_CONNECTION_FAILURE] = "CONNECTION_FAILURE",
+ [BCMOLT_DEVICE_AUTO_ID_CONNECTION_COMPLETE] = "CONNECTION_COMPLETE",
+ [BCMOLT_DEVICE_AUTO_ID_DISCONNECTION_COMPLETE] = "DISCONNECTION_COMPLETE",
+ [BCMOLT_DEVICE_AUTO_ID_SW_ERROR] = "SW_ERROR",
+ [BCMOLT_DEVICE_AUTO_ID__NUM_OF] = "UNKNOWN"
+ };
+ return strings[auto_id > BCMOLT_DEVICE_AUTO_ID__NUM_OF ? BCMOLT_DEVICE_AUTO_ID__NUM_OF : auto_id];
+}
+#endif
+
+const char *bcm_str_host_connection_fail_reason(bcmolt_host_connection_fail_reason reason)
+{
+ static const char *strings[] =
+ {
+ [BCMOLT_HOST_CONNECTION_FAIL_REASON_TIMEOUT] = "TIMEOUT",
+ [BCMOLT_HOST_CONNECTION_FAIL_REASON_KEEPALIVE] = "KEEPALIVE",
+ [BCMOLT_HOST_CONNECTION_FAIL_REASON_USER_CALLBACK_ERROR] = "USER_CALLBACK_ERROR",
+ [BCMOLT_HOST_CONNECTION_FAIL_REASON_SOFTWARE_VERSION_MISMATCH] = "SOFTWARE_VERSION_MISMATCH",
+ [BCMOLT_HOST_CONNECTION_FAIL_REASON_SYSTEM_MODE_MISMATCH] = "SYSTEM_MODE_MISMATCH",
+ [BCMOLT_HOST_CONNECTION_FAIL_REASON_NNI_SPEED_MISMATCH] = "NNI_SPEED_MISMATCH",
+ [BCMOLT_HOST_CONNECTION_FAIL_REASON_RECONNECT_TIMEOUT] = "RECONNECT_TIMEOUT",
+ [BCMOLT_HOST_CONNECTION_FAIL_REASON_INTERNAL_ERROR] = "INTERNAL_ERROR",
+ [BCMOLT_HOST_CONNECTION_FAIL_REASON_SYSTEM_MODE_NOT_SUPPORTED] = "SYSTEM_MODE_NOT_SUPPORTED",
+ [BCMOLT_HOST_CONNECTION_FAIL_REASON_PARAMETER] = "PARAMETER",
+ [BCMOLT_HOST_CONNECTION_FAIL_REASON__NUM_OF] = "UNKNOWN"
+ };
+ return strings[
+ reason > BCMOLT_HOST_CONNECTION_FAIL_REASON__NUM_OF ? BCMOLT_HOST_CONNECTION_FAIL_REASON__NUM_OF : reason];
+}
+
+const char *bcm_str_host_connecting_state(dev_ctrl_connecting_state state)
+{
+ static const char *strings[] =
+ {
+ [DEV_CTRL_CONNECTING_STATE_ESTABLISHING] = "ESTABLISHING",
+ [DEV_CTRL_CONNECTING_STATE_CONFIGURING] = "CONFIGURING",
+ [DEV_CTRL_CONNECTING_STATE_STANDALONE] = "STANDALONE"
+ };
+ return (state > DEV_CTRL_CONNECTING_STATE_STANDALONE) ? "UNKNOWN" : strings[state];
+}
+
+static inline bcmos_bool dev_ctrl_is_connected(bcmolt_device_state state)
+{
+ return (state == BCMOLT_DEVICE_STATE_READY || state == BCMOLT_DEVICE_STATE_WAITING_FOR_DEVICE);
+}
+
+void dev_ctrl_read_db(bcmolt_devid device, dev_ctrl_database *db)
+{
+ *db = dev_ctrl_db[device];
+}
+
+#ifndef IN_BAND
+#ifdef ENABLE_LOG
+static bcmos_errno dev_ctrl_get_dev_log(bcmolt_devid device, bcmolt_logger_cfg *msg)
+{
+ char *log_buf;
+ char *log_buf_copy;
+ int log_len;
+ int msg_len;
+ int i;
+ bcmos_errno rc;
+ bcm_dev_log_file log_file;
+ uint32_t msg_buf_offset;
+
+ if (msg->key.file_id != BCMOLT_LOG_FILE_ID_SRAM)
+ {
+ return bcmolt_msg_err(
+ &msg->hdr.hdr,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_KEY_RANGE,
+ BCMOLT_LOGGER_KEY_ID_FILE_ID,
+ "While disconnected, only the SRAM logger may be read");
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET(msg, logger, wrap_around))
+ {
+ return bcmolt_msg_err(
+ &msg->hdr.hdr,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_RANGE,
+ BCMOLT_LOGGER_CFG_ID_WRAP_AROUND,
+ "wrap_around cannot be retrieved while disconnected");
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET(msg, logger, enable_log))
+ {
+ return bcmolt_msg_err(
+ &msg->hdr.hdr,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_RANGE,
+ BCMOLT_LOGGER_CFG_ID_ENABLE_LOG,
+ "enable_log cannot be retrieved while disconnected");
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET(msg, logger, log_names))
+ {
+ return bcmolt_msg_err(
+ &msg->hdr.hdr,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_RANGE,
+ BCMOLT_LOGGER_CFG_ID_LOG_NAMES,
+ "log_names cannot be retrieved while disconnected");
+ }
+
+ if (!BCMOLT_CFG_PROP_IS_SET(msg, logger, buffer))
+ {
+ return BCM_ERR_OK; /* nothing to do */
+ }
+
+ if (dev_ctrl_db[device].fld_info.soc_sram_base == 0)
+ {
+ return bcmolt_msg_err(
+ &msg->hdr.hdr,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_LOGGER_CFG_ID_BUFFER,
+ "log buffer can only be retreived after initial device connection");
+ }
+
+ rc = bcm_fld_get_logs(device, &log_buf, &log_len);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcm_fld_get_logs\n");
+
+ if (!log_len)
+ return BCM_ERR_OK;
+
+ /* Make a copy to avoid working over PCIe. Otherwise, the behavior can be unpredictable
+ * based on PCIe transaction size and controller configuration */
+ log_buf_copy = bcmos_alloc(log_len);
+ if (!log_buf_copy)
+ return BCM_ERR_NOMEM;
+
+ /* Copy byte by byte. Slow but works for any PCIe configuration */
+ for (i = 0; i < log_len; i++)
+ log_buf_copy[i] = log_buf[i];
+
+ msg->hdr.hdr.presence_mask |= (1 << BCMOLT_LOGGER_CFG_ID_BUFFER);
+
+ /* Attach log file to the buffer and read from the file */
+ rc = bcm_dev_log_file_attach(log_buf_copy, log_len, &log_file);
+
+ if (rc != BCM_ERR_OK || bcm_dev_log_get_num_of_messages(&log_file) == 0)
+ {
+ bcmos_free(log_buf_copy);
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "SRAM log buffer is empty\n");
+ return BCM_ERR_OK;
+ }
+
+ /* copy all messages from SRAM to the API message buffer (stopping when buffer is full) */
+ msg_buf_offset = 0;
+ do
+ {
+ msg_len = bcm_dev_log_file_read(&log_file, &dev_ctrl_db[device].sram_log_offset,
+ &msg->data.buffer.buff[msg_buf_offset], sizeof(msg->data.buffer.buff)- msg_buf_offset - 1);
+ if (msg_len <= 0)
+ break;
+ ++dev_ctrl_db[device].msgs_read;
+ /* The last character is 0-terminator. Take it out */
+ msg_buf_offset += msg_len - 1;
+ } while (msg_buf_offset < sizeof(msg->data.buffer.buff) - 1);
+
+ /* terminate the string with a null character */
+ msg->data.buffer.buff[msg_buf_offset] = '\0';
+ if (msg_len == BCM_ERR_OVERFLOW)
+ {
+ /* More records to read */
+ msg->data.buffer.msg_to_read = bcm_dev_log_get_num_of_messages(&log_file) - dev_ctrl_db[device].msgs_read;
+ }
+ else
+ {
+ /* all done */
+ msg->data.buffer.msg_to_read = 0;
+ dev_ctrl_db[device].sram_log_offset = 0;
+ dev_ctrl_db[device].msgs_read = 0;
+ }
+
+ /* Detach file from buffer */
+ bcm_dev_log_file_detach(&log_file);
+
+ bcmos_free(log_buf_copy);
+
+ return BCM_ERR_OK;
+}
+#endif
+
+static bcmos_errno dev_ctrl_get_sw_error_table(bcmolt_devid device)
+{
+ bcmos_sw_error_table *sw_error_table;
+ uint8_t *sram;
+ uint8_t *local;
+ uint32_t size;
+ uint32_t i;
+
+ sram = bcm_fld_get_sw_error_table(device, &size);
+ local = bcmos_alloc(size);
+ for (i = 0; i < size; i++)
+ {
+ local[i] = sram[i];
+ }
+
+ sw_error_table = (bcmos_sw_error_table*)local;
+ dev_ctrl_db[device].sw_error_count = BCMOS_ENDIAN_LITTLE_TO_CPU_U32(sw_error_table->count);
+ if (dev_ctrl_db[device].sw_error_count > NUM_ELEM(dev_ctrl_db[device].sw_errors))
+ {
+ bcmos_free(local);
+ return BCM_ERR_OVERFLOW;
+ }
+
+ for (i = 0; i < dev_ctrl_db[device].sw_error_count; i++)
+ {
+ dev_ctrl_db[device].sw_errors[i].first_error_time_us =
+ BCMOS_ENDIAN_LITTLE_TO_CPU_U64(sw_error_table->error[i].first_error_time);
+ dev_ctrl_db[device].sw_errors[i].last_error_time_us =
+ BCMOS_ENDIAN_LITTLE_TO_CPU_U64(sw_error_table->error[i].last_error_time);
+ dev_ctrl_db[device].sw_errors[i].line_number =
+ BCMOS_ENDIAN_LITTLE_TO_CPU_U32(sw_error_table->error[i].line_number);
+ dev_ctrl_db[device].sw_errors[i].error_counter =
+ BCMOS_ENDIAN_LITTLE_TO_CPU_U32(sw_error_table->error[i].error_counter);
+ dev_ctrl_db[device].sw_errors[i].instance =
+ BCMOS_ENDIAN_LITTLE_TO_CPU_U32(sw_error_table->error[i].instance);
+ strncpy(
+ dev_ctrl_db[device].sw_errors[i].filename,
+ sw_error_table->error[i].file_name,
+ BCMOLT_SW_ERROR_MAX_FILE_NAME_LEN);
+ dev_ctrl_db[device].sw_errors[i].filename[BCMOLT_SW_ERROR_MAX_FILE_NAME_LEN-1] = 0;
+ strncpy(
+ dev_ctrl_db[device].sw_errors[i].task_name,
+ sw_error_table->error[i].task_name,
+ BCMOLT_SW_ERROR_MAX_TASK_NAME_LEN);
+ dev_ctrl_db[device].sw_errors[i].task_name[BCMOLT_SW_ERROR_MAX_TASK_NAME_LEN-1] = 0;
+ }
+
+ bcmos_free(local);
+
+ return BCM_ERR_OK;
+}
+
+static bcmos_bool sw_error_key_valid(const bcmolt_software_error_key *key)
+{
+ bcmolt_devid device = (bcmolt_devid)bcmos_task_current()->parm.data;
+ return key->idx < dev_ctrl_db[device].sw_error_count;
+}
+
+static bcmos_errno mh_software_error_key_validate(bcmolt_msg *msg, const bcmolt_software_error_key *key)
+{
+ return sw_error_key_valid(key) ? BCM_ERR_OK : BCM_ERR_NOENT;
+}
+
+static bcmos_errno mh_software_error_cfg_get(
+ bcmolt_msg *msg,
+ const bcmolt_software_error_key *key,
+ bcmolt_software_error_cfg_data *data)
+{
+ bcmolt_devid device = (bcmolt_devid)bcmos_task_current()->parm.data;
+ bcmolt_presence_mask props = msg->presence_mask;
+ bcmos_errno rc = BCM_ERR_OK;
+
+ if (props == BCMOLT_PRESENCE_MASK_ALL)
+ {
+ /* Convert from sentinel "all" presence bits to set of all valid bits*/
+ props = (1U << BCMOLT_SOFTWARE_ERROR_CFG_ID__NUM_OF) - 1;
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET((bcmolt_software_error_cfg*)msg, software_error, entry))
+ {
+ if (dev_ctrl_db[device].fld_info.soc_sram_base == 0)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_SOFTWARE_ERROR_CFG_ID_ENTRY,
+ "Software errors can only be retreived after initial device connection");
+ }
+
+ data->entry = dev_ctrl_db[device].sw_errors[key->idx];
+ props &= ~BCMOLT_PROP_MASK_GET(software_error, _cfg, entry);
+ }
+
+ if (props != 0)
+ {
+ rc = bcmolt_msg_err(msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_NOT_SUPPORTED,
+ BCMOLT_ERR_FIELD_NONE,
+ "Unsupported properties: 0x%llx", (unsigned long long)props);
+ }
+
+ return rc;
+}
+
+static bcmos_errno mh_software_error_key_iterate(bcmolt_software_error_key *key)
+{
+ key->idx++;
+ return sw_error_key_valid(key) ? BCM_ERR_OK : BCM_ERR_NO_MORE;
+}
+
+static bcmos_errno mh_software_error_key_resolve_wildcards(bcmolt_software_error_key *key)
+{
+ return BCM_ERR_OK;
+}
+
+MH_DECLARE_CFG_GET_MULTI(software_error)
+
+static bcmos_errno dev_ctrl_sw_error_get(bcmolt_devid device, bcmolt_msg *msg)
+{
+ bcmolt_software_error_cfg *cfg = (bcmolt_software_error_cfg*)msg;
+ bcmos_errno err = dev_ctrl_get_sw_error_table(device);
+ if (err != BCM_ERR_OK)
+ {
+ return BCM_ERR_INTERNAL;
+ }
+
+ if (msg->type == BCMOLT_MSG_TYPE_GET)
+ {
+ bcmolt_software_error_key_id key_prop_id;
+ if (!bcmolt_software_error_key_bounds_check(&cfg->key, BCMOLT_PRESENCE_MASK_ALL, &key_prop_id))
+ {
+ msg->err_field_idx = (uint16_t) key_prop_id;
+ return BCM_ERR_KEY_RANGE;
+ }
+
+ err = mh_software_error_key_validate(msg, &cfg->key);
+ if (err != BCM_ERR_OK)
+ {
+ return err;
+ }
+
+ return mh_software_error_cfg_get(msg, &cfg->key, &cfg->data);
+ }
+ else if (msg->type == BCMOLT_MSG_TYPE_GET_MULTI)
+ {
+ return mh_software_error_cfg_get_multi(cfg, msg->msg_set->filter_flags, msg->msg_set);
+ }
+ else
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Unexpected type 0x%x\n", msg->type);
+ }
+ return BCM_ERR_INTERNAL;
+}
+#endif
+
+static void dev_ctrl_send_indication(bcmolt_devid device, bcmolt_msg *msg)
+{
+ msg->subch = BCMTRMUX_CHANNEL_AUTO_PROXY;
+ msg->type = BCMOLT_MSG_TYPE_SET;
+ bcmtrmux_control_to_host(device, msg);
+}
+
+static void dev_ctrl_send_ind_connection_complete(bcmolt_devid device, bcmos_bool standalone)
+{
+ bcmolt_device_connection_complete ind = {};
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Connection complete: standalone=%s\n", standalone ? "yes" : "no");
+ BCMOLT_AUTO_INIT(&ind, device, connection_complete);
+ ind.data.standalone = standalone;
+ dev_ctrl_send_indication(device, &ind.hdr.hdr);
+}
+
+static void dev_ctrl_send_ind_disconnection_complete(bcmolt_devid device)
+{
+ bcmolt_device_disconnection_complete ind = {};
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Disconnection complete\n");
+ BCMOLT_AUTO_INIT(&ind, device, disconnection_complete);
+ dev_ctrl_send_indication(device, &ind.hdr.hdr);
+}
+
+static void dev_ctrl_send_ind_connection_failure(bcmolt_devid device, bcmolt_host_connection_fail_reason reason)
+{
+ bcmolt_device_connection_failure ind = {};
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Connection failure: %s\n", bcm_str_host_connection_fail_reason(reason));
+ BCMOLT_AUTO_INIT(&ind, device, connection_failure);
+ ind.data.reason = reason;
+ dev_ctrl_send_indication(device, &ind.hdr.hdr);
+ dev_ctrl_db[device].conn_fail_reason = reason; /* log the failure reason to the db. */
+}
+
+static void dev_ctrl_send_ind_connection_failure_from_msg(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ BUG_ON(msg->subgroup != BCMOLT_DEVICE_AUTO_ID_CONNECTION_FAILURE);
+ dev_ctrl_send_ind_connection_failure(device, ((const bcmolt_device_connection_failure *)msg)->data.reason);
+}
+
+#ifndef IN_BAND
+static void dev_ctrl_send_ind_exception_log(bcmolt_devid device, uint32_t cpuid, const char *exception_buf)
+{
+ /* Because indication size is limited (but IND_MSG_MAX_SIZE > sizeof(bcmolt_str_2000.str), we may need to split into multiple indications.
+ * We use a static variable because our stack size is limited. */
+ static bcmolt_str_2000 api_exception_str;
+ const char *pos = exception_buf;
+ uint32_t remaining_len = strlen(pos);
+
+ while (remaining_len)
+ {
+ bcmolt_device_sw_exception ind = {};
+ uint32_t bytes_copied;
+
+ strncpy(api_exception_str.str, pos, sizeof(api_exception_str.str) - 1);
+ api_exception_str.str[sizeof(api_exception_str.str) - 1] = '\0';
+
+ BCMOLT_AUTO_INIT(&ind, device, sw_exception);
+ ind.data.cpu_id = cpuid;
+ ind.data.text = api_exception_str;
+ dev_ctrl_send_indication(device, &ind.hdr.hdr);
+
+ if (sizeof(api_exception_str.str) - 1 < remaining_len)
+ {
+ bytes_copied = sizeof(api_exception_str.str) - 1;
+ }
+ else
+ {
+ bytes_copied = remaining_len;
+ }
+ remaining_len -= bytes_copied;
+ pos += bytes_copied;
+ }
+}
+#endif
+
+static void dev_ctrl_send_config_set_msg(
+ bcmolt_devid device,
+ bcmolt_presence_mask mask,
+ uint16_t corr_tag,
+ const bcmolt_device_cfg_data *data)
+{
+ bcmolt_device_key key = {};
+ bcmolt_device_cfg cfg;
+ bcmos_errno rc;
+
+ BCMOLT_CFG_INIT(&cfg, device, key);
+ cfg.data = *data;
+ cfg.hdr.hdr.presence_mask = mask;
+
+ cfg.hdr.hdr.corr_tag = corr_tag;
+ cfg.hdr.hdr.type = BCMOLT_MSG_TYPE_SET;
+
+ rc = bcmtrmux_control_to_line(device, &cfg.hdr.hdr);
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id,
+ "bcmtrmux_control_to_line of device config msg returned error %s (%d)\n",
+ bcmos_strerror(rc),
+ rc);
+ }
+}
+
+static void dev_ctrl_send_config_get_msg(bcmolt_devid device, bcmolt_presence_mask mask, uint16_t corr_tag)
+{
+ bcmolt_device_key key = {};
+ bcmolt_device_cfg cfg;
+ bcmos_errno rc;
+
+ BCMOLT_CFG_INIT(&cfg, device, key);
+ cfg.hdr.hdr.presence_mask = mask;
+
+ cfg.hdr.hdr.corr_tag = corr_tag;
+ cfg.hdr.hdr.type = BCMOLT_MSG_TYPE_GET;
+
+ rc = bcmtrmux_control_to_line(device, &cfg.hdr.hdr);
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id,
+ "bcmtrmux_control_to_line of device config msg returned error %s (%d)\n",
+ bcmos_strerror(rc),
+ rc);
+ }
+}
+
+static void dev_ctrl_send_device_disconnect_msg(bcmolt_devid device, uint16_t corr_tag)
+{
+ bcmolt_device_key key = {};
+ bcmolt_device_disconnect oper;
+ bcmos_errno rc;
+
+ BCMOLT_OPER_INIT(&oper, device, disconnect, key);
+
+ oper.hdr.hdr.corr_tag = corr_tag;
+ oper.hdr.hdr.type = BCMOLT_MSG_TYPE_SET;
+ rc = bcmtrmux_control_to_line(device, &oper.hdr.hdr);
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id,
+ "bcmtrmux_control_to_line of device disconnect operation returned error %s (%d)\n",
+ bcmos_strerror(rc),
+ rc);
+ }
+}
+
+/* Set all device object properties to default values. */
+static void dev_ctrl_clear_device_cfg(bcmolt_devid device)
+{
+ dev_ctrl_db[device].device_params_present = 0;
+
+ /* Pay attention: We use the interval and tolerance from dev_ctrl_db[device].ka_info and not from
+ * dev_ctrl_db[device].device_params. These parameters exist in dev_ctrl_db[device].device_params only because it is
+ * the data model representation. */
+ bcmolt_device_cfg_data_set_default(&dev_ctrl_db[device].device_params, BCMOLT_PRESENCE_MASK_ALL);
+ dev_ctrl_db[device].ka_info.ka_interval =
+ dev_ctrl_db[device].device_params.keepalive_interval * BCMOS_MICROSECONDS_IN_SECONDS;
+ dev_ctrl_db[device].ka_info.ka_tolerance = dev_ctrl_db[device].device_params.keepalive_tolerance;
+}
+
+static void dev_ctrl_init_connection_state(bcmolt_devid device)
+{
+ dev_ctrl_db[device].connection_info.config_send_counter = CONFIG_SEND_MAX_NUMBER;
+ dev_ctrl_db[device].connection_info.config_interval = DEVICE_CONTROL_CONFIG_TIME_US;
+}
+
+static bcmos_errno dev_ctrl_validate_cfg_set(bcmolt_devid device, bcmolt_msg *msg)
+{
+#ifndef IN_BAND
+ bcmos_errno rc;
+#endif
+ bcmolt_device_cfg *cfg = (bcmolt_device_cfg *)msg;
+ bcmolt_device_state state = dev_ctrl_db[device].device_params.state;
+ bcmolt_device_cfg_id failed_prop = BCMOLT_ERR_FIELD_NONE;
+
+ if (!bcmolt_device_cfg_data_bounds_check(&cfg->data, msg->presence_mask, &failed_prop))
+ {
+ msg->err_field_idx = (uint16_t)failed_prop;
+ return BCM_ERR_RANGE;
+ }
+
+#ifndef IN_BAND
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, system_mode))
+ {
+ if (state != BCMOLT_DEVICE_STATE_DISCONNECTED)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_SYSTEM_MODE,
+ "System mode can only be changed while disconnected");
+ }
+
+ rc = dev_ctrl_params.system_mode_validate_cb(device, cfg->data.system_mode);
+ if (rc != BCM_ERR_OK)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ rc,
+ BCMOLT_DEVICE_CFG_ID_SYSTEM_MODE,
+ "Given system mode is not supported for this board");
+ }
+ }
+#endif
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, nni_speed) && state != BCMOLT_DEVICE_STATE_DISCONNECTED)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_NNI_SPEED,
+ "NNI speed can only be changed while disconnected");
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, debug) && state != BCMOLT_DEVICE_STATE_DISCONNECTED)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_DEBUG,
+ "Debug parameters can only be changed while disconnected");
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, firmware_sw_version) ||
+ BCMOLT_CFG_PROP_IS_SET(cfg, device, host_sw_version) ||
+ BCMOLT_CFG_PROP_IS_SET(cfg, device, chip_revision)||
+ BCMOLT_CFG_PROP_IS_SET(cfg, device, state)||
+ BCMOLT_CFG_PROP_IS_SET(cfg, device, chip_temperature)||
+ BCMOLT_CFG_PROP_IS_SET(cfg, device, chip_voltage))
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_ERR_FIELD_NONE,
+ "Cannot set read only fields");
+ }
+
+ return BCM_ERR_OK;
+}
+
+static bcmos_errno dev_ctrl_validate_cfg_get(bcmolt_devid device, bcmolt_msg *msg)
+{
+ bcmolt_device_state state = dev_ctrl_db[device].device_params.state;
+ bcmolt_device_cfg *cfg = (bcmolt_device_cfg *)msg;
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, firmware_sw_version) ||
+ BCMOLT_CFG_PROP_IS_SET(cfg, device, chip_revision) ||
+ BCMOLT_CFG_PROP_IS_SET(cfg, device, chip_temperature)||
+ BCMOLT_CFG_PROP_IS_SET(cfg, device, chip_voltage) ||
+ BCMOLT_CFG_PROP_IS_SET(cfg, device, epon_tod_string))
+ {
+ if (!dev_ctrl_is_connected(state))
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_ERR_FIELD_NONE,
+ "Cannot retrieve parameter while disconnected.");
+ }
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, protection_switching_ext_irq))
+ {
+ if (!dev_ctrl_is_connected(state) &&
+ (dev_ctrl_db[device].device_params_present &
+ BCMOLT_PROP_MASK_GET(device, _cfg, protection_switching_ext_irq)) == 0)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_PROTECTION_SWITCHING_EXT_IRQ,
+ "Cannot retrieve protection_switching_ext_irq while disconnected and not having a cache.");
+ }
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, epon_clock_transport_sample_delay))
+ {
+ if (!dev_ctrl_is_connected(state) &&
+ (dev_ctrl_db[device].device_params_present &
+ BCMOLT_PROP_MASK_GET(device, _cfg, epon_clock_transport_sample_delay)) == 0)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_EPON_CLOCK_TRANSPORT_SAMPLE_DELAY,
+ "Cannot retrieve epon_clock_transport_sample_delay while disconnected and not having a cache.");
+ }
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, indication_shaping))
+ {
+ if (!dev_ctrl_is_connected(state) &&
+ (dev_ctrl_db[device].device_params_present & BCMOLT_PROP_MASK_GET(device, _cfg, indication_shaping)) == 0)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_INDICATION_SHAPING,
+ "Cannot retrieve indication_shaping while disconnected and not having a cache.");
+ }
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, gpon_xgpon_tod_enable))
+ {
+ if (!dev_ctrl_is_connected(state) &&
+ (dev_ctrl_db[device].device_params_present &
+ BCMOLT_PROP_MASK_GET(device, _cfg, gpon_xgpon_tod_enable)) == 0)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_GPON_XGPON_TOD_ENABLE,
+ "Cannot retrieve gpon_xgpon_tod_enable while disconnected and not having a cache.");
+ }
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, gpon_xgpon_tod_gpio_pin))
+ {
+ if (!dev_ctrl_is_connected(state) &&
+ (dev_ctrl_db[device].device_params_present &
+ BCMOLT_PROP_MASK_GET(device, _cfg, gpon_xgpon_tod_gpio_pin)) == 0)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_GPON_XGPON_TOD_GPIO_PIN,
+ "Cannot retrieve gpon_xgpon_tod_gpio_pin while disconnected and not having a cache.");
+ }
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, gpon_xgpon_tod_connected_internally))
+ {
+ if (!dev_ctrl_is_connected(state) &&
+ (dev_ctrl_db[device].device_params_present &
+ BCMOLT_PROP_MASK_GET(device, _cfg, gpon_xgpon_tod_connected_internally)) == 0)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_GPON_XGPON_TOD_CONNECTED_INTERNALLY,
+ "Cannot retrieve gpon_xgpon_tod_connected_internally while disconnected and not having a cache.");
+ }
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, epon_8021_as_tod_format))
+ {
+ if (!dev_ctrl_is_connected(state) &&
+ (dev_ctrl_db[device].device_params_present &
+ BCMOLT_PROP_MASK_GET(device, _cfg, epon_8021_as_tod_format)) == 0)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_EPON_8021_AS_TOD_FORMAT,
+ "Cannot retrieve epon_8021_as_tod_format while disconnected and not having a cache.");
+ }
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, epon_shaper_mode))
+ {
+ if (!dev_ctrl_is_connected(state) &&
+ (dev_ctrl_db[device].device_params_present &
+ BCMOLT_PROP_MASK_GET(device, _cfg, epon_shaper_mode)) == 0)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_EPON_SHAPER_MODE,
+ "Cannot retrieve epon_shaper_mode while disconnected and not having a cache.");
+ }
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, embedded_image_list))
+ {
+ if (!dev_ctrl_is_connected(state) &&
+ (dev_ctrl_db[device].device_params_present &
+ BCMOLT_PROP_MASK_GET(device, _cfg, embedded_image_list)) == 0)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_EMBEDDED_IMAGE_LIST,
+ "Cannot retrieve embedded_image_list while disconnected and not having a cache.");
+ }
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, gpon_xgpon_tod_string_length))
+ {
+ if (!dev_ctrl_is_connected(state) &&
+ (dev_ctrl_db[device].device_params_present &
+ BCMOLT_PROP_MASK_GET(device, _cfg, gpon_xgpon_tod_string_length)) == 0)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_GPON_XGPON_TOD_STRING_LENGTH,
+ "Cannot retrieve gpon_xgpon_tod_string_length while disconnected and not having a cache.");
+ }
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, tod_uart_baudrate))
+ {
+ if (!dev_ctrl_is_connected(state) &&
+ (dev_ctrl_db[device].device_params_present &
+ BCMOLT_PROP_MASK_GET(device, _cfg, tod_uart_baudrate)) == 0)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_DEVICE_CFG_ID_TOD_UART_BAUDRATE,
+ "Cannot retrieve tod_uart_baudrate while disconnected and not having a cache.");
+ }
+ }
+ return BCM_ERR_OK;
+}
+
+static bcmos_errno dev_ctrl_validate_cfg_clear(bcmolt_devid device, bcmolt_msg *msg)
+{
+ if (dev_ctrl_db[device].device_params.state != BCMOLT_DEVICE_STATE_DISCONNECTED)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_ERR_FIELD_NONE,
+ "Device cfg_clear is only allowed while disconnected");
+ }
+ return BCM_ERR_OK;
+}
+
+static bcmos_errno bcm_dev_ctrl_validate_oper_connect(bcmolt_devid device, bcmolt_msg *msg)
+{
+ bcmolt_device_state state = dev_ctrl_db[device].device_params.state;
+
+ if (dev_ctrl_is_connected(state))
+ {
+ return bcmolt_msg_err(msg, DEV_LOG_INVALID_ID, BCM_ERR_ALREADY, BCMOLT_ERR_FIELD_NONE, "already connected");
+ }
+
+ /* If not all mandatory properties are valid return "mandatory parameter is missing" */
+ if (dev_ctrl_db[device].device_params.system_mode >= BCMOLT_SYSTEM_MODE__NUM_OF)
+ {
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Cannot connect: system mode not included\n");
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_MANDATORY_PARM_IS_MISSING,
+ BCMOLT_DEVICE_CFG_ID_SYSTEM_MODE,
+ "System mode must be set before connecting");
+ }
+#ifdef IN_BAND
+ /* For In Band Management IP Address and UDP port must be set prior to connecting*/
+ /* If not all mandatory properties are valid return "mandatory parameter is missing" */
+ if (dev_ctrl_db[device].device_params.device_ip_address.u32 == 0)
+ {
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Cannot connect: must set IP Address port\n");
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_MANDATORY_PARM_IS_MISSING,
+ BCMOLT_DEVICE_CFG_ID_DEVICE_IP_ADDRESS,
+ "Device IP Address must be set before connecting");
+ }
+ if (dev_ctrl_db[device].device_params.device_udp_port == 0)
+ {
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Cannot connect: must set IP Address UDP port\n");
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_MANDATORY_PARM_IS_MISSING,
+ BCMOLT_DEVICE_CFG_ID_DEVICE_UDP_PORT,
+ "UDP port must be set before connecting");
+ }
+#endif
+
+ return BCM_ERR_OK;
+}
+
+static bcmos_errno bcm_dev_ctrl_validate_oper_disconnect(bcmolt_devid device, bcmolt_msg *msg)
+{
+ bcmolt_device_state state = dev_ctrl_db[device].device_params.state;
+ if (state == BCMOLT_DEVICE_STATE_DISCONNECTED)
+ {
+ return bcmolt_msg_err(msg, DEV_LOG_INVALID_ID, BCM_ERR_ALREADY, BCMOLT_ERR_FIELD_NONE, "already disconnected");
+ }
+ return BCM_ERR_OK;
+}
+
+static bcmos_errno bcm_dev_ctrl_validate_oper_run_ddr_test(bcmolt_devid device, bcmolt_msg *msg)
+{
+ bcmolt_device_run_ddr_test *ddr_test = (bcmolt_device_run_ddr_test*)msg;
+ bcmos_bool is_standalone;
+ bcmos_errno rc;
+
+ if (BCMOLT_DEVICE_STATE_DISCONNECTED != dev_ctrl_db[device].device_params.state)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_ERR_FIELD_NONE,
+ "DDR test can only be run when disconnected");
+ }
+
+ if (dev_ctrl_db[device].is_host_reset_pending)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_ERR_FIELD_NONE,
+ "Cannot run DDR test while host reset is pending");
+ }
+
+ /* Check if the chip is running in standalone mode */
+ rc = dev_ctrl_params.device_is_running_cb(device, &is_standalone);
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "device_is_running_cb returned error: %s (%d)\n", bcmos_strerror(rc), rc);
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ rc,
+ BCMOLT_ERR_FIELD_NONE,
+ "Failed to retrieve device status");
+ }
+ if (is_standalone)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_ERR_FIELD_NONE,
+ "Cannot run DDR test while device is running");
+ }
+
+ if (!ddr_test->data.cpu && !ddr_test->data.ras_0 && !ddr_test->data.ras_1)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_ERR_FIELD_NONE,
+ "Must request at least one DDR Test");
+ }
+
+ return BCM_ERR_OK;
+}
+
+static bcmos_errno dev_ctrl_validate_operation(bcmolt_devid device, bcmolt_msg *msg)
+{
+ bcmolt_device_state state = dev_ctrl_db[device].device_params.state;
+ if (state == BCMOLT_DEVICE_STATE_CONNECTING)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_ERR_FIELD_NONE,
+ "Device operations are not allowed while connecting");
+ }
+ if (state == BCMOLT_DEVICE_STATE_TESTING_DDR)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_ERR_FIELD_NONE,
+ "Device operations are not allowed while DDR test is in progress");
+ }
+
+ switch (msg->subgroup)
+ {
+ case BCMOLT_DEVICE_OPER_ID_CONNECT:
+ return bcm_dev_ctrl_validate_oper_connect(device, msg);
+ case BCMOLT_DEVICE_OPER_ID_DISCONNECT:
+ return bcm_dev_ctrl_validate_oper_disconnect(device, msg);
+ case BCMOLT_DEVICE_OPER_ID_RUN_DDR_TEST:
+ return bcm_dev_ctrl_validate_oper_run_ddr_test(device, msg);
+ default:
+ return BCM_ERR_OK;
+ }
+}
+
+static bcmos_errno dev_ctrl_validate_msg(bcmolt_devid device, bcmolt_msg *msg)
+{
+ if (dev_ctrl_db[device].device_params.state == BCMOLT_DEVICE_STATE_WAITING_FOR_DEVICE)
+ {
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_STATE,
+ BCMOLT_ERR_FIELD_NONE,
+ "The device object is busy processing another API request");
+ }
+
+ if (msg->group == BCMOLT_MGT_GROUP_CFG)
+ {
+ switch (msg->type)
+ {
+ case BCMOLT_MSG_TYPE_CLEAR:
+ return dev_ctrl_validate_cfg_clear(device, msg);
+ case BCMOLT_MSG_TYPE_SET:
+ return dev_ctrl_validate_cfg_set(device, msg);
+ case BCMOLT_MSG_TYPE_GET:
+ return dev_ctrl_validate_cfg_get(device, msg);
+ default:
+ break;
+ }
+ }
+
+ if (msg->group == BCMOLT_MGT_GROUP_OPER && msg->type == BCMOLT_MSG_TYPE_SET)
+ {
+ return dev_ctrl_validate_operation(device, msg);
+ }
+
+ return bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_INTERNAL,
+ BCMOLT_ERR_FIELD_NONE,
+ "Invalid message for device control");
+}
+
+static bcmolt_presence_mask dev_ctrl_fill_from_local(bcmolt_devid device)
+{
+ bcmolt_device_cfg *cfg = (bcmolt_device_cfg *)dev_ctrl_db[device].last_message;
+ bcmolt_presence_mask mask = dev_ctrl_db[device].last_message->presence_mask;
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, system_mode))
+ {
+ cfg->data.system_mode = dev_ctrl_db[device].device_params.system_mode;
+ mask &= ~BCMOLT_PROP_MASK_GET(device, _cfg, system_mode);
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, keepalive_interval))
+ {
+ cfg->data.keepalive_interval = dev_ctrl_db[device].ka_info.ka_interval / BCMOS_MICROSECONDS_IN_SECONDS;
+ mask &= ~BCMOLT_PROP_MASK_GET(device, _cfg, keepalive_interval);
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, keepalive_tolerance))
+ {
+ cfg->data.keepalive_tolerance = dev_ctrl_db[device].ka_info.ka_tolerance;
+ mask &= ~BCMOLT_PROP_MASK_GET(device, _cfg, keepalive_tolerance);
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, host_sw_version))
+ {
+ cfg->data.host_sw_version.major = BCMOLT_HOST_MAJOR_VER;
+ cfg->data.host_sw_version.minor = BCMOLT_HOST_MINOR_VER;
+ cfg->data.host_sw_version.revision = BCMOLT_HOST_REVISION_VER;
+ cfg->data.host_sw_version.model = BCMOLT_MODEL_REVISION;
+ snprintf(
+ cfg->data.host_sw_version.build_time,
+ sizeof(cfg->data.host_sw_version.build_time),
+ "%s %s",
+ __DATE__,
+ __TIME__);
+ mask &= ~BCMOLT_PROP_MASK_GET(device, _cfg, host_sw_version);
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, state))
+ {
+ cfg->data.state = dev_ctrl_db[device].device_params.state;
+ mask &= ~BCMOLT_PROP_MASK_GET(device, _cfg, state);
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, debug))
+ {
+ cfg->data.debug = dev_ctrl_db[device].device_params.debug;
+ mask &= ~BCMOLT_PROP_MASK_GET(device, _cfg, debug);
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, nni_speed))
+ {
+ cfg->data.nni_speed = dev_ctrl_db[device].device_params.nni_speed;
+ mask &= ~BCMOLT_PROP_MASK_GET(device, _cfg, nni_speed);
+ }
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, xgpon_num_of_onus))
+ {
+ cfg->data.xgpon_num_of_onus = dev_ctrl_db[device].device_params.xgpon_num_of_onus;
+ mask &= ~BCMOLT_PROP_MASK_GET(device, _cfg, xgpon_num_of_onus);
+ }
+
+ return mask;
+}
+
+static void dev_ctrl_update_local_configuration(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ const bcmolt_device_cfg *cfg = (const bcmolt_device_cfg *)msg;
+
+ dev_ctrl_db[device].device_params_present |= msg->presence_mask;
+
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, system_mode))
+ {
+ dev_ctrl_db[device].device_params.system_mode = cfg->data.system_mode;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, debug))
+ {
+ dev_ctrl_db[device].device_params.debug = cfg->data.debug;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, nni_speed))
+ {
+ dev_ctrl_db[device].device_params.nni_speed = cfg->data.nni_speed;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, keepalive_interval))
+ {
+ dev_ctrl_db[device].ka_info.ka_interval = (cfg->data.keepalive_interval * BCMOS_MICROSECONDS_IN_SECONDS);
+ dev_ctrl_db[device].device_params.keepalive_interval = cfg->data.keepalive_interval;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, keepalive_tolerance))
+ {
+ dev_ctrl_db[device].ka_info.ka_tolerance = cfg->data.keepalive_tolerance;
+ dev_ctrl_db[device].device_params.keepalive_tolerance = cfg->data.keepalive_tolerance;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, protection_switching_ext_irq))
+ {
+ dev_ctrl_db[device].device_params.protection_switching_ext_irq = cfg->data.protection_switching_ext_irq;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, epon_clock_transport_sample_delay))
+ {
+ dev_ctrl_db[device].device_params.epon_clock_transport_sample_delay =
+ cfg->data.epon_clock_transport_sample_delay;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, indication_shaping))
+ {
+ dev_ctrl_db[device].device_params.indication_shaping = cfg->data.indication_shaping;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, gpon_xgpon_tod_enable))
+ {
+ dev_ctrl_db[device].device_params.gpon_xgpon_tod_enable = cfg->data.gpon_xgpon_tod_enable;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, gpon_xgpon_tod_gpio_pin))
+ {
+ dev_ctrl_db[device].device_params.gpon_xgpon_tod_gpio_pin = cfg->data.gpon_xgpon_tod_gpio_pin;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, gpon_xgpon_tod_connected_internally))
+ {
+ dev_ctrl_db[device].device_params.gpon_xgpon_tod_connected_internally = cfg->data.gpon_xgpon_tod_connected_internally;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, epon_shaper_mode))
+ {
+ dev_ctrl_db[device].device_params.epon_shaper_mode = cfg->data.epon_shaper_mode;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, embedded_image_list))
+ {
+ dev_ctrl_db[device].device_params.embedded_image_list = cfg->data.embedded_image_list;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, xgpon_num_of_onus))
+ {
+ dev_ctrl_db[device].device_params.xgpon_num_of_onus = cfg->data.xgpon_num_of_onus;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, device_ip_address))
+ {
+ dev_ctrl_db[device].device_params.device_ip_address = cfg->data.device_ip_address;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, device_udp_port))
+ {
+ dev_ctrl_db[device].device_params.device_udp_port = cfg->data.device_udp_port;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, gpon_xgpon_tod_string_length))
+ {
+ dev_ctrl_db[device].device_params.gpon_xgpon_tod_string_length = cfg->data.gpon_xgpon_tod_string_length;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(cfg, device, tod_uart_baudrate))
+ {
+ dev_ctrl_db[device].device_params.tod_uart_baudrate = cfg->data.tod_uart_baudrate;
+ }
+}
+
+static bcmos_errno dev_ctrl_validate_fw_version(bcmolt_devid device, const bcmolt_firmware_sw_version *version)
+{
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id,
+ "Firmware SW version %u.%u.%u (Object model revision %u, Build time: %s)\n",
+ version->major,
+ version->minor,
+ version->revision,
+ version->model,
+ version->build_time);
+
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id,
+ "Host SW version %u.%u.%u (Object model revision %u, Build time: %s %s)\n",
+ BCMOLT_HOST_MAJOR_VER,
+ BCMOLT_HOST_MINOR_VER,
+ BCMOLT_HOST_REVISION_VER,
+ BCMOLT_MODEL_REVISION,
+ __DATE__,
+ __TIME__);
+
+ /* Version mismatch - note that only the Host/Firmware revisions can be different between the host and the firmware */
+ if (version->major != BCMOLT_HOST_MAJOR_VER ||
+ version->minor != BCMOLT_HOST_MINOR_VER ||
+ version->model != BCMOLT_MODEL_REVISION)
+ {
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id,
+ "SW Versions Mismatch: Host SW version is %u.%u.%u with object model revision %d, while Firmware SW version is %u.%u.%u with object model revision %u\n",
+ BCMOLT_HOST_MAJOR_VER,
+ BCMOLT_HOST_MINOR_VER,
+ BCMOLT_HOST_REVISION_VER,
+ BCMOLT_MODEL_REVISION,
+ version->major,
+ version->minor,
+ version->revision,
+ version->model);
+ return BCM_ERR_STATE;
+ }
+ return BCM_ERR_OK;
+}
+
+#ifndef IN_BAND
+static bcmos_errno dev_ctrl_register_fld(bcmolt_devid device)
+{
+ bcmos_errno rc;
+ bcm_ll_dev_info ll_info;
+
+ if (dev_ctrl_db[device].fld_info.soc_sram_base > 0)
+ {
+ /* we have already queried the PCIe / registered with the FLD */
+ return BCM_ERR_OK;
+ }
+
+ rc = bcm_ll_pcie_query(device, &ll_info);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcm_ll_pcie_query\n");
+ dev_ctrl_db[device].fld_info.soc_ddr_length = ll_info.soc_ddr_length;
+ dev_ctrl_db[device].fld_info.soc_sram_base = ll_info.soc_sram_base;
+ dev_ctrl_db[device].fld_info.soc_ddr_base = ll_info.soc_ddr_base;
+ dev_ctrl_db[device].fld_info.soc_regs_base = ll_info.soc_regs_base;
+
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id,
+ "FLD_INFO: ddr_length=0x%x sram_base=%p soc_ddr_base=%p soc_regs_base=%p\n",
+ dev_ctrl_db[device].fld_info.soc_ddr_length,
+ (void *)dev_ctrl_db[device].fld_info.soc_sram_base,
+ (void *)dev_ctrl_db[device].fld_info.soc_ddr_base,
+ (void *)dev_ctrl_db[device].fld_info.soc_regs_base);
+
+ rc = bcm_fld_register(device, &dev_ctrl_db[device].fld_info);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcm_fld_register\n");
+
+ return BCM_ERR_OK;
+}
+
+static bcmos_errno dev_ctrl_handle_file(bcmolt_devid device, bcmolt_device_image_type image_type)
+{
+ int32_t read_len;
+ BCM_FLD_HOST_DEBUG_VALUES host_debug_value;
+ bcmos_errno rc;
+ uint32_t offset_r = 0, offset_w = 0;
+ volatile unsigned long write_complete[2];
+ const char *image_name;
+
+ BUG_ON((image_type != BCMOLT_DEVICE_IMAGE_TYPE_BOOTLOADER) && (image_type != BCMOLT_DEVICE_IMAGE_TYPE_APPLICATION));
+
+ image_name = image_type == BCMOLT_DEVICE_IMAGE_TYPE_APPLICATION ? "application" : "boot loader";
+
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Loading %s\n", image_name);
+
+ host_debug_value = image_type == BCMOLT_DEVICE_IMAGE_TYPE_APPLICATION ? BCM_FLD_HOST_WRITE_DDR : BCM_FLD_HOST_WRITE_SRAM;
+ rc = bcm_fld_set_host_debug_status(device, host_debug_value);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcm_fld_set_host_debug_status\n");
+
+ /* If this is the application image, skip the envelope (jump to the data itself). */
+ if (image_type == BCMOLT_DEVICE_IMAGE_TYPE_APPLICATION)
+ {
+ bcmolt_firmware_envelope envelope;
+
+ read_len = dev_ctrl_params.image_read_cb(device, image_type, offset_r, (uint8_t *)&envelope, sizeof(envelope));
+ if (read_len < sizeof(envelope))
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "image_read_cb returned error %s (%d)\n", bcmos_strerror(rc), rc);
+ return rc;
+ }
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Upload firmware version=%u.%u.%u.%u\n",
+ envelope.revision.release_major_id, envelope.revision.release_minor_id, envelope.revision.release_revision_id, envelope.revision.model_id);
+ offset_r += read_len;
+ }
+
+ do
+ {
+ read_len = dev_ctrl_params.image_read_cb(device, image_type, offset_r, image_buf[device], IMAGE_BUF_SIZE);
+ if (read_len < 0)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "image_read_cb returned error %s (%d)\n", bcmos_strerror(rc), rc);
+ return rc;
+ }
+
+ if (!read_len)
+ break;
+
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Writing %s (%d)\n", image_name, read_len);
+ rc = bcm_fld_write(device, (char *)image_buf[device], read_len, offset_w, image_type);
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "bcm_fld_write returned error %s (%d)\n", bcmos_strerror(rc), rc);
+ return rc;
+ }
+
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Reading %s for checking (%d)\n", image_name, read_len);
+ rc = bcm_fld_read(device, (char *)rd_image_buf[device], (uint32_t *)&read_len, offset_w, image_type);
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "bcm_fld_read returned error %s (%d)\n", bcmos_strerror(rc), rc);
+ return rc;
+ }
+
+ offset_r += read_len;
+ offset_w += read_len;
+
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Comparing %s (%d)/(%u)\n", image_name, read_len, offset_w);
+ if (memcmp(rd_image_buf[device], image_buf[device], read_len))
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Error during image uploading %x\n", offset_w);
+ return BCM_ERR_INTERNAL;
+ }
+ } while (read_len);
+
+ if (!offset_w)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "%s image file empty or corrupted!!!\n", image_name);
+ return BCM_ERR_INTERNAL;
+ }
+
+ if (image_type == BCMOLT_DEVICE_IMAGE_TYPE_APPLICATION)
+ {
+ read_len = sizeof(unsigned long);
+ /* first read word from star of the image */
+ bcm_fld_read(device, (char *)(long)&write_complete[0], (uint32_t *)&read_len, 0, image_type);
+ /* sync before read tail of image */
+ bcmos_barrier();
+ /* read from tail of the image */
+ bcm_fld_read(
+ device,
+ (char *)(long)&write_complete[1],
+ (uint32_t *)&read_len,
+ offset_w - sizeof(unsigned long),
+ image_type);
+ /* now we can be sure that full image in the embedded memory */
+ }
+
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Transferred %u bytes\n", offset_w);
+
+ return BCM_ERR_OK;
+}
+
+static bcmos_errno dev_ctrl_handle_application_image(bcmolt_devid device)
+{
+ bcmolt_device_cfg_data *dev_params = &dev_ctrl_db[device].device_params;
+ bcmos_errno rc = BCM_ERR_OK;
+
+ rc = dev_ctrl_handle_file(device, BCMOLT_DEVICE_IMAGE_TYPE_APPLICATION);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "dev_ctrl_handle_file()\n");
+ rc = bcm_fld_host_finish_write_ddr(device, 0);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcm_fld_host_finish_write_ddr()\n");
+ rc = bcmtrmux_connect(device, dev_params->debug.host_dma_tx_queue_size, dev_params->debug.host_dma_rx_queue_size);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcmtrmux_connect()\n");
+ /* We want that in case ONLY the host is reset, Maple enters standalone mode - this means we need to turn off "hot reset" on the PCIe channel. */
+ rc = bcm_ll_pcie_host_reset_enable(device,BCMOS_FALSE);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcm_ll_pcie_host_reset_enable()\n");
+
+ return rc;
+}
+
+static bcmos_errno dev_ctrl_handle_bootloader_image(bcmolt_devid device, uint32_t test_ddr)
+{
+ bcmos_errno rc = BCM_ERR_OK;
+
+ rc = dev_ctrl_handle_file(device, BCMOLT_DEVICE_IMAGE_TYPE_BOOTLOADER);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "dev_ctrl_handle_file()\n");
+ rc = bcm_fld_start_bootloader(device, test_ddr);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcm_fld_start_bootloader()\n");
+ bcmos_timer_start(
+ &dev_ctrl_db[device].boot_seq_info.timer.timer,
+ dev_ctrl_db[device].boot_seq_info.polling_interval);
+
+ return rc;
+}
+
+static bcmos_errno dev_ctrl_start_fld(bcmolt_devid device, uint32_t test_ddr)
+{
+ bcmos_errno rc = BCM_ERR_OK;
+
+ bcm_fld_clear_comm_area(device);
+
+ rc = dev_ctrl_handle_bootloader_image(device, test_ddr);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "dev_ctrl_handle_bootloader_image\n");
+
+ return rc;
+}
+
+static bcmos_errno dev_ctrl_get_exception_log_by_cpu(bcmolt_devid device, uint32_t cpuid)
+{
+ char *exception_buf;
+ int exception_buf_len;
+ bcmos_errno rc;
+
+ exception_buf = bcmos_alloc(BCM_FLD_CPU_POSTMORTEM_BUF_SIZE);
+ rc = bcm_fld_copy_exception_log(device, cpuid, exception_buf, &exception_buf_len);
+ if (rc)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "bcm_fld_copy_exception_log failed, rc=%u (%s)\n", rc, bcmos_strerror(rc));
+ goto exit;
+ }
+ bcm_fld_clear_exception_state(device, cpuid);
+
+ dev_ctrl_send_ind_exception_log(device, cpuid, exception_buf);
+ rc = BCM_ERR_OK;
+
+exit:
+ bcmos_free(exception_buf);
+ return rc;
+}
+
+/** Dump exception log if there is one, return BCM_ERR_NOENT if not. */
+static bcmos_errno dev_ctrl_get_exception_log_if_present(bcmolt_devid dev_id)
+{
+ bcmos_errno rc;
+ uint32_t state0, state1;
+
+ /* Dump exception log, if any.
+ * This should be done prior to writing bootloader, as it will overwrite the same place in SRAM. */
+ rc = bcm_fld_get_exception_state(dev_id, &state0, &state1);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(dev_id, rc, "bcm_fld_get_exception_state\n");
+ if (state0)
+ dev_ctrl_get_exception_log_by_cpu(dev_id, 0);
+ if (state1)
+ dev_ctrl_get_exception_log_by_cpu(dev_id, 1);
+ if (!state0 && !state1)
+ return BCM_ERR_NOENT;
+
+ return BCM_ERR_OK;
+}
+
+/** Dump exception log if there is one, print a message and return BCM_ERR_OK if not. */
+static bcmos_errno dev_ctrl_get_exception_log(bcmolt_devid dev_id)
+{
+ bcmos_errno rc = dev_ctrl_get_exception_log_if_present(dev_id);
+ if (rc == BCM_ERR_NOENT)
+ {
+ BCM_LOG(DEBUG, dev_ctrl_db[dev_id].log_id, "Exception log for device %d is empty\n", dev_id);
+ rc = BCM_ERR_OK;
+ }
+ return rc;
+}
+
+static void dev_ctrl_sw_error_table_dump(bcmolt_devid dev_id)
+{
+ bcmos_errno err = dev_ctrl_get_sw_error_table(dev_id);
+ uint8_t i;
+
+ if (BCM_ERR_OK != err)
+ {
+ BCM_LOG(INFO, dev_ctrl_db[dev_id].log_id, "Failed to retrieve Embedded Software Error(s): %d\n", err);
+ }
+ else
+ {
+ BCM_LOG(INFO, dev_ctrl_db[dev_id].log_id, "Found %u Embedded Software Error(s):\n", dev_ctrl_db[dev_id].sw_error_count);
+ for (i = 0; i < dev_ctrl_db[dev_id].sw_error_count; i++)
+ {
+ BCM_LOG(INFO, dev_ctrl_db[dev_id].log_id,
+ "\t[%s] %s:%u inst:%u count:%u first:%llu last:%llu\n",
+ dev_ctrl_db[dev_id].sw_errors[i].task_name,
+ dev_ctrl_db[dev_id].sw_errors[i].filename,
+ dev_ctrl_db[dev_id].sw_errors[i].line_number,
+ dev_ctrl_db[dev_id].sw_errors[i].instance,
+ dev_ctrl_db[dev_id].sw_errors[i].error_counter,
+ (unsigned long long)dev_ctrl_db[dev_id].sw_errors[i].first_error_time_us,
+ (unsigned long long)dev_ctrl_db[dev_id].sw_errors[i].last_error_time_us);
+ }
+ }
+}
+#endif
+
+static bcmolt_host_connection_fail_reason dev_ctrl_connect_from_reset(bcmolt_devid device, uint32_t test_ddr)
+{
+#ifndef IN_BAND
+ bcmos_errno rc;
+
+ rc = dev_ctrl_params.device_on_cb(device);
+ BCMOS_TRACE_CHECK_RETURN(
+ rc != BCM_ERR_OK,
+ BCMOLT_HOST_CONNECTION_FAIL_REASON_USER_CALLBACK_ERROR,
+ "device_on_cb\n");
+
+ rc = dev_ctrl_params.pcie_channel_prepare_cb(device);
+ BCMOS_TRACE_CHECK_RETURN(
+ rc != BCM_ERR_OK,
+ BCMOLT_HOST_CONNECTION_FAIL_REASON_USER_CALLBACK_ERROR,
+ "pcie_channel_prepare_cb\n");
+
+
+ rc = dev_ctrl_register_fld(device);
+ BCMOS_TRACE_CHECK_RETURN(
+ rc != BCM_ERR_OK,
+ BCMOLT_HOST_CONNECTION_FAIL_REASON_INTERNAL_ERROR,
+ "dev_ctrl_register_fld\n");
+
+ dev_ctrl_get_exception_log(device);
+ dev_ctrl_sw_error_table_dump(device);
+
+#ifndef SIMULATION_BUILD
+ bcm_fld_set_host_event(device, dev_ctrl_db[device].trx_disable_mask);
+#endif
+ rc = dev_ctrl_start_fld(device, test_ddr);
+ BCMOS_TRACE_CHECK_RETURN(
+ rc != BCM_ERR_OK,
+ BCMOLT_HOST_CONNECTION_FAIL_REASON_INTERNAL_ERROR,
+ "dev_ctrl_start_fld\n");
+#endif
+ return BCMOLT_HOST_CONNECTION_FAIL_REASON_NONE;
+}
+
+static bcmolt_host_connection_fail_reason dev_ctrl_connect_to_standalone(bcmolt_devid device)
+{
+ bcmos_errno rc;
+
+ /* if Maple runs in standalone mode, and host did reset, we need to register maple to fld and and
+ reconnect the transport layer - no need to rescan, it was done automatically by host when
+ ll_pcie registered maple
+ re-scan without passing thru remove and maple off, lets maple out of reset, remapped, but stucked
+ not, really, working in standaloane mode
+ */
+
+ /* The chip is running and the PCIe channel hardware is initialized, we can now safely:
+ * - Register with the FLD driver.
+ * - Restart the PCIe connection process. As part of this process, the host will set the 'host queues valid' flag.
+ * If the device is running and sees this flag is set, it will start the reconnection process as well, in sync
+ * with the host. If the device fails to connect, it means that the device is unresponsive, so the best we can do
+ * is reset the device and reprogram it from scratch. */
+#ifndef IN_BAND
+ rc = dev_ctrl_register_fld(device);
+ BCMOS_TRACE_CHECK_RETURN(
+ rc != BCM_ERR_OK,
+ BCMOLT_HOST_CONNECTION_FAIL_REASON_INTERNAL_ERROR,
+ "dev_ctrl_register_fld\n");
+
+ dev_ctrl_get_exception_log(device);
+
+#ifndef SIMULATION_BUILD
+ bcm_fld_set_host_event(device, dev_ctrl_db[device].trx_disable_mask);
+#endif
+#endif
+
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Requesting re-connect to running device...\n");
+#ifndef IN_BAND
+ rc = bcmtrmux_connect(
+ device,
+ dev_ctrl_db[device].device_params.debug.host_dma_tx_queue_size,
+ dev_ctrl_db[device].device_params.debug.host_dma_rx_queue_size);
+#else
+ /*Need to pass in IP Address and UDP port when running in linux user space*/
+ rc = bcmtrmux_connect(device,
+ dev_ctrl_db[device].device_params.device_ip_address,
+ dev_ctrl_db[device].device_params.device_udp_port);
+
+#endif
+
+ if (rc == BCM_ERR_OK)
+ {
+ dev_ctrl_db[device].connection_info.state = DEV_CTRL_CONNECTING_STATE_STANDALONE;
+ return BCMOLT_HOST_CONNECTION_FAIL_REASON_NONE;
+ }
+ else
+ {
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Connection failed - running device didn't respond to connection request\n");
+ return BCMOLT_HOST_CONNECTION_FAIL_REASON_RECONNECT_TIMEOUT;
+ }
+}
+
+static void dev_ctrl_disconnect(bcmolt_devid device)
+{
+ bcmos_errno rc;
+
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_DISCONNECTED;
+#ifdef ENABLE_LOG
+ dev_ctrl_db[device].sram_log_offset = 0;
+ dev_ctrl_db[device].msgs_read = 0;
+#endif
+ stop_keep_alive_process(&dev_ctrl_db[device].ka_info);
+ bcmos_timer_stop(&dev_ctrl_db[device].exception_monitor_timer.timer);
+ dev_ctrl_init_connection_state(device);
+ rc = bcmtrmux_disconnect(device);
+ if (rc != BCM_ERR_OK && rc != BCM_ERR_ALREADY)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "bcmtrmux_disconnect returned error: %s (%d)\n", bcmos_strerror(rc), rc);
+ }
+}
+
+static bcmos_errno dev_ctrl_perform_reset_device(bcmolt_devid device)
+{
+ bcmos_errno rc = BCM_ERR_OK;
+
+ dev_ctrl_disconnect(device);
+
+#ifndef IN_BAND
+ rc = dev_ctrl_params.pcie_channel_remove_cb(device);
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Device remove callback failed: %s (%d)\n", bcmos_strerror(rc), rc);
+ }
+ rc = dev_ctrl_params.device_off_cb(device);
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Device off callback failed: %s (%d)\n", bcmos_strerror(rc), rc);
+ }
+
+ /* the device has been reset so our FLD info is now invalid */
+ dev_ctrl_db[device].fld_info.soc_sram_base = 0;
+ bcm_fld_unregister(device);
+#endif
+ return rc;
+}
+static bcmos_errno dev_ctrl_perform_reset(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ bcmos_errno rc = BCM_ERR_OK;
+ bcmolt_device_reset_mode mode = ((const bcmolt_device_reset *)msg)->data.mode;
+ bcmolt_devid i;
+
+ switch (mode)
+ {
+ case BCMOLT_DEVICE_RESET_MODE_DEVICE:
+ return dev_ctrl_perform_reset_device(device);
+
+ case BCMOLT_DEVICE_RESET_MODE_HOST:
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_DISCONNECTED;
+ dev_ctrl_db[device].is_host_reset_pending = BCMOS_TRUE;
+ dev_ctrl_send_device_disconnect_msg(device, 0);
+ /* instead of resetting the host right away, wait a few ms so the host can receive the ack / indication */
+ bcmos_timer_start(&dev_ctrl_db[device].reset_delay_timer.timer, HOST_RESET_DELAY_US);
+ break;
+
+ case BCMOLT_DEVICE_RESET_MODE_ALL:
+ for (i = 0; i < BCMTR_MAX_OLTS; i++)
+ {
+ dev_ctrl_db[i].device_params.state = BCMOLT_DEVICE_STATE_DISCONNECTED;
+ dev_ctrl_db[i].is_host_reset_pending = BCMOS_TRUE;
+ rc = dev_ctrl_params.device_off_cb(i);
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[i].log_id, "Device off callback failed: %s (%d)\n", bcmos_strerror(rc), rc);
+ }
+ }
+ /* instead of resetting the host right away, wait a few ms so the host can receive the ack / indication */
+ bcmos_timer_start(&dev_ctrl_db[device].reset_delay_timer.timer, HOST_RESET_DELAY_US);
+ break;
+
+ default:
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Unrecognized reset mode: %d\n", mode);
+ break;
+ }
+
+ return rc;
+}
+
+static void dev_ctrl_disconnected_state_device_clear_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ dev_ctrl_clear_device_cfg(device);
+}
+
+static void dev_ctrl_disconnected_state_device_config_set_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ if (dev_ctrl_db[device].last_message == NULL)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Our saved message was invalid\n");
+ return;
+ }
+
+ dev_ctrl_update_local_configuration(device, msg);
+ dev_ctrl_db[device].last_message->dir = BCMOLT_MSG_DIR_RESPONSE;
+ bcmtrmux_control_to_host(device, dev_ctrl_db[device].last_message);
+ bcmolt_msg_free(dev_ctrl_db[device].last_message);
+ dev_ctrl_db[device].last_message = NULL;
+}
+
+static void dev_ctrl_disconnected_state_device_config_get_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ bcmolt_presence_mask mask;
+ bcmolt_device_cfg *cfg;
+
+ if (dev_ctrl_db[device].last_message == NULL)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Our saved message was invalid --- aborting\n");
+ return;
+ }
+
+ cfg = (bcmolt_device_cfg *)dev_ctrl_db[device].last_message;
+ cfg->data = dev_ctrl_db[device].device_params;
+ mask = dev_ctrl_fill_from_local(device);
+
+ if ((mask & ~dev_ctrl_db[device].device_params_present) != 0)
+ {
+ bcmolt_msg_err(
+ dev_ctrl_db[device].last_message,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_INVALID_OP,
+ BCMOLT_ERR_FIELD_NONE,
+ "Unable to get parameters that have never been set");
+ }
+
+ dev_ctrl_db[device].last_message->dir = BCMOLT_MSG_DIR_RESPONSE;
+ bcmtrmux_control_to_host(device, dev_ctrl_db[device].last_message);
+ bcmolt_msg_free(dev_ctrl_db[device].last_message);
+ dev_ctrl_db[device].last_message = NULL;
+}
+
+static void dev_ctrl_disconnected_state_device_connect_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+#ifdef IN_BAND
+ bcmolt_device_connect oper;
+ bcmolt_device_key key = {};
+#else
+ bcmos_errno rc;
+#endif
+ bcmolt_host_connection_fail_reason fail_reason;
+ bcmos_bool is_standalone;
+
+ if (dev_ctrl_db[device].is_host_reset_pending)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Cannot connect while host reset is pending\n");
+ return;
+ }
+
+#ifndef IN_BAND
+ /* Check if the chip is running in standalone mode */
+
+ rc = dev_ctrl_params.device_is_running_cb(device, &is_standalone);
+
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "device_status_get_cb returned error: %s (%d)\n", bcmos_strerror(rc), rc);
+ return;
+ }
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "device_status_get_cb returned success: is_standalone=%s\n", is_standalone ? "yes" : "no");
+
+ /* If the chip is running in standalone mode, connect to it:
+ * - Check the status of the PCIe channel and prepare it if necessary, using host callbacks
+ * - Register the device in the FLD driver
+ * - Use FLD to ask the device to re-initialize its PCIe transport layer
+ * - Initialize the host PCIe transport layer
+ * Otherwise, we must start the boot sequence:
+ * - Power on the device
+ * - Prepare the PCIe channel via host callback
+ * - Register the device in the FLD driver
+ * - Check if there is an exception log from the last time the application was run (and print it if so)
+ * - Start the FLD timer to load the bootcode
+ * In either case, the resulting state is 'connecting'.
+ */
+ dev_ctrl_db[device].boot_seq_info.polling_counter = BOOT_SEQ_POLLING_MAX_NUMBER;
+ bcmos_timer_handler_set(&dev_ctrl_db[device].boot_seq_info.timer.timer, dev_ctrl_boot_seq_timer_handler, device);
+#else
+ is_standalone= BCMOS_TRUE;
+#endif
+ if (is_standalone)
+ {
+ fail_reason = dev_ctrl_connect_to_standalone(device);
+ }
+ else
+ {
+ fail_reason = dev_ctrl_connect_from_reset(device, 0);
+ dev_ctrl_db[device].connection_info.state = DEV_CTRL_CONNECTING_STATE_ESTABLISHING;
+ }
+
+ if (fail_reason == BCMOLT_HOST_CONNECTION_FAIL_REASON_NONE)
+ {
+ bcmos_timer_start(&dev_ctrl_db[device].connection_info.timer.timer, DEVICE_CONTROL_CONNECT_TIME_US);
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_CONNECTING;
+ BCM_LOG(DEBUG, dev_ctrl_db[device].log_id, "began connecting to %s\n", is_standalone ? "standby device" : "device from reset");
+
+#ifndef IN_BAND
+ /*Do nothing*/
+#else
+ BCMOLT_OPER_INIT(&oper, device, connect, key);
+ oper.hdr.hdr.type = BCMOLT_MSG_TYPE_SET;
+ (void)bcmtrmux_control_to_line(device, &oper.hdr.hdr);
+ bcmos_printf("Sent connect to embedded...\n");
+#endif
+
+ }
+ else
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id,
+ "failed to begin connection process: %s (%d)\n",
+ bcm_str_host_connection_fail_reason(fail_reason),
+ fail_reason);
+ dev_ctrl_send_ind_connection_failure(device, fail_reason);
+ }
+}
+
+static void dev_ctrl_disconnected_state_device_reset_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ dev_ctrl_perform_reset(device, msg);
+}
+
+#ifndef IN_BAND
+static void dev_ctrl_disconnected_state_device_run_ddr_test_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ bcmolt_host_connection_fail_reason fail_reason;
+ uint32_t test_ddr = 0;
+
+ const bcmolt_device_run_ddr_test_data *params = &((const bcmolt_device_run_ddr_test *)msg)->data;
+ if (params->cpu)
+ {
+ test_ddr |= BCM_FLD_HOST_RUN_CPU_DDR_TEST_MASK;
+ }
+ if (params->ras_0)
+ {
+ test_ddr |= BCM_FLD_HOST_RUN_RAS_0_TEST_MASK;
+ }
+ if (params->ras_1)
+ {
+ test_ddr |= BCM_FLD_HOST_RUN_RAS_1_TEST_MASK;
+ }
+
+ dev_ctrl_db[device].boot_seq_info.polling_counter = DDR_TEST_POLLING_MAX_NUMBER;
+ bcmos_timer_handler_set(&dev_ctrl_db[device].boot_seq_info.timer.timer, dev_ctrl_ddr_test_timer_handler, device);
+ fail_reason = dev_ctrl_connect_from_reset(device, test_ddr);
+ if (fail_reason == BCMOLT_HOST_CONNECTION_FAIL_REASON_NONE)
+ {
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_TESTING_DDR;
+ }
+ else
+ {
+ bcmolt_device_ddr_test_complete ind = {};
+ BCMOLT_AUTO_INIT(&ind, device, ddr_test_complete);
+ ind.data.ddr_test.status = BCMOLT_DDR_TEST_STATUS_CONNECTION_FAILED;
+ ind.data.ddr_test.u.connection_failed.reason = fail_reason;
+ dev_ctrl_send_indication(device, &ind.hdr.hdr);
+ }
+
+}
+
+static void dev_ctrl_testing_ddr_state_ddr_test_completed_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ bcmolt_device_ddr_test_complete ind = {};
+
+ BCMOLT_AUTO_INIT(&ind, device, ddr_test_complete);
+
+ ind.data.ddr_test.status = BCMOLT_DDR_TEST_STATUS_COMPLETED;
+ ind.data.ddr_test.u.completed.cpu_result = bcm_fld_ddr_test_result_get(device, 0);
+ ind.data.ddr_test.u.completed.ras_0_result = bcm_fld_ddr_test_result_get(device, 1);
+ ind.data.ddr_test.u.completed.ras_1_result = bcm_fld_ddr_test_result_get(device, 2);
+
+ dev_ctrl_perform_reset_device(device);
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_DISCONNECTED;
+
+ dev_ctrl_send_indication(device, &ind.hdr.hdr);
+}
+
+static void dev_ctrl_testing_ddr_state_ddr_test_timeout_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ bcmolt_device_ddr_test_complete ind = {};
+
+ dev_ctrl_perform_reset_device(device);
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_DISCONNECTED;
+
+ BCMOLT_AUTO_INIT(&ind, device, ddr_test_complete);
+ ind.data.ddr_test.status = BCMOLT_DDR_TEST_STATUS_TIMEOUT;
+ dev_ctrl_send_indication(device, &ind.hdr.hdr);
+}
+#endif
+
+static void dev_ctrl_connecting_state_connection_failure_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ dev_ctrl_disconnect(device);
+ dev_ctrl_send_ind_connection_failure_from_msg(device, msg);
+}
+
+static void dev_ctrl_connecting_state_connection_established_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ if (dev_ctrl_db[device].connection_info.state == DEV_CTRL_CONNECTING_STATE_ESTABLISHING)
+ {
+ /* Initial connection is complete, now wait for the firmware to be initialized. */
+ dev_ctrl_db[device].connection_info.state = DEV_CTRL_CONNECTING_STATE_CONFIGURING;
+ dev_ctrl_send_config_set_msg(
+ device,
+ dev_ctrl_db[device].device_params_present,
+ 0,
+ &dev_ctrl_db[device].device_params);
+ if (dev_ctrl_db[device].connection_info.config_send_counter > 0)
+ {
+ dev_ctrl_db[device].connection_info.config_send_counter--;
+ }
+ bcmos_timer_start(
+ &dev_ctrl_db[device].connection_info.timer.timer,
+ dev_ctrl_db[device].connection_info.config_interval);
+ }
+ else
+ {
+ /* Initial connection was already done - something must have gone wrong. Try again. */
+ if (dev_ctrl_db[device].connection_info.config_send_counter > 0)
+ {
+ dev_ctrl_send_config_set_msg(
+ device,
+ dev_ctrl_db[device].device_params_present,
+ 0,
+ &dev_ctrl_db[device].device_params);
+ bcmos_timer_start(
+ &dev_ctrl_db[device].connection_info.timer.timer,
+ dev_ctrl_db[device].connection_info.config_interval);
+ dev_ctrl_db[device].connection_info.config_send_counter--;
+ }
+ else
+ {
+ dev_ctrl_disconnect(device);
+ dev_ctrl_send_ind_connection_failure(device, BCMOLT_HOST_CONNECTION_FAIL_REASON_TIMEOUT);
+ }
+ }
+}
+
+static inline bcmos_bool dev_ctrl_nni_speed_equal(const bcmolt_device_nni_speed *a, const bcmolt_device_nni_speed *b)
+{
+ return (a->first_half == b->first_half && a->second_half == b->second_half);
+}
+
+static void dev_ctrl_connecting_state_device_ready_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ bcmos_errno rc;
+ const bcmolt_device_device_ready *ready_msg = (const bcmolt_device_device_ready *)msg;
+ bcmolt_host_connection_fail_reason fail_reason = BCMOLT_HOST_CONNECTION_FAIL_REASON__NUM_OF;
+
+ if (dev_ctrl_db[device].connection_info.state == DEV_CTRL_CONNECTING_STATE_ESTABLISHING)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Unexpected 'device ready' indication before connection is established\n");
+ return;
+ }
+
+ if (ready_msg->data.system_mode != dev_ctrl_db[device].device_params.system_mode)
+ {
+ fail_reason = BCMOLT_HOST_CONNECTION_FAIL_REASON_SYSTEM_MODE_MISMATCH;
+ }
+ else if ((dev_ctrl_db[device].device_params_present & BCMOLT_PROP_MASK_GET(device, _cfg, nni_speed)) != 0 &&
+ !dev_ctrl_nni_speed_equal(&ready_msg->data.nni_speed, &dev_ctrl_db[device].device_params.nni_speed))
+ {
+ fail_reason = BCMOLT_HOST_CONNECTION_FAIL_REASON_NNI_SPEED_MISMATCH;
+ }
+ else
+ {
+ rc = dev_ctrl_validate_fw_version(device, &ready_msg->data.firmware_sw_version);
+ if (rc != BCM_ERR_OK)
+ {
+ fail_reason = BCMOLT_HOST_CONNECTION_FAIL_REASON_SOFTWARE_VERSION_MISMATCH;
+ }
+ }
+
+ if (fail_reason == BCMOLT_HOST_CONNECTION_FAIL_REASON__NUM_OF)
+ {
+ dev_ctrl_db[device].device_params.firmware_sw_version = ready_msg->data.firmware_sw_version;
+ dev_ctrl_db[device].device_params.chip_revision = ready_msg->data.chip_revision;
+ if ((dev_ctrl_db[device].device_params_present & BCMOLT_PROP_MASK_GET(device, _cfg, nni_speed)) == 0)
+ {
+ dev_ctrl_db[device].device_params.nni_speed = ready_msg->data.nni_speed;
+ dev_ctrl_db[device].device_params_present |= BCMOLT_PROP_MASK_GET(device, _cfg, nni_speed);
+ }
+
+ if (dev_ctrl_db[device].ka_info.ka_interval > 0)
+ {
+ start_keep_alive_process(&dev_ctrl_db[device].ka_info);
+ }
+
+#ifndef IN_BAND
+ bcmos_timer_start(&dev_ctrl_db[device].exception_monitor_timer.timer, EXCEPTION_LOG_MONITOR_INTERVAL);
+#endif
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_READY;
+ dev_ctrl_send_ind_connection_complete(
+ device,
+ dev_ctrl_db[device].connection_info.state == DEV_CTRL_CONNECTING_STATE_STANDALONE);
+ }
+ else
+ {
+ dev_ctrl_send_device_disconnect_msg(device, 0);
+ dev_ctrl_disconnect(device);
+ dev_ctrl_send_ind_connection_failure(device, fail_reason);
+ }
+}
+
+static void dev_ctrl_connecting_state_received_ack(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ /* This is called when we receive the ACK response against the configuraiton set message which was sent while the
+ * state-machine as part of the initial connection process. If the result is OK, we should just move on and keep
+ * waiting for the "ready" indication. If the result is not OK, the device rejected the configuration so we
+ * should disconnect the device and send a failure indication. */
+ if (msg->err != BCM_ERR_OK)
+ {
+ bcmolt_host_connection_fail_reason fail_reason;
+
+ dev_ctrl_disconnect(device);
+
+ /* Figure out which failure reason based on the message error code. */
+ switch (msg->err)
+ {
+ case BCM_ERR_NOT_SUPPORTED:
+ fail_reason = BCMOLT_HOST_CONNECTION_FAIL_REASON_SYSTEM_MODE_NOT_SUPPORTED;
+ break;
+ case BCM_ERR_PARM:
+ fail_reason = BCMOLT_HOST_CONNECTION_FAIL_REASON_PARAMETER;
+ break;
+ default:
+ fail_reason = BCMOLT_HOST_CONNECTION_FAIL_REASON_INTERNAL_ERROR;
+ break;
+ }
+
+ dev_ctrl_send_ind_connection_failure(device, fail_reason);
+ }
+}
+
+static void dev_ctrl_ready_state_device_config_set_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ const bcmolt_device_cfg *cfg = (const bcmolt_device_cfg *)msg;
+
+ dev_ctrl_send_config_set_msg(device, msg->presence_mask, dev_ctrl_db[device].last_message->corr_tag, &cfg->data);
+
+ bcmos_timer_start(&dev_ctrl_db[device].device_response_timer.timer, DEVICE_RESPONSE_TIMEOUT_LENGTH);
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_WAITING_FOR_DEVICE;
+}
+
+static void dev_ctrl_ready_state_device_config_get_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ bcmolt_presence_mask mask;
+
+ if (dev_ctrl_db[device].last_message == NULL)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Our saved message was invalid --- aborting\n");
+ return;
+ }
+
+ mask = dev_ctrl_fill_from_local(device);
+ if (mask == 0)
+ {
+ dev_ctrl_db[device].last_message->dir = BCMOLT_MSG_DIR_RESPONSE;
+ bcmtrmux_control_to_host(device, dev_ctrl_db[device].last_message);
+ bcmolt_msg_free(dev_ctrl_db[device].last_message);
+ dev_ctrl_db[device].last_message = NULL;
+ }
+ else
+ {
+ bcmos_timer_start(&dev_ctrl_db[device].device_response_timer.timer, DEVICE_RESPONSE_TIMEOUT_LENGTH);
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_WAITING_FOR_DEVICE;
+ dev_ctrl_send_config_get_msg(device, mask, dev_ctrl_db[device].last_message->corr_tag);
+ }
+}
+
+static void dev_ctrl_ready_state_device_disconnect_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ dev_ctrl_send_device_disconnect_msg(device, 0);
+ dev_ctrl_disconnect(device);
+ dev_ctrl_send_ind_disconnection_complete(device);
+}
+
+static void dev_ctrl_ready_state_device_reset_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ dev_ctrl_perform_reset(device, msg);
+ dev_ctrl_send_ind_disconnection_complete(device);
+}
+
+static void dev_ctrl_ready_state_connection_failure_event(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ dev_ctrl_disconnect(device);
+ dev_ctrl_send_ind_connection_failure_from_msg(device, msg);
+}
+
+static void dev_ctrl_waiting_for_device_state_timer_timeout(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ if (dev_ctrl_db[device].last_message == NULL)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Our saved message was invalid --- aborting\n");
+ return;
+ }
+
+ bcmolt_msg_err(
+ dev_ctrl_db[device].last_message,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_INTERNAL,
+ BCMOLT_ERR_FIELD_NONE,
+ "No response to configuration message from embedded");
+ dev_ctrl_db[device].last_message->dir = BCMOLT_MSG_DIR_RESPONSE;
+ bcmtrmux_control_to_host(device, dev_ctrl_db[device].last_message);
+ bcmolt_msg_free(dev_ctrl_db[device].last_message);
+ dev_ctrl_db[device].last_message = NULL;
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_READY;
+}
+
+static void dev_ctrl_waiting_for_device_state_received_ack(bcmolt_devid device, const bcmolt_msg *msg)
+{
+ bcmos_timer_stop(&dev_ctrl_db[device].device_response_timer.timer);
+
+ if (dev_ctrl_db[device].last_message == NULL)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Our saved message was invalid --- aborting\n");
+ return;
+ }
+
+ if (msg->corr_tag != dev_ctrl_db[device].last_message->corr_tag)
+ {
+ /* ignore this response as it was to something other than our request */
+ return;
+ }
+
+ if (msg->err != BCM_ERR_OK)
+ {
+ dev_ctrl_db[device].last_message->err = msg->err;
+ dev_ctrl_db[device].last_message->err_field_idx = msg->err_field_idx;
+ memcpy(dev_ctrl_db[device].last_message->err_text, msg->err_text, sizeof(msg->err_text));
+ dev_ctrl_db[device].last_message->dir = BCMOLT_MSG_DIR_RESPONSE;
+ bcmtrmux_control_to_host(device, dev_ctrl_db[device].last_message);
+ bcmolt_msg_free(dev_ctrl_db[device].last_message);
+ dev_ctrl_db[device].last_message = NULL;
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_READY;
+ return;
+ }
+
+ if (msg->type == BCMOLT_MSG_TYPE_GET)
+ {
+ const bcmolt_device_cfg *source = (const bcmolt_device_cfg *)msg;
+ bcmolt_device_cfg *dest = (bcmolt_device_cfg *)dev_ctrl_db[device].last_message;
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, protection_switching_ext_irq))
+ {
+ dest->data.protection_switching_ext_irq = source->data.protection_switching_ext_irq;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, epon_clock_transport_sample_delay))
+ {
+ dest->data.epon_clock_transport_sample_delay = source->data.epon_clock_transport_sample_delay;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, indication_shaping))
+ {
+ dest->data.indication_shaping = source->data.indication_shaping;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, gpon_xgpon_tod_enable))
+ {
+ dest->data.gpon_xgpon_tod_enable = source->data.gpon_xgpon_tod_enable;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, gpon_xgpon_tod_gpio_pin))
+ {
+ dest->data.gpon_xgpon_tod_gpio_pin = source->data.gpon_xgpon_tod_gpio_pin;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, gpon_xgpon_tod_connected_internally))
+ {
+ dest->data.gpon_xgpon_tod_connected_internally = source->data.gpon_xgpon_tod_connected_internally;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, epon_8021_as_tod_format))
+ {
+ dest->data.epon_8021_as_tod_format = source->data.epon_8021_as_tod_format;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, firmware_sw_version))
+ {
+ dest->data.firmware_sw_version = source->data.firmware_sw_version;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, chip_revision))
+ {
+ dest->data.chip_revision = source->data.chip_revision;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, chip_temperature))
+ {
+ dest->data.chip_temperature = source->data.chip_temperature;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, epon_shaper_mode))
+ {
+ dest->data.epon_shaper_mode = source->data.epon_shaper_mode;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, embedded_image_list))
+ {
+ dest->data.embedded_image_list = source->data.embedded_image_list;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, chip_voltage))
+ {
+ dest->data.chip_voltage = source->data.chip_voltage;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, epon_tod_string))
+ {
+ dest->data.epon_tod_string = source->data.epon_tod_string;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, xgpon_num_of_onus))
+ {
+ dest->data.xgpon_num_of_onus = source->data.xgpon_num_of_onus;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, gpon_xgpon_tod_string_length))
+ {
+ dest->data.gpon_xgpon_tod_string_length = source->data.gpon_xgpon_tod_string_length;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, tod_uart_baudrate))
+ {
+ dest->data.tod_uart_baudrate = source->data.tod_uart_baudrate;
+ }
+ }
+
+ if (msg->type == BCMOLT_MSG_TYPE_SET)
+ {
+ bcmolt_device_cfg *source = (bcmolt_device_cfg *)dev_ctrl_db[device].last_message;
+ bcmolt_device_cfg_data *dest = &dev_ctrl_db[device].device_params;
+ dev_ctrl_db[device].device_params_present |= source->hdr.hdr.presence_mask;
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, protection_switching_ext_irq))
+ {
+ dest->protection_switching_ext_irq = source->data.protection_switching_ext_irq;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, epon_clock_transport_sample_delay))
+ {
+ dest->epon_clock_transport_sample_delay = source->data.epon_clock_transport_sample_delay;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, indication_shaping))
+ {
+ dest->indication_shaping = source->data.indication_shaping;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, gpon_xgpon_tod_enable))
+ {
+ dest->gpon_xgpon_tod_enable = source->data.gpon_xgpon_tod_enable;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, gpon_xgpon_tod_gpio_pin))
+ {
+ dest->gpon_xgpon_tod_gpio_pin = source->data.gpon_xgpon_tod_gpio_pin;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, gpon_xgpon_tod_connected_internally))
+ {
+ dest->gpon_xgpon_tod_connected_internally = source->data.gpon_xgpon_tod_connected_internally;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, epon_8021_as_tod_format))
+ {
+ dest->epon_8021_as_tod_format = source->data.epon_8021_as_tod_format;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, epon_tod_string))
+ {
+ dest->epon_tod_string = source->data.epon_tod_string;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, epon_shaper_mode))
+ {
+ dest->epon_shaper_mode = source->data.epon_shaper_mode;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, keepalive_tolerance))
+ {
+ dev_ctrl_db[device].ka_info.ka_tolerance = source->data.keepalive_tolerance;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, keepalive_interval))
+ {
+ dev_ctrl_db[device].ka_info.ka_interval = source->data.keepalive_interval * BCMOS_MICROSECONDS_IN_SECONDS;
+ if (dev_ctrl_db[device].ka_info.ka_interval > 0)
+ {
+ start_keep_alive_process(&dev_ctrl_db[device].ka_info);
+ }
+ else
+ {
+ stop_keep_alive_process(&dev_ctrl_db[device].ka_info);
+ }
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, gpon_xgpon_tod_string_length))
+ {
+ dest->gpon_xgpon_tod_string_length = source->data.gpon_xgpon_tod_string_length;
+ }
+ if (BCMOLT_CFG_PROP_IS_SET(source, device, tod_uart_baudrate))
+ {
+ dest->tod_uart_baudrate = source->data.tod_uart_baudrate;
+ }
+ }
+
+ dev_ctrl_db[device].last_message->dir = BCMOLT_MSG_DIR_RESPONSE;
+ bcmtrmux_control_to_host(device, dev_ctrl_db[device].last_message);
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_READY;
+ bcmolt_msg_free(dev_ctrl_db[device].last_message);
+ dev_ctrl_db[device].last_message = NULL;
+}
+
+static dev_ctrl_sm_cb dev_ctrl_sm[BCMOLT_DEVICE_STATE__NUM_OF][DEVICE_CONTROL_EVENT__NUM_OF] =
+{
+ [BCMOLT_DEVICE_STATE_DISCONNECTED] =
+ {
+ [DEVICE_CONTROL_EVENT_DEVICE_CLEAR] = dev_ctrl_disconnected_state_device_clear_event,
+ [DEVICE_CONTROL_EVENT_DEVICE_CONFIG_SET] = dev_ctrl_disconnected_state_device_config_set_event,
+ [DEVICE_CONTROL_EVENT_DEVICE_CONFIG_GET] = dev_ctrl_disconnected_state_device_config_get_event,
+ [DEVICE_CONTROL_EVENT_DEVICE_CONNECT] = dev_ctrl_disconnected_state_device_connect_event,
+ [DEVICE_CONTROL_EVENT_DEVICE_RESET] = dev_ctrl_disconnected_state_device_reset_event,
+#ifndef IN_BAND
+ [DEVICE_CONTROL_EVENT_RUN_DDR_TEST] = dev_ctrl_disconnected_state_device_run_ddr_test_event,
+#endif
+ },
+
+ [BCMOLT_DEVICE_STATE_CONNECTING] =
+ {
+ [DEVICE_CONTROL_EVENT_CONNECTION_FAILURE] = dev_ctrl_connecting_state_connection_failure_event,
+ [DEVICE_CONTROL_EVENT_CONNECTION_ESTABLISHED] = dev_ctrl_connecting_state_connection_established_event,
+ [DEVICE_CONTROL_EVENT_DEVICE_READY] = dev_ctrl_connecting_state_device_ready_event,
+ [DEVICE_CONTROL_EVENT_DEVICE_RECEIVED_ACK] = dev_ctrl_connecting_state_received_ack,
+ },
+
+ [BCMOLT_DEVICE_STATE_READY] =
+ {
+ [DEVICE_CONTROL_EVENT_DEVICE_CONFIG_SET] = dev_ctrl_ready_state_device_config_set_event,
+ [DEVICE_CONTROL_EVENT_DEVICE_CONFIG_GET] = dev_ctrl_ready_state_device_config_get_event,
+ [DEVICE_CONTROL_EVENT_DEVICE_DISCONNECT] = dev_ctrl_ready_state_device_disconnect_event,
+ [DEVICE_CONTROL_EVENT_DEVICE_RESET] = dev_ctrl_ready_state_device_reset_event,
+ [DEVICE_CONTROL_EVENT_CONNECTION_FAILURE] = dev_ctrl_ready_state_connection_failure_event,
+ },
+
+ [BCMOLT_DEVICE_STATE_WAITING_FOR_DEVICE] =
+ {
+ [DEVICE_CONTROL_EVENT_DEVICE_TIMER_TIMEOUT] = dev_ctrl_waiting_for_device_state_timer_timeout,
+ [DEVICE_CONTROL_EVENT_DEVICE_RECEIVED_ACK] = dev_ctrl_waiting_for_device_state_received_ack
+ },
+
+#ifndef IN_BAND
+ [BCMOLT_DEVICE_STATE_TESTING_DDR] =
+ {
+ [DEVICE_CONTROL_EVENT_DDR_TEST_COMPLETED] = dev_ctrl_testing_ddr_state_ddr_test_completed_event,
+ [DEVICE_CONTROL_EVENT_DDR_TEST_TIMEOUT] = dev_ctrl_testing_ddr_state_ddr_test_timeout_event
+ }
+#endif
+};
+
+static void dev_ctrl_sm_err_cb(bcmolt_devid device, dev_ctrl_event event)
+{
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id,
+ "Unexpected event: device=%d, state=%s, event=%s\n",
+ device,
+ bcm_str_device_state(dev_ctrl_db[device].device_params.state),
+ bcm_str_device_event(event));
+}
+
+static void dev_ctrl_sm_call_state_cb(bcmolt_devid device, dev_ctrl_event event, const bcmolt_msg *msg)
+{
+ dev_ctrl_sm_cb cb;
+ dev_ctrl_db[device].last_event = event;
+ cb = dev_ctrl_sm[dev_ctrl_db[device].device_params.state][event];
+ if (cb == NULL)
+ {
+ dev_ctrl_sm_err_cb(device, event);
+ }
+ else
+ {
+ cb(device, msg);
+ }
+}
+
+static void dev_ctrl_ka_rx_handler(bcmolt_devid device, bcmolt_device_device_keep_alive *msg)
+{
+ keep_alive_rx_handler((const bcmos_keep_alive_data_msg *)&msg->data, &dev_ctrl_db[device].ka_info);
+}
+
+static bcmos_errno dev_ctrl_ka_tx_handler(bcmolt_devid device, bcmolt_msg *msg)
+{
+ bcmos_errno rc;
+
+ if (!dev_ctrl_is_connected(dev_ctrl_db[device].device_params.state))
+ {
+ return BCM_ERR_OK; /* in case this happens during a disconnect/reset operation */
+ }
+
+ msg->corr_tag = ++dev_ctrl_db[device].corr_tag;
+ rc = bcmtrmux_control_to_line(device, msg);
+ return rc;
+}
+
+static bcmos_errno dev_ctrl_ka_disconnect_handler(bcmolt_devid device)
+{
+ dev_ctrl_disconnect(device);
+ dev_ctrl_send_ind_connection_failure(device, BCMOLT_HOST_CONNECTION_FAIL_REASON_KEEPALIVE);
+ return BCM_ERR_OK;
+}
+
+static void handle_oper_set_msg(bcmolt_devid device, bcmolt_msg *msg)
+{
+ dev_ctrl_event event;
+
+ switch (msg->subgroup)
+ {
+ case BCMOLT_DEVICE_OPER_ID_RESET:
+ event = DEVICE_CONTROL_EVENT_DEVICE_RESET;
+ break;
+ case BCMOLT_DEVICE_OPER_ID_CONNECT:
+ event = DEVICE_CONTROL_EVENT_DEVICE_CONNECT;
+ break;
+ case BCMOLT_DEVICE_OPER_ID_DISCONNECT:
+ event = DEVICE_CONTROL_EVENT_DEVICE_DISCONNECT;
+ break;
+ case BCMOLT_DEVICE_OPER_ID_RUN_DDR_TEST:
+ event = DEVICE_CONTROL_EVENT_RUN_DDR_TEST;
+ break;
+ default :
+ event = DEVICE_CONTROL_EVENT_NO_EVENT;
+ break;
+ }
+
+ /* Send response to the waiting application */
+ msg->dir = BCMOLT_MSG_DIR_RESPONSE;
+ bcmtrmux_control_to_host(device, msg);
+
+ /* Handle event */
+ if (event != DEVICE_CONTROL_EVENT_NO_EVENT)
+ {
+ dev_ctrl_sm_call_state_cb(device, event, msg);
+ }
+}
+
+static void dev_ctrl_process_msg(bcmolt_devid device, bcmolt_msg *msg)
+{
+ if (msg->dir == BCMOLT_MSG_DIR_RESPONSE)
+ {
+ dev_ctrl_sm_call_state_cb(device, DEVICE_CONTROL_EVENT_DEVICE_RECEIVED_ACK, msg);
+ }
+
+ if (msg->group == BCMOLT_MGT_GROUP_AUTO)
+ {
+ if (msg->subgroup != BCMOLT_DEVICE_AUTO_ID_DEVICE_KEEP_ALIVE)
+ {
+ BCM_LOG(DEBUG, dev_ctrl_db[device].log_id, "Indication = %s (%d)\n", bcm_str_auto_id(msg->subgroup), msg->subgroup);
+ }
+
+ switch (msg->subgroup)
+ {
+ case BCMOLT_DEVICE_AUTO_ID_DEVICE_KEEP_ALIVE:
+ dev_ctrl_ka_rx_handler(device, (bcmolt_device_device_keep_alive *)msg);
+ break;
+ case BCMOLT_DEVICE_AUTO_ID_CONNECTION_FAILURE:
+ /* note: this indication is not generated by the device - it's generated by device control itself */
+ dev_ctrl_sm_call_state_cb(device, DEVICE_CONTROL_EVENT_CONNECTION_FAILURE, msg);
+ break;
+ case BCMOLT_DEVICE_AUTO_ID_CONNECTION_ESTABLISHED:
+ dev_ctrl_sm_call_state_cb(device, DEVICE_CONTROL_EVENT_CONNECTION_ESTABLISHED, msg);
+ break;
+ case BCMOLT_DEVICE_AUTO_ID_DEVICE_READY:
+ dev_ctrl_sm_call_state_cb(device, DEVICE_CONTROL_EVENT_DEVICE_READY, msg);
+ break;
+ default:
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Unexpected indication\n");
+ break;
+ }
+ }
+
+ if (msg->group == BCMOLT_MGT_GROUP_OPER && msg->type == BCMOLT_MSG_TYPE_SET && msg->dir != BCMOLT_MSG_DIR_RESPONSE)
+ {
+ /* All operations happen entirely on the host side */
+ handle_oper_set_msg(device, msg);
+ }
+
+ if (msg->group == BCMOLT_MGT_GROUP_CFG && msg->dir != BCMOLT_MSG_DIR_RESPONSE)
+ {
+ dev_ctrl_db[device].last_message = msg;
+ switch (msg->type)
+ {
+ case BCMOLT_MSG_TYPE_GET:
+ dev_ctrl_sm_call_state_cb(device, DEVICE_CONTROL_EVENT_DEVICE_CONFIG_GET, msg);
+ break;
+ case BCMOLT_MSG_TYPE_CLEAR:
+ dev_ctrl_sm_call_state_cb(device, DEVICE_CONTROL_EVENT_DEVICE_CLEAR, msg);
+ break;
+ case BCMOLT_MSG_TYPE_SET:
+ dev_ctrl_sm_call_state_cb(device, DEVICE_CONTROL_EVENT_DEVICE_CONFIG_SET, msg);
+ break;
+ default:
+ break;
+ }
+ msg = NULL;
+ }
+
+ if (msg != NULL)
+ {
+ bcmolt_msg_free(msg);
+ }
+}
+
+static bcmos_timer_rc dev_ctrl_connection_timer_handler(bcmos_timer *timer, long data)
+{
+ bcmolt_devid device = DEVICE_ID_FROM_MODULE_ID(timer->parm.owner);
+
+ if (dev_ctrl_db[device].device_params.state != BCMOLT_DEVICE_STATE_CONNECTING)
+ {
+ /* The timer is irrelevant in this state - discard it and return. */
+ }
+ else if (dev_ctrl_db[device].connection_info.state == DEV_CTRL_CONNECTING_STATE_CONFIGURING)
+ {
+ /* After we have sent the first "device configuration set" message to the device, the connection timer is used
+ * for retransmitting this message in case the device missed it. */
+ bcmolt_device_connection_established ind = {};
+ BCMOLT_AUTO_INIT(&ind, device, connection_established);
+ dev_ctrl_sm_call_state_cb(device, DEVICE_CONTROL_EVENT_CONNECTION_ESTABLISHED, &ind.hdr.hdr);
+ }
+ else
+ {
+ /* Connection failure due to timeout. */
+ bcmolt_device_connection_failure ind = {};
+ BCMOLT_AUTO_INIT(&ind, device, connection_failure);
+ ind.data.reason = BCMOLT_HOST_CONNECTION_FAIL_REASON_TIMEOUT;
+ dev_ctrl_sm_call_state_cb(device, DEVICE_CONTROL_EVENT_CONNECTION_FAILURE, &ind.hdr.hdr);
+ }
+
+ return BCMOS_TIMER_STOP;
+}
+
+#ifndef IN_BAND
+static void dev_ctrl_get_ras_modes(bcmolt_system_mode system_mode, uint32_t *ras_0_mode, uint32_t *ras_1_mode)
+{
+ switch (system_mode)
+ {
+ case BCMOLT_SYSTEM_MODE_GPON__4_X:
+ case BCMOLT_SYSTEM_MODE_GPON__8_X:
+ *ras_0_mode = BCM_FLD_RAS_MODE_GPON;
+ *ras_1_mode = BCM_FLD_RAS_MODE_NOT_CONFIGURED;
+ break;
+ case BCMOLT_SYSTEM_MODE_GPON__16_X:
+ *ras_0_mode = BCM_FLD_RAS_MODE_GPON;
+ *ras_1_mode = BCM_FLD_RAS_MODE_GPON;
+ break;
+ case BCMOLT_SYSTEM_MODE_XGPON_1__4_X:
+ case BCMOLT_SYSTEM_MODE_XGPON_1__8_X:
+ case BCMOLT_SYSTEM_MODE_NGPON2__8_X_2_P_5_G:
+ *ras_0_mode = BCM_FLD_RAS_MODE_XGPON;
+ *ras_1_mode = BCM_FLD_RAS_MODE_XGPON;
+ break;
+ case BCMOLT_SYSTEM_MODE_GPON_8_XGPON_4_X_COEXISTENCE:
+ *ras_0_mode = BCM_FLD_RAS_MODE_XGPON;
+ *ras_1_mode = BCM_FLD_RAS_MODE_GPON;
+ break;
+ case BCMOLT_SYSTEM_MODE_XGS__2_X_10_G:
+ case BCMOLT_SYSTEM_MODE_NGPON2__2_X_10_G:
+ *ras_0_mode = BCM_FLD_RAS_MODE_XGS_NGPON2;
+ *ras_1_mode = BCM_FLD_RAS_MODE_XGS_NGPON2;
+ break;
+ default:
+ *ras_0_mode = BCM_FLD_RAS_MODE_NOT_CONFIGURED;
+ *ras_1_mode = BCM_FLD_RAS_MODE_NOT_CONFIGURED;
+ break;
+ }
+}
+
+static bcmos_timer_rc dev_ctrl_boot_seq_timer_handler(bcmos_timer *timer, long data)
+{
+ bcmos_bool is_bootloader_done;
+ bcmolt_devid device;
+ uint32_t ras_0_mode;
+ uint32_t ras_1_mode;
+ bcmos_errno rc = BCM_ERR_OK;
+ bcmos_timer_rc timer_rc = BCMOS_TIMER_STOP;
+
+ device = (bcmolt_devid)data;
+
+ if (dev_ctrl_db[device].boot_seq_info.polling_counter > 0)
+ {
+ dev_ctrl_db[device].boot_seq_info.polling_counter--;
+ is_bootloader_done = bcm_fld_is_bootloader_done(device);
+ if (is_bootloader_done)
+ {
+ /* Stop the boot timer */
+ timer_rc = BCMOS_TIMER_STOP;
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Boot loader phase done.\n");
+
+ if (dev_ctrl_db[device].device_params.debug.avs_control)
+ {
+ rc = bcm_fld_set_avs_cont(device, BCM_FLD_AVS_CONT); /* don't stop the cpu when avs fails. */
+ }
+ else
+ {
+ rc = bcm_fld_set_avs_cont(device, BCM_FLD_AVS_STOP); /* stop the cpu when avs fails. */
+ }
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcm_fld_set_avs_cont\n");
+
+ dev_ctrl_get_ras_modes(dev_ctrl_db[device].device_params.system_mode, &ras_0_mode, &ras_1_mode);
+ rc = bcm_fld_set_ras_mode_set(device, 0, ras_0_mode);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcm_fld_set_ras_0_mode_set\n");
+ rc = bcm_fld_set_ras_mode_set(device, 1, ras_1_mode);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcm_fld_set_ras_1_mode_set\n");
+ rc = dev_ctrl_handle_application_image(device);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "dev_ctrl_handle_application_image()\n");
+ }
+ else
+ {
+ /* Restart the boot timer */
+ timer_rc = BCMOS_TIMER_OK;
+ }
+ }
+ else
+ {
+ timer_rc = BCMOS_TIMER_STOP;
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "dev_ctrl_boot_seq timer expired while trying to burn BOOTLOADER\n");
+ }
+
+ return timer_rc;
+}
+
+static bcmos_timer_rc dev_ctrl_ddr_test_timer_handler(bcmos_timer *timer, long data)
+{
+ bcmos_bool is_ddr_test_done;
+ bcmolt_devid device;
+ bcmos_timer_rc timer_rc = BCMOS_TIMER_STOP;
+
+ device = (bcmolt_devid)data;
+
+ if (dev_ctrl_db[device].boot_seq_info.polling_counter > 0)
+ {
+ dev_ctrl_db[device].boot_seq_info.polling_counter--;
+ is_ddr_test_done = bcm_fld_is_ddr_test_done(device);
+ if (is_ddr_test_done)
+ {
+ /* Stop the boot timer */
+ timer_rc = BCMOS_TIMER_STOP;
+ dev_ctrl_sm_call_state_cb(device, DEVICE_CONTROL_EVENT_DDR_TEST_COMPLETED, NULL);
+ }
+ else
+ {
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "Waiting for DDR Test %u\n", dev_ctrl_db[device].boot_seq_info.polling_counter);
+ /* Restart the boot timer */
+ timer_rc = BCMOS_TIMER_OK;
+ }
+ }
+ else
+ {
+ timer_rc = BCMOS_TIMER_STOP;
+ dev_ctrl_sm_call_state_cb(device, DEVICE_CONTROL_EVENT_DDR_TEST_TIMEOUT, NULL);
+ }
+
+ return timer_rc;
+}
+#endif
+
+static bcmos_errno dev_ctrl_init_modules(bcmolt_devid device)
+{
+ bcmos_module_parm module_params = {};
+ bcmos_errno rc = BCM_ERR_OK;
+ dev_ctrl_db[device].module_info.module_id = MODULE_ID_FROM_DEVICE_ID(device);
+ snprintf(
+ dev_ctrl_db[device].module_info.name,
+ sizeof(dev_ctrl_db[device].module_info.name),
+ "dev_ctrl%u_module",
+ device);
+ module_params.qparm.name = dev_ctrl_db[device].module_info.name;
+ module_params.qparm.size = DEVICE_CONTROL_MSG_QUEUE_SIZE;
+ module_params.init = NULL;
+ rc = bcmos_module_create(
+ dev_ctrl_db[device].module_info.module_id,
+ &dev_ctrl_db[device].task_info.task,
+ &module_params);
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id,
+ "bcmos_module_create returned error %s (%d), module id %d\n",
+ bcmos_strerror(rc),
+ rc,
+ dev_ctrl_db[device].module_info.module_id);
+ }
+ return rc;
+}
+
+static bcmos_errno dev_ctrl_init_tasks(bcmolt_devid device)
+{
+ bcmos_task_parm task_params = {};
+ bcmos_errno rc = BCM_ERR_OK;
+ snprintf(dev_ctrl_db[device].task_info.name, sizeof(dev_ctrl_db[device].task_info.name), "dev_ctrl%u", device);
+ task_params.name = dev_ctrl_db[device].task_info.name;
+ task_params.priority = TASK_PRIORITY_DEVICE_CONTROL;
+ task_params.core = BCMOS_CPU_CORE_ANY; /* No CPU affinity */
+ task_params.init_handler = NULL;
+ task_params.data = (long)device;
+ rc = bcmos_task_create(&dev_ctrl_db[device].task_info.task, &task_params);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcmos_task_create()\n");
+
+ return rc;
+}
+
+static void dev_ctrl_mod_msg_handler(bcmos_module_id module_id, bcmos_msg *os_msg)
+{
+ bcmolt_msg *msg;
+ bcmolt_devid device;
+
+ device = DEVICE_ID_FROM_MODULE_ID(module_id);
+ msg = os_msg->data;
+
+#ifndef IN_BAND
+#ifdef ENABLE_LOG
+ if (msg->obj_type == BCMOLT_OBJ_ID_LOGGER &&
+ msg->group == BCMOLT_MGT_GROUP_CFG &&
+ msg->type == BCMOLT_MSG_TYPE_GET &&
+ !dev_ctrl_is_connected(dev_ctrl_db[device].device_params.state))
+ {
+ /* The device is not ready, but still we can fetch the logger file from SRAM. */
+ msg->err = dev_ctrl_get_dev_log(device, (bcmolt_logger_cfg *)msg);
+ msg->dir = BCMOLT_MSG_DIR_RESPONSE;
+ bcmtrmux_control_to_host(device, msg);
+ bcmolt_msg_free(msg);
+ return;
+ }
+#endif
+
+ if (msg->obj_type == BCMOLT_OBJ_ID_SOFTWARE_ERROR &&
+ msg->group == BCMOLT_MGT_GROUP_CFG &&
+ (msg->type == BCMOLT_MSG_TYPE_GET || msg->type == BCMOLT_MSG_TYPE_GET_MULTI) &&
+ !dev_ctrl_is_connected(dev_ctrl_db[device].device_params.state))
+ {
+ /* get sw error table from SRAM */
+ msg->err = dev_ctrl_sw_error_get(device, msg);
+ msg->dir = BCMOLT_MSG_DIR_RESPONSE;
+ bcmtrmux_control_to_host(device, msg);
+ bcmolt_msg_free(msg);
+ return;
+ }
+#endif
+
+ if (msg->obj_type == BCMOLT_OBJ_ID_DEBUG)
+ {
+ bcmolt_debug_ctrl_process_msg(device, msg, dev_ctrl_is_connected(dev_ctrl_db[device].device_params.state));
+ return;
+ }
+
+ if (msg->obj_type != BCMOLT_OBJ_ID_DEVICE)
+ {
+ bcmolt_msg_err(
+ msg,
+ DEV_LOG_INVALID_ID,
+ BCM_ERR_INTERNAL,
+ BCMOLT_ERR_FIELD_NONE,
+ "Can't access target when disconnected");
+ msg->dir = BCMOLT_MSG_DIR_RESPONSE;
+ bcmtrmux_control_to_host(device, msg);
+ bcmolt_msg_free(msg);
+ }
+ else if (msg->group == BCMOLT_MGT_GROUP_AUTO)
+ {
+ dev_ctrl_process_msg(device, msg);
+ }
+ else if (msg->dir == BCMOLT_MSG_DIR_RESPONSE)
+ {
+ if (msg->group == BCMOLT_MGT_GROUP_OPER && msg->subgroup == BCMOLT_DEVICE_OPER_ID_HOST_KEEP_ALIVE)
+ {
+ /* Just free it, otherwise ignore keepalive oper responses */
+ bcmolt_msg_free(msg);
+ }
+ else if ((dev_ctrl_db[device].device_params.state == BCMOLT_DEVICE_STATE_WAITING_FOR_DEVICE) || (dev_ctrl_db[device].device_params.state == BCMOLT_DEVICE_STATE_CONNECTING))
+ {
+ dev_ctrl_process_msg(device, msg);
+ }
+ else
+ {
+ BCM_LOG(INFO, dev_ctrl_db[device].log_id, "received unexpected response: group=%u subgroup=%u\n", msg->group, msg->subgroup);
+ bcmolt_msg_free(msg);
+ }
+ }
+ else if (dev_ctrl_db[device].device_params.state != BCMOLT_DEVICE_STATE_CONNECTING)
+ {
+ msg->err = dev_ctrl_validate_msg(device, msg);
+ if (msg->err == BCM_ERR_OK)
+ {
+ dev_ctrl_process_msg(device, msg);
+ }
+ else
+ {
+ msg->dir = BCMOLT_MSG_DIR_RESPONSE;
+ bcmtrmux_control_to_host(device, msg);
+ bcmolt_msg_free(msg);
+ }
+ }
+ else
+ {
+ bcmolt_msg_err(msg, DEV_LOG_INVALID_ID, BCM_ERR_STATE, BCMOLT_ERR_FIELD_NONE, "Device is busy");
+ msg->dir = BCMOLT_MSG_DIR_RESPONSE;
+ bcmtrmux_control_to_host(device, msg);
+ bcmolt_msg_free(msg);
+ }
+}
+
+static void dev_ctrl_mod_msg_release(bcmos_msg *os_msg)
+{
+ bcmolt_msg_free(container_of(os_msg, bcmolt_msg, os_msg));
+}
+
+static bcmos_msg dev_ctrl_ipc_msg = { .handler = dev_ctrl_mod_msg_handler, .release = dev_ctrl_mod_msg_release };
+
+static void bcmdev_rx_handler(bcmolt_devid device, bcmolt_msg *msg, void *data)
+{
+ bcmos_errno rc;
+
+ msg->os_msg = dev_ctrl_ipc_msg;
+ msg->os_msg.data = msg;
+ rc = bcmos_msg_send_to_module(dev_ctrl_db[device].module_info.module_id, &msg->os_msg, BCMOS_MSG_SEND_AUTO_FREE);
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id,
+ "bcmos_msg_send_to_module returned error %s (%d), module id %d\n",
+ bcmos_strerror(rc),
+ rc,
+ dev_ctrl_db[device].module_info.module_id);
+ }
+}
+
+#ifndef IN_BAND
+static bcmos_timer_rc exception_monitor_timer_handler(bcmos_timer *timer, long data)
+{
+ bcmolt_devid device = (bcmolt_devid)data;
+ bcmos_errno rc;
+
+ if (!dev_ctrl_is_connected(dev_ctrl_db[device].device_params.state))
+ {
+ return BCM_ERR_OK; /* in case this happens during a disconnect/reset operation */
+ }
+
+ rc = dev_ctrl_get_exception_log_if_present(device);
+ if (rc != BCM_ERR_OK && rc != BCM_ERR_NOENT)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "cant read Exception log for device %d error %s (%d)\n", device, bcmos_strerror(rc), rc);
+ }
+ return BCMOS_TIMER_OK;
+}
+#endif
+
+static bcmos_timer_rc device_response_timer_handler(bcmos_timer *timer, long data)
+{
+ bcmolt_devid device = (bcmolt_devid)data;
+ dev_ctrl_sm_call_state_cb(device, DEVICE_CONTROL_EVENT_DEVICE_TIMER_TIMEOUT, NULL);
+ return BCMOS_TIMER_OK;
+}
+
+static bcmos_timer_rc reset_delay_timer_handler(bcmos_timer *timer, long data)
+{
+ bcmos_errno rc = dev_ctrl_params.host_reset_cb();
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[(bcmolt_devid)data].log_id, "Host reset callback failed: %s (%d)\n", bcmos_strerror(rc), rc);
+ }
+ return BCMOS_TIMER_OK;
+}
+
+static bcmos_errno dev_ctrl_timer_create(
+ bcmolt_devid device,
+ bcmos_module_id module_id,
+ dev_ctrl_timer *timer,
+ const char *name,
+ bcmos_bool periodic,
+ F_bcmos_timer_handler handler)
+{
+ bcmos_timer_parm timer_params = {};
+ bcmos_errno rc = BCM_ERR_OK;
+
+ snprintf(timer->name, sizeof(timer->name), "dev_ctrl_%s_timer%u", name, device);
+ timer_params.name = timer->name;
+ timer_params.owner = module_id;
+ timer_params.periodic = periodic;
+ timer_params.handler = handler;
+ timer_params.data = device;
+ rc = bcmos_timer_create(&timer->timer, &timer_params);
+ if (rc != BCM_ERR_OK)
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id,
+ "'%s' timer creation failed, bcmos_timer_create returned error %s (%d)\n",
+ timer->name,
+ bcmos_strerror(rc),
+ rc);
+ }
+
+ return rc;
+}
+
+#ifndef IN_BAND
+static void dev_ctrl_link_up_down_cb(uint8_t dev_id, bcm_ll_pcie_link_status status)
+{
+ BCM_LOG(INFO, dev_ctrl_db[dev_id].log_id, "Device %u: PCIe link %s\n", dev_id, status == BCM_LL_PCIE_LINK_DOWN ? "down" : "up");
+}
+#endif
+
+static bcmtrmux_msg_dest dev_ctrl_msg_filter_cb(
+ bcmolt_devid device,
+ bcmolt_obj_id obj,
+ bcmolt_mgt_group group,
+ uint16_t subgroup)
+{
+ /* Device control should intercept the message if one of the two happens:
+ * 1. The message object is "device".
+ * 2. The message object is not "device", but the device is not ready, so an appropriate error should be returned to
+ * the host application. */
+ bcmtrmux_msg_dest dest = BCMTRMUX_DEST_REMOTE;
+
+ if (!dev_ctrl_is_connected(dev_ctrl_db[device].device_params.state))
+ {
+ dest = BCMTRMUX_DEST_LOCAL;
+ }
+ else if (obj == BCMOLT_OBJ_ID_DEBUG)
+ {
+ dest = BCMTRMUX_DEST_LOCAL;
+ }
+ else if (obj == BCMOLT_OBJ_ID_DEVICE)
+ {
+ switch (group)
+ {
+ case BCMOLT_MGT_GROUP_OPER:
+ switch (subgroup)
+ {
+ case BCMOLT_DEVICE_OPER_ID_IMAGE_TRANSFER_START:
+ case BCMOLT_DEVICE_OPER_ID_IMAGE_TRANSFER_DATA:
+ case BCMOLT_DEVICE_OPER_ID_SW_UPGRADE_ACTIVATE:
+ return BCMTRMUX_DEST_REMOTE;
+ default:
+ return BCMTRMUX_DEST_LOCAL;
+ }
+ break;
+ default:
+ return BCMTRMUX_DEST_LOCAL;
+ }
+ }
+ return dest;
+}
+
+static void dev_ctrl_init_device_objects(bcmolt_devid device)
+{
+ dev_ctrl_clear_device_cfg(device);
+ dev_ctrl_init_connection_state(device);
+ dev_ctrl_db[device].device_params.state = BCMOLT_DEVICE_STATE_DISCONNECTED;
+ dev_ctrl_db[device].device_params.system_mode = BCMOLT_SYSTEM_MODE__NUM_OF;
+ dev_ctrl_db[device].boot_seq_info.polling_counter = BOOT_SEQ_POLLING_MAX_NUMBER;
+ dev_ctrl_db[device].boot_seq_info.polling_interval = BOOT_SEQ_POLL_INTERVAL_SEC * BCMOS_MICROSECONDS_IN_SECONDS;
+ dev_ctrl_db[device].corr_tag = 0;
+#ifdef ENABLE_LOG
+ dev_ctrl_db[device].sram_log_offset = 0;
+ dev_ctrl_db[device].msgs_read = 0;
+#endif
+
+#ifndef SIMULATION_BUILD
+ dev_ctrl_db[device].trx_disable_mask = 0xFFFF; /* Mark all PONs with TRX disabled. */
+#endif
+
+ dev_ctrl_db[device].conn_fail_reason = BCMOLT_HOST_CONNECTION_FAIL_REASON_NONE;
+ dev_ctrl_db[device].last_event = DEVICE_CONTROL_EVENT_NO_EVENT;
+}
+
+bcmos_errno bcmolt_dev_ctrl_host_event_write(uint32_t device, uint32_t event)
+{
+#ifndef IN_BAND
+ bcmolt_device_state state = dev_ctrl_db[device].device_params.state;
+#endif
+#ifndef SIMULATION_BUILD
+ /* Update local database, so that after reset we will be able to sync this value with the device. */
+ dev_ctrl_db[device].trx_disable_mask = event;
+#endif
+#ifndef IN_BAND
+ /* Notify device using SRAM, but only if we are already connected (otherwise FLD might be not ready). */
+ if (dev_ctrl_is_connected(state))
+ bcm_fld_set_host_event(device, event);
+#endif
+ return BCM_ERR_OK;
+}
+/*Use different function signatures linux kernel device control and other*/
+#if !defined(LINUX_USER_SPACE)
+bcmos_errno bcmolt_dev_ctrl_init(bcmolt_dev_ctrl_params *params)
+#else
+bcmos_errno bcmolt_dev_ctrl_init()
+#endif
+{
+ bcmolt_devid device;
+ bcmos_errno rc = BCM_ERR_OK;
+
+#if !defined(LINUX_USER_SPACE)
+ if (!params->system_mode_validate_cb ||
+ !params->image_read_cb ||
+ !params->device_off_cb ||
+ !params->device_on_cb ||
+ !params->device_is_running_cb ||
+ !params->host_reset_cb ||
+ !params->pcie_channel_prepare_cb ||
+ !params->pcie_channel_remove_cb)
+ {
+ BCMOS_TRACE_ERR("Missing required callbacks\n");
+ return BCM_ERR_PARM;
+ }
+
+ dev_ctrl_params = *params;
+#endif
+ rc = bcmtrmux_init(dev_ctrl_msg_filter_cb);
+ BCMOS_TRACE_CHECK_RETURN(rc, rc, "bcmtrmux_init()\n");
+
+#ifndef IN_BAND
+ rc = bcm_fld_init(BCMTR_MAX_OLTS);
+ BCMOS_TRACE_CHECK_RETURN(rc, rc, "bcm_fld_init()\n");
+#endif
+
+ for (device = 0; device < BCMTR_MAX_OLTS; device++)
+ {
+#ifdef ENABLE_LOG
+ char log_name[MAX_DEV_LOG_ID_NAME];
+ snprintf(log_name, sizeof(log_name) - 1, "dev_ctrl_%u", device);
+ dev_ctrl_db[device].log_id = bcm_dev_log_id_register(log_name, DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
+#endif
+ dev_ctrl_init_device_objects(device);
+ image_buf[device] = bcmos_alloc(IMAGE_BUF_SIZE);
+ if (!image_buf[device])
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Can't allocate packet buffer\n");
+ return BCM_ERR_NOMEM;
+ }
+ rd_image_buf[device] = bcmos_alloc(IMAGE_BUF_SIZE);
+ if (!rd_image_buf[device])
+ {
+ BCM_LOG(ERROR, dev_ctrl_db[device].log_id, "Can't allocate nh_packet buffer\n");
+ return BCM_ERR_NOMEM;
+ }
+ rc = dev_ctrl_init_tasks(device);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "dev_ctrl_init_tasks()\n");
+
+ rc = dev_ctrl_init_modules(device);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "dev_ctrl_init_modules()\n");
+
+ dev_ctrl_db[device].ka_info.orig = BCM_KEEP_ALIVE_MSG_ORIG_HOST;
+ dev_ctrl_db[device].ka_info.send_handler = dev_ctrl_ka_tx_handler;
+ dev_ctrl_db[device].ka_info.disconnect_handler = dev_ctrl_ka_disconnect_handler;
+ dev_ctrl_db[device].ka_info.device = device;
+ rc = create_keep_alive_timer(&dev_ctrl_db[device].ka_info, dev_ctrl_db[device].module_info.module_id);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "create_keep_alive_timer()\n");
+
+ rc = dev_ctrl_timer_create(
+ device,
+ dev_ctrl_db[device].module_info.module_id,
+ &dev_ctrl_db[device].connection_info.timer,
+ "connection",
+ BCMOS_FALSE, /* non-periodic */
+ dev_ctrl_connection_timer_handler);
+ BCMOS_CHECK_RETURN_ERROR(rc, rc);
+
+#ifndef IN_BAND
+ rc = dev_ctrl_timer_create(
+ device,
+ dev_ctrl_db[device].module_info.module_id,
+ &dev_ctrl_db[device].boot_seq_info.timer,
+ "boot_seq",
+ BCMOS_TRUE, /* periodic */
+ dev_ctrl_boot_seq_timer_handler);
+ BCMOS_CHECK_RETURN_ERROR(rc, rc);
+
+ rc = dev_ctrl_timer_create(
+ device,
+ dev_ctrl_db[device].module_info.module_id,
+ &dev_ctrl_db[device].exception_monitor_timer,
+ "exception_monitor",
+ BCMOS_TRUE, /* periodic */
+ exception_monitor_timer_handler);
+ BCMOS_CHECK_RETURN_ERROR(rc, rc);
+#endif
+ rc = dev_ctrl_timer_create(
+ device,
+ dev_ctrl_db[device].module_info.module_id,
+ &dev_ctrl_db[device].device_response_timer,
+ "device_response",
+ BCMOS_FALSE, /* non-periodic */
+ device_response_timer_handler);
+ BCMOS_CHECK_RETURN_ERROR(rc, rc);
+
+ rc = dev_ctrl_timer_create(
+ device,
+ dev_ctrl_db[device].module_info.module_id,
+ &dev_ctrl_db[device].reset_delay_timer,
+ "reset_delay",
+ BCMOS_FALSE, /* non-periodic */
+ reset_delay_timer_handler);
+ BCMOS_CHECK_RETURN_ERROR(rc, rc);
+
+ /* Register callback to MUX */
+ rc = bcmtrmux_local_handler_register(device, bcmdev_rx_handler, (void *)(long)device);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcmtrmux_local_handler_register()\n");
+
+ /* Intercept CONNECTION_ESTABLISHED, DEVICE_READY, KEEP_ALIVE messages */
+ rc = bcmtrmux_control_auto_intercept_filter(
+ device,
+ BCMOLT_OBJ_ID_DEVICE,
+ BCMOLT_DEVICE_AUTO_ID_CONNECTION_ESTABLISHED);
+ rc = rc ? rc : bcmtrmux_control_auto_intercept_filter(
+ device,
+ BCMOLT_OBJ_ID_DEVICE,
+ BCMOLT_DEVICE_AUTO_ID_DEVICE_READY);
+ rc = rc ? rc : bcmtrmux_control_auto_intercept_filter(
+ device,
+ BCMOLT_OBJ_ID_DEVICE,
+ BCMOLT_DEVICE_AUTO_ID_DEVICE_KEEP_ALIVE);
+ BCM_DEV_CTRL_RETURN_ON_ERROR(device, rc, "bcmtrmux_control_auto_intercept_filter()\n");
+ }
+#ifndef IN_BAND
+ /* Register for link_up / link_down interrupt */
+ bcm_ll_pcie_status_change_register(dev_ctrl_link_up_down_cb);
+#endif
+
+ bcmolt_debug_ctrl_init();
+
+ return rc;
+}
+
+void bcmolt_dev_ctrl_exit(void)
+{
+#ifndef IN_BAND
+ bcmolt_devid device;
+
+ for (device = 0; device < BCMTR_MAX_OLTS; device++)
+ {
+ bcmtrmux_local_handler_unregister(device);
+ bcmos_free(image_buf[device]);
+ bcmos_free(rd_image_buf[device]);
+ bcmos_timer_destroy(&dev_ctrl_db[device].connection_info.timer.timer);
+ bcmos_timer_destroy(&dev_ctrl_db[device].ka_info.ka_timer.timer);
+ bcmos_timer_destroy(&dev_ctrl_db[device].boot_seq_info.timer.timer);
+ bcmos_timer_destroy(&dev_ctrl_db[device].exception_monitor_timer.timer);
+ bcmos_timer_destroy(&dev_ctrl_db[device].device_response_timer.timer);
+ bcmos_timer_destroy(&dev_ctrl_db[device].reset_delay_timer.timer);
+ bcmos_module_destroy(dev_ctrl_db[device].module_info.module_id);
+ bcmos_task_destroy(&dev_ctrl_db[device].task_info.task);
+ }
+#endif
+#ifndef IN_BAND
+ bcm_fld_exit();
+#endif
+ bcmtrmux_exit();
+#ifndef IN_BAND
+ bcm_ll_pcie_status_change_unregister();
+#endif
+}
diff --git a/bcm68620_release/release/host_driver/dev_ctrl/bcmolt_dev_ctrl.h b/bcm68620_release/release/host_driver/dev_ctrl/bcmolt_dev_ctrl.h
new file mode 100644
index 0000000..7187ba3
--- /dev/null
+++ b/bcm68620_release/release/host_driver/dev_ctrl/bcmolt_dev_ctrl.h
@@ -0,0 +1,205 @@
+/*
+<: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.
+
+:>
+ */
+
+#ifndef _BCMOLT_DEV_CTRL_H_
+#define _BCMOLT_DEV_CTRL_H_
+
+#include <bcmos_system.h>
+#include <bcmolt_msg.h>
+#include <bcmolt_model_types.h>
+#include "bcm_keep_alive.h"
+#include "bcmolt_fld.h"
+#include "bcmolt_sw_error.h"
+
+typedef int (*bcmolt_dev_ctrl_cb_image_read)(
+ bcmolt_devid device,
+ bcmolt_device_image_type image_type,
+ uint32_t offset,
+ uint8_t *buf,
+ uint32_t buf_size);
+typedef bcmos_errno (*bcmolt_dev_ctrl_cb_system_mode_validate)(bcmolt_devid device, bcmolt_system_mode system_mode);
+typedef bcmos_errno (*bcmolt_dev_ctrl_cb_device_off)(bcmolt_devid device);
+typedef bcmos_errno (*bcmolt_dev_ctrl_cb_device_on)(bcmolt_devid device);
+typedef bcmos_errno (*bcmolt_dev_ctrl_cb_device_is_running)(bcmolt_devid device, bcmos_bool *is_running);
+typedef bcmos_errno (*bcmolt_dev_ctrl_cb_host_reset)(void);
+typedef bcmos_errno (*bcmolt_dev_ctrl_cb_pcie_channel_prepare)(bcmolt_devid device);
+typedef bcmos_errno (*bcmolt_dev_ctrl_cb_pcie_channel_remove)(bcmolt_devid device);
+typedef bcmos_errno (*bcmolt_dev_ctrl_cb_pcie_status_get)(bcmolt_devid device, bcmos_bool *is_prepared);
+
+typedef struct
+{
+ bcmolt_dev_ctrl_cb_system_mode_validate system_mode_validate_cb;
+ bcmolt_dev_ctrl_cb_image_read image_read_cb;
+ bcmolt_dev_ctrl_cb_device_off device_off_cb;
+ bcmolt_dev_ctrl_cb_device_on device_on_cb;
+ bcmolt_dev_ctrl_cb_device_is_running device_is_running_cb;
+ bcmolt_dev_ctrl_cb_host_reset host_reset_cb;
+ bcmolt_dev_ctrl_cb_pcie_channel_prepare pcie_channel_prepare_cb;
+ bcmolt_dev_ctrl_cb_pcie_channel_remove pcie_channel_remove_cb;
+} bcmolt_dev_ctrl_params;
+
+#define DEVICE_CONTROL_MSG_QUEUE_SIZE BCMOS_MSG_POOL_DEFAULT_SIZE
+#define IMAGE_BUF_SIZE (1 * 1024 * 1024) /* 1MB */
+#define BOOT_SEQ_POLL_INTERVAL_SEC 1
+#define BOOT_SEQ_POLLING_MAX_NUMBER 5
+#define DDR_TEST_POLLING_MAX_NUMBER 20
+#define DEVICE_CONTROL_CONFIG_TIME_US (15 * 1000000) /* 15 seconds */
+#define DEVICE_CONTROL_CONNECT_TIME_US (40 * 1000000) /* 40 seconds */
+#define CONFIG_SEND_MAX_NUMBER 2
+#define FILE_PATH_LEN 128
+#define HOST_DMA_RX_DEFAULT_QUEUE_SIZE 128
+#define HOST_DMA_TX_DEFAULT_QUEUE_SIZE 128
+#define EXCEPTION_LOG_MONITOR_INTERVAL (5 * 1000000) /* 5 second */
+#define DEVICE_RESPONSE_TIMEOUT_LENGTH (2 * 100000) /* 200 milliseconds */
+#define HOST_RESET_DELAY_US 100000 /* how long to wait before resetting the host via callback (100ms) */
+
+/* indicates successful connection - used internally, no need to expose this in the host-facing enum */
+#define BCMOLT_HOST_CONNECTION_FAIL_REASON_NONE ((bcmolt_host_connection_fail_reason)0xFF)
+
+typedef enum
+{
+ DEVICE_CONTROL_EVENT_DEVICE_CLEAR,
+ DEVICE_CONTROL_EVENT_DEVICE_CONFIG_SET,
+ DEVICE_CONTROL_EVENT_DEVICE_CONFIG_GET,
+ DEVICE_CONTROL_EVENT_DEVICE_TIMER_TIMEOUT,
+ DEVICE_CONTROL_EVENT_DEVICE_RECEIVED_ACK,
+ DEVICE_CONTROL_EVENT_DEVICE_DISCONNECT,
+ DEVICE_CONTROL_EVENT_DEVICE_CONNECT,
+ DEVICE_CONTROL_EVENT_DEVICE_RESET,
+ DEVICE_CONTROL_EVENT_CONNECTION_FAILURE,
+ DEVICE_CONTROL_EVENT_CONNECTION_ESTABLISHED,
+ DEVICE_CONTROL_EVENT_DEVICE_READY,
+ DEVICE_CONTROL_EVENT_RUN_DDR_TEST,
+ DEVICE_CONTROL_EVENT_DDR_TEST_COMPLETED,
+ DEVICE_CONTROL_EVENT_DDR_TEST_TIMEOUT,
+
+ DEVICE_CONTROL_EVENT__NUM_OF,
+ DEVICE_CONTROL_EVENT_NO_EVENT = DEVICE_CONTROL_EVENT__NUM_OF
+} dev_ctrl_event;
+
+typedef enum
+{
+ DEV_CTRL_CONNECTING_STATE_ESTABLISHING, /* writing software via FLD, waiting for "connection established" */
+ DEV_CTRL_CONNECTING_STATE_CONFIGURING, /* connection established, cfg sent, waiting for "device ready" */
+ DEV_CTRL_CONNECTING_STATE_STANDALONE, /* connecting to a standalone device, waiting for "device ready" */
+} dev_ctrl_connecting_state;
+
+typedef struct
+{
+ char name[MAX_TASK_NAME_SIZE];
+ bcmos_task task;
+} dev_ctrl_task;
+
+typedef struct
+{
+ char name[MAX_MODULE_NAME_SIZE];
+ bcmos_module_id module_id;
+} dev_ctrl_module;
+
+typedef struct
+{
+ char name[MAX_TIMER_NAME_SIZE];
+ bcmos_timer timer;
+} dev_ctrl_timer;
+
+typedef struct
+{
+ uint32_t pcie_addr;
+} dev_ctrl_pcie;
+
+typedef struct
+{
+ dev_ctrl_connecting_state state;
+ uint32_t config_send_counter;
+ uint32_t config_interval;
+ dev_ctrl_timer timer;
+} dev_ctrl_connection;
+
+typedef struct
+{
+ uint32_t polling_counter;
+ uint32_t polling_interval;
+ dev_ctrl_timer timer;
+} dev_ctrl_boot_seq;
+
+typedef struct
+{
+ dev_ctrl_task task_info;
+ dev_ctrl_module module_info;
+ dev_ctrl_connection connection_info;
+ dev_ctrl_pcie pcie_info;
+ bcmos_keep_alive_info ka_info;
+ dev_ctrl_boot_seq boot_seq_info;
+ bcm_fld_device_info fld_info;
+ bcmolt_device_cfg_data device_params;
+ bcmolt_presence_mask device_params_present;
+ dev_ctrl_timer exception_monitor_timer;
+ uint16_t corr_tag;
+ bcmolt_msg * last_message;
+ dev_ctrl_timer device_response_timer;
+ dev_ctrl_timer reset_delay_timer;
+ bcmos_bool is_host_reset_pending;
+#ifdef ENABLE_LOG
+ uint32_t sram_log_offset;
+ uint32_t msgs_read;
+#endif
+ bcmolt_control_state enable_tod;
+#ifndef SIMULATION_BUILD
+ uint32_t trx_disable_mask;
+#endif
+ dev_ctrl_event last_event;
+ bcmolt_host_connection_fail_reason conn_fail_reason;
+ uint32_t sw_error_count;
+ bcmolt_sw_error sw_errors[30];
+ dev_log_id log_id;
+} dev_ctrl_database;
+
+typedef void (*dev_ctrl_sm_cb)(bcmolt_devid device, const bcmolt_msg *msg);
+
+#define DEVICE_ID_FROM_MODULE_ID(module_id) ((bcmolt_devid)(module_id - BCMOS_MODULE_ID_DEV_CTRL_DEV0))
+#define MODULE_ID_FROM_DEVICE_ID(device) ((bcmos_module_id)(device + BCMOS_MODULE_ID_DEV_CTRL_DEV0))
+
+const char *bcm_str_device_state(bcmolt_device_state device_state);
+const char *bcm_str_device_event(dev_ctrl_event device_event);
+const char *bcm_str_host_connection_fail_reason(bcmolt_host_connection_fail_reason reason);
+const char *bcm_str_host_connecting_state(dev_ctrl_connecting_state state);
+void dev_ctrl_read_db(bcmolt_devid device, dev_ctrl_database *db);
+
+bcmos_errno bcmolt_dev_ctrl_host_event_write(uint32_t device, uint32_t event);
+
+/*Use different function signatures linux kernel device control and other*/
+#if !defined(LINUX_USER_SPACE)
+bcmos_errno bcmolt_dev_ctrl_init(bcmolt_dev_ctrl_params *params);
+#else
+bcmos_errno bcmolt_dev_ctrl_init(void);
+#endif
+
+void bcmolt_dev_ctrl_exit(void);
+
+#endif