blob: 382499649719be507932c57dc4961b5b3f752b17 [file] [log] [blame]
/******************************************************************************
*
* <:copyright-BRCM:2016:DUAL/GPL:standard
*
* Copyright (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.
*
* :>
*
*****************************************************************************/
/**
* @file bal_mac_util.c
*
* @brief mac util interfaces definition used by Bal Core
*
* This file expose the APIs to the core to configure the mac
* with regarding to the operation of access terminal, interface, subscriber terminal and flow.
*
* @addtogroup mac_util
*/
/*@{*/
#include <bal_mac_util.h>
#include <bal_mac_util_common_itu_pon.h>
#include <bal_mac_util_epon.h>
#include <bal_worker.h>
#include <bal_core.h>
#include <bal_cli.h>
#ifdef BOARD
#include <bcmolt_board.h>
#include <bcmolt_board_cli.h>
#endif
#include <bcm_api_cli.h>
#include <bcmolt_dev_selector.h>
#include <bcmolt_host_sw_version.h>
#include <bcmolt_model_revision.h>
#ifdef ENABLE_LOG
#define INBOLD_BAD(a) "\033[31m"a"\033[0m"
/*
* mac util logging for generic logging, as well as on per PON basis
*/
dev_log_id log_id_mac_util;
dev_log_id log_id_mac_util_pon_if[NUM_SUPPORTED_SUBSCRIBER_INTERFACES];
/** @def size of log Id string */
#define MAC_UTIL_LOG_STR_SZ 64
/** @def to make a log string for a PON interface, to register with logging module during initialization */
#define MAC_UTIL_MAKE_LOG_STR_FOR_PON_IF(_pon_if_id, _buf, _buf_sz) \
do \
{ \
int n = 0; \
n = snprintf((_buf), (_buf_sz), "MAC_UTIL_PON_%d", (_pon_if_id)); \
BUG_ON((0 > n) || ((_buf_sz) <= n)); \
} while (0); \
static bcmos_errno mac_util_register_logging_per_pon (void);
#endif //ENABLE_LOG
/* This is not exposed in the object model, so we can use BCMOLT_SYSTEM_MODE__NUM_OF as a special value for loopback. */
#define BCMOLT_SYSTEM_MODE_LOOPBACK BCMOLT_SYSTEM_MODE__NUM_OF
#define BCM_TOPO_PON_MODE_LOOPBACK BCM_TOPO_PON_MODE__NUM_OF
static bcmos_errno mac_util_indication_handle_for_device (bcmolt_devid device_id, bcmolt_msg *p_msg);
static bcmos_errno mac_util_system_mode_get(bcmolt_devid device_id);
/* Maple CLI directory */
static bcmcli_entry *maple_dir;
/** @brief array stores the list of device related auto indications from Maple to subscribe */
static mac_util_ind_obj_and_handlers mac_util_device_ind_handlers[] =
{
{BCMOLT_OBJ_ID_DEVICE, "BCMOLT_OBJ_ID_DEVICE", mac_util_indication_handle_for_device}
};
#if !defined(WRX_BUILD)
/* external structures to be used with bcmos_tr
* specifying IP:Port assignments of the remote mac device */
extern uint32_t bcmtr_olt_ip[BCMTR_MAX_OLTS];
extern uint16_t bcmtr_olt_udp_port[BCMTR_MAX_OLTS];
extern uint16_t bcmtr_host_udp_port;
#endif
/**
* @brief BAL request handlers for system mode specific set & validate
**/
static mac_util_bal_req_handlers_for_system_mode_t mac_util_bal_req_handlers_for_system_mode[] =
{
[BCMOLT_SYSTEM_MODE_GPON__16_X] =
{
.acc_term_set = mac_util_access_terminal_set_for_gpon_16,
.acc_term_post_indication_set = mac_util_access_terminal_post_indication_set_for_gpon
},
[BCMOLT_SYSTEM_MODE_GPON__8_X] =
{
.acc_term_set = mac_util_access_terminal_set_for_gpon_8,
.acc_term_post_indication_set = mac_util_access_terminal_post_indication_set_for_gpon
},
[BCMOLT_SYSTEM_MODE_XGPON_1__8_X] =
{
.acc_term_set = mac_util_access_terminal_set_for_xgpon_8,
.acc_term_post_indication_set = mac_util_access_terminal_post_indication_set_for_xgpon_xgs
},
[BCMOLT_SYSTEM_MODE_XGS__2_X_10_G] =
{
.acc_term_set = mac_util_access_terminal_set_for_xgs,
.acc_term_post_indication_set = mac_util_access_terminal_post_indication_set_for_xgpon_xgs
},
[BCMOLT_SYSTEM_MODE_EPON__8_X_COEXISTENCE_TDMA] =
{
.acc_term_set = mac_util_access_terminal_set_for_epon_8_tdma,
.acc_term_post_indication_set = NULL
},
[BCMOLT_SYSTEM_MODE_EPON__4_X_COEXISTENCE_TDMA] =
{
.acc_term_set = mac_util_access_terminal_set_for_epon_4_tdma,
.acc_term_post_indication_set = NULL
},
[BCMOLT_SYSTEM_MODE_EPON__16_X] =
{
.acc_term_set = mac_util_access_terminal_set_for_epon_16_1g,
.acc_term_post_indication_set = NULL
},
[BCMOLT_SYSTEM_MODE_EPON__8_X] =
{
.acc_term_set = mac_util_access_terminal_set_for_epon_8_1g,
.acc_term_post_indication_set = NULL
},
[BCMOLT_SYSTEM_MODE_EPON__4_X] =
{
.acc_term_set = mac_util_access_terminal_set_for_epon_4_1g,
.acc_term_post_indication_set = NULL
},
[BCMOLT_SYSTEM_MODE_EPON__8_X_10_G] =
{
.acc_term_set = mac_util_access_terminal_set_for_epon_8_10g,
.acc_term_post_indication_set = NULL
},
[BCMOLT_SYSTEM_MODE_EPON__4_X_10_G] =
{
.acc_term_set = mac_util_access_terminal_set_for_epon_4_10g,
.acc_term_post_indication_set = NULL
},
[BCMOLT_SYSTEM_MODE_EPON__2_X_10_G] =
{
.acc_term_set = mac_util_access_terminal_set_for_epon_2_10g,
.acc_term_post_indication_set = NULL
},
[BCMOLT_SYSTEM_MODE_LOOPBACK] =
{
.acc_term_set = mac_util_access_terminal_set_for_loopback,
.acc_term_post_indication_set = NULL
}
};
/**
* @brief BAL request handlers for PON protocol specific set & validate
*
* @note The handling would be like object-oriented programming. The common
* handling would be done in the top level call. And then based on protocol,
* the mac specific handling will be done in the corresponding mac specific
* handler functions.
**/
mac_util_handlers_per_pon_mode_t mac_util_bal_req_handlers_for_pon_mode [BCM_TOPO_PON_MODE__NUM_OF + 1] =
{
[BCM_TOPO_PON_MODE_GPON] =
{
.if_validate = NULL,
.if_set = mac_util_interface_set_for_gpon,
.sub_term_validate = mac_util_validate_subscriber_terminal_info_for_gpon,
.sub_term_set = mac_util_subscriber_terminal_set_for_gpon,
.flow_validate = mac_util_validate_flow_info_for_gpon,
.flow_set = mac_util_flow_set_for_gpon,
.group_validate = NULL,
.group_set = mac_util_group_set_for_gpon,
.sla_us_rate_factor = 1
},
[BCM_TOPO_PON_MODE_XGPON] =
{
.if_validate = NULL,
.if_set = mac_util_interface_set_for_xgpon,
.sub_term_validate = mac_util_validate_subscriber_terminal_info_for_xgpon,
.sub_term_set = mac_util_subscriber_terminal_set_for_xgpon,
.flow_validate = mac_util_validate_flow_info_for_xgpon,
.flow_set = mac_util_flow_set_for_xgpon,
.group_validate = NULL,
.group_set = mac_util_group_set_for_xgpon,
.sla_us_rate_factor = 2
},
[BCM_TOPO_PON_MODE_XGS] =
{
.if_validate = NULL,
.if_set = mac_util_interface_set_for_xgpon,
.sub_term_validate = mac_util_validate_subscriber_terminal_info_for_xgpon,
.sub_term_set = mac_util_subscriber_terminal_set_for_xgpon,
.flow_validate = mac_util_validate_flow_info_for_xgpon,
.flow_set = mac_util_flow_set_for_xgpon,
.group_validate = NULL,
.group_set = mac_util_group_set_for_xgpon,
.sla_us_rate_factor = 8
},
[BCM_TOPO_PON_MODE_EPON_TDMA] =
{
.if_validate = NULL,
.if_set = mac_util_interface_set_for_epon,
.sub_term_validate = NULL,
.sub_term_set = NULL,
.flow_validate = NULL,
.flow_set = NULL,
.group_validate = NULL,
.group_set = NULL,
.sla_us_rate_factor = 0
},
[BCM_TOPO_PON_MODE_EPON_1G] =
{
.if_validate = NULL,
.if_set = mac_util_interface_set_for_epon,
.sub_term_validate = NULL,
.sub_term_set = NULL,
.flow_validate = NULL,
.flow_set = NULL,
.group_validate = NULL,
.group_set = NULL,
.sla_us_rate_factor = 0
},
[BCM_TOPO_PON_MODE_EPON_10G] =
{
.if_validate = NULL,
.if_set = mac_util_interface_set_for_epon,
.sub_term_validate = NULL,
.sub_term_set = NULL,
.flow_validate = NULL,
.flow_set = NULL,
.group_validate = NULL,
.group_set = NULL,
.sla_us_rate_factor = 0
},
[BCM_TOPO_PON_MODE_LOOPBACK] =
{
.if_validate = NULL,
.if_set = mac_util_interface_set_for_loopback,
.sub_term_validate = NULL,
.sub_term_set = mac_util_subscriber_terminal_set_for_loopback,
.flow_validate = NULL,
.flow_set = mac_util_flow_set_for_loopback,
.group_validate = NULL,
.group_set = NULL,
.sla_us_rate_factor = 1
}
};
static f_bcmolt_msg_handler g_indication_handler;
static bcm_topo_pon_mode mac_util_get_pon_mode(uint32_t logical_intf_id)
{
bcm_topo_pon_mode mode;
if (bcmbal_is_mac_in_loopback())
mode = BCM_TOPO_PON_MODE_LOOPBACK;
else
mode = bcm_topo_pon_get_pon_mode(logical_intf_id);
return mode;
}
static uint16_t oper_status_from_pon_state_get(uint32_t logical_intf_id, uint16_t state)
{
uint16_t oper_status;
bcm_topo_pon_family pon_family;
pon_family = bcm_topo_pon_get_pon_family(logical_intf_id);
switch (pon_family)
{
case BCM_TOPO_PON_FAMILY_EPON:
oper_status = (((bcmolt_epon_ni_en_state)state == BCMOLT_EPON_NI_EN_STATE_ENABLED) ?
BAL_UTIL_OPER_IF_UP : BAL_UTIL_OPER_IF_DOWN);
break;
case BCM_TOPO_PON_FAMILY_GPON:
oper_status = (((bcmolt_pon_state)state == BCMOLT_PON_STATE_ACTIVE_WORKING) ?
BAL_UTIL_OPER_IF_UP : BAL_UTIL_OPER_IF_DOWN);
break;
case BCM_TOPO_PON_FAMILY_INVALID:
default:
BCMOS_TRACE_ERR("Unknown PON family on intf %u: %d\n", logical_intf_id, pon_family);
oper_status = BAL_UTIL_OPER_IF_DOWN;
break;
}
return oper_status;
}
/*****************************************************************************/
/**
* @brief Function to send a util indication message to the core
*
* @param msg_payload A pointer to a well formed MAC util indication message
*
* @returns bcmos_errno == BCM_ERR_OK
*
*****************************************************************************/
static bcmos_errno mac_util_ind_send(bal_util_msg_ind *msg_payload)
{
bcmos_errno rc;
rc = bcmos_msg_dispatch(bcmbal_bcmos_hdr_get(msg_payload), BCMOS_MSG_SEND_AUTO_FREE);
if (rc)
{
BCM_LOG(ERROR, log_id_mac_util,
"Couldn't dispatch indication message from MAC util (%d:%d)\n",
(int)(bcmbal_bcmos_hdr_get(msg_payload))->type,
(int)(bcmbal_bcmos_hdr_get(msg_payload))->instance);
}
return rc;
}
/*****************************************************************************/
/**
* @brief Function to send a util auto indication message to the core
*
* @param msg_payload A pointer to a well formed MAC util indication message
*
* @returns bcmos_errno == BCM_ERR_OK
*
*****************************************************************************/
static bcmos_errno mac_util_auto_ind_send(bal_util_msg_auto_ind *msg_payload)
{
bcmos_errno rc;
rc = bcmos_msg_dispatch(bcmbal_bcmos_hdr_get(msg_payload), BCMOS_MSG_SEND_AUTO_FREE);
if (rc)
{
BCM_LOG(ERROR, log_id_mac_util,
"Couldn't dispatch auto indication message from MAC util (%d:%d)\n",
(int)(bcmbal_bcmos_hdr_get(msg_payload))->type,
(int)(bcmbal_bcmos_hdr_get(msg_payload))->instance);
}
return rc;
}
/* Report acc_term event */
void mac_util_report_acc_term_event(uint16_t event)
{
bal_util_msg_ind *p_bal_util_ind_msg;
if(NULL != (p_bal_util_ind_msg = bcmbal_msg_calloc(sizeof(bal_util_msg_ind))))
{
p_bal_util_ind_msg->version = BAL_UTIL_MSG_VERSION;
/* device connect */
if (BCMOLT_DEVICE_AUTO_ID_CONNECTION_COMPLETE == event)
{
p_bal_util_ind_msg->status = BCM_ERR_OK;
}
else
{
p_bal_util_ind_msg->status = BCM_ERR_PARM;
}
bcmbal_msg_hdr_set(p_bal_util_ind_msg,
BCMBAL_MAC_UTIL_MSG,
BAL_MSG_TYPE_IND,
BAL_SUBSYSTEM_MAC_UTIL,
BCMBAL_OBJ_ID_ACCESS_TERMINAL,
BAL_UTIL_OPER_ACC_TERM_CONNECT,
0);
BCM_LOG(INFO, log_id_mac_util, "Reporting to Core: BAL_UTIL_OPER_ACC_TERM_CONNECT indication. Status=%s\n",
bcmos_strerror(p_bal_util_ind_msg->status));
mac_util_ind_send(p_bal_util_ind_msg);
}
else
{
BCM_LOG(ERROR, log_id_mac_util, "Could not allocate memory for access-terminal IND message\n");
}
}
/**
* @brief Report interface event
* @note we consider both err and result for reporting the status to Core
* */
void mac_util_report_if_event(bcmbal_intf_id intf_id,
bcmbal_intf_type intf_type,
bcmos_errno err,
bcmolt_result result,
bcmolt_pon_state new_state)
{
bal_util_msg_ind *p_bal_util_ind_msg;
if(NULL != (p_bal_util_ind_msg = bcmbal_msg_calloc(sizeof(bal_util_msg_ind))))
{
/** @todo validate inf_id is within range based on intf_type */
p_bal_util_ind_msg->version = BAL_UTIL_MSG_VERSION;
p_bal_util_ind_msg->obj_key.if_key.intf_id = intf_id;
p_bal_util_ind_msg->obj_key.if_key.intf_type = intf_type;
if ((BCM_ERR_OK == err) && (BCMOLT_RESULT_SUCCESS != result))
{
err = BCM_ERR_INTERNAL;
}
p_bal_util_ind_msg->status = err;
bcmbal_msg_hdr_set(p_bal_util_ind_msg,
BCMBAL_MAC_UTIL_MSG,
BAL_MSG_TYPE_IND,
BAL_SUBSYSTEM_MAC_UTIL,
BCMBAL_OBJ_ID_INTERFACE,
oper_status_from_pon_state_get(intf_id, new_state),
0);
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(intf_id), "Reporting to Core: interface id %d %s indication: %s\n",
intf_id,
(BAL_UTIL_OPER_IF_UP == oper_status_from_pon_state_get(intf_id, new_state)) ? "UP" : "DOWN",
bcmos_strerror(p_bal_util_ind_msg->status));
mac_util_ind_send(p_bal_util_ind_msg);
}
else
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(intf_id),
"Could not allocate memory for interface IND message\n");
}
}
/* Report subscriber terminal event */
/**
* @note p_serial_number may be NULL and is only valid when an ONU
* is being reported as DISCOVERED
* @note result is config status reported by Maple, whereas err is messaging status
* between the MAC util & Maple
* */
void mac_util_report_sub_term_event(bcmbal_intf_id pon_ni,
bcmbal_sub_id onu_id,
bcmolt_serial_number *p_serial_number,
bal_util_oper_sub_term oper,
bcmos_errno err,
bcmolt_result result,
bcmolt_activation_fail_reason fail_reason,
bcmolt_epon_tunnel_id tunnel_id)
{
bal_util_msg_ind *p_bal_util_ind_msg;
uint16_t total_msglen;
bcm_topo_pon_family pon_family;
total_msglen = sizeof(bal_util_msg_ind);
pon_family = bcm_topo_pon_get_pon_family(pon_ni);
/**
* @note if pon mode is invalid then this error should have been caught in the validation stage itself.
* However, still checking here to make sure and report an error if needed.
*/
if (pon_family == BCM_TOPO_PON_FAMILY_INVALID)
{
result = BCMOLT_RESULT_FAIL;
}
if (pon_family == BCM_TOPO_PON_FAMILY_EPON)
{
total_msglen += sizeof(bcmolt_epon_tunnel_id);
}
else if(NULL != p_serial_number)
{
total_msglen += sizeof(bcmbal_serial_number);
}
/* consolidate "err" and "result" into one report status */
if ((BCM_ERR_OK == err) && (BCMOLT_RESULT_SUCCESS != result))
{
err = BCM_ERR_INTERNAL;
}
if(NULL != (p_bal_util_ind_msg = bcmbal_msg_calloc(total_msglen)))
{
/* set the object key */
p_bal_util_ind_msg->obj_key.sub_term_key.intf_id = pon_ni;
p_bal_util_ind_msg->obj_key.sub_term_key.sub_term_id = onu_id;
/* set bal util msg version */
p_bal_util_ind_msg->version = BAL_UTIL_MSG_VERSION;
bcmbal_msg_hdr_set(p_bal_util_ind_msg,
BCMBAL_MAC_UTIL_MSG,
(BAL_UTIL_OPER_SUB_TERM_DISCOVERY == oper) ? BAL_MSG_TYPE_AUTO_IND : BAL_MSG_TYPE_IND,
BAL_SUBSYSTEM_MAC_UTIL,
BCMBAL_OBJ_ID_SUBSCRIBER_TERMINAL,
oper,
0);
/*
* Set all the message header parameters
*/
if ((BCM_ERR_OK == err) &&
(((BAL_UTIL_OPER_SUB_TERM_ADD == oper) && (fail_reason == BCMOLT_ACTIVATION_FAIL_REASON_NONE)) ||
((BAL_UTIL_OPER_SUB_TERM_ADD != oper) && (fail_reason == MAC_UTIL_DEACTIVATION_FAIL_REASON_NONE))) )
{
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(pon_ni),
"Reporting to Core: %s "
"indication from mac util: Success\n",
(BAL_UTIL_OPER_SUB_TERM_ADD == oper) ? "BAL_UTIL_OPER_SUB_TERM_ADD" :
(BAL_UTIL_OPER_SUB_TERM_REMOVE == oper) ? "BAL_UTIL_OPER_SUB_TERM_REMOVE" :
"BAL_UTIL_OPER_SUB_TERM_DISCOVERY");
p_bal_util_ind_msg->status = BCM_ERR_OK;
if (pon_family == BCM_TOPO_PON_FAMILY_EPON)
{
memcpy(&p_bal_util_ind_msg->data, &tunnel_id, sizeof(bcmolt_epon_tunnel_id));
}
else if (NULL != p_serial_number)
{
/* This assumes an identical definition of serial number between BAL and MAPLE */
memcpy(&p_bal_util_ind_msg->data, p_serial_number, sizeof(bcmbal_serial_number));
}
}
else
{
p_bal_util_ind_msg->status = err;
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(pon_ni),
"Reporting to Core: %s Indication from mac util: Failure, with status = %s, fail_reason = %d\n",
((BAL_UTIL_OPER_SUB_TERM_ADD == oper) ? "BAL_UTIL_OPER_SUB_TERM_ADD" :
(BAL_UTIL_OPER_SUB_TERM_REMOVE == oper) ? "BAL_UTIL_OPER_SUB_TERM_REMOVE" :
"BAL_UTIL_OPER_SUB_TERM_DISCOVERY"),
bcmos_strerror(err), fail_reason);
}
mac_util_ind_send(p_bal_util_ind_msg);
}
else
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(pon_ni),
"Could not allocate memory for subscriber-terminal IND message\n");
}
}
/**
* Notify core flow FSM that flow add/modify/remove was success or failed
*
* @param flow_key
* @param pon_if pon interface
* @param op_type ADD, REMOVE, MODIFY
* @param err error code to be sent up
*
**/
static void _mac_util_report_flow_set_indication(bcmbal_flow_key flow_key, uint32_t pon_if, bal_util_oper_flow op_type, bcmos_errno err)
{
bal_util_msg_ind *p_bal_util_ind_msg;
if(NULL != (p_bal_util_ind_msg = bcmbal_msg_calloc(sizeof(bal_util_msg_ind))))
{
BCM_LOG(INFO, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(pon_if), "Reporting to Core: flow %d, %s %s, result=%s\n",
flow_key.flow_id,
(BCMBAL_FLOW_TYPE_UPSTREAM == flow_key.flow_type ? "upstream" :
BCMBAL_FLOW_TYPE_DOWNSTREAM == flow_key.flow_type ? "downstream" :
BCMBAL_FLOW_TYPE_MULTICAST == flow_key.flow_type ? "multicast" :"broadcast"),
(BAL_UTIL_OPER_FLOW_ADD == op_type ? "FLOW ADD":
(BAL_UTIL_OPER_FLOW_REMOVE == op_type ? "FLOW REMOVE" : "FLOW_CLEAR")),
bcmos_strerror(err));
/* set bal app p_msg version */
p_bal_util_ind_msg->version = BAL_UTIL_MSG_VERSION;
p_bal_util_ind_msg->obj_key.flow_key = flow_key;
p_bal_util_ind_msg->status = err; /* set the error code */
bcmbal_msg_hdr_set(p_bal_util_ind_msg,
BCMBAL_MAC_UTIL_MSG,
BAL_MSG_TYPE_IND,
BAL_SUBSYSTEM_MAC_UTIL,
BCMBAL_OBJ_ID_FLOW,
op_type,
0);
mac_util_ind_send(p_bal_util_ind_msg);
}
else
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(pon_if), "Could not allocate memory for flow IND message\n");
}
}
void mac_util_report_tm_sched_set_indication(bcmbal_tm_sched_key tm_sched_key, bcmos_errno err, bcmolt_result ind_result)
{
bal_util_msg_ind *p_bal_util_ind_msg;
if ((BCM_ERR_OK == err) && (BCMOLT_RESULT_SUCCESS != ind_result))
{
err = BCM_ERR_INTERNAL;
}
if(NULL != (p_bal_util_ind_msg = bcmbal_msg_calloc(sizeof(bal_util_msg_ind))))
{
BCM_LOG(INFO, log_id_mac_util, "Reporting to Core: tm sched %d, %s, result=%s\n",
tm_sched_key.id,
(BCMBAL_TM_SCHED_DIR_US == tm_sched_key.dir ? "upstream" :"downstream"),
bcmos_strerror(err));
/* set bal app p_msg version */
p_bal_util_ind_msg->version = BAL_UTIL_MSG_VERSION;
p_bal_util_ind_msg->obj_key.tm_sched_key = tm_sched_key;
p_bal_util_ind_msg->status = err; /* set the error code */
bcmbal_msg_hdr_set(p_bal_util_ind_msg,
BCMBAL_MAC_UTIL_MSG,
BAL_MSG_TYPE_IND,
BAL_SUBSYSTEM_MAC_UTIL,
BCMBAL_OBJ_ID_TM_SCHED,
BAL_UTIL_OPER_AGG_PORT_ADD,
0);
mac_util_ind_send(p_bal_util_ind_msg);
}
else
{
BCM_LOG(ERROR, log_id_mac_util, "Could not allocate memory for tm sched IND message\n");
}
}
/**
* Notify core group FSM that group set request was success or failed
*
* @param group_key
* @param op_type ADD, REMOVE, SET, CREATE, DESTROY
* @param err error code to be sent up
*
**/
static void _mac_util_report_group_set_indication (bcmbal_group_key group_key, bal_util_oper_group op_type, bcmos_errno err)
{
bal_util_msg_ind *p_bal_util_ind_msg;
if(NULL != (p_bal_util_ind_msg = bcmbal_msg_calloc(sizeof(bal_util_msg_ind))))
{
BCM_LOG(INFO, log_id_mac_util, "Reporting to Core: group %d, %s, result=%s\n",
group_key.group_id,
BCMBAL_UTIL_GROUP_OPER_STR_GET(op_type),
bcmos_strerror(err));
/* set bal app p_msg version */
p_bal_util_ind_msg->version = BAL_UTIL_MSG_VERSION;
p_bal_util_ind_msg->obj_key.group_key = group_key;
p_bal_util_ind_msg->status = err; /* set the error code */
bcmbal_msg_hdr_set(p_bal_util_ind_msg,
BCMBAL_MAC_UTIL_MSG,
BAL_MSG_TYPE_IND,
BAL_SUBSYSTEM_MAC_UTIL,
BCMBAL_OBJ_ID_GROUP,
op_type,
0);
mac_util_ind_send(p_bal_util_ind_msg);
}
else
{
BCM_LOG(ERROR, log_id_mac_util, "Could not allocate memory for group IND message\n");
}
}
/**
* Notify core flow FSM that flow operational state was changed
*
* @param pon_if - the flow interface
* @param flow_key
* @param op_type - relevant flow latest operation
* @param ind - success/fail represent current flow state is up/down
*
**/
void mac_util_report_flow_auto_ind (uint32_t pon_if, bcmbal_flow_key flow_key ,bal_util_oper_flow op_type, bal_util_flow_ind ind)
{
bal_util_msg_auto_ind *p_bal_util_auto_ind_msg;
if(NULL != (p_bal_util_auto_ind_msg = bcmbal_msg_calloc(sizeof(bal_util_msg_auto_ind) + sizeof(bcmbal_status))))
{
BCM_LOG(INFO, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(pon_if), "Reporting to Core: flow %d, %s %s, change to %s\n",
flow_key.flow_id,
(BCMBAL_FLOW_TYPE_UPSTREAM == flow_key.flow_type ? "upstream" :
BCMBAL_FLOW_TYPE_DOWNSTREAM == flow_key.flow_type ? "downstream" :
BCMBAL_FLOW_TYPE_MULTICAST == flow_key.flow_type ? "multicast" :"broadcast"),
(BAL_UTIL_OPER_FLOW_ADD == op_type ? "FLOW ADD":
(BAL_UTIL_OPER_FLOW_REMOVE == op_type ? "FLOW REMOVE" : "FLOW_CLEAR")),
ind == BAL_UTIL_FLOW_IND_SEND_FAIL ? "fail" : "success");
/* set bal app p_msg version */
p_bal_util_auto_ind_msg->version = BAL_UTIL_MSG_VERSION;
p_bal_util_auto_ind_msg->obj_key.flow_key = flow_key;
/*data will indicate the new operational state*/
*(p_bal_util_auto_ind_msg->data) = ((ind == BAL_UTIL_FLOW_IND_SEND_FAIL) ? BCMBAL_STATUS_DOWN : BCMBAL_STATUS_UP);
p_bal_util_auto_ind_msg->status = BCM_ERR_OK;
bcmbal_msg_hdr_set(p_bal_util_auto_ind_msg,
BCMBAL_MAC_UTIL_MSG,
BAL_MSG_TYPE_AUTO_IND,
BAL_SUBSYSTEM_MAC_UTIL,
BCMBAL_OBJ_ID_FLOW,
op_type,
0);
mac_util_auto_ind_send(p_bal_util_auto_ind_msg);
}
}
/** @brief Wrapper routine to Notify core flow FSM that flow ADD Success */
void mac_util_report_flow_add_success(bcmbal_flow_key flow_key, uint32_t pon_if)
{
_mac_util_report_flow_set_indication(flow_key, pon_if, BAL_UTIL_OPER_FLOW_ADD, BCM_ERR_OK);
}
/** @brief Wrapper routine to Notify core flow FSM that flow Add failed, based on result in indication msg from Maple */
void mac_util_report_flow_add_failed(bcmbal_flow_key flow_key, uint32_t pon_if, bcmos_errno err)
{
_mac_util_report_flow_set_indication(flow_key, pon_if, BAL_UTIL_OPER_FLOW_ADD, err);
}
/** @brief Wrapper routine to Notify core flow FSM that flow REMOVE is Success */
void mac_util_report_flow_remove_success(bcmbal_flow_key flow_key, uint32_t pon_if, bal_util_oper_flow op_type)
{
_mac_util_report_flow_set_indication(flow_key, pon_if, op_type, BCM_ERR_OK);
}
/** @brief Wrapper routine to Notify core flow FSM that flow Remove failed, based on result in indication msg from Maple */
void mac_util_report_flow_remove_failed(bcmbal_flow_key flow_key, uint32_t pon_if, bal_util_oper_flow op_type, bcmos_errno err)
{
_mac_util_report_flow_set_indication(flow_key, pon_if, op_type, err);
}
/*****************************************************************************/
/**
* @brief mac_util_access_terminal_info_validate
*
* This routine is used to validate all input attributes required for an acc term
* setting received from the core.
*
* @param p_acc_term_req the acc term request info
*
* @return bcmos_errno
*/
/*****************************************************************************/
bcmos_errno mac_util_access_terminal_info_validate(const bcmbal_access_terminal_cfg *p_acc_term_req)
{
bcmos_errno rc = BCM_ERR_OK;
if (BCMOS_TRUE != BCMBAL_CFG_PROP_IS_SET(p_acc_term_req, access_terminal, iwf_mode))
{
/*
* This is an error because the iwf mode is implicitly set by the core, based
* either on a parameter in the bal_config.txt file, or it is assigned a
* default value. Either way, this property must be set when this code
* executes.
*/
rc = BCM_ERR_PARM;
}
return rc;
}
/*****************************************************************************/
/**
* @brief check_send_flow_bal_ind_msg
* the routine checks the indication status of a specific given flow, which its entry was just updated
* As flows may be 'waiting' for a single of few maple gem port configuration complete indications
* before an indication of complete flow setup can be indicated to bal_core
*
* @note this send routine is called multiple times for the scenario multiple flows per GEM/Alloc Id.
*
* @todo this routine currently assumes just flow add. This should handle a flow Remove case too
*
* @param p_flow - flow instance pointer from mac util DB
* @param err - remote error in msg from Maple
* @param ind_result - the status(BCMOLT_RESULT_SUCCESS/BCMOLT_RESULT_FAIL) of indication from Maple
*
* @return bcmos_errno
*/
/*****************************************************************************/
bcmos_errno check_send_flow_bal_ind_msg (flow_list_entry *p_flow, bcmos_errno err, bcmolt_result ind_result)
{
bcmos_errno rc = BCM_ERR_OK;
bcmos_bool send_ind = BCMOS_TRUE;
/* for a ds flow, indication should be sent only if all constraints fulfilled:
indication was not sent yet
flow configuration completed - all related gem ports were configured to maple
all related gem ports configuration complete indication were received from device
*/
if (NULL == p_flow)
{
BCM_LOG(ERROR, log_id_mac_util, "%s: NULL flow passed in: flow\n", __FUNCTION__);
return BCM_ERR_NOENT;
}
else
{
if (BCMOS_FALSE == p_flow->is_configuration_completed
|| BCMOS_TRUE == p_flow->is_waiting_for_svc_port_active
|| BAL_UTIL_FLOW_IND_SEND_NONE != p_flow->ind_sent)
{
send_ind = BCMOS_FALSE;
}
//else all conditions satisfied for sending an indication up to Core.
}
if ((BCM_ERR_OK == err) && (BCMOLT_RESULT_SUCCESS != ind_result))
{
err = BCM_ERR_INTERNAL;
}
if (BCMOS_TRUE == send_ind)
{
switch (p_flow->op_type)
{
case BAL_UTIL_OPER_FLOW_ADD:
if (BCM_ERR_OK != err)
{
/* report flow failed to Core; It is upto the core to cleanup the flows */
p_flow->ind_sent = BAL_UTIL_FLOW_IND_SEND_FAIL;
mac_util_report_flow_add_failed(p_flow->bal_flow_key, p_flow->if_id, err);
}
else
{
p_flow->ind_sent = BAL_UTIL_FLOW_IND_SEND_SUCCESS;
mac_util_report_flow_add_success(p_flow->bal_flow_key, p_flow->if_id);
}
break;
case BAL_UTIL_OPER_FLOW_REMOVE:
case BAL_UTIL_OPER_FLOW_CLEAR:
if (BCM_ERR_OK != err)
{
/* report flow failed to Core; It is upto the core to cleanup the flows */
p_flow->ind_sent = BAL_UTIL_FLOW_IND_SEND_FAIL;
mac_util_report_flow_remove_failed(p_flow->bal_flow_key, p_flow->if_id, p_flow->op_type, err);
}
else
{
p_flow->ind_sent = BAL_UTIL_FLOW_IND_SEND_SUCCESS;
mac_util_report_flow_remove_success(p_flow->bal_flow_key, p_flow->if_id, p_flow->op_type);
}
/* One more step for Flow Remove: remove from DB & Free the flow */
_mac_util_db_flow_remove (p_flow->if_id, p_flow);
_mac_util_db_flow_free (p_flow->if_id, p_flow);
break;
default:
rc = BCM_ERR_INTERNAL;
break;
}
}
return rc;
}
/**
* @brief mac_util_indication_cb
* this routine is the callback function that is registered by mac_util_indication_handler_register()
* to handle any indications coming from maple device
* this is the entry point for the device towards mac_util/bal
*
* @param device_id the maple device id generating the current indication
* @param p_msg pointer to the maple indication message
*
* @return void
*
* @todo Note that the pon interface in Auto Indication msgs from Maple is a physical interface
* on a device. The PON interface that is used by Core in it's requests to MAC Util,
* and stored in local DBs will be logical interface.
* So the rule of thumb would be anything coming from Maple side, translate (device + physical Interface)
* to Logical interface and use for logging, internal DB access etc.
*/
void mac_util_indication_cb(bcmolt_devid device_id, bcmolt_msg *p_msg)
{
bcmos_errno rc = BCM_ERR_OK;
switch (p_msg->obj_type)
{
case BCMOLT_OBJ_ID_DEVICE:
{
rc = mac_util_indication_handle_for_device (device_id, p_msg);
}
break;
case BCMOLT_OBJ_ID_GPON_NI:
case BCMOLT_OBJ_ID_GPON_ONU:
case BCMOLT_OBJ_ID_GPON_ALLOC:
case BCMOLT_OBJ_ID_GPON_GEM_PORT:
{
rc = mac_util_handle_all_olt_ind_for_gpon (device_id, p_msg);
}
break;
case BCMOLT_OBJ_ID_XGPON_NI:
case BCMOLT_OBJ_ID_XGPON_ONU:
case BCMOLT_OBJ_ID_XGPON_ALLOC:
{
rc = mac_util_handle_all_olt_ind_for_xgpon (device_id, p_msg);
}
break;
default:
BCM_LOG(DEBUG, log_id_mac_util, "Unhandled message indication for obj type %d\n",
p_msg->obj_type);
rc = BCM_ERR_INTERNAL;
break;
}
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, log_id_mac_util, "Error handling Auto Indication from Maple for obj type %d\n", p_msg->obj_type);
}
return;
}
/**
* @brief get string for the indication object type for device
*/
static char *mac_util_indication_get_obj_type_str_for_device (bcmolt_obj_id obj_type)
{
int i = 0;
for (i=0; i < BCM_SIZEOFARRAY(mac_util_device_ind_handlers); i++)
{
if (obj_type == mac_util_device_ind_handlers[i].obj_type)
{
return mac_util_device_ind_handlers[i].obj_type_str;
}
}
return "Unhandled";
}
/**
* @brief check if mac util should report access terminal connect event to core.
* event will be sent only when all devices are connected successfully
*
* @return bcmos_bool
*/
static bcmos_bool mac_util_check_acc_term_report_event (void)
{
bcmolt_devid device_id;
BCM_TOPO_FOR_EACH_DEV(device_id)
{
if (!acc_term_connectivity.devices[device_id].is_connected)
{
return BCMOS_FALSE;
}
}
return BCMOS_TRUE;
}
/**
* @brief Handler function for Maple auto indications for a OLT Device
*
* @param device_id the maple device id generating the current indication
* @param p_msg pointer to the maple indication message
*
* @return bcmos_errno
*/
static bcmos_errno mac_util_indication_handle_for_device (bcmolt_devid device_id, bcmolt_msg *p_msg)
{
bcmos_errno rc = BCM_ERR_OK;
BCM_LOG(DEBUG, log_id_mac_util,
"mac_util_indication_cb received indication obj=%d/%s group=%d subgroup=%d\n",
p_msg->obj_type, mac_util_indication_get_obj_type_str_for_device(p_msg->obj_type),
p_msg->group, p_msg->subgroup);
if (BCMOLT_DEVICE_AUTO_ID_CONNECTION_COMPLETE == p_msg->subgroup)
{
BCM_LOG(INFO, log_id_mac_util, "Device %u is ready.\n", device_id);
acc_term_connectivity.devices[device_id].is_connected = BCMOS_TRUE;
if (mac_util_check_acc_term_report_event())
{
mac_util_report_acc_term_event(p_msg->subgroup);
}
if (mac_util_bal_req_handlers_for_system_mode[acc_term_connectivity.devices[device_id].system_mode].acc_term_post_indication_set)
{
rc = mac_util_bal_req_handlers_for_system_mode[acc_term_connectivity.devices[device_id].system_mode].acc_term_post_indication_set(device_id);
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, log_id_mac_util, "%s: post indication set FAILED: rc = %s (%d)\n",
__FUNCTION__, bcmos_strerror(rc), rc);
}
}
}
else if (BCMOLT_DEVICE_AUTO_ID_CONNECTION_FAILURE == p_msg->subgroup)
{
BCM_LOG(INFO, log_id_mac_util, "Device %u connection failed.\n", device_id);
if(!acc_term_connectivity.fail_reported)
{
mac_util_report_acc_term_event(p_msg->subgroup);
}
acc_term_connectivity.fail_reported = BCMOS_TRUE;
}
return rc;
}
/**
* @brief Common routine to get string of indication object
*
* @param obj_type obj type to get string for
* @param obj_types_and_handlers obj types array
* @param num_obj_types num obj types
*
* @return char*
*/
char *_mac_util_get_obj_type_str_for_indications ( bcmolt_obj_id obj_type,
mac_util_ind_obj_and_handlers obj_types_and_handlers[], uint16_t num_obj_types)
{
int i;
for (i = 0; i < num_obj_types; i++)
{
if (obj_type == obj_types_and_handlers[i].obj_type)
{
return obj_types_and_handlers[i].obj_type_str;
}
}
return "Unhandled";
}
/**
* @brief Common routine to register for Maple auto indications
*
* @param p_rx_cfg handler config structure
* @param obj_types_and_handlers obj types to subscribe
* @param num_obj_types num obj types
* @param device_id specific device id (for multiple devices support)
*
* @return bcmos_errno
*
* @todo with multiple devices in future this needs to be done on per device basis and based on epon or gpon mode
*/
bcmos_errno _mac_util_register_for_auto_indications (struct bcmolt_rx_cfg *p_rx_cfg,
mac_util_ind_obj_and_handlers obj_types_and_handlers[], uint16_t num_obj_types,
bcmolt_devid device_id)
{
bcmos_errno rc = BCM_ERR_OK;
int i;
for (i = 0; i < num_obj_types; i++)
{
/* set to specific auto indication object type */
p_rx_cfg->obj_type = obj_types_and_handlers[i].obj_type;
rc = bcmolt_auto_rx_cb_set(device_id, p_rx_cfg);
if (BCM_ERR_OK != rc)
{
return rc;
}
}
return BCM_ERR_OK;
}
/**
* @brief Maple auto indication register for specific device based indications
*
* @param p_rx_cfg handler config structure
*@param device_id specific device id (for multiple devices support)
*
* @return bcmos_errno
*/
bcmos_errno mac_util_register_for_device_auto_indications (struct bcmolt_rx_cfg *p_rx_cfg, bcmolt_devid device_id)
{
return _mac_util_register_for_auto_indications (p_rx_cfg, mac_util_device_ind_handlers, BCM_SIZEOFARRAY(mac_util_device_ind_handlers),device_id);
}
/**
* @brief mac_util_indication_handler_register
* this local routine registers the local function 'mac_util_indication_cb'
* as the callback for any indications coming from maple device
*
*@param device_id specific device id (for multiple devices support)
*
* @return bcmos_errno
*/
static bcmos_errno mac_util_indication_handler_register(bcmolt_devid device_id)
{
bcmos_errno rc = BCM_ERR_OK;
struct bcmolt_rx_cfg rx_cfg =
{
.obj_type = BCMOLT_OBJECT_ANY,
.rx_cb = g_indication_handler,
.flags = BCMOLT_AUTO_FLAGS_DISPATCH,
.module = BCMOS_MODULE_ID_WORKER_MGMT,
.pon_ni_mask = 0 /** Bitmask of pon_ni interfaces the registration applies to. 0=all interfaces. */
};
rc = mac_util_register_for_device_auto_indications(&rx_cfg, device_id);
if (BCM_ERR_OK != rc)
{
return rc;
}
rc = mac_util_register_for_gpon_auto_indications(&rx_cfg, device_id);
if (BCM_ERR_OK != rc)
{
return rc;
}
rc = mac_util_register_for_xgpon_auto_indications(&rx_cfg, device_id);
if (BCM_ERR_OK != rc)
{
return rc;
}
return BCM_ERR_OK;
}
/**
* @brief reset mac_util access terminal internal db
* all devices marked as disconnected
*/
static void mac_util_access_terminal_reset (void)
{
bcmolt_devid device_id;
BCM_TOPO_FOR_EACH_DEV(device_id)
{
acc_term_connectivity.devices[device_id].is_connected = BCMOS_FALSE;
}
acc_term_connectivity.fail_reported = BCMOS_FALSE;
}
/**
* @brief reset a single maple device
*
* @param device_id the maple device id to be reset
*
* @return bcmos_errno
*/
static bcmos_errno reset_device(bcmolt_devid device_id)
{
bcmolt_device_key key = {};
bcmolt_device_reset oper;
BCMOLT_OPER_INIT(&oper, device, reset, key);
BCMOLT_OPER_PROP_SET(&oper, device, reset, mode, BCMOLT_DEVICE_RESET_MODE_DEVICE);
return bcmolt_oper_submit(device_id , &oper.hdr);
}
/**
* @brief common config across mac modes during access terminal set.
* currently only the admin up case is supported (op_type is ignored))
* @note this is called from individual mac handler files rather than calling upfront here in this file
* in access_terminal_set(), because this is not to be called for loopback mode.
*
*
* @return bcmos_errno
*/
bcmos_errno maple_access_terminal_set_common (acc_term_inst *p_acc_term, bal_util_oper_acc_term op_type, bcmolt_devid device_id)
{
bcmos_errno rc = BCM_ERR_OK;
rc = reset_device(device_id);
if (rc != BCM_ERR_OK)
{
BCM_LOG(ERROR, log_id_mac_util, "Failed to reset device %d (%s)\n", device_id, bcmos_strerror(rc));
return rc;
}
/* Because there is no indication coming from Maple that device reset is complete, we should sleep here. 1 second should be enough. */
bcmos_usleep(1000000);
/* register for maple indications - doing it after reset to avoid catching stale indications */
rc = mac_util_indication_handler_register(device_id);
if (rc != BCM_ERR_OK)
{
BCM_LOG(ERROR, log_id_mac_util, "Failed to register for device %d indications (%s)\n", device_id, bcmos_strerror(rc));
return rc;
}
/* using 1 second delay between the indication registration and configuration setup
to let the maple proxy queue get empty */
bcmos_usleep(1000000);
return BCM_ERR_OK;
}
bcmos_errno maple_access_terminal_connect_common (bcmolt_devid device_id)
{
bcmos_errno rc;
bcmolt_device_connect dev_connect_oper;
bcmolt_device_key key = {};
/* invoking the connect operation */
BCMOLT_OPER_INIT(&dev_connect_oper, device, connect, key);
rc = bcmolt_oper_submit(device_id, &dev_connect_oper.hdr);
if (rc != BCM_ERR_OK)
{
BCM_LOG(ERROR, log_id_mac_util, "Failed to submit connect operation for device %d (%s), err_text = %s\n",
device_id, bcmos_strerror(rc), dev_connect_oper.hdr.hdr.err_text);
}
return rc;
}
/* Derive a specific device system mode from topology and store it at the internal db*/
static bcmos_errno mac_util_system_mode_get(bcmolt_devid device_id)
{
uint32_t logical_pon;
uint32_t pon_mode2max_physical_pons[BCM_TOPO_PON_MODE__NUM_OF] = {};
BCM_TOPO_DEV_FOR_EACH_PON(device_id, logical_pon)
{
uint32_t physical_pon;
bcm_topo_pon_mode pon_mode;
pon_mode = bcm_topo_pon_get_pon_mode(logical_pon);
bcm_topo_pon_get_logical2physical(logical_pon, &device_id, &physical_pon);
/* Get the number of physical PONs mapped.
* For example, if the user mapped only 4 physical PONs out of 16 in GPON mode, and the maximum physical PON mapped was 11, then the system mode should be GPONx16, not GPONx8. */
pon_mode2max_physical_pons[pon_mode] = MAX(pon_mode2max_physical_pons[pon_mode], physical_pon + 1);
}
if (bcmbal_is_mac_in_loopback())
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_LOOPBACK;
else if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_GPON])
{
if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_GPON] <= 8)
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_GPON__8_X;
else
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_GPON__16_X;
}
else if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_XGPON])
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_XGPON_1__8_X;
else if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_XGS])
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_XGS__2_X_10_G;
else if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_EPON_TDMA])
{
if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_EPON_TDMA] <= 4)
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_EPON__4_X_COEXISTENCE_TDMA;
else
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_EPON__8_X_COEXISTENCE_TDMA;
}
else if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_EPON_1G])
{
if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_EPON_1G] <= 4)
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_EPON__4_X;
else if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_EPON_1G] <= 8)
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_EPON__8_X;
else
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_EPON__16_X;
}
else if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_EPON_10G])
{
if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_EPON_10G] <= 2)
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_EPON__2_X_10_G;
else if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_EPON_10G] <= 4)
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_EPON__4_X_10_G;
else
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_EPON__8_X_10_G;
}
else if (pon_mode2max_physical_pons[BCM_TOPO_PON_MODE_LOOPBACK])
acc_term_connectivity.devices[device_id].system_mode = BCMOLT_SYSTEM_MODE_LOOPBACK;
else
{
BCM_LOG(ERROR, log_id_mac_util, "Cannot determine system mode from topology\n");
return BCM_ERR_PARM;
}
return BCM_ERR_OK;
}
/**
* @brief Command Set setup routine for access terminal connect to the mac devices
*
* This routine is called by acc_term_fsm in the BAL core, at an admin up operation
* and will result in setting and connecting all the access terminal devices
*
* @param p_acc_term Pointer to access terminal instance
* @param op_type Operation type on access terminal instance
*
* @return bcmos_errno
*
* @todo this code will change with multiple devices
*/
bcmos_errno mac_util_access_terminal_set(acc_term_inst *p_acc_term, bal_util_oper_acc_term op_type)
{
bcmos_errno rc = BCM_ERR_OK;
bcmolt_devid device_id;
bcmos_bool is_wait_for_report = BCMOS_FALSE;
BCM_TOPO_FOR_EACH_DEV(device_id)
{
/*will reset and connect, in case the device is not already connected*/
if (!acc_term_connectivity.devices[device_id].is_connected)
{
/* Add timeout between bringing up maple devices.
* Otherwise, maple APIs can time out
*/
if (is_wait_for_report)
bcmos_usleep(10000000);
is_wait_for_report = BCMOS_TRUE;
/* mac mode specific acc term set */
if (mac_util_bal_req_handlers_for_system_mode[acc_term_connectivity.devices[device_id].system_mode].acc_term_set)
{
rc = mac_util_bal_req_handlers_for_system_mode[acc_term_connectivity.devices[device_id].system_mode].acc_term_set(p_acc_term, op_type, device_id);
}
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, log_id_mac_util, "%s: FAILED: rc = %s (%d)\n",
__FUNCTION__, bcmos_strerror(rc), rc);
return rc;
}
}
}
if (!is_wait_for_report)
{
mac_util_report_acc_term_event(BCMOLT_DEVICE_AUTO_ID_CONNECTION_COMPLETE);
}
return rc;
}
/*---------------------------------------------------------------------------------------------*/
/*----------------------------------interface set handling-------------------------------------------*/
/**
* @brief Command Set setup routine for interface up to mac application
*
* This routine is called by if_fsm in the BAL core to initialize the command
* set to up the interface of the mac application. The cmdset actually
* consists of two commands, one is to send the if up request message to the mac
* App and handle the relevant response, the other is to handle the indication message
* from the mac APP when the operation is completed.
*
* @param p_interface_inst Pointer to interface instance
* @param op_type Operation type on interface instance
*
* @return bcmos_errno
*
* @todo system mode to identify handler function is global across olt now.
* This should be queried for per pon interface and used to identify the protocol
* and the corresponding handler.
*/
bcmos_errno mac_util_interface_set(acc_term_interface *p_interface_inst, bal_util_oper_if op_type)
{
/* Parameter checks */
BUG_ON(NULL == p_interface_inst);
bcmos_errno rc = BCM_ERR_OK;
bcmbal_interface_key intf_key = p_interface_inst->api_req_int_obj_info.key;
bcm_topo_pon_mode pon_mode;
/* First check if it is for PON interface. If not (i.e. NNI), then just return a success without
* forwarding anything to MAC hardware.
*/
if (BCMBAL_INTF_TYPE_PON != intf_key.intf_type)
{
mac_util_report_if_event(intf_key.intf_id,
intf_key.intf_type,
BCM_ERR_OK, BCMOLT_RESULT_SUCCESS,
((BAL_UTIL_OPER_IF_UP == op_type) ? BCMOLT_PON_STATE_ACTIVE_WORKING : BCMOLT_PON_STATE_INACTIVE));
return BCM_ERR_OK;
}
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(intf_key.intf_id),
"SET if %s , intf_type: %s, intf_id: %d\n",
(BAL_UTIL_OPER_IF_UP == op_type ? "UP" : "DOWN"),
(BCMBAL_INTF_TYPE_PON == intf_key.intf_type ? "PON":"NNI"),
intf_key.intf_id);
/* query PON mode */
pon_mode = mac_util_get_pon_mode(intf_key.intf_id);
if (pon_mode == BCM_TOPO_PON_MODE_INVALID)
rc = BCM_ERR_INTERNAL;
/* system mode specific interface set */
if ((BCM_ERR_OK == rc) && mac_util_bal_req_handlers_for_pon_mode[pon_mode].if_set)
{
rc = mac_util_bal_req_handlers_for_pon_mode[pon_mode].if_set(p_interface_inst, op_type);
}
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(intf_key.intf_id),
"Failed INTERFACE-%s operation for IF %d\n",
(BAL_UTIL_OPER_IF_UP == op_type) ? "UP" : "DOWN", intf_key.intf_id);
}
return rc;
}
/*****************************************************************************/
/**
* @brief mac_util_subscriber_terminal_info_validate
*
* This routine is used to validate all input attributes required for a sub term setting
* received from core
*
* @param p_sub_term_req A pointer to a subscriber terminal object
*
* @return bcmos_errno
*/
/*****************************************************************************/
bcmos_errno mac_util_subscriber_terminal_info_validate(const bcmbal_subscriber_terminal_cfg *p_sub_term_req)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_topo_pon_mode pon_mode;
/* query system mode */
pon_mode = mac_util_get_pon_mode(p_sub_term_req->key.intf_id);
if (pon_mode == BCM_TOPO_PON_MODE_INVALID)
rc = BCM_ERR_INTERNAL;
/* validate system mode specific things */
if ((BCM_ERR_OK == rc) && mac_util_bal_req_handlers_for_pon_mode[pon_mode].sub_term_validate)
{
rc = mac_util_bal_req_handlers_for_pon_mode[pon_mode].sub_term_validate(p_sub_term_req);
}
return rc;
}
/*----------------------------------subscriber terminal set handling-----------------------------------*/
/**
* @brief Command Set setup routine for subscriber terminal connect to mac application
*
* This routine is called by sub_term_fsm in the BAL core to initialize the command
* set to connect the subscriber terminal of the mac application. The cmdset actually
* consists of two commands, one is to send the sub_term request message to the mac
* App and handle the relevant response, the other is to handle the indication message
* from the mac APP when the operation is completed.
*
* @param p_sub_term_inst A pointer to a subscriber terminal instance
* @param op_type Type of operation being performed on the subscriber terminal instance
* @param is_post_discovery Used for ADD, indicates if this request is after a ONU Discovery
*
* @return bcmos_errno
*/
bcmos_errno mac_util_subscriber_terminal_set(sub_term_inst *p_sub_term_inst, bal_util_oper_sub_term op_type, bcmos_bool is_post_discovery)
{
bcmos_errno rc = BCM_ERR_OK;
bcmbal_subscriber_terminal_cfg *p_sub_term_req = &p_sub_term_inst->api_req_sub_term_info;
bcm_topo_pon_mode pon_mode;
BCM_LOG(DEBUG, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_sub_term_req->key.intf_id),
"IN : %s pon_id = %d onu_id= %d "
"omci_gem_port = %d\n",
__FUNCTION__,
p_sub_term_req->key.intf_id,
p_sub_term_req->key.sub_term_id, p_sub_term_req->data.svc_port_id);
if ((BAL_UTIL_OPER_SUB_TERM_ADD != op_type)
&& (BAL_UTIL_OPER_SUB_TERM_REMOVE != op_type)
&& (BAL_UTIL_OPER_SUB_TERM_CLEAR != op_type))
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_sub_term_req->key.intf_id),
"Unsupported operation %d for sub_term %u\n",
op_type, p_sub_term_req->key.sub_term_id);
return BCM_ERR_NOT_SUPPORTED;
}
/* query system mode */
pon_mode = mac_util_get_pon_mode(p_sub_term_req->key.intf_id);
if (pon_mode == BCM_TOPO_PON_MODE_INVALID)
rc = BCM_ERR_INTERNAL;
/* system mode specific sub term set */
if ((BCM_ERR_OK == rc) && mac_util_bal_req_handlers_for_pon_mode[pon_mode].sub_term_set)
{
rc = mac_util_bal_req_handlers_for_pon_mode[pon_mode].sub_term_set(p_sub_term_inst, op_type, is_post_discovery);
}
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_sub_term_req->key.intf_id),
"%s: Failed: rc = %s (%d)\n",
__FUNCTION__, bcmos_strerror(rc), rc);
}
return rc;
}
/*---------------------------------------------------------------------------------------------*/
/*------------------group set handling GROUP routines and helper functions-------------------*/
/*---------------------------------------------------------------------------------------------*/
/*****************************************************************************/
/**
* @brief mac_util_group_info_validate
*
* This routine is used to validate all input attributes required for a group
* setting received from core
*
* @param p_group_req A pointer to a group object
*
* @return bcmos_errno
*/
/*****************************************************************************/
bcmos_errno mac_util_group_info_validate(const bcmbal_group_cfg *p_group_req)
{
bcmos_errno rc = BCM_ERR_OK;
int i;
do
{
/* if the group has no owner, no need to check as service port will not be assigned */
if (p_group_req->data.owner == BCMBAL_GROUP_OWNER_NONE)
{
break;
}
/* if group member command is set, there has to be member info,
for remove, service port is an option
*/
if (BCMBAL_CFG_PROP_IS_SET(p_group_req, group, members_cmd))
{
if(p_group_req->data.members.len)
{
for(i=0; i< p_group_req->data.members.len; i++)
{
/* all members should have the service port as non-zero */
if (!p_group_req->data.members.val[i].svc_port_id)
{
BCM_LOG(ERROR, log_id_mac_util,
"svc_port_id is a mandatory parameter for a group member, and it can not set to zero\n");
rc = BCM_ERR_MANDATORY_PARM_IS_MISSING;
break;
}
}
}
}
}while(0);
return rc;
}
/**
* @brief Core interface: setup routine for group
*
* This routine is called by group_fsm in the BAL core to
* add/remove/set group in the mac application. Unlike flow request,
* the mac driver does not send indication messages back upon completion.
* This routine needs to fake an indication message to core to trigger the group_fsm.
*
* @param p_grp_inst Pointer to group instance
* @param op_type Operation type on group instance
* @param send_ind TRUE - send indication, FALSE - don't send indication
*
* @return bcmos_errno
*/
bcmos_errno mac_util_group_set(group_inst *p_grp_inst, bal_util_oper_group op_type, bcmos_bool send_ind)
{
bcmbal_group_cfg *p_group_req = &p_grp_inst->api_req_group_info;
bcmos_errno rc = BCM_ERR_OK;
bcmbal_group_cfg *p_group_lookup_info = NULL;
bcm_topo_pon_mode pon_mode;
do
{
/* if the group has no owner, no need to access the HW as service port will not be set */
if (p_group_req->data.owner == BCMBAL_GROUP_OWNER_NONE)
{
break;
}
/*
* When we are doing a GROUP_ADD, the API request has the information we need,
* When we are doing a GROUP_DESTROY, the current group info has this information (because
* the GROUP_DESTROY request only has the group key populated. The current flow info has
* all of the attributes used when create the group.
*/
p_group_lookup_info = (BAL_UTIL_OPER_GROUP_DESTROY == op_type) ? &p_grp_inst->current_group_info : p_group_req;
BCM_LOG(INFO, log_id_mac_util, "%s group_id = %d with oper type %s\n ",
__FUNCTION__,
p_group_lookup_info->key.group_id,
BCMBAL_UTIL_GROUP_OPER_STR_GET(op_type)
);
/* mac only need to response to set member when op_type is ADD/REMOVE/SET - configure multicast service ports */
if ((BAL_UTIL_OPER_GROUP_ADD == op_type ||
BAL_UTIL_OPER_GROUP_REMOVE == op_type ||
BAL_UTIL_OPER_GROUP_SET == op_type ) &&
BCMBAL_CFG_PROP_IS_SET(p_group_req, group, members))
{
/* assume all members are of same mode */
/* query system mode */
pon_mode = mac_util_get_pon_mode(p_group_req->data.members.val[0].intf_id);
if (pon_mode == BCM_TOPO_PON_MODE_INVALID)
{
rc = BCM_ERR_INTERNAL;
}
/* system mode specific group set */
else if ( mac_util_bal_req_handlers_for_pon_mode[pon_mode].group_set)
{
rc = mac_util_bal_req_handlers_for_pon_mode[pon_mode].group_set(p_group_req, op_type, p_grp_inst);
}
}
/* special case - destroy with valid members, then need to remove all members */
else if ((BAL_UTIL_OPER_GROUP_DESTROY == op_type && p_group_lookup_info->data.members.len != 0))
{
/* query system mode - use first member as default */
pon_mode = mac_util_get_pon_mode(p_group_lookup_info->data.members.val[0].intf_id);
if (pon_mode == BCM_TOPO_PON_MODE_INVALID)
{
rc = BCM_ERR_INTERNAL;
}
/* system mode specific group set */
else if ( mac_util_bal_req_handlers_for_pon_mode[pon_mode].group_set)
{
rc = mac_util_bal_req_handlers_for_pon_mode[pon_mode].group_set(p_group_lookup_info, BAL_UTIL_OPER_GROUP_REMOVE, p_grp_inst);
}
}
}while(0);
/* return an indication message to core */
if(send_ind)
{
_mac_util_report_group_set_indication(p_group_req->key, op_type, rc);
}
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, log_id_mac_util,
"%s Failed: rc = %s (%d)\n",
__FUNCTION__,
bcmos_strerror(rc), rc);
}
return rc;
}
/*---------------------------------------------------------------------------------------------*/
/*------------------flow set handling Interface routines and helper functions-------------------*/
/*---------------------------------------------------------------------------------------------*/
/*****************************************************************************/
/**
* @brief mac_util_flow_info_validate
*
* This routine is used to validate all input attributes required for a flow
* setting received from core
*
* @param p_flow_req A pointer to a flow object
*
* @return bcmos_errno
*/
/*****************************************************************************/
bcmos_errno mac_util_flow_info_validate(const bcmbal_flow_cfg *p_flow_req)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_topo_pon_mode pon_mode;
do
{
if (p_flow_req->key.flow_type == BCMBAL_FLOW_TYPE_MULTICAST)
{
/* nothing to do in multicast FLOW - validate in GROUP*/
break;
}
if (p_flow_req->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM &&
BCMBAL_CFG_PROP_IS_SET(p_flow_req, flow, group_id) )
{
/* nothing to do in DS N:1 FLOW - validate in GROUP */
break;
}
if (!BCMBAL_CFG_PROP_IS_SET(p_flow_req, flow, access_int_id))
{
BCM_LOG(ERROR, log_id_mac_util,
"access if id is a mandatory parameter for a flow, and it is not set\n");
rc = BCM_ERR_MANDATORY_PARM_IS_MISSING;
break; /* if interface id not set then skip rest of the checks */
}
if (p_flow_req->key.flow_type != BCMBAL_FLOW_TYPE_BROADCAST)
{
if (!BCMBAL_CFG_PROP_IS_SET(p_flow_req, flow, sub_term_id))
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow_req->data.access_int_id),
"sub term id is a mandatory parameter for a flow, and it is not set\n");
rc = BCM_ERR_MANDATORY_PARM_IS_MISSING;
}
}
if (!BCMBAL_CFG_PROP_IS_SET(p_flow_req, flow, svc_port_id))
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow_req->data.access_int_id),
"svc_port_id is a mandatory parameter for a flow, and it is not set\n");
rc = BCM_ERR_MANDATORY_PARM_IS_MISSING;
}
/* validate flow id */
if (BCMOS_FALSE == MAC_UTIL_FLOW_DB_FLOW_ID_IS_VALID(p_flow_req->key.flow_id))
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow_req->data.access_int_id),
"flow Id from user is not within range: %d <= flow id <= %d\n",
MAC_UTIL_FLOW_DB_FLOW_ID_START_VAL, MAC_UTIL_FLOW_DB_FLOW_ID_MAX_VAL);
rc = BCM_ERR_PARM;
}
/* query system mode */
pon_mode = mac_util_get_pon_mode(p_flow_req->data.access_int_id);
if (pon_mode == BCM_TOPO_PON_MODE_INVALID)
{
rc = BCM_ERR_INTERNAL;
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow_req->data.access_int_id),
"could not get system mode for pon interface\n");
}
}
/* system mode specific validation */
if ((BCM_ERR_OK == rc) && mac_util_bal_req_handlers_for_pon_mode[pon_mode].flow_validate)
{
rc = mac_util_bal_req_handlers_for_pon_mode[pon_mode].flow_validate(p_flow_req);
/* the called function will log any protocol specific validation errors */
}
} while (0);
return rc;
}
/**
* @brief Core interface: setup routine for flow
*
* This routine is called by flow_fsm in the BAL core to initialize the command
* to add flow to the mac application. The cmdset actually
* consists of two commands, one is to send the flow request message to the mac
* App and handle the relevant response, the other is to handle the indication message
* from the mac APP when the operation is completed.
*
* @param p_flow_core Pointer to flow instance from core fsm
* @param op_type Operation type on flow instance
*
* @return bcmos_errno
*/
bcmos_errno mac_util_flow_set(flow_inst *p_flow_core, bal_util_oper_flow op_type)
{
bcmbal_flow_cfg *p_flow_req = &p_flow_core->api_req_flow_info;
bcmos_errno rc = BCM_ERR_OK;
bcmbal_flow_cfg *p_flow_lookup_info = NULL;
bcm_topo_pon_mode pon_mode;
/*
* When we are doing a FLOW_ADD, the API request has the information we need,
* When we are doing a FLOW_REMOVE, the current flow info has this information (because
* the FLOW_REMOVE request only has the flow key populated. The current flow info has
* all of the attributes used to create the flow in the first place.
*/
p_flow_lookup_info = (BAL_UTIL_OPER_FLOW_ADD == op_type) ? p_flow_req : &p_flow_core->current_flow_info;
bcmos_bool flow_is_destined_to_host = BAL_UTIL_OPER_FLOW_ADD == op_type ?
((BCMBAL_CFG_PROP_IS_SET(&p_flow_core->api_req_flow_info, flow, action) &&
(p_flow_core->api_req_flow_info.data.action.cmds_bitmask &
BCMBAL_ACTION_CMD_ID_TRAP_TO_HOST)) ? BCMOS_TRUE : BCMOS_FALSE) :
((BCMBAL_CFG_PROP_IS_SET(&p_flow_core->current_flow_info, flow, action) &&
(p_flow_core->current_flow_info.data.action.cmds_bitmask &
BCMBAL_ACTION_CMD_ID_TRAP_TO_HOST)) ? BCMOS_TRUE : BCMOS_FALSE);
/* There's no need to do anything with the MAC in downstream flows that
* that are destined to the host CPU (i.e. NNI->CPU)
*/
if(((BCMBAL_FLOW_TYPE_DOWNSTREAM == p_flow_req->key.flow_type) &&
flow_is_destined_to_host))
{
/* When the flow is downstream and destined to the host (i.e. NNI->CPU), then there
* is nothing to do in the MAC, so just return an indication to allow the FSM to continue on.
*/
if (BAL_UTIL_OPER_FLOW_ADD == op_type)
{
mac_util_report_flow_add_success(p_flow_req->key, p_flow_req->data.access_int_id);
}
else if ((BAL_UTIL_OPER_FLOW_REMOVE == op_type) || (BAL_UTIL_OPER_FLOW_CLEAR == op_type))
{
mac_util_report_flow_remove_success(p_flow_req->key, p_flow_req->data.access_int_id, op_type);
}
}
/* for multicast flow all works are done in GROUP object, simply send the indication to Core */
else if (BCMBAL_FLOW_TYPE_MULTICAST == p_flow_req->key.flow_type)
{
/* there is no access_int_id for multicast flow, pass 0 as parameter.
The interface number is just used for logging purpose in the indication API */
_mac_util_report_flow_set_indication(p_flow_req->key, 0, op_type, rc);
}
/* for downstream n:1 flow all works are done in GROUP object, simply send the indication to Core */
else if (BCMBAL_FLOW_TYPE_DOWNSTREAM == p_flow_req->key.flow_type &&
(BCMBAL_CFG_PROP_IS_SET(p_flow_req, flow, group_id)) )
{
/* there is no access_int_id for DS N:1 flow, pass 0 as parameter.
The interface number is just used for logging purpose in the indication API */
_mac_util_report_flow_set_indication(p_flow_req->key, 0, op_type, rc);
}
else
{
BCM_LOG(INFO, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow_req->data.access_int_id),
"%s flow_id = %d dir = %s, pon_id = %d "
"onu_id= %d alloc_id = %d gem_port = %d, op_type = %s\n",
__FUNCTION__,
p_flow_lookup_info->key.flow_id,
p_flow_lookup_info->key.flow_type == BCMBAL_FLOW_TYPE_UPSTREAM ? "up":"down",
p_flow_lookup_info->data.access_int_id,
p_flow_lookup_info->data.sub_term_id,
p_flow_lookup_info->data.agg_port_id,
p_flow_lookup_info->data.svc_port_id,
(BAL_UTIL_OPER_FLOW_ADD == op_type ? "FLOW_ADD":
(BAL_UTIL_OPER_FLOW_REMOVE == op_type ? "FLOW_REMOVE" : "FLOW_CLEAR")));
/* query system mode */
pon_mode = mac_util_get_pon_mode(p_flow_req->data.access_int_id);
if (pon_mode == BCM_TOPO_PON_MODE_INVALID)
rc = BCM_ERR_INTERNAL;
/* system mode specific flow set */
if ((BCM_ERR_OK == rc) && mac_util_bal_req_handlers_for_pon_mode[pon_mode].flow_set)
{
rc = mac_util_bal_req_handlers_for_pon_mode[pon_mode].flow_set(p_flow_lookup_info, op_type, p_flow_core);
}
}
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow_req->data.access_int_id),
"%s Failed: rc = %s (%d)\n",
__FUNCTION__,
bcmos_strerror(rc), rc);
}
return rc;
}
/*****************************************************************************/
/**
* @brief mac_util_tm sched_info_validate
*
* This routine is used to validate all input attributes required for a tm sched
* setting received from core
*
* @param p_tm_sched_req A pointer to a tm sched object
*
* @return bcmos_errno
*/
/*****************************************************************************/
bcmos_errno mac_util_tm_sched_info_validate(const bcmbal_tm_sched_cfg *p_tm_sched_req)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_topo_pon_mode pon_mode;
do
{
if (!BCMBAL_CFG_PROP_IS_SET(p_tm_sched_req, tm_sched, owner))
{
/* nothing to do in MAC */
break;
}
if (p_tm_sched_req->data.owner.type != BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT)
{
/* nothing to do in MAC */
break;
}
/* query system mode */
pon_mode = mac_util_get_pon_mode(p_tm_sched_req->data.owner.u.agg_port.intf_id);
if (pon_mode == BCM_TOPO_PON_MODE_INVALID)
rc = BCM_ERR_INTERNAL;
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_tm_sched_req->data.owner.u.agg_port.intf_id),
"could not get system mode for pon interface\n");
}
} while (0);
return rc;
}
bcmos_errno mac_util_agg_port_set(tm_sched_inst *p_tm_sched, bal_util_oper_agg_port op_type)
{
bcmbal_tm_sched_cfg *p_agg_port_req = &p_tm_sched->req_tm_sched_info;
bcmos_errno rc = BCM_ERR_OK;
bcm_topo_pon_mode pon_mode;
do
{
/* query system mode */
pon_mode = mac_util_get_pon_mode(p_agg_port_req->data.owner.u.agg_port.intf_id);
if (pon_mode == BCM_TOPO_PON_MODE_INVALID)
{
rc = BCM_ERR_INTERNAL;
break;
}
rc = maple_mac_util_agg_port_set(p_agg_port_req, op_type, p_tm_sched);
}while(0);
return rc;
}
#if !defined(WRX_BUILD)
/* Internal function that finds UDP port to bind to */
static bcmos_errno _mac_util_find_free_udp_port(uint16_t *p_port)
{
#define MAX_UDP_PORT_TRY_ITER 100 /* Try 100 times, then give up */
#define MAX_UDP_PORT 60000
#define MIN_UDP_PORT (MAX_UDP_PORT / 2)
uint16_t port;
struct sockaddr_in sa;
int sock;
int bind_rc;
int i = 0;
/* Open UDP socket */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
{
BCMOS_TRACE_RETURN(BCM_ERR_PARM, "Can't create UDP socket. error %s\n", strerror(errno));
}
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = INADDR_ANY;
do
{
port = rand() % MAX_UDP_PORT;
if (port < MIN_UDP_PORT)
port += MIN_UDP_PORT;
sa.sin_port = htons(port);
bind_rc = bind(sock, (struct sockaddr *)&sa, sizeof(sa));
} while (bind_rc < 0 && ++i < MAX_UDP_PORT_TRY_ITER);
/* Yes, yes. There is a possible race condition that someone will take the port we've just found
* before we had a chance to bind it again.
* In this unlikely case BAL application will fail on startup and will have to be restarted.
*/
close(sock);
if (bind_rc < 0)
{
BCMOS_TRACE_RETURN(BCM_ERR_NORES, "Couldn't find unused UDP port after %d tries. Giving up.\n", i);
}
*p_port = port;
return BCM_ERR_OK;
}
#endif
static void bal_indication_cb(bcmolt_devid olt, bcmolt_msg *p_msg)
{
mac_util_indication_cb(olt, p_msg);
bcmolt_msg_free(p_msg);
}
#ifdef ENABLE_LOG
/**
* @brief routine to register per pon log strings with logger
*
* @param system_mode -OLT system mode
*
* @return bcmos_errno
*/
static bcmos_errno mac_util_register_logging_per_pon (void)
{
char log_str_buf[MAC_UTIL_LOG_STR_SZ] = {0};
bcmolt_devid device_id;
uint32_t logical_pon;
/** @note if by any chance the system mode is set multiple times, then we want to avoid
* re-registering already registered pon interfaces, because there is currently no way
* to de-register those interfaces first. We will just register the not-registered ones.
*/
/* register log Ids for each PON interface, that is not already registered */
BCM_TOPO_FOR_EACH_PON(device_id, logical_pon)
{
if (0 != log_id_mac_util_pon_if[logical_pon])
{
continue;
}
/* make a log id string */
MAC_UTIL_MAKE_LOG_STR_FOR_PON_IF(logical_pon, log_str_buf, sizeof(log_str_buf));
/* register log id string for pon interface */
log_id_mac_util_pon_if[logical_pon] = bcm_dev_log_id_register(log_str_buf, DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
BUG_ON(log_id_mac_util_pon_if[logical_pon] == DEV_LOG_INVALID_ID);
}
return BCM_ERR_OK;
}
#endif
/**
* @brief get ip & port for MAC/Maple
*/
bcmos_errno mac_util_init_parse_mac_ip_and_port (const char *maple_address)
{
bcmos_errno rc = BCM_ERR_OK;
#if !defined(WRX_BUILD)
rc = app_util_parse_ip_port(maple_address, &bcmtr_olt_ip[0], &bcmtr_olt_udp_port[0]);
if (rc)
{
return rc;
}
srand(bcmos_timestamp());
rc = _mac_util_find_free_udp_port(&bcmtr_host_udp_port);
#endif
return rc;
}
/**
* @brief mac_util_init routine for mac application
* @param maple_address - pointer to maple device instance
* @return bcmos_errno
*/
bcmos_errno mac_util_init(const char *maple_address)
{
bcmos_errno rc = BCM_ERR_OK;
bcmolt_devid device_id;
do
{
#ifdef ENABLE_LOG
/* register a generic MAC util log Id too, for use other than PON If related logs */
log_id_mac_util = bcm_dev_log_id_register("MAC_UTIL", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
BUG_ON(log_id_mac_util == DEV_LOG_INVALID_ID);
#endif
if (!bcmbal_is_mac_in_loopback())
{
rc = mac_util_init_parse_mac_ip_and_port (maple_address);
if (BCM_ERR_OK != rc)
break;
}
g_indication_handler = bal_indication_cb;
BCM_TOPO_FOR_EACH_DEV(device_id)
{
rc = mac_util_system_mode_get(device_id);
if (BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, log_id_mac_util, "%s: system mode get for device %d FAILED: rc = %s (%d)\n",
__FUNCTION__, device_id, bcmos_strerror(rc), rc);
break;
}
}
#ifdef ENABLE_LOG
/* register logging for each PON based on mac mode*/
mac_util_register_logging_per_pon();
#endif
mac_util_access_terminal_reset();
} while(0);
return rc;
}
/*****************************************************************************/
/**
* @brief This function is the helper for the mac app print_flows CLI command backend
* which print the full internal flows list
*
* @param sess Pointer to the current cli session
* @param parm An array of parameters from the CLI command, which will be empty on that no parameters command case
* @param nParms The number of elements in the parm array (above) that have
* valid data, which will be 0 on that case.
*
* @returns BCM_ERR_OK on success, other bcmos_errno codes otherwise
*
*****************************************************************************/
static bcmos_errno _cmd_flows_print(bcmcli_session *sess, const bcmcli_cmd_parm parm[], uint16_t nParms)
{
flow_list_entry *p_current_entry = NULL;
flow_list_entry *p_next_entry = NULL;
uint32_t if_id = 0;
printf("Flow DB: starting flow id=%d, max flow id=%d\n",
MAC_UTIL_FLOW_DB_FLOW_ID_START_VAL, MAC_UTIL_FLOW_DB_FLOW_ID_MAX_VAL);
for (if_id=0; if_id < NUM_SUPPORTED_SUBSCRIBER_INTERFACES; if_id++)
{
/* before every db segment, NULL the current entry */
p_current_entry = NULL;
p_next_entry = NULL;
/* get first */
p_current_entry = _mac_util_db_flow_get_next_w_flow_key (if_id, p_current_entry, &p_next_entry);
while (NULL != p_current_entry)
{
printf("\n------------------------------\n");
printf ("\nflow_id = %d flow_type = %d\n", p_current_entry->bal_flow_key.flow_id, p_current_entry->bal_flow_key.flow_type);
printf ("\n if_id = %d sub_term_id = %d svc_port_id = %d agg_id = %d vlan_id = %d\n",
p_current_entry->if_id, p_current_entry->sub_term_id, p_current_entry->svc_port_id, p_current_entry->agg_id, p_current_entry->vlan_id);
printf("\n is_waiting_for_svc_port_active = %s is_configuration_completed=%s ind_sent = %d\n",
p_current_entry->is_waiting_for_svc_port_active==BCMOS_TRUE ? "true" : "false",
p_current_entry->is_configuration_completed==BCMOS_TRUE ? "true" : "false",
p_current_entry->ind_sent);
printf("\n------------------------------\n");
/* get next */
p_current_entry = _mac_util_db_flow_get_next_w_flow_key (if_id, p_current_entry, &p_next_entry);
}
}
return BCM_ERR_OK;
}
static bcmos_errno _cmd_flows_print_for_gem(bcmcli_session *sess, const bcmcli_cmd_parm parm[], uint16_t nParms)
{
flow_list_entry *p_current_entry = NULL;
void *p_rsc_mgr_curr_entry = NULL;
void *p_rsc_mgr_next_entry = NULL;
uint32_t if_id = 0;
printf("Flow DB for a GEM port [%ld]: starting flow id=%d, max flow id=%d\n",
parm[0].value.unumber, MAC_UTIL_FLOW_DB_FLOW_ID_START_VAL, MAC_UTIL_FLOW_DB_FLOW_ID_MAX_VAL);
for (if_id=0; if_id < NUM_SUPPORTED_SUBSCRIBER_INTERFACES; if_id++)
{
/* before every db segment, NULL the current entry */
p_current_entry = NULL;
/* get first */
p_current_entry = _mac_util_db_flow_get_next_w_gem (if_id, parm[0].value.unumber, &p_rsc_mgr_curr_entry, &p_rsc_mgr_next_entry);
while (NULL != p_current_entry)
{
printf("\n------------------------------\n");
printf ("\nflow_id = %d flow_type = %d\n", p_current_entry->bal_flow_key.flow_id, p_current_entry->bal_flow_key.flow_type);
printf ("\n if_id = %d sub_term_id = %d svc_port_id = %d agg_id = %d vlan_id = %d\n",
p_current_entry->if_id, p_current_entry->sub_term_id, p_current_entry->svc_port_id, p_current_entry->agg_id, p_current_entry->vlan_id);
printf("\n is_waiting_for_svc_port_active = %s is_configuration_completed=%s ind_sent = %d\n",
p_current_entry->is_waiting_for_svc_port_active==BCMOS_TRUE ? "true" : "false",
p_current_entry->is_configuration_completed==BCMOS_TRUE ? "true" : "false",
p_current_entry->ind_sent);
printf("\n------------------------------\n");
/* get next */
p_current_entry = _mac_util_db_flow_get_next_w_gem (if_id, parm[0].value.unumber, &p_rsc_mgr_curr_entry, &p_rsc_mgr_next_entry);
}
}
return BCM_ERR_OK;
}
static bcmos_errno _cmd_flows_print_for_alloc_id(bcmcli_session *sess, const bcmcli_cmd_parm parm[], uint16_t nParms)
{
flow_list_entry *p_current_entry = NULL;
void *p_rsc_mgr_curr_entry = NULL;
void *p_rsc_mgr_next_entry = NULL;
uint32_t if_id = 0;
printf("Flow DB for a Alloc Id [%ld]: starting flow id=%d, max flow id=%d\n",
parm[0].value.unumber, MAC_UTIL_FLOW_DB_FLOW_ID_START_VAL, MAC_UTIL_FLOW_DB_FLOW_ID_MAX_VAL);
for (if_id=0; if_id < NUM_SUPPORTED_SUBSCRIBER_INTERFACES; if_id++)
{
/* before every db segment, NULL the current entry */
p_current_entry = NULL;
/* get first */
p_current_entry = _mac_util_db_flow_get_next_w_alloc_id (if_id, parm[0].value.unumber, &p_rsc_mgr_curr_entry, &p_rsc_mgr_next_entry);
while (NULL != p_current_entry)
{
printf("\n------------------------------\n");
printf ("\nflow_id = %d flow_type = %d\n", p_current_entry->bal_flow_key.flow_id, p_current_entry->bal_flow_key.flow_type);
printf ("\n if_id = %d sub_term_id = %d svc_port_id = %d agg_id = %d vlan_id = %d\n",
p_current_entry->if_id, p_current_entry->sub_term_id, p_current_entry->svc_port_id, p_current_entry->agg_id, p_current_entry->vlan_id);
printf("\n is_waiting_for_svc_port_active = %s is_configuration_completed=%s ind_sent = %d\n",
p_current_entry->is_waiting_for_svc_port_active==BCMOS_TRUE ? "true" : "false",
p_current_entry->is_configuration_completed==BCMOS_TRUE ? "true" : "false",
p_current_entry->ind_sent);
printf("\n------------------------------\n");
/* get next */
p_current_entry = _mac_util_db_flow_get_next_w_alloc_id (if_id, parm[0].value.unumber, &p_rsc_mgr_curr_entry, &p_rsc_mgr_next_entry);
}
}
return BCM_ERR_OK;
}
/* Update CLI based on the system mode */
static void handle_system_mode_change(bcmolt_devid dev)
{
if (dev == current_device)
{
bcmcli_entry *cur_dir = bcmcli_dir_get(current_session);
char old_dir_name[32] = "";
if (cur_dir)
strncpy(old_dir_name, bcmcli_token_name(cur_dir), sizeof(old_dir_name) - 1);
bcmcli_dir_set(current_session, maple_dir);
api_cli_set_commands(current_session);
/* Restore current CLI directory */
cur_dir = bcmcli_dir_find(NULL, old_dir_name);
bcmcli_dir_set(current_session, cur_dir);
}
}
/*****************************************************************************/
/**
* @brief mac_util_cli_init
*
* This routine is called from main to initialize the mac_app cli,
*that is used for internal unit testing.
*
* @param cli_dir - a pointer to the cli directory to init that cli in
* @return bcmos_errno
*/
/*****************************************************************************/
bcmos_errno mac_util_cli_init(bcmcli_entry *cli_dir)
{
bcmcli_entry *p_cli_dir;
bcmos_errno rc = BCM_ERR_OK;
do
{
p_cli_dir = bcmcli_dir_add(cli_dir, "Mac_Util", "Mac Util (debug)", BCMCLI_ACCESS_ADMIN, NULL);
BCMCLI_MAKE_CMD_NOPARM(p_cli_dir, "print_flows", "print mac app flows list", _cmd_flows_print);
BCMCLI_MAKE_CMD(p_cli_dir, "print_flows_for_gem", "print mac flows sharing a GEM port", _cmd_flows_print_for_gem,
BCMCLI_MAKE_PARM("gem_port_id", "GEM Port Id", BCMCLI_PARM_UNUMBER, 0));
BCMCLI_MAKE_CMD(p_cli_dir, "print_flows_for_alloc_id", "print mac flows sharing an Alloc Id", _cmd_flows_print_for_alloc_id,
BCMCLI_MAKE_PARM("alloc_id", "Alloc Id", BCMCLI_PARM_UNUMBER, 0));
/* Initialize the bal api cli UI */
maple_dir = bcmcli_dir_add(NULL, "maple", "Maple API access", BCMCLI_ACCESS_ADMIN, NULL);
sm_change_cb = handle_system_mode_change;
/* Init device selector */
rc = bcmolt_dev_sel_init(maple_dir);
/* Add Maple API commands */
rc = rc ? rc : api_cli_init(maple_dir, current_session);
#ifdef BOARD
rc = rc ? rc : bcm_board_init();
rc = rc ? rc : bcm_board_cli_init(NULL);
#endif
rc = rc ? rc : bcmtr_init();
rc = rc ? rc : bcmtr_cld_cli_init();
rc = rc ? rc : bcmtr_cli_init();
} while(0);
return rc;
return BCM_ERR_OK;
}
/*****************************************************************************/
/**
* @brief Un-initialize the mac util internal data structures
*
* @returns bcmos_errno == BCM_ERR_OK
*
* @note this routine does not seem to be used currently
*****************************************************************************/
bcmos_errno mac_util_finish(void)
{
flow_list_entry *p_current_entry = NULL, *p_next_entry = NULL;
uint32_t if_id = 0;
for (if_id=0; if_id < NUM_SUPPORTED_SUBSCRIBER_INTERFACES; if_id++)
{
/* before every db segment, NULL the current entry */
p_current_entry = NULL;
p_next_entry = NULL;
/* Free all the entries on the flows list */
/* get first */
p_current_entry = _mac_util_db_flow_get_next_w_flow_key (if_id, p_current_entry, &p_next_entry);
while (NULL != p_current_entry)
{
/* Remove it from the list, and free memory */
_mac_util_db_flow_remove (if_id, p_current_entry);
_mac_util_db_flow_free (if_id, p_current_entry);
/* get next */
p_current_entry = _mac_util_db_flow_get_next_w_flow_key (if_id, p_current_entry, &p_next_entry);
}
}
return BCM_ERR_OK;
}
bcmos_errno mac_util_access_terminal_sw_version_validate(bcmolt_devid device)
{
bcmolt_device_cfg cfg = {};
bcmolt_device_key key = {};
bcmos_errno rc;
BCMOLT_CFG_INIT(&cfg, device, key);
BCMOLT_CFG_PROP_GET(&cfg, device, host_sw_version);
rc = bcmolt_cfg_get(device, &cfg.hdr);
if (rc != BCM_ERR_OK)
{
BCM_LOG(ERROR, log_id_mac_util, "Unable to get OLT SW version\n");
return rc;
}
BCM_LOG(INFO, log_id_mac_util,
"Actual OLT SW version %d.%d.%X (Object model revision %d)\n",
cfg.data.host_sw_version.major,
cfg.data.host_sw_version.minor,
cfg.data.host_sw_version.revision,
cfg.data.host_sw_version.model);
BCM_LOG(INFO, log_id_mac_util,
"BAL OLT SW version %d.%d.%X (Object model revision %d)\n",
BCMOLT_HOST_MAJOR_VER,
BCMOLT_HOST_MINOR_VER,
BCMOLT_HOST_REVISION_VER,
BCMOLT_MODEL_REVISION);
/* Check for versions mismatch */
if (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)
{
BCM_LOG(ERROR, log_id_mac_util, INBOLD_BAD(
"SW versions mismatch: BAL was complied with OTL SW version %d.%d.%X (Object model revision %d), "
"while actual OLT SW version is %d.%d.%X (Object model revision %d)\n"),
BCMOLT_HOST_MAJOR_VER,
BCMOLT_HOST_MINOR_VER,
BCMOLT_HOST_REVISION_VER,
BCMOLT_MODEL_REVISION,
cfg.data.host_sw_version.major,
cfg.data.host_sw_version.minor,
cfg.data.host_sw_version.revision,
cfg.data.host_sw_version.model);
return BCM_ERR_STATE;
}
return BCM_ERR_OK;
}
/*@}*/