| /****************************************************************************** |
| * |
| * <: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; |
| |
| } |
| |
| /*@}*/ |