blob: e44a574d9f0a1855207ca95aa614832f0df538f0 [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_common_itu_pon.c
*
* @brief mac util interfaces definition used by Bal Core, for ITU PON flavors : GPON, XG-PON1, XGS-PON , NG-PON2
*
* 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 <bcm_topo.h>
/**
* @brief get string for the indication object type
*/
char *mac_util_indication_get_obj_type_str(bcmolt_obj_id obj_type, mac_util_ind_obj_and_handlers handlers[], size_t handlers_size)
{
return _mac_util_get_obj_type_str_for_indications(obj_type, handlers, handlers_size);
}
/**
* @brief handle indications for any PON ITU flavor.
*/
bcmos_errno mac_util_handle_indication(bcmolt_devid device_id, bcmolt_msg *p_msg, mac_util_ind_obj_and_handlers handlers[], size_t handlers_size)
{
int i = 0;
for(i=0; i < handlers_size; i++)
{
if(p_msg->obj_type == handlers[i].obj_type)
{
if(NULL != handlers[i].ind_handler)
{
return handlers[i].ind_handler(device_id, p_msg);
}
}
}
/* log an error if unhandled */
return BCM_ERR_INTERNAL;
}
/**
* @brief checks if a gem port is configured in OLT already for the same PON If and ONU
*
* @param svc_port_id gem port
* @param if_id PON NI
* @param onu_id ONU Id
* @param is_config_required TRUE/FALSE
* @param is_wait_for_indication TRUE/FALSE
*
* @return bcmos_errno
*
* @todo with multi-thread support in future, the code from checking the maple object
* to the actual config will need to be atomic(i.e. using mutex). This, to avoid closely parallel threads
* from getting a state of gem slightly before a new config another thread would make on the same gem,
* before this thread could configure it. This applies to both gem and alloc id checks.
*
*/
static bcmos_errno maple_mac_check_gem_port_id_config(uint16_t svc_port_id, uint32_t if_id, uint32_t onu_id,
bcmos_bool *is_config_required, bcmos_bool *is_wait_for_indication)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_topo_pon_sub_family pon_sub_family;
bcmos_bool is_configured = BCMOS_FALSE, is_activated = BCMOS_FALSE;
/* assume config is not required, if there is an error */
*is_config_required = BCMOS_FALSE;
*is_wait_for_indication = BCMOS_FALSE;
pon_sub_family = bcm_topo_pon_get_pon_sub_family(if_id);
switch(pon_sub_family)
{
case BCM_TOPO_PON_SUB_FAMILY_GPON:
{
rc = maple_gpon_mac_check_gem_port_id(if_id, onu_id, svc_port_id, &is_configured, &is_activated);
}
break;
case BCM_TOPO_PON_SUB_FAMILY_XGPON:
{
rc = maple_xgpon_mac_check_gem_port_id(if_id, onu_id, svc_port_id, &is_configured, &is_activated);
}
break;
default:
{
rc = BCM_ERR_NOT_SUPPORTED;
}
}
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id), "%s failed with error %s\n",__FUNCTION__, bcmos_strerror(rc));
return rc;
}
*is_config_required = !is_configured;
*is_wait_for_indication = !is_activated;
if(BCMOS_FALSE == *is_config_required)
{
BCM_LOG(INFO, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id),
"%s: gem port id is already configured: if_id = %d onu_id = %d svc_port_id = %d is_wait_for_indication = %s\n",
__FUNCTION__,
if_id, onu_id,svc_port_id,
(*is_wait_for_indication == BCMOS_TRUE ? "TRUE":"FALSE"));
}
return rc;
}
/**
* @brief Checks if a gem port needs to be actually deconfigured.
* This would be used during flow remove.
*
* @param svc_port_id gem port
* @param if_id PON NI
* @param onu_id ONU Id
* @param is_deconfig_required TRUE/FALSE
* @param is_wait_for_indication TRUE/FALSE
*
* @return bcmos_errno
*/
static bcmos_errno maple_mac_check_gem_port_id_deconfig(uint16_t svc_port_id, uint32_t if_id, uint32_t onu_id,
bcmos_bool *is_deconfig_required, bcmos_bool *is_wait_for_indication)
{
bcmos_errno rc = BCM_ERR_OK;
uint32_t ref_count = 0;
bcm_topo_pon_mode pon_mode;
bcmos_bool is_configured = BCMOS_FALSE, is_activated = BCMOS_FALSE;
/* assume De-config not required, in case of an error */
*is_deconfig_required = BCMOS_FALSE;
*is_wait_for_indication = BCMOS_FALSE;
pon_mode = bcm_topo_pon_get_pon_mode(if_id);
if(pon_mode == BCM_TOPO_PON_MODE_GPON)
{
rc = maple_gpon_mac_check_gem_port_id(if_id, onu_id, svc_port_id, &is_configured, &is_activated);
}
else if(BCM_TOPO_PON_SUB_FAMILY_XGPON == bcm_topo_pon_get_pon_sub_family(if_id))
{
rc = maple_xgpon_mac_check_gem_port_id(if_id, onu_id, svc_port_id, &is_configured, &is_activated);
}
else
{
rc = BCM_ERR_NOT_SUPPORTED;
}
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id), "%s failed with error %s\n",__FUNCTION__, bcmos_strerror(rc));
return rc;
}
if(!is_configured)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id),
"%s error in gpon gem port state: svc_port_id = %d if_id = %d onu_id = %d, gem state: NOT_CONFIGURED\n",
__FUNCTION__,
svc_port_id, if_id, onu_id);
return BCM_ERR_INTERNAL;
}
/** First: Check if gem deconfig is required:
* gem deconfig is not needed if other flows are still using the same gem, or it is already being deconfigured.
*/
#if RSRC_MGR_KEEPS_FLOW_LIST_PER_GEM
/** @todo the rsrc mgr ref count will not work for now since core fsm keeps the flow with admin down,
* though mac util does a clear on the gem.
*/
/* get the ref count for the gem from rsc mgr */
rc = rsc_mgr_gem_lookup(if_id, svc_port_id, &ref_count);
if(BCM_ERR_OK != rc)
{
return BCM_ERR_PARM;
}
#else
rc = _mac_util_db_flow_count_w_gem(if_id, svc_port_id, &ref_count);
if(BCM_ERR_OK != rc)
{
return rc;
}
#endif
/* if more than 1 flow is using the gem in whatever state, skip deconfig */
if(1 < ref_count)
{
*is_deconfig_required = BCMOS_FALSE;
}
else
{
*is_deconfig_required = BCMOS_TRUE;
}
/* Gem port configuration indications are available on GPON only */
if(pon_mode == BCM_TOPO_PON_MODE_GPON)
{
/** Next: Check if need to wait for indication */
if(BCMOS_TRUE == *is_deconfig_required)
{
if(!is_activated)
{
*is_wait_for_indication = BCMOS_FALSE;
}
else
{
*is_wait_for_indication = BCMOS_TRUE;
}
}
else
{
*is_wait_for_indication = BCMOS_FALSE;
}
}
else
{
*is_wait_for_indication = BCMOS_FALSE;
}
if(BCMOS_FALSE == *is_deconfig_required)
{
BCM_LOG(INFO, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id),
"Skip gem port deconfig: is_deconfig_required = %s, is_wait_for_indication = %s, svc_port_id = %d if_id = %d onu_id = %d, [ref_count=%d, gem_is configured=%d, gem_is_activated=%d]\n",
(*is_deconfig_required == BCMOS_TRUE ? "TRUE":"FALSE"),
(*is_wait_for_indication == BCMOS_TRUE ? "TRUE":"FALSE"),
svc_port_id, if_id, onu_id,
ref_count, is_configured, is_activated);
}
return rc;
}
/**
* @brief maple_gem_port_id_add
*
* This routine is used for configuring at maple a specific gem port id on a given pon interface
* and assign it to a given onu id
* currently all sla properties are hard coded
*
* @param svc_port_id the gem port id
* @param if_id the interface id
* @param onu_id the onu id it will assign to
*
* @return bcmos_errno
*/
static bcmos_errno maple_gem_port_id_add(uint16_t svc_port_id, uint32_t if_id, uint32_t onu_id)
{
bcmos_errno rc = BCM_ERR_OK;
bcmolt_gem_port_configuration configuration = {};
bcm_topo_pon_mode pon_mode;
if(onu_id < MAC_UTIL_DUMMY_ONU_ID_FOR_MULTICAST_GEM)
{
configuration.direction = BCMOLT_GEM_PORT_DIRECTION_BIDIRECTIONAL;
configuration.type = BCMOLT_GEM_PORT_TYPE_UNICAST;
}
else
{
configuration.direction = BCMOLT_GEM_PORT_DIRECTION_DOWNSTREAM;
configuration.type = BCMOLT_GEM_PORT_TYPE_MULTICAST;
}
pon_mode = bcm_topo_pon_get_pon_mode(if_id);
if(pon_mode == BCM_TOPO_PON_MODE_GPON)
{
rc = maple_gpon_gem_port_id_add(if_id, svc_port_id, onu_id, &configuration);
}
else if(BCM_TOPO_PON_SUB_FAMILY_XGPON == bcm_topo_pon_get_pon_sub_family(if_id))
{
rc = maple_xgpon_gem_port_id_add(if_id, svc_port_id, onu_id, &configuration);
}
else
{
rc = BCM_ERR_NOT_SUPPORTED;
}
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id), "%s failed with error %s\n",__FUNCTION__, bcmos_strerror(rc));
}
return rc;
}
/**
* @brief maple_gem_port_id_remove
*
* This routine is used Clear a specific gem port id config in OLT on a given pon interface.
*
* @param svc_port_id the gem port id
* @param if_id the interface id
*
* @return bcmos_errno
*
* @todo do we need to fill in all parameters to disable GEM or just the gem key ?
*/
static bcmos_errno maple_gem_port_id_remove(uint16_t svc_port_id, uint32_t if_id)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_topo_pon_mode pon_mode;
pon_mode = bcm_topo_pon_get_pon_mode(if_id);
if(pon_mode == BCM_TOPO_PON_MODE_GPON)
{
rc = maple_gpon_gem_port_id_remove(if_id, svc_port_id);
}
else if(BCM_TOPO_PON_SUB_FAMILY_XGPON == bcm_topo_pon_get_pon_sub_family(if_id))
{
rc = maple_xgpon_gem_port_id_remove(if_id, svc_port_id);
}
else
{
rc = BCM_ERR_NOT_SUPPORTED;
}
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id),
"Failed to clear gem port configuration(%s) in OLT\n",
bcmos_strerror(rc));
}
return rc;
}
/**
* @brief checks if a alloc id is configured in OLT already for the same PON If and ONU
*
* @param agg_id alloc id
* @param if_id PON NI
* @param onu_id ONU Id
* @param p_alloc_id_state alloc id current state
*
* @return bcmos_errno
*/
static bcmos_errno maple_mac_check_alloc_id_state(uint16_t agg_id, uint32_t if_id, uint32_t onu_id, bcmolt_alloc_state *p_alloc_id_state)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_topo_pon_mode pon_mode;
pon_mode = bcm_topo_pon_get_pon_mode(if_id);
if(pon_mode == BCM_TOPO_PON_MODE_GPON)
{
rc = maple_gpon_mac_get_alloc_id_config(if_id, onu_id, agg_id, p_alloc_id_state);
}
else if(BCM_TOPO_PON_SUB_FAMILY_XGPON == bcm_topo_pon_get_pon_sub_family(if_id))
{
rc = maple_xgpon_mac_get_alloc_id_config(if_id, onu_id, agg_id, p_alloc_id_state);
}
else
{
rc = BCM_ERR_NOT_SUPPORTED;
}
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id), "%s failed with error %s\n",__FUNCTION__, bcmos_strerror(rc));
return rc;
}
return rc;
}
static bcmos_errno maple_mac_check_alloc_id_config(uint16_t agg_id, uint32_t if_id, uint32_t onu_id)
{
bcmos_errno rc;
bcmolt_alloc_state alloc_id_state;
rc = maple_mac_check_alloc_id_state(agg_id, if_id, onu_id, &alloc_id_state);
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id), "%s failed with error %s\n",
__FUNCTION__, bcmos_strerror(rc));
return rc;
}
if(BCMOLT_ALLOC_STATE_NOT_CONFIGURED != alloc_id_state)
rc = BCM_ERR_PARM;
return rc;
}
static bcmos_errno maple_mac_check_alloc_id_active(uint16_t agg_id, uint32_t if_id, uint32_t onu_id, bcmos_bool *is_alloc_id_wait_for_ind)
{
bcmos_errno rc;
bcmolt_alloc_state alloc_id_state;
rc = maple_mac_check_alloc_id_state(agg_id, if_id, onu_id, &alloc_id_state);
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id), "%s failed with error %s\n",__FUNCTION__, bcmos_strerror(rc));
return rc;
}
*is_alloc_id_wait_for_ind = BCMOLT_ALLOC_STATE_ACTIVE != alloc_id_state;
return rc;
}
/**
* @brief helper function to check flow with double tag and with action remove outer tag.
* Used for validation as well as flow config.
*
* @param p_flow_req A pointer to a flow object
*
* @return bcmos_errno
*/
bcmos_bool mac_util_check_flow_is_double_tag_remove_o_tag(const bcmbal_flow_cfg *p_flow_req)
{
if(NULL != p_flow_req)
{
if(BCMBAL_FLOW_TYPE_DOWNSTREAM == p_flow_req->key.flow_type &&
BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow_req, flow, action) &&
(p_flow_req->data.action.cmds_bitmask & BCMBAL_ACTION_CMD_ID_REMOVE_OUTER_TAG) &&
(p_flow_req->data.classifier.pkt_tag_type == BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG))
{
return BCMOS_TRUE;
}
}
return BCMOS_FALSE;
}
/**
* @brief maple_mac_unicast_flow_add
*
* This routine is used to configure a flow at the internal flows list to
* handle incoming and outgoing relevant indications.
* the flow svc_port is defined using a single gem port by a base_gem_port
* and single pbit(=0 in case of pbit is not available)
* it will also configure gem port and alloc id at the device if required.
*
*
* @param if_id - the pon interface id
* @param onu_id - the onu id
* @param agg_id - the alloc id
* @param sla - the sla configuration of the alloc id
*
* @return bcmos_errno
*/
bcmos_errno maple_mac_agg_port_add(uint32_t if_id, uint32_t onu_id, uint16_t agg_id, bcmolt_pon_alloc_sla sla)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_topo_pon_mode pon_mode;
do
{
rc = maple_mac_check_alloc_id_config(agg_id, if_id, onu_id);
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id),
"Failed to query alloc state\n");
break;
}
pon_mode = bcm_topo_pon_get_pon_mode(if_id);
if(pon_mode == BCM_TOPO_PON_MODE_GPON)
{
rc = maple_gpon_us_alloc_id_add(if_id, onu_id, agg_id, sla);
}
else if(BCM_TOPO_PON_SUB_FAMILY_XGPON == bcm_topo_pon_get_pon_sub_family(if_id))
{
rc = maple_xgpon_us_alloc_id_add(if_id, onu_id, agg_id, sla);
}
else
{
rc = BCM_ERR_NOT_SUPPORTED;
}
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id), "%s failed with error %s\n",__FUNCTION__, bcmos_strerror(rc));
}
}while(0);
return rc;
}
/**
* @brief maple_mac_agg_port_remove
*
* This routine is used for De-configuring at maple a specific alloc_id on a given pon interface
*
* @param if_id - the pon interface id
*
* @param agg_id - the alloc id
*
* @return bcmos_errno
*/
bcmos_errno maple_mac_agg_port_remove(uint32_t if_id, uint16_t agg_id)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_topo_pon_mode pon_mode;
pon_mode = bcm_topo_pon_get_pon_mode(if_id);
if(pon_mode == BCM_TOPO_PON_MODE_GPON)
{
rc = maple_gpon_us_alloc_id_remove(if_id, agg_id);
}
else if(BCM_TOPO_PON_SUB_FAMILY_XGPON == bcm_topo_pon_get_pon_sub_family(if_id))
{
rc = maple_xgpon_us_alloc_id_remove(if_id, agg_id);
}
else
{
rc = BCM_ERR_NOT_SUPPORTED;
}
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(if_id), "%s failed with error %s\n",__FUNCTION__, bcmos_strerror(rc));
}
return rc;
}
bcmos_errno maple_mac_unicast_flow_add(bcmbal_flow_cfg *p_flow, uint16_t pbit, uint16_t per_flow_mode_vlan_id, bal_util_oper_flow op_type,
flow_list_entry **pp_mac_util_flow_entry)
{
bcmos_errno rc = BCM_ERR_OK;
bcmos_bool is_gem_config_required = BCMOS_TRUE;
bcmos_bool is_gem_wait_for_ind = BCMOS_TRUE , is_alloc_id_wait_for_ind = BCMOS_TRUE;
flow_list_entry *p_new_flow_entry = NULL;
*pp_mac_util_flow_entry = NULL;
do
{
/* Allocate & add the new flow to the flow list to follow indications/gem reuse/alloc reuse */
p_new_flow_entry = _mac_util_db_flow_alloc();
if(NULL == p_new_flow_entry)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"Failed to allocate the flow entry\n");
rc = BCM_ERR_NOMEM;
break;
}
memcpy(&p_new_flow_entry->bal_flow_key, &p_flow->key,
sizeof(bcmbal_flow_key));
p_new_flow_entry->if_id = p_flow->data.access_int_id;
p_new_flow_entry->sub_term_id = p_flow->data.sub_term_id;
p_new_flow_entry->svc_port_id = p_flow->data.svc_port_id;
if(BCMBAL_FLOW_TYPE_UPSTREAM == p_flow->key.flow_type)
{
p_new_flow_entry->agg_id = p_flow->data.agg_port_id;
}
p_new_flow_entry->vlan_id = per_flow_mode_vlan_id;
p_new_flow_entry->is_waiting_for_svc_port_active = BCMOS_TRUE;
p_new_flow_entry->ind_sent = BAL_UTIL_FLOW_IND_SEND_NONE;
p_new_flow_entry->is_configuration_completed = BCMOS_FALSE;
/* save the operation type so as to report back the right indication type to core on an indication from Maple */
p_new_flow_entry->op_type = op_type;
/* check if gem configuration is required or it was already configured,
could happen in case of us flow configured after a ds flow(with the same flow_id)
and vise versus, or if that is a case of different flow sharing the same gem port id */
if(BCMOS_TRUE == is_gem_config_required)
{
rc = maple_mac_check_gem_port_id_config(p_new_flow_entry->svc_port_id,
p_new_flow_entry->if_id,
p_new_flow_entry->sub_term_id,
&is_gem_config_required,
&is_gem_wait_for_ind);
if(BCM_ERR_OK != rc)
{
/* free the flow entry */
_mac_util_db_flow_free(p_flow->data.access_int_id, p_new_flow_entry);
rc = BCM_ERR_PARM;
break;
}
/* set wait for ind flag */
p_new_flow_entry->is_waiting_for_svc_port_active = is_gem_wait_for_ind;
}
/* if that's an us flow, check if alloc configuration is required or it was already configured */
if(p_new_flow_entry->bal_flow_key.flow_type == BCMBAL_FLOW_TYPE_UPSTREAM)
{
rc = maple_mac_check_alloc_id_active(p_new_flow_entry->agg_id,
p_new_flow_entry->if_id,
p_new_flow_entry->sub_term_id,
&is_alloc_id_wait_for_ind);
if(BCM_ERR_OK != rc)
{
/* free the flow entry */
_mac_util_db_flow_free(p_flow->data.access_int_id, p_new_flow_entry);
rc = BCM_ERR_PARM;
break;
}
}
/* add the new flow to the flow DB */
rc = _mac_util_db_flow_add(p_flow->data.access_int_id, p_new_flow_entry);
if(BCM_ERR_OK != rc)
{
/* free the flow entry */
_mac_util_db_flow_free(p_flow->data.access_int_id, p_new_flow_entry);
break;
}
/* configure the gem port id if required */
if(BCMOS_TRUE == is_gem_config_required)
{
rc = maple_gem_port_id_add(p_new_flow_entry->svc_port_id, p_new_flow_entry->if_id, p_new_flow_entry->sub_term_id);
if(BCM_ERR_OK != rc)
{
break;
}
}
} while(0);
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"%s Failed: rc = %s(%d), flow Id/Type=%d/%d, pbit=%d, if_id=%d, sub_term_id=%d, "
"svc_port_id=%d, agg_id=%d, vlan_id=%d, op type=%s\n",
__FUNCTION__,
bcmos_strerror(rc), rc,
p_flow->key.flow_id, p_flow->key.flow_type, pbit,
p_flow->data.access_int_id, p_flow->data.sub_term_id,
p_flow->data.svc_port_id, p_flow->data.agg_port_id, per_flow_mode_vlan_id,
(BAL_UTIL_OPER_FLOW_ADD == op_type ? "FLOW_ADD":"INVALID"));
}
/* set the arg to return the local flow entry to caller */
*pp_mac_util_flow_entry = p_new_flow_entry;
return rc;
}
/**
* @brief utility routine to correctly assign the SLAs to new tm sched owned by agg port
* This routine adjusts the BW values to be aligned with 8KBytes/sec boundary. It also
* adjusts the difference between pbr & sbr to be at least 32KBytes/sec
*
* @param p_tm_sched_req new tm sched instance
* @param p_agg_sla pointer to the sla configuration
*
* @note For Maple to accept the sla config:
* (1) the sbr and pbr values from BAL user should be in increments of 256 KBits/sec.
* (2) Also, the sbr should be at least 256 Kbits/sec less than the pbr.
* (3) sbr value can be 0 or else at least 256 Kbits/sec
* (4) pbr value can be 256 Kbits/sec or above
*
* @note The SLA is used for the upstream alloc_id really, even though this is being called for downstream and upstream.
*
*/
void mac_util_assign_agg_port_sla(bcmbal_tm_sched_cfg *p_tm_sched_req, bcmolt_pon_alloc_sla *p_agg_sla)
{
BUG_ON(NULL == p_tm_sched_req);
if(BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_tm_sched_req->data.rate,tm_shaping, sbr))
{
p_agg_sla->guaranteed_bw = KILOBITS_PER_SEC2BYTES_PER_SEC(p_tm_sched_req->data.rate.sbr);
/* Align the BW to 8KBytes granularity(always upward adjustment) */
p_agg_sla->guaranteed_bw = SLA_BW_NKBYTES_ALIGNED(p_agg_sla->guaranteed_bw, MAC_UTIL_PMDB(p_tm_sched_req->data.owner.u.agg_port.intf_id).sla_us_rate_factor);
if(BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_tm_sched_req->data.rate, tm_shaping, pbr))
{
p_agg_sla->maximum_bw = KILOBITS_PER_SEC2BYTES_PER_SEC(p_tm_sched_req->data.rate.pbr);
/* max rate should be bigger by 32KBytes/sec than guaranteed rate */
if(MAPLE_MIN_BYTES_PER_SEC_FOR_DEFAULT_ALLOC_ID >(p_agg_sla->maximum_bw - p_agg_sla->guaranteed_bw))
{
p_agg_sla->maximum_bw = p_agg_sla->guaranteed_bw + MAPLE_MIN_BYTES_PER_SEC_FOR_DEFAULT_ALLOC_ID;
}
else
{
/* Else, align the BW to 8KBytes granularity(always upward adjustment) */
p_agg_sla->maximum_bw = SLA_BW_NKBYTES_ALIGNED(p_agg_sla->maximum_bw, MAC_UTIL_PMDB(p_tm_sched_req->data.owner.u.agg_port.intf_id).sla_us_rate_factor);
}
}
else
{
/* max rate should be bigger by 32KBytes/sec than guaranteed rate */
p_agg_sla->maximum_bw = p_agg_sla->guaranteed_bw + MAPLE_MIN_BYTES_PER_SEC_FOR_DEFAULT_ALLOC_ID;
}
}
else if(BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_tm_sched_req->data.rate, tm_shaping, pbr))
{
p_agg_sla->maximum_bw = KILOBITS_PER_SEC2BYTES_PER_SEC(p_tm_sched_req->data.rate.pbr);
/* Align the BW to 8KBytes granularity(always upward adjustment) */
p_agg_sla->maximum_bw = SLA_BW_NKBYTES_ALIGNED(p_agg_sla->maximum_bw , MAC_UTIL_PMDB(p_tm_sched_req->data.owner.u.agg_port.intf_id).sla_us_rate_factor);
/* since only max_rate was specified, it is best effort, so set the min rate = 0 */
p_agg_sla->guaranteed_bw = 0;
}
else
{
/* Nothing is set, so assign the defaults(that suits GPON) times the SLA US rate factor(GPON=1, XG-PON1=2, XGS-PON,NG-PON2=8) */
p_agg_sla->guaranteed_bw = SLA_GUARANTEED_BW_DEFAULT_BYTES_PER_SEC * MAC_UTIL_PMDB(p_tm_sched_req->data.owner.u.agg_port.intf_id).sla_us_rate_factor;
p_agg_sla->maximum_bw = SLA_MAX_BW_DEFAULT_BYTES_PER_SEC * MAC_UTIL_PMDB(p_tm_sched_req->data.owner.u.agg_port.intf_id).sla_us_rate_factor;
}
if(BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_tm_sched_req->data.tcont_sla, tm_tcont_sla, nrt_cbr))
{
/* Align the BW to 8KBytes granularity(always upward adjustment) */
p_agg_sla->cbr_nrt_bw = SLA_BW_NKBYTES_ALIGNED(p_tm_sched_req->data.tcont_sla.nrt_cbr, MAC_UTIL_PMDB(p_tm_sched_req->data.owner.u.agg_port.intf_id).sla_us_rate_factor);
}
else
{
p_agg_sla->cbr_nrt_bw = 0;
}
if(BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_tm_sched_req->data.tcont_sla, tm_tcont_sla, rt_cbr))
{
/* Align the BW to 8KBytes granularity(always upward adjustment) */
p_agg_sla->cbr_rt_bw = SLA_BW_NKBYTES_ALIGNED(p_tm_sched_req->data.tcont_sla.rt_cbr, MAC_UTIL_PMDB(p_tm_sched_req->data.owner.u.agg_port.intf_id).sla_us_rate_factor);
}
else
{
p_agg_sla->cbr_rt_bw = 0;
}
if(BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_tm_sched_req->data.tcont_sla, tm_tcont_sla, extra_bw_elig))
{
p_agg_sla->additional_bw_eligibility = p_tm_sched_req->data.tcont_sla.extra_bw_elig;
}
else
{
p_agg_sla->additional_bw_eligibility = BCMOLT_ADDITIONAL_BW_ELIGIBILITY_BEST_EFFORT;
}
if(BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_tm_sched_req->data.tcont_sla, tm_tcont_sla, rt_profile))
{
p_agg_sla->cbr_rt_ap_index = p_tm_sched_req->data.tcont_sla.rt_profile;
}
else
{
p_agg_sla->cbr_rt_ap_index = 0;
}
if(BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_tm_sched_req->data.tcont_sla, tm_tcont_sla, nrt_profile))
{
p_agg_sla->cbr_nrt_ap_index = p_tm_sched_req->data.tcont_sla.nrt_profile;
}
else
{
p_agg_sla->cbr_nrt_ap_index = 0;
}
p_agg_sla->alloc_type = BCMOLT_ALLOC_TYPE_NSR;
p_agg_sla->cbr_rt_compensation = BCMOS_FALSE;
p_agg_sla->weight = 0;
p_agg_sla->priority = 0;
}
/**
* @brief mark_flow_config_complete
*
* This routine is used to mark all related flow entries, that the flow configuration requests to device was completed,
* meaning now it is ready to be checked for configuration completion indication from device, and to be indicated to core.
*
* @param p_flow_entry pointer to mac util flow instance
*
* @return void
*/
void mac_util_mark_flow_config_complete(flow_list_entry *p_flow_entry)
{
if(NULL != p_flow_entry)
{
p_flow_entry->is_configuration_completed = BCMOS_TRUE;
}
}
/**
* @brief maple_mac_broadcast_flow_add
*
* This routine is used for setting required configuration for a new broadcast flow :
* gem port id, iwf ds flow and configure it as a miss fallback of its assigned interface.
* it will also create an entry for the new flow at the internal flows list to follow relevant indication
*
* @param p_flow A pointer to a flow object
* @param per_flow_mode_vlan_id vlan id used for GEM port mapping in per flow mode
* @param op_type flow "add" or "modify"
* @param pp_mac_util_flow_entry addr of pointer to flow entry in mac util DB
*
* @return bcmos_errno
*/
bcmos_errno maple_mac_broadcast_flow_add(bcmbal_flow_cfg *p_flow, uint16_t per_flow_mode_vlan_id, bal_util_oper_flow op_type,
flow_list_entry **pp_mac_util_flow_entry)
{
bcmos_errno rc = BCM_ERR_PARM;
flow_list_entry *p_new_flow_entry = NULL;
bcmolt_gpon_iwf_ds_ingress_flow_key in_key;
bcmolt_gpon_iwf_ds_ingress_flow_cfg in_cfg;
bcmolt_gpon_iwf_ds_egress_flow_key egr_key;
bcmolt_gpon_iwf_ds_egress_flow_cfg egr_cfg;
bcmolt_gpon_iwf_key iwf_key;
bcmolt_gpon_iwf_cfg get_iwf_cfg, set_iwf_cfg;
bcmolt_mac_table_configuration mac_table_configuration;
bcmos_bool is_gem_config_required = BCMOS_TRUE;
bcmos_bool is_gem_wait_for_ind = BCMOS_TRUE;
bcmolt_devid device_id;
uint32_t physical_if_id;
bcm_topo_pon_mode pon_mode;
*pp_mac_util_flow_entry = NULL;
/* add the new flow to the flow list */
p_new_flow_entry = _mac_util_db_flow_alloc();
if(NULL == p_new_flow_entry)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"Failed to allocate the flow entry\n");
return BCM_ERR_NOMEM;
}
memcpy(&p_new_flow_entry->bal_flow_key, &p_flow->key, sizeof(bcmbal_flow_key));
p_new_flow_entry->if_id = p_flow->data.access_int_id;
p_new_flow_entry->sub_term_id = p_flow->data.sub_term_id;
p_new_flow_entry->svc_port_id = p_flow->data.svc_port_id;
/* broadcast gem are active by default once they are set, no indications */
p_new_flow_entry->is_waiting_for_svc_port_active = BCMOS_FALSE;
p_new_flow_entry->ind_sent = BAL_UTIL_FLOW_IND_SEND_NONE;
p_new_flow_entry->is_configuration_completed = BCMOS_FALSE;
/* make sure the broadcast gem port is not already configured / assigned to any onu on the if */
rc = maple_mac_check_gem_port_id_config(p_new_flow_entry->svc_port_id,
p_new_flow_entry->if_id,
p_new_flow_entry->sub_term_id,
&is_gem_config_required,
&is_gem_wait_for_ind);
if(BCM_ERR_OK != rc)
{
/* free the flow */
_mac_util_db_flow_free(p_flow->data.access_int_id, p_new_flow_entry);
return BCM_ERR_PARM;
}
if(BCMOS_FALSE == is_gem_config_required)
{
/* some error, can't have the broadcast flow already configured for the onu */
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"Gem %d is already configured on if %d(assigned to onu_id %d)\n",
p_new_flow_entry->svc_port_id, p_new_flow_entry->if_id, p_new_flow_entry->sub_term_id);
/* free the flow */
_mac_util_db_flow_free(p_flow->data.access_int_id, p_new_flow_entry);
return BCM_ERR_PARM;
}
/* add the new flow to the local flows list */
rc = _mac_util_db_flow_add(p_flow->data.access_int_id, p_new_flow_entry);
if(BCM_ERR_OK != rc)
{
return rc;
}
/* a broadcast gem port is 'assigned' to the special MAC_UTIL_DUMMY_ONU_ID_FOR_MULTICAST_GEM onu id */
rc = maple_gem_port_id_add(p_new_flow_entry->svc_port_id, p_new_flow_entry->if_id, MAC_UTIL_DUMMY_ONU_ID_FOR_MULTICAST_GEM);
if(BCM_ERR_OK != rc)
{
return rc;
}
/* get physical interface from logical interface */
rc = bcm_topo_pon_get_logical2physical(p_flow->data.access_int_id, &device_id, &physical_if_id);
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"Failed to get physical if from logical if(%s)\n", bcmos_strerror(rc));
return rc;
}
/* Inter-working(IWF) stuff is relevant for GPON only */
pon_mode = bcm_topo_pon_get_pon_mode(p_flow->data.access_int_id);
if(pon_mode == BCM_TOPO_PON_MODE_GPON)
{
/* configure the ingress flow as default fallback ingress flow */
in_key.pon_ni = physical_if_id;
in_key.vlan_id = per_flow_mode_vlan_id;
BCMOLT_CFG_INIT(&in_cfg, gpon_iwf_ds_ingress_flow, in_key);
BCMOLT_CFG_PROP_SET(&in_cfg, gpon_iwf_ds_ingress_flow, mapping_method,
BCMOLT_VLAN_TO_FLOW_MAPPING_METHOD_MACPLUSVID);
BCMOLT_CFG_PROP_SET(&in_cfg, gpon_iwf_ds_ingress_flow, mapping_tag,
BCMOLT_MAPPING_TAG_METHOD_OUTER_VID);
BCMOLT_CFG_PROP_SET(&in_cfg, gpon_iwf_ds_ingress_flow, vlan_action, BCMOLT_DS_VLAN_ACTION_TRANSPARENT);
rc = bcmolt_cfg_set(device_id, &in_cfg.hdr);
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"Failed to configure ingress flow pon_ni = %d vlan_id = %d rc = %s(%d), err_text = %s\n",
in_key.pon_ni, in_key.vlan_id, bcmos_strerror(rc), rc, in_cfg.hdr.hdr.err_text);
return rc;
}
/* configure the egress flow as default fallback egress flow */
egr_key.pon_ni = physical_if_id;
egr_key.flow_id = p_flow->data.svc_port_id;
/* Configure DS egress handling: flow -> GEM */
BCMOLT_CFG_INIT(&egr_cfg, gpon_iwf_ds_egress_flow, egr_key);
BCMOLT_CFG_PROP_SET(&egr_cfg, gpon_iwf_ds_egress_flow, gem_port, p_flow->data.svc_port_id);
BCMOLT_CFG_PROP_SET(&egr_cfg, gpon_iwf_ds_egress_flow, pbit_control, BCMOS_FALSE);
rc = bcmolt_cfg_set(device_id, &egr_cfg.hdr);
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"Failed to configure egress flow pon_ni = %d, rc = %s(%d), err_text = %s\n",
egr_key.pon_ni, bcmos_strerror(rc), rc, egr_cfg.hdr.hdr.err_text);
return rc;
}
/* update the if miss fallback flow */
iwf_key.pon_ni = physical_if_id;
BCMOLT_CFG_INIT(&get_iwf_cfg, gpon_iwf, iwf_key);
BCMOLT_CFG_INIT(&set_iwf_cfg, gpon_iwf, iwf_key);
BCMOLT_CFG_PROP_GET(&get_iwf_cfg, gpon_iwf, all_properties);
rc = bcmolt_cfg_get(device_id, &get_iwf_cfg.hdr);
if(BCM_ERR_OK != rc)
{
return rc;
}
mac_table_configuration = get_iwf_cfg.data.mac_table_configuration;
mac_table_configuration.miss_fallback = BCMOLT_MAC_TABLE_MISS_FALLBACK_DEFAULT_FLOW;
mac_table_configuration.default_flow_id = egr_key.flow_id;
BCMOLT_CFG_PROP_SET(&set_iwf_cfg, gpon_iwf, mac_table_configuration, mac_table_configuration);
rc = bcmolt_cfg_set(device_id, &set_iwf_cfg.hdr);
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"Failed to configure iwf: pon_ni = %d, rc = %s(%d), err_text = %s\n",
iwf_key.pon_ni, bcmos_strerror(rc), rc, set_iwf_cfg.hdr.hdr.err_text);
return rc;
}
}
p_new_flow_entry->is_configuration_completed = BCMOS_TRUE;
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"%s Failed: rc = %s(%d), flow Id/Type=%d/%d, if_id=%d, sub_term_id=%d, "
"svc_port_id=%d, agg_id=%d, vlan_id=%d, op type=%s\n",
__FUNCTION__,
bcmos_strerror(rc), rc,
p_flow->key.flow_id, p_flow->key.flow_type,
p_flow->data.access_int_id, p_flow->data.sub_term_id,
p_flow->data.svc_port_id, p_flow->data.agg_port_id, per_flow_mode_vlan_id,
(BAL_UTIL_OPER_FLOW_ADD == op_type ? "FLOW_ADD": "INVALID"));
}
/* set the arg to return the local flow entry to caller */
*pp_mac_util_flow_entry = p_new_flow_entry;
return rc;
}
/**
* @brief maple_mac_broadcast_flow_remove
*
* This routine is removes a broadcast flow from Maple
*
* @param p_flow A pointer to a flow object
* @param per_flow_mode_vlan_id vlan id for per flow mode
* @param op_type flow "remove" or "clear"
* @param p_mac_util_flow_entry mac util flow entry
*
* @return bcmos_errno
*/
bcmos_errno maple_mac_broadcast_flow_remove(bcmbal_flow_cfg *p_flow, uint16_t per_flow_mode_vlan_id, bal_util_oper_flow op_type,
flow_list_entry *p_mac_util_flow_entry)
{
bcmos_errno rc = BCM_ERR_OK;
flow_list_entry *p_target_flow_entry = NULL;
bcmolt_gpon_iwf_ds_ingress_flow_key in_key;
bcmolt_gpon_iwf_ds_ingress_flow_cfg in_cfg;
bcmolt_gpon_iwf_ds_egress_flow_key egr_key;
bcmolt_gpon_iwf_ds_egress_flow_cfg egr_cfg;
bcmolt_gpon_iwf_key iwf_key;
bcmolt_gpon_iwf_cfg set_iwf_cfg;
bcmolt_devid device_id;
uint32_t physical_if_id;
bcm_topo_pon_mode pon_mode;
/* First find the flow in local database */
p_target_flow_entry = _mac_util_db_flow_get_w_flow_key(p_flow->data.access_int_id, &(p_flow->key));
if(NULL == p_target_flow_entry)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"%s: Failed to find the flow entry: flow id: %d, flow_type: %s\n",
__FUNCTION__,
p_flow->key.flow_id,
(p_flow->key.flow_type == BCMBAL_FLOW_TYPE_BROADCAST ? "broadcast":"unicast/multicast"));
return BCM_ERR_NOENT;
}
/* broadcast gem are active by default once they are set, no indications */
p_target_flow_entry->is_waiting_for_svc_port_active = BCMOS_FALSE;
p_target_flow_entry->ind_sent = BAL_UTIL_FLOW_IND_SEND_NONE;
p_target_flow_entry->is_configuration_completed = BCMOS_FALSE;
/* clear broadcast gem port */
rc = maple_gem_port_id_remove(p_target_flow_entry->svc_port_id, p_target_flow_entry->if_id);
if(BCM_ERR_OK != rc)
{
return rc;
}
/* get physical interface from logical interface */
rc = bcm_topo_pon_get_logical2physical(p_flow->data.access_int_id, &device_id, &physical_if_id);
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"Failed to get physical if from logical if(%s)\n", bcmos_strerror(rc));
return rc;
}
/* Inter-working(IWF) stuff is relevant for GPON only */
pon_mode = bcm_topo_pon_get_pon_mode(p_flow->data.access_int_id);
if(pon_mode == BCM_TOPO_PON_MODE_GPON)
{
/* clear the ingress flow as default fallback ingress flow */
in_key.pon_ni = physical_if_id;
in_key.vlan_id = per_flow_mode_vlan_id;
BCMOLT_CFG_INIT(&in_cfg, gpon_iwf_ds_ingress_flow, in_key);
rc = bcmolt_cfg_clear(device_id, &in_cfg.hdr);
if(BCM_ERR_OK != rc)
{
BCM_LOG(WARNING, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"Failed to clear ingress flow pon_ni = %d vlan_id = %d rc = %s(%d)\n",
in_key.pon_ni, in_key.vlan_id, bcmos_strerror(rc), rc);
return rc;
}
/* clear the egress flow as default fallback egress flow */
egr_key.pon_ni = physical_if_id;
egr_key.flow_id = p_flow->data.svc_port_id;
/* Configure DS egress handling: flow -> GEM */
BCMOLT_CFG_INIT(&egr_cfg, gpon_iwf_ds_egress_flow, egr_key);
rc = bcmolt_cfg_clear(device_id, &egr_cfg.hdr);
if(BCM_ERR_OK != rc)
{
BCM_LOG(WARNING, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"Failed to clear egress flow pon_ni = %d gem port = %d rc = %s(%d)\n",
egr_key.pon_ni, egr_key.flow_id, bcmos_strerror(rc), rc);
return rc;
}
/* update the if miss fallback flow */
iwf_key.pon_ni = physical_if_id;
BCMOLT_CFG_INIT(&set_iwf_cfg, gpon_iwf, iwf_key);
rc = bcmolt_cfg_clear(device_id, &set_iwf_cfg.hdr);
if(BCM_ERR_OK != rc)
{
BCM_LOG(WARNING, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"Failed to clear iwf flow pon_ni = %d rc = %s(%d)\n",
iwf_key.pon_ni, bcmos_strerror(rc), rc);
return rc;
}
}
/* all De-config done */
p_target_flow_entry->is_configuration_completed = BCMOS_TRUE;
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"%s Failed: rc = %s(%d), flow Id/Type=%d/%d, if_id=%d, sub_term_id=%d, "
"svc_port_id=%d, agg_id=%d, vlan_id=%d, op type=%s\n",
__FUNCTION__,
bcmos_strerror(rc), rc,
p_flow->key.flow_id, p_flow->key.flow_type,
p_flow->data.access_int_id, p_flow->data.sub_term_id,
p_flow->data.svc_port_id, p_flow->data.agg_port_id, per_flow_mode_vlan_id,
(BAL_UTIL_OPER_FLOW_REMOVE == op_type ? "FLOW_REMOVE":(BAL_UTIL_OPER_FLOW_CLEAR == op_type ? "FLOW_CLEAR":"INVALID")));
}
return rc;
}
/**
* @brief maple_mac_unicast_flow_remove
*
* This routine is used to De-configure a flow at the internal flows list to
* handle incoming and outgoing relevant indications.
* It will also De-configure gem port and alloc id at the device if required.
*
* @param p_flow Pointer to the flow info
* @param op_type Flow operation type i.e. FLOW_REMOVE, FLOW_CLEAR
* @param p_mac_util_flow_entry Pointer to mac util flow entry
*
* @return bcmos_errno
*/
bcmos_errno maple_mac_unicast_flow_remove(bcmbal_flow_cfg *p_flow, bal_util_oper_flow op_type,
flow_list_entry *p_mac_util_flow_entry)
{
bcmos_errno rc = BCM_ERR_OK;
bcmos_bool is_gem_deconfig_required = BCMOS_TRUE;
bcmos_bool is_gem_wait_for_ind = BCMOS_TRUE;
flow_list_entry *p_target_flow_entry = NULL;
BUG_ON(NULL == p_mac_util_flow_entry);
do
{
p_target_flow_entry = p_mac_util_flow_entry;
p_target_flow_entry->is_waiting_for_svc_port_active = BCMOS_TRUE;
p_target_flow_entry->ind_sent = BAL_UTIL_FLOW_IND_SEND_NONE;
p_target_flow_entry->is_configuration_completed = BCMOS_FALSE;
/* save the operation type so as to report back the right indication type to core on an indication from Maple */
p_target_flow_entry->op_type = op_type;
/* check if gem configuration is used by other flows still.
could happen in case of us flow configured after a ds flow(with the same flow_id)
and vice versa, or if that is a case of different flow sharing the same gem port id */
if(BCMOS_TRUE == is_gem_deconfig_required)
{
rc = maple_mac_check_gem_port_id_deconfig(p_target_flow_entry->svc_port_id,
p_target_flow_entry->if_id,
p_target_flow_entry->sub_term_id,
&is_gem_deconfig_required,
&is_gem_wait_for_ind);
/* set wait for ind flag */
p_target_flow_entry->is_waiting_for_svc_port_active = is_gem_wait_for_ind;
if(BCM_ERR_OK != rc)
{
rc = BCM_ERR_PARM;
break;
}
}
/* do not remove the flow entry from local flows list yet; wait for indication before removing */
/* De-configure the gem port id if required */
if(BCMOS_TRUE == is_gem_deconfig_required)
{
rc = maple_gem_port_id_remove(p_target_flow_entry->svc_port_id, p_target_flow_entry->if_id);
if(BCM_ERR_OK != rc)
{
break;
}
}
} while(0);
if(BCM_ERR_OK != rc)
{
if(!((BCM_ERR_NOENT == rc) &&(BAL_UTIL_OPER_FLOW_CLEAR == op_type)))
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_flow->data.access_int_id),
"%s Failed: rc = %s(%d), flow Id/Type=%d/%d, if_id=%d, sub_term_id=%d, "
"svc_port_id=%d, agg_id=%d, op type=%s\n",
__FUNCTION__,
bcmos_strerror(rc), rc,
p_flow->key.flow_id, p_flow->key.flow_type,
p_flow->data.access_int_id, p_flow->data.sub_term_id,
p_flow->data.svc_port_id, p_flow->data.agg_port_id,
(BAL_UTIL_OPER_FLOW_REMOVE == op_type ? "FLOW_REMOVE":(BAL_UTIL_OPER_FLOW_CLEAR == op_type ? "FLOW_CLEAR":"INVALID")));
}
}
return rc;
}
bcmos_errno mac_util_update_flows_w_sub_term_update(uint32_t pon_if, uint32_t sub_term_id, maple_mac_check_gem_port_id check_gem_port_id_func, maple_mac_check_agg_port_id check_agg_port_id_func)
{
flow_list_entry *p_current_entry = NULL;
flow_list_entry *p_next_entry = NULL;
bcmos_bool dummy;
bcmos_bool is_gem_activated;
bcmos_bool is_wait_for_gem_activated;
bcmolt_alloc_state alloc_id_state;
bcmos_errno rc = BCM_ERR_OK;
/*find all related flows, check their state and update if needed*/
do
{
p_current_entry = _mac_util_db_flow_get_next_w_sub_term_id(pon_if, sub_term_id, p_current_entry, &p_next_entry);
if(NULL == p_current_entry)
break;
rc = check_gem_port_id_func(pon_if,sub_term_id, p_current_entry->svc_port_id, &dummy, &is_gem_activated);
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(pon_if), "%s failed with error %s\n",__FUNCTION__, bcmos_strerror(rc));
continue;
}
is_wait_for_gem_activated = !is_gem_activated;
if(p_current_entry->agg_id)
{
rc = check_agg_port_id_func(pon_if, sub_term_id, p_current_entry->agg_id, &alloc_id_state);
if(BCM_ERR_OK != rc)
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(pon_if), "%s failed with error %s\n",__FUNCTION__, bcmos_strerror(rc));
continue;
}
}
/*if something was changed.....*/
if(p_current_entry->is_waiting_for_svc_port_active != is_wait_for_gem_activated)
{
/*update current flow entry*/
p_current_entry->is_waiting_for_svc_port_active = is_wait_for_gem_activated;
/*check if a flow became up*/
if(p_current_entry->op_type == BAL_UTIL_OPER_FLOW_ADD
&&(is_wait_for_gem_activated)
&& BAL_UTIL_FLOW_IND_SEND_FAIL != p_current_entry->ind_sent)
{
mac_util_report_flow_auto_ind(pon_if,p_current_entry->bal_flow_key,p_current_entry->op_type, BAL_UTIL_FLOW_IND_SEND_FAIL);
p_current_entry->ind_sent = BAL_UTIL_FLOW_IND_SEND_FAIL;
}
/*check if a flow became down*/
if(p_current_entry->op_type == BAL_UTIL_OPER_FLOW_ADD
&&(!is_wait_for_gem_activated)
&&(BAL_UTIL_FLOW_IND_SEND_SUCCESS != p_current_entry->ind_sent))
{
mac_util_report_flow_auto_ind(pon_if,p_current_entry->bal_flow_key,p_current_entry->op_type, BAL_UTIL_FLOW_IND_SEND_SUCCESS);
p_current_entry->ind_sent = BAL_UTIL_FLOW_IND_SEND_SUCCESS;
}
}
/* go through all flows(assigned with the given sub term) until break by
_mac_util_db_flow_get_next_w_sub_term_id returning NULL*/
}while(1);
return rc;
}
/**
* @brief agg_port set
* @param p_tm_sched_req pointer to tm_sched request structure from core
* @param op_type ADD, REMOVE or CLEAR
* @param p_tm_sched_inst pointer to the core tm sched Object instance
*
* @return errno error
*
*/
bcmos_errno maple_mac_util_agg_port_set(bcmbal_tm_sched_cfg *p_tm_sched_req, bal_util_oper_agg_port op_type, tm_sched_inst *p_tm_sched_inst)
{
bcmos_errno ret = BCM_ERR_OK;
do
{
/* Check the operation id */
if((BAL_UTIL_OPER_AGG_PORT_ADD != op_type) &&
(BAL_UTIL_OPER_AGG_PORT_REMOVE != op_type) &&
(BAL_UTIL_OPER_AGG_PORT_REMOVE != op_type))
{
BCM_LOG(ERROR, MAC_UTIL_GET_LOG_ID_FOR_PON_IF(p_tm_sched_req->data.owner.u.agg_port.intf_id),
"Unexpected mac_util agg port operation %d \n", op_type);
ret = BCM_ERR_PARM;
break;
}
/* agg port Add or Modify */
if(BAL_UTIL_OPER_AGG_PORT_ADD == op_type)
{
bcmolt_pon_alloc_sla agg_sla;
mac_util_assign_agg_port_sla(p_tm_sched_req, &agg_sla);
ret = maple_mac_agg_port_add(p_tm_sched_req->data.owner.u.agg_port.intf_id, p_tm_sched_req->data.owner.u.agg_port.sub_term_id, p_tm_sched_req->data.owner.u.agg_port.agg_port_id, agg_sla);
}
if(BAL_UTIL_OPER_AGG_PORT_REMOVE== op_type)
{
ret = maple_mac_agg_port_remove(p_tm_sched_req->data.owner.u.agg_port.intf_id, p_tm_sched_req->data.owner.u.agg_port.agg_port_id);
}
}while(0);
return ret;
}
/*@}*/