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