| /****************************************************************************** |
| * |
| * <: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 tm_sched_fsm.c |
| * @brief Code to support the BAL tm_sched FSM |
| * |
| * |
| */ |
| |
| /*@{*/ |
| |
| #include <bcmos_system.h> |
| #include <tm_sched_fsm.h> |
| #include <bal_msg.h> |
| #include <bal_osmsg.h> |
| #include "bal_worker.h" |
| #include "bal_mac_util.h" |
| #include "bal_switch_util.h" |
| #include <bal_api.h> |
| //#include <bal_mac_util_common_itu_pon.h> |
| |
| |
| #include <bal_objs.h> |
| #include <fsm_common.h> |
| |
| #ifdef ENABLE_LOG |
| #include <bcm_dev_log.h> |
| |
| /* |
| * @brief The logging device id for tm sched |
| */ |
| static dev_log_id log_id_tm_sched; |
| #endif |
| |
| /* local function declarations */ |
| |
| static bcmos_errno tm_sched_fsm_create(tm_sched_inst *p_tm_sched_inst, |
| void *msg, |
| tm_sched_fsm_event *p_event); |
| |
| static bcmos_errno tm_sched_free_by_entry(tm_sched_inst *p_entry); |
| static void tm_sched_inst_entry_obj_init(tm_sched_inst *p_entry); |
| static bcmos_errno queues_list_fill(tm_sched_inst *p_tm_sched_inst, |
| bcmbal_tm_queue_id_list_u8 *queues_list); |
| |
| |
| static bcmos_errno tm_sched_fsm_state_err(tm_sched_inst *p_tm_sched_inst, |
| void *msg, |
| tm_sched_fsm_event *p_event); |
| static bcmos_errno tm_sched_fsm_assigned_process_util_msg(tm_sched_inst *p_tm_sched_inst, |
| void *msg, |
| tm_sched_fsm_event *p_event); |
| static bcmos_errno tm_sched_fsm_deleting_process_util_msg(tm_sched_inst *p_tm_sched_inst, |
| void *msg, |
| tm_sched_fsm_event *p_event); |
| |
| static bcmos_errno tm_sched_fsm_inactive_destroy(tm_sched_inst *p_tm_sched_inst, |
| void *msg, |
| tm_sched_fsm_event *p_event); |
| |
| static bcmos_errno tm_sched_fsm_active_destroy(tm_sched_inst *p_tm_sched_inst, |
| void *msg, |
| tm_sched_fsm_event *p_event); |
| |
| static bcmos_errno tm_sched_fsm_assigned_destroy(tm_sched_inst *p_tm_sched_inst, |
| void *msg, |
| tm_sched_fsm_event *p_event); |
| |
| static bcmos_errno tm_sched_fsm_destroy(tm_sched_inst *p_tm_sched_inst); |
| |
| static bcmos_errno tm_sched_fsm_exec(tm_sched_inst *p_tm_sched_inst, tm_sched_fsm_event *p_event); |
| |
| static tm_sched_inst* tm_sched_find_by_owner(bcmbal_tm_sched_owner owner); |
| |
| static bcmos_errno bcmbal_tm_sched_sub_scheds_list_entry_add(tm_sched_inst *p_tm_sched_inst, bcmbal_tm_sched_id sched_id); |
| static bcmos_errno bcmbal_tm_sched_sub_scheds_list_entry_remove(tm_sched_inst *p_tm_sched_inst, bcmbal_tm_sched_id sched_id); |
| |
| static bcmos_errno sub_scheds_list_fill(tm_sched_inst *p_tm_sched_inst, bcmbal_tm_sched_id_list_u8 *sub_scheds_list); |
| /* |
| * @brief The Global tm_sched fsm context data structure |
| */ |
| static tm_sched_fsm_ctx g_tm_sched_fsm_tm_sched_list_ctx; |
| |
| /* |
| * Macros for tm_sched ctx access |
| */ |
| #define TM_SCHED_FSM_TM_SCHED_LIST_CTX (g_tm_sched_fsm_tm_sched_list_ctx) |
| #define TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR (&g_tm_sched_fsm_tm_sched_list_ctx) |
| |
| |
| /* |
| * @brief The definition of a tm_sched FSM state processing function |
| */ |
| typedef bcmos_errno (* tm_sched_fsm_state_processor)(tm_sched_inst *, void *, tm_sched_fsm_event *); |
| /* |
| * @brief The tm sched FSM state processing array |
| */ |
| static tm_sched_fsm_state_processor tm_sched_states[TM_SCHED_FSM_STATE__NUM_OF][TM_SCHED_FSM_EVENT_TYPE__NUM_OF] = |
| { |
| |
| [TM_SCHED_FSM_STATE_NULL] = |
| { |
| [TM_SCHED_FSM_EVENT_TYPE_CREATE] = tm_sched_fsm_create, |
| [TM_SCHED_FSM_EVENT_TYPE_DESTROY] = tm_sched_fsm_state_err, |
| [TM_SCHED_FSM_EVENT_TYPE_ASSIGN] = tm_sched_fsm_state_err, |
| [TM_SCHED_FSM_EVENT_TYPE_UTIL_MSG] = tm_sched_fsm_state_err, |
| |
| }, |
| [TM_SCHED_FSM_STATE_INACTIVE] = |
| { |
| [TM_SCHED_FSM_EVENT_TYPE_CREATE] = tm_sched_fsm_state_err, |
| [TM_SCHED_FSM_EVENT_TYPE_DESTROY] = tm_sched_fsm_inactive_destroy, |
| [TM_SCHED_FSM_EVENT_TYPE_ASSIGN] = tm_sched_fsm_state_err, |
| [TM_SCHED_FSM_EVENT_TYPE_UTIL_MSG] = tm_sched_fsm_state_err, |
| }, |
| [TM_SCHED_FSM_STATE_ASSIGNED] = |
| { |
| [TM_SCHED_FSM_EVENT_TYPE_CREATE] = tm_sched_fsm_state_err, |
| [TM_SCHED_FSM_EVENT_TYPE_DESTROY] = tm_sched_fsm_assigned_destroy, |
| [TM_SCHED_FSM_EVENT_TYPE_ASSIGN] = tm_sched_fsm_state_err, |
| [TM_SCHED_FSM_EVENT_TYPE_UTIL_MSG] = tm_sched_fsm_assigned_process_util_msg, |
| }, |
| [TM_SCHED_FSM_STATE_ACTIVE] = |
| { |
| [TM_SCHED_FSM_EVENT_TYPE_CREATE] = tm_sched_fsm_state_err, |
| [TM_SCHED_FSM_EVENT_TYPE_DESTROY] = tm_sched_fsm_active_destroy, |
| [TM_SCHED_FSM_EVENT_TYPE_ASSIGN] = tm_sched_fsm_state_err, |
| [TM_SCHED_FSM_EVENT_TYPE_UTIL_MSG] = tm_sched_fsm_state_err, |
| }, |
| |
| [TM_SCHED_FSM_STATE_DELETING] = |
| { |
| [TM_SCHED_FSM_EVENT_TYPE_CREATE] = tm_sched_fsm_state_err, |
| [TM_SCHED_FSM_EVENT_TYPE_DESTROY] = tm_sched_fsm_state_err, |
| [TM_SCHED_FSM_EVENT_TYPE_ASSIGN] = tm_sched_fsm_state_err, |
| [TM_SCHED_FSM_EVENT_TYPE_UTIL_MSG] = tm_sched_fsm_deleting_process_util_msg, |
| |
| }, |
| |
| }; |
| |
| static char *state_name_str[] = |
| { |
| "TM_SCHED_FSM_STATE_NULL", |
| "TM_SCHED_FSM_STATE_INACTIVE", |
| "TM_SCHED_FSM_STATE_ASSIGNED", |
| "TM_SCHED_FSM_STATE_ACTIVE", |
| "TM_SCHED_FSM_STATE_DELETING", |
| }; |
| |
| /* Ensure that the name array size matches the associated enum */ |
| BAL_STATIC_ASSERT(TM_SCHED_FSM_STATE__LAST == (sizeof (state_name_str) / sizeof (char *)), tm_sched_fsm_state); |
| |
| static char *tm_sched_state_name_get(tm_sched_fsm_state state) |
| { |
| if(state < TM_SCHED_FSM_STATE__LAST) |
| { |
| return state_name_str[state]; |
| } |
| else |
| { |
| return "TM_SCHED_UNKNOWN"; |
| } |
| } |
| |
| static char *event_name_str[] = |
| { |
| "TM_SCHED_FSM_CREATE_EVENT", |
| "TM_SCHED_FSM_DESTROY_EVENT", |
| "TM_SCHED_FSM_ASSIGN_EVENT", |
| "FLOW_FSM_UTIL_MSG_EVENT", |
| }; |
| |
| /* Ensure that the name array size matches the associated enum */ |
| BAL_STATIC_ASSERT(TM_SCHED_FSM_EVENT_TYPE__LAST == (sizeof (event_name_str) / sizeof (char *)), tm_sched_fsm_event_type); |
| |
| static char *tm_sched_event_name_get(tm_sched_fsm_event_type event) |
| { |
| if(event < TM_SCHED_FSM_EVENT_TYPE__LAST) |
| { |
| return event_name_str[event]; |
| } |
| else |
| { |
| return "TM_SCHED_EVT_UNKNOWN"; |
| } |
| } |
| |
| |
| |
| |
| /*****************************************************************************/ |
| /** |
| * @brief A function to initialize the tm sched FSM infrastructure. |
| * |
| * NOTE: This is called once on startup and NOT for each FSM instance. |
| * |
| * @returns bcmos_errno |
| *****************************************************************************/ |
| bcmos_errno tm_sched_fsm_init(void) |
| { |
| int ii; |
| tm_sched_inst *new_entry; |
| bcmos_errno ret = BCM_ERR_OK; |
| |
| #ifdef ENABLE_LOG |
| log_id_tm_sched = bcm_dev_log_id_register("TM_SCHED", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH); |
| BUG_ON(log_id_tm_sched == DEV_LOG_INVALID_ID); |
| #endif |
| |
| /* Initialize all of the tm_sched queues */ |
| TAILQ_INIT(&TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->free_tm_sched_list); |
| TAILQ_INIT(&TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->active_tm_sched_list); |
| |
| /* Populate the free list with it's initial set of tm_scheds */ |
| for(ii=0; ii<TM_SCHED_ALLOCATION_BLOCK_SIZE; ii++) |
| { |
| |
| new_entry = bcmos_calloc(sizeof(tm_sched_inst)); |
| |
| if(NULL == new_entry) |
| { |
| BCM_LOG(FATAL, log_id_tm_sched, "Failed to initialize the tm_sched free list - FATAL\n"); |
| ret = BCM_ERR_NOMEM; |
| break; |
| } |
| |
| tm_sched_free_by_entry(new_entry); |
| } |
| |
| return ret; |
| } |
| |
| /*****************************************************************************/ |
| /** |
| * @brief A function to un-initialize the tm sched FSM infrastructure. |
| * |
| * NOTE: This is called once on shutdown and NOT for each FSM instance. |
| * |
| * @returns bcmos_errno |
| *****************************************************************************/ |
| bcmos_errno tm_sched_fsm_finish(void) |
| { |
| |
| tm_sched_inst *current_entry, *p_temp_entry; |
| |
| /* Free all the entries on the active list */ |
| TAILQ_FOREACH_SAFE(current_entry, |
| &TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->active_tm_sched_list, |
| tm_sched_inst_next, |
| p_temp_entry) |
| { |
| /* Remove it from the active list */ |
| TAILQ_REMOVE(&TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->active_tm_sched_list, current_entry, tm_sched_inst_next); |
| |
| bcmos_free(current_entry); |
| |
| } |
| |
| /* Free all the entries on the free list */ |
| TAILQ_FOREACH_SAFE(current_entry, |
| &TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->free_tm_sched_list, |
| tm_sched_inst_next, |
| p_temp_entry) |
| { |
| /* Remove it from the active list */ |
| TAILQ_REMOVE(&TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->free_tm_sched_list, current_entry, tm_sched_inst_next); |
| |
| bcmos_free(current_entry); |
| } |
| |
| return BCM_ERR_OK; |
| } |
| |
| /*****************************************************************************/ |
| /** |
| * @brief A function to retrieve a tm_sched instance of the specified class. |
| * |
| * @param key A pointer to the key of the tm_sched being referenced |
| * @param search_flag A flag specifying the type of tm_sched |
| * instance to be retrieved |
| * |
| * @returns tm_sched_inst_t* A pointer to the found tm_sched instance, |
| * or NULL if one is not found |
| *****************************************************************************/ |
| tm_sched_inst *tm_sched_inst_get(bcmbal_tm_sched_key key, tm_sched_flag search_flag) |
| { |
| tm_sched_inst *current_entry = NULL; |
| |
| /* |
| * First, check the active list if the caller has chosen to do so |
| */ |
| if(TM_SCHED_FLAG_ACTIVE & search_flag) |
| { |
| TAILQ_FOREACH(current_entry, |
| &TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->active_tm_sched_list, |
| tm_sched_inst_next) |
| { |
| |
| if(current_entry->req_tm_sched_info.key.id == key.id |
| && current_entry->req_tm_sched_info.key.dir == key.dir) |
| { |
| BCM_LOG(DEBUG, log_id_tm_sched, "Found active tm_sched\n"); |
| /* The tm_sched instance pointer is in current_entry */ |
| break; |
| } |
| } |
| } |
| |
| /* |
| * Next, check the free list if the caller has chosen to do so |
| */ |
| if((TM_SCHED_FLAG_FREE & search_flag) && (NULL == current_entry)) |
| { |
| /* Now check the free list */ |
| if(!TAILQ_EMPTY(&TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->free_tm_sched_list)) |
| { |
| /* Just grab the first entry */ |
| current_entry = TAILQ_FIRST(&TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->free_tm_sched_list); |
| |
| /* Remove it from the free list */ |
| TAILQ_REMOVE(&TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->free_tm_sched_list, current_entry, tm_sched_inst_next); |
| |
| /* And add it to the active list */ |
| TAILQ_INSERT_TAIL(&TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->active_tm_sched_list, current_entry, tm_sched_inst_next); |
| |
| /* |
| * Initialize the fsm state |
| */ |
| current_entry->fsm_state = TM_SCHED_FSM_STATE_NULL; |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, "Using new tm_sched\n"); |
| |
| } |
| } |
| |
| if((TM_SCHED_FLAG_ANY & search_flag) && (NULL == current_entry)) |
| { |
| /*A tm_sched was not found on either list */ |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, "************** ERROR: no tm_sched found\n"); |
| } |
| |
| return current_entry; |
| } |
| |
| static bcmos_errno bcmbal_tm_sched_validate_sched_parent(const bcmbal_tm_sched_cfg *p_tm_sched_cfg, tm_sched_inst **p_parent_tm_sched_inst) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| bcmbal_tm_sched_key tm_sched_key; |
| tm_sched_key.dir = p_tm_sched_cfg->key.dir; |
| tm_sched_key.id = p_tm_sched_cfg->data.sched_parent.sched_id; |
| |
| do |
| { |
| (*p_parent_tm_sched_inst) = tm_sched_inst_get(tm_sched_key, TM_SCHED_FLAG_ACTIVE); |
| if(NULL == (*p_parent_tm_sched_inst)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Sched parent dir = %s id = %d does not exist and therefor can not be set at the tm sched parent\n", |
| TM_SCHED_DIR_TO_STR(tm_sched_key.dir), tm_sched_key.id); |
| ret = BCM_ERR_NOENT; |
| break; |
| } |
| |
| /*check weight/priority setting based on parent sched_type*/ |
| if(BCMBAL_TM_SCHED_TYPE_SP == (*p_parent_tm_sched_inst)->req_tm_sched_info.data.sched_type) |
| { |
| if(!BCMBAL_ATTRIBUTE_PROP_IS_SET(&(p_tm_sched_cfg->data.sched_parent), tm_sched_parent, priority)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Sched parent must be set with a priority, as its sched_parent' sched_type is sp\n"); |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| if(BCMBAL_ATTRIBUTE_PROP_IS_SET(&(p_tm_sched_cfg->data.sched_parent), tm_sched_parent, weight)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Sched parent can not be set with a weight, as its sched_parent' sched_type is sp\n"); |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| if(p_tm_sched_cfg->data.sched_parent.priority >= (*p_parent_tm_sched_inst)->req_tm_sched_info.data.num_priorities) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "sched priority (%d) is higher than the allowed at parent sched (id = %d dir = %s num of priorities = %d )\n", |
| p_tm_sched_cfg->data.sched_parent.priority , tm_sched_key.id, TM_SCHED_DIR_TO_STR(tm_sched_key.dir), |
| (*p_parent_tm_sched_inst)->req_tm_sched_info.data.num_priorities); |
| |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| } |
| else |
| if(BCMBAL_TM_SCHED_TYPE_WFQ == (*p_parent_tm_sched_inst)->req_tm_sched_info.data.sched_type) |
| { |
| if(!BCMBAL_ATTRIBUTE_PROP_IS_SET(&(p_tm_sched_cfg->data.sched_parent), tm_sched_parent, weight)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Sched parent must be set with a weight, as its sched_parent' sched_type is wrr\n"); |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| if(BCMBAL_ATTRIBUTE_PROP_IS_SET(&(p_tm_sched_cfg->data.sched_parent), tm_sched_parent, priority)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Sched parent can not be set with a priority, as its sched_parent' sched_type is wrr \n"); |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| } |
| else |
| if(BCMBAL_TM_SCHED_TYPE_SP_WFQ == (*p_parent_tm_sched_inst)->req_tm_sched_info.data.sched_type) |
| { |
| if(BCMBAL_ATTRIBUTE_PROP_IS_SET(&(p_tm_sched_cfg->data.sched_parent), tm_sched_parent, priority) |
| && BCMBAL_ATTRIBUTE_PROP_IS_SET(&(p_tm_sched_cfg->data.sched_parent), tm_sched_parent, weight)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Sched parent must be set with either weight or priority, not both. as its sched_parent' sched_type is sp_wrr\n"); |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| if(!BCMBAL_ATTRIBUTE_PROP_IS_SET(&(p_tm_sched_cfg->data.sched_parent), tm_sched_parent, priority) |
| && !BCMBAL_ATTRIBUTE_PROP_IS_SET(&(p_tm_sched_cfg->data.sched_parent), tm_sched_parent, weight)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Sched parent must be set with either weight or priority, as its sched_parent' sched_type is sp_wrr\n"); |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| } |
| }while(0); |
| |
| return ret; |
| |
| } |
| |
| /*****************************************************************************/ |
| /** |
| * @brief tm_sched_fsm_info_validate |
| * |
| * This routine is used to validate all input attributes required for a tm_sched |
| * settings |
| * |
| * @param p_tm_sched_cfg A pointer to a tm sched object |
| * |
| * @return bcmos_errno |
| */ |
| /*****************************************************************************/ |
| static bcmos_errno tm_sched_fsm_info_validate(const bcmbal_tm_sched_cfg *p_tm_sched_cfg) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| bcmbal_tm_sched_owner owner = p_tm_sched_cfg->data.owner; |
| bcmbal_interface_key intf_key; |
| bcmbal_subscriber_terminal_key sub_term_key; |
| sub_term_inst *p_sub_term_inst = NULL; |
| tm_sched_inst *p_tm_sched_inst; |
| bcmos_bool is_sched_type_and_level_mandatory = BCMOS_TRUE; |
| |
| do |
| { |
| if(!_rsc_mgr_tm_sched_id_validate(p_tm_sched_cfg->key.id)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "Illegal tm sched id (reserved for auto created) \n"); |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| |
| if(BCMBAL_CFG_PROP_IS_SET(p_tm_sched_cfg, tm_sched, owner)) |
| { |
| switch(owner.type) |
| { |
| case BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT: |
| { |
| /*tm sched owned by agg port is the only case sched type might be unset*/ |
| is_sched_type_and_level_mandatory = BCMOS_FALSE; |
| |
| if(BCMBAL_TM_SCHED_DIR_US != p_tm_sched_cfg->key.dir) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "tm sched owned by agg port must be of US direction, while tm sched id = %d is not\n", p_tm_sched_cfg->key.dir); |
| return BCM_ERR_PARM; |
| } |
| /*agg port owned tm sched can not be part of hqos, therefor can not have sched parent set*/ |
| if(BCMBAL_CFG_PROP_IS_SET(p_tm_sched_cfg, tm_sched, sched_parent)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "tm sched owned by agg port is a tsand alone and can not have sched_parent set to it"); |
| return BCM_ERR_PARM; |
| } |
| /*validate all required parameters are set*/ |
| if((owner.u.agg_port.intf_id == BAL_API_MAX_INTF_ID) |
| || (owner.u.agg_port.sub_term_id == BCMBAL_SUB_ID_UNKNOWN)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "Illegal owner agg port settings intf_id = %d sub_id = %d \n", |
| owner.u.agg_port.intf_id, owner.u.agg_port.sub_term_id); |
| return BCM_ERR_PARM; |
| } |
| |
| /*validate interface is up*/ |
| intf_key.intf_id = owner.u.agg_port.intf_id; |
| intf_key.intf_type = BCMBAL_INTF_TYPE_PON; |
| |
| if(bcmbal_interface_status_get(intf_key)!= BCMBAL_STATUS_UP) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "intf = %d is not UP\n", |
| intf_key.intf_id); |
| return BCM_ERR_NOT_CONNECTED; |
| } |
| |
| /*validate sub terminal exist*/ |
| sub_term_key.intf_id = owner.u.agg_port.intf_id; |
| sub_term_key.sub_term_id = owner.u.agg_port.sub_term_id; |
| |
| p_sub_term_inst = sub_term_inst_get(&sub_term_key, SUB_TERM_FLAG_ACTIVE); |
| |
| if(!p_sub_term_inst) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "Failed to get subscriber terminal with intf = %d id = %u\n", |
| sub_term_key.intf_id, sub_term_key.sub_term_id); |
| return BCM_ERR_NOENT; |
| } |
| } |
| break; |
| |
| case BCMBAL_TM_SCHED_OWNER_TYPE_UNI: |
| { |
| /*validate sub terminal exist*/ |
| sub_term_key.intf_id = owner.u.uni.intf_id; |
| sub_term_key.sub_term_id = owner.u.uni.sub_term_id; |
| |
| p_sub_term_inst = sub_term_inst_get(&sub_term_key, SUB_TERM_FLAG_ACTIVE); |
| |
| if(!p_sub_term_inst) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "Failed to get subscriber terminal with intf = %d id = %u\n", |
| sub_term_key.intf_id, sub_term_key.sub_term_id); |
| return BCM_ERR_NOENT; |
| } |
| |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| if(BCMOS_TRUE == is_sched_type_and_level_mandatory) |
| { |
| if(!BCMBAL_CFG_PROP_IS_SET(p_tm_sched_cfg, tm_sched, sched_type)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Sched type is a mandatory parameter for setting tm sched\n"); |
| ret = BCM_ERR_MANDATORY_PARM_IS_MISSING; |
| break; |
| } |
| /*if sched type is sp or wrr_sp, num_of_priorities is a mandatory parameter*/ |
| if(BCMBAL_TM_SCHED_TYPE_SP == p_tm_sched_cfg->data.sched_type |
| || BCMBAL_TM_SCHED_TYPE_SP_WFQ == p_tm_sched_cfg->data.sched_type) |
| { |
| if(!BCMBAL_CFG_PROP_IS_SET(p_tm_sched_cfg, tm_sched, num_priorities)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "num_priorities is a mandatory parameter for setting tm sched with sched type %s\n", |
| BCMBAL_TM_SCHED_TYPE_SP == p_tm_sched_cfg->data.sched_type ? "sp" : "sp_wrr"); |
| ret = BCM_ERR_MANDATORY_PARM_IS_MISSING; |
| break; |
| } |
| } |
| if(!BCMBAL_CFG_PROP_IS_SET(p_tm_sched_cfg, tm_sched, sched_child_type)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Sched child type is a mandatory parameter for setting tm sched\n"); |
| ret = BCM_ERR_MANDATORY_PARM_IS_MISSING; |
| break; |
| } |
| } |
| |
| if(BCMBAL_CFG_PROP_IS_SET(p_tm_sched_cfg, tm_sched, sched_parent)) |
| { |
| if(BCM_ERR_OK == (ret = bcmbal_tm_sched_validate_sched_parent(p_tm_sched_cfg, &p_tm_sched_inst))) |
| { |
| if(BCM_ERR_OK != (ret = bcmbal_tm_sched_sub_scheds_list_entry_add(p_tm_sched_inst, p_tm_sched_cfg->key.id))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "could not set scheduler dir = %s id = %d as parent of sched dir = %s id = %d (err= %s)\n", |
| TM_SCHED_DIR_TO_STR(p_tm_sched_inst->req_tm_sched_info.key.dir), p_tm_sched_cfg->data.sched_parent.sched_id, |
| TM_SCHED_DIR_TO_STR(p_tm_sched_cfg->key.dir), p_tm_sched_cfg->key.id, bcmos_strerror(ret)); |
| break; |
| } |
| } |
| else |
| { |
| |
| BCM_LOG(ERROR, log_id_tm_sched, "could not validate scheduler dir = %s id = %d as parent of sched dir = %s id = %d (err= %s)\n", |
| TM_SCHED_DIR_TO_STR(p_tm_sched_cfg->key.dir), p_tm_sched_cfg->data.sched_parent.sched_id, |
| TM_SCHED_DIR_TO_STR(p_tm_sched_cfg->key.dir), p_tm_sched_cfg->key.id, bcmos_strerror(ret)); |
| break; |
| } |
| } |
| |
| }while(0); |
| |
| return ret; |
| |
| } |
| /*****************************************************************************/ |
| /** |
| * @brief A function called by the core worker thread to process an |
| * tm_sched object message (SET, GET, CLEAR, STATS) received |
| * from the BAL Public API. |
| * |
| * @param msg_payload Pointer to a BAL message received from the |
| * BAL Public API. |
| * |
| * @returns bcmos_errno |
| *****************************************************************************/ |
| bcmos_errno process_tm_sched_object(void *msg_payload) |
| { |
| bcmos_errno ret = BCM_ERR_OK, rsp_ret = BCM_ERR_OK; |
| bcmbal_tm_sched_cfg *p_tm_sched_cfg = (bcmbal_tm_sched_cfg *)msg_payload; |
| tm_sched_inst *p_tm_sched_inst = NULL; |
| tm_sched_fsm_event fsm_event; |
| bcmbal_tm_sched_key tm_sched_key; |
| bcmbal_obj_msg_type oper_type; |
| bcmbal_tm_sched_owner owner; |
| uint32_t ref_count; |
| queue_entry *current_queue_entry; |
| bcmbal_tm_queue_key current_queue_key; |
| tm_queue_inst *current_queue_inst; |
| bcmbal_interface_key intf_key; |
| |
| do |
| { |
| BUG_ON(NULL == msg_payload); |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, "Processing a tm sched object\n"); |
| |
| tm_sched_key = p_tm_sched_cfg->key; |
| oper_type = p_tm_sched_cfg->hdr.hdr.type; |
| |
| /* |
| * A message pointer may be passed inside the event structure. |
| */ |
| fsm_event.msg = msg_payload; |
| |
| /* SET or GET or CLEAR...? */ |
| switch(oper_type) |
| { |
| case(BCMBAL_OBJ_MSG_TYPE_SET): |
| { |
| BCM_LOG(DEBUG, log_id_tm_sched, "Processing a tm sched SET REQ mgmt message\n"); |
| do |
| { |
| if(BCMBAL_STATUS_UP != acc_term_status_get()) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "ERROR - Access-terminal is not UP. No further processing\n"); |
| ret = BCM_ERR_STATE; |
| break; |
| } |
| |
| /*Find the specified tm_sched instance is already created */ |
| p_tm_sched_inst = tm_sched_inst_get(tm_sched_key, TM_SCHED_FLAG_ACTIVE); |
| |
| if(NULL != p_tm_sched_inst) |
| { |
| /* This is a fatal error condition */ |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "ERROR - tm sched found. Set after create is currently not supported. No further processing\n"); |
| ret = BCM_ERR_NOT_SUPPORTED; |
| break; |
| } |
| |
| p_tm_sched_inst = tm_sched_inst_get(tm_sched_key, TM_SCHED_FLAG_FREE); |
| if(NULL == p_tm_sched_inst) |
| { |
| /* This is a fatal error condition */ |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "ERROR - tm sched not found. No further processing\n"); |
| ret = BCM_ERR_NOMEM; |
| break; |
| } |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, |
| "Creating a new tm sched\n"); |
| |
| BCMBAL_CFG_PROP_SET(p_tm_sched_cfg, tm_sched, creation_mode, BCMBAL_TM_CREATION_MODE_MANUAL); |
| |
| /* Fill in given cfg with current tm sched instance API request data structure and validate it*/ |
| bcmbal_tm_sched_object_overlay_w_src_priority(&p_tm_sched_inst->req_tm_sched_info, p_tm_sched_cfg); |
| |
| /* Check if the mandatory tm sched attributes have been set, and range check where applicable */ |
| if(BCM_ERR_OK != (ret = tm_sched_fsm_info_validate(p_tm_sched_cfg))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "tm_sched fsm validation Failed (%d)\n", ret); |
| tm_sched_free_by_entry(p_tm_sched_inst); |
| break; |
| } |
| |
| |
| /* Perform the validation check(s) that the utils require */ |
| if(BCM_ERR_OK != (ret = sw_util_tm_sched_validate(p_tm_sched_cfg))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "tm_sched switch validation Failed (%d)\n", ret); |
| tm_sched_free_by_entry(p_tm_sched_inst); |
| break; |
| } |
| |
| }while(0); |
| /* We respond to the BAL public API backend with a result. We always |
| * send a complete msg_payload back to the API, but the data portion |
| * of the object is only relevant when a GET or GET-STATS has been requested. |
| */ |
| rsp_ret = mgmt_msg_send_balapi_rsp(ret, msg_payload, oper_type, log_id_tm_sched); |
| if(BCM_ERR_OK != rsp_ret || BCM_ERR_OK != ret) |
| { |
| break; |
| } |
| |
| /* |
| * Initial checks complete. Process the request |
| */ |
| fsm_event.event_type = TM_SCHED_FSM_EVENT_TYPE_CREATE; |
| /* |
| * Run the tm sched FSM to process this event |
| */ |
| ret = tm_sched_fsm_exec(p_tm_sched_inst, &fsm_event); |
| |
| }//SET |
| break; |
| |
| case(BCMBAL_OBJ_MSG_TYPE_GET): |
| { |
| bcmbal_tm_queue_id_list_u8 queues_list = {}; |
| bcmbal_tm_sched_id_list_u8 sub_scheds_list = {}; |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, "Processing a tm sched GET REQ mgmt message\n"); |
| |
| /* Just return the tm sched data info that we have on record for tm sched instance */ |
| /*Find the specified tm sched instance */ |
| p_tm_sched_inst = tm_sched_inst_get(tm_sched_key, TM_SCHED_FLAG_ACTIVE); |
| |
| if(NULL == p_tm_sched_inst) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Specified tm_sched not found on GET\n"); |
| ret = BCM_ERR_NOENT; |
| } |
| else |
| { |
| /* Return the queues list if requested */ |
| BCMBAL_CFG_PROP_CLEAR(&p_tm_sched_inst->req_tm_sched_info, |
| tm_sched, |
| queues); |
| |
| /* If the user requested the list of queues for this tm sched then return the list.*/ |
| if(BCMBAL_CFG_PROP_IS_SET(p_tm_sched_cfg, |
| tm_sched, |
| queues)) |
| { |
| |
| if(BCM_ERR_OK == queues_list_fill(p_tm_sched_inst, &queues_list)) |
| { |
| /* NOTE: The returned list may be empty */ |
| BCMBAL_CFG_PROP_SET(&p_tm_sched_inst->req_tm_sched_info, |
| tm_sched, |
| queues, |
| queues_list); |
| } |
| else |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Error trying to fill queues list to return\n"); |
| ret = BCM_ERR_INTERNAL; |
| break; |
| } |
| } |
| |
| /* Return the sub scheds list if requested */ |
| BCMBAL_CFG_PROP_CLEAR(&p_tm_sched_inst->req_tm_sched_info, |
| tm_sched, |
| sub_scheds); |
| |
| /* If the user requested the list of sub scheds for this tm sched then return the list.*/ |
| if(BCMBAL_CFG_PROP_IS_SET(p_tm_sched_cfg, |
| tm_sched, |
| sub_scheds)) |
| { |
| |
| if(BCM_ERR_OK == sub_scheds_list_fill(p_tm_sched_inst, &sub_scheds_list)) |
| { |
| /* NOTE: The returned list may be empty */ |
| BCMBAL_CFG_PROP_SET(&p_tm_sched_inst->req_tm_sched_info, |
| tm_sched, |
| sub_scheds, |
| sub_scheds_list); |
| } |
| else |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Error trying to fill sub_scheds list to return\n"); |
| ret = BCM_ERR_INTERNAL; |
| break; |
| } |
| } |
| /* We respond to the BAL public API backend with a result. We always |
| * send a complete msg_payload back to the API, but the data portion |
| * of the object is only relevant when a GET or GET-STATS has been requested. |
| */ |
| |
| p_tm_sched_inst->req_tm_sched_info.hdr.hdr.comm_hdr = ((bcmbal_obj *)msg_payload)->comm_hdr; |
| *((bcmbal_tm_sched_cfg *)msg_payload) = p_tm_sched_inst->req_tm_sched_info; |
| |
| } |
| |
| mgmt_msg_send_balapi_rsp(ret, msg_payload, oper_type, log_id_tm_sched); |
| |
| /* Free the temporary lists if they were used */ |
| if(queues_list.val) |
| { |
| bcmos_free(queues_list.val); |
| } |
| }//GET |
| break; |
| |
| case(BCMBAL_OBJ_MSG_TYPE_CLEAR): |
| { |
| do |
| { |
| BCM_LOG(DEBUG, log_id_tm_sched, "Processing a tm sched CLEAR REQ mgmt message\n"); |
| /*Find the specified tm sched instance */ |
| p_tm_sched_inst = tm_sched_inst_get(tm_sched_key, TM_SCHED_FLAG_ACTIVE); |
| |
| if(NULL == p_tm_sched_inst) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Specified tm_sched not found on Clear\n"); |
| ret = BCM_ERR_NOENT; |
| break; |
| } |
| |
| /*user can not clear auto created sched owned by agg port*/ |
| if(BCMBAL_CFG_PROP_IS_SET(&p_tm_sched_inst->req_tm_sched_info, tm_sched, owner)) |
| { |
| owner = p_tm_sched_inst->req_tm_sched_info.data.owner; |
| if(BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT == owner.type |
| && BCMBAL_TM_CREATION_MODE_AUTO == p_tm_sched_inst->req_tm_sched_info.data.creation_mode) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Specified tm_sched is auto created, therefor can not be manually deleted\n"); |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| |
| /*check that a tm is not active, |
| if that tm owned by interface, it is active if any of its queue is active. |
| if it is owned by agg port, it is active if the agg port id has ref count > 1 */ |
| switch(owner.type) |
| { |
| case BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT: |
| { |
| rsc_mgr_alloc_id_get_ref_count(owner.u.agg_port.intf_id,owner.u.agg_port.agg_port_id,&ref_count); |
| if(ref_count > 1) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Specified tm_sched is active and therefor can not be deleted (if = %d agg id = %d, ref count = %d \n", |
| owner.u.agg_port.intf_id,owner.u.agg_port.agg_port_id, ref_count); |
| ret = BCM_ERR_PARM; |
| } |
| break; |
| }//BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT |
| |
| case BCMBAL_TM_SCHED_OWNER_TYPE_INTERFACE: |
| { |
| TAILQ_FOREACH(current_queue_entry, |
| &p_tm_sched_inst->queues_list, |
| next) |
| { |
| if(NULL != current_queue_entry) |
| { |
| current_queue_key.sched_id = p_tm_sched_inst->req_tm_sched_info.key.id; |
| current_queue_key.sched_dir = p_tm_sched_inst->req_tm_sched_info.key.dir; |
| current_queue_key.id = current_queue_entry->queue_id; |
| current_queue_inst = tm_queue_inst_get(current_queue_key, TM_QUEUE_FLAG_ACTIVE); |
| if(NULL == current_queue_inst) |
| { |
| ret = BCM_ERR_INTERNAL; |
| break; |
| } |
| if(TM_QUEUE_FSM_STATE_IN_USE == current_queue_inst->fsm_state) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Specified tm_sched is active (has an in use queue) and therefor can not be deleted (queue id = %d \n", |
| current_queue_key.id); |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| } |
| }//TAILQ_FOREACH |
| if(BCM_ERR_OK == ret) |
| { |
| /*TM_SCHEDs (either auto or manually created) with owner interface may only be deleted there are no attached TM_QUEUEs, and only when the associated interface is in the ADMIN-DOWN state*/ |
| intf_key.intf_type = owner.u.interface.intf_type; |
| intf_key.intf_id = owner.u.interface.intf_id; |
| if(BCMBAL_STATUS_DOWN != bcmbal_interface_status_get(intf_key)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Specified tm_sched is owned by interface that is not admin down, and can be removed only when the associated interface is in the ADMIN-DOWN state\n"); |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| } |
| }//BCMBAL_TM_SCHED_OWNER_TYPE_INTERFACE |
| break; |
| |
| default: |
| break; |
| }//switch owner.type |
| }//owner is set |
| /*generate destroy event*/ |
| if(BCM_ERR_OK == ret) |
| { |
| fsm_event.event_type = TM_SCHED_FSM_EVENT_TYPE_DESTROY; |
| fsm_event.msg = msg_payload; |
| ret = tm_sched_fsm_exec(p_tm_sched_inst,&fsm_event); |
| } |
| }while(0); |
| |
| mgmt_msg_send_balapi_rsp(ret, msg_payload, oper_type, log_id_tm_sched); |
| }//CLEAR |
| break; |
| |
| default: |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Unsupported operation on tm sched object (%d)\n", |
| oper_type); |
| ret = BCM_ERR_NOT_SUPPORTED; |
| } |
| } |
| }while(0); |
| BCM_LOG(DEBUG, log_id_tm_sched, "%s returns\n", __FUNCTION__); |
| |
| return ret; |
| } |
| |
| |
| static void tm_sched_inst_entry_obj_init(tm_sched_inst *p_entry) |
| { |
| /* The actual key content is irrelevant for free tm_scheds */ |
| bcmbal_tm_sched_key key = { .id = 0, .dir = BCMBAL_TM_SCHED_DIR_DS}; |
| |
| BCMBAL_CFG_INIT(&p_entry->current_tm_sched_info, |
| tm_sched, |
| key); |
| p_entry->fsm_state = TM_SCHED_FSM_STATE_NULL; |
| /* Initialize the queues and suc scheds lists */ |
| p_entry->num_queues_on_node = 0; |
| TAILQ_INIT(&p_entry->queues_list); |
| |
| p_entry->num_sub_scheds_on_node = 0; |
| TAILQ_INIT(&p_entry->sub_scheds_list); |
| |
| BCMBAL_OBJ_IN_PROGRESS_SET(&(p_entry->current_tm_sched_info), BCMOS_FALSE); |
| } |
| /*****************************************************************************/ |
| /** |
| * @brief A function to free a tm_sched instance specified by a the supplied |
| * entry pointer. |
| * |
| * @param p_entry A pointer to the entry to be freed |
| * |
| * |
| * @returns bcmos_errno |
| *****************************************************************************/ |
| static bcmos_errno tm_sched_free_by_entry(tm_sched_inst *p_entry) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| tm_sched_inst *current_entry; |
| tm_sched_inst *p_temp_entry; |
| /* |
| * First, check the active list (an active tm_sched can be in the adding or removing state) |
| */ |
| TAILQ_FOREACH_SAFE(current_entry, |
| &TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->active_tm_sched_list, |
| tm_sched_inst_next, |
| p_temp_entry) |
| { |
| if(current_entry == p_entry) |
| { |
| /* Remove it from the active list */ |
| TAILQ_REMOVE(&TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->active_tm_sched_list, current_entry, tm_sched_inst_next); |
| break; |
| } |
| } |
| tm_sched_inst_entry_obj_init(p_entry); |
| |
| /* And add it to the free list */ |
| TAILQ_INSERT_TAIL(&TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->free_tm_sched_list, p_entry, tm_sched_inst_next); |
| |
| return ret; |
| } |
| |
| /*****************************************************************************/ |
| /** |
| * @brief The tm sched FSM state processing executive function |
| * |
| * @param p_tm_sched_inst Pointer to a tm_sched instance |
| * @param p_event Pointer to a tm_sched event structure |
| * |
| * @returns bcmos_errno |
| *****************************************************************************/ |
| static bcmos_errno tm_sched_fsm_exec(tm_sched_inst *p_tm_sched_inst, tm_sched_fsm_event *p_event) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| tm_sched_fsm_state pre_state; |
| tm_sched_fsm_state_processor tm_sched_state_processor; |
| |
| /* Parameter checks */ |
| BUG_ON(NULL == p_tm_sched_inst); |
| BUG_ON(NULL == p_event); |
| |
| /* Record the present state for debug printing |
| */ |
| pre_state = p_tm_sched_inst->fsm_state; |
| |
| /* |
| * Get the state processing function |
| */ |
| tm_sched_state_processor = tm_sched_states[p_tm_sched_inst->fsm_state][p_event->event_type]; |
| |
| /* |
| * If there's a state processing function for this event and state, execute it. |
| * Otherwise, process a generic error. |
| */ |
| if(tm_sched_state_processor) |
| { |
| ret = tm_sched_state_processor(p_tm_sched_inst, p_event->msg, p_event); |
| } |
| else |
| { |
| tm_sched_fsm_state_err(p_tm_sched_inst, p_event->msg, p_event); |
| } |
| |
| if(BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "*** Error detected during state processing\n"); |
| p_tm_sched_inst->fsm_state = pre_state; |
| } |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, "*** Event %s, State: %s --> %s\n\n", |
| tm_sched_event_name_get(p_event->event_type), |
| tm_sched_state_name_get(pre_state), |
| tm_sched_state_name_get(p_tm_sched_inst->fsm_state)); |
| |
| return ret; |
| } |
| |
| |
| |
| /*****************************************************************************/ |
| /** |
| * @brief The tm sched FSM function which is executed when an error |
| * is encountered during FSM processing. |
| * |
| * @param p_tm_sched_inst Pointer to a tm_sched instance |
| * @param msg Pointer to a BAL message received from one of |
| * the BAL apps. |
| * @param p_event Pointer to a tm_sched event structure |
| * |
| * @returns bcmos_errno |
| *****************************************************************************/ |
| static bcmos_errno tm_sched_fsm_state_err(tm_sched_inst *p_tm_sched_inst, |
| void *msg, |
| tm_sched_fsm_event *p_event) |
| { |
| bcmos_errno ret = BCM_ERR_INVALID_OP; |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, |
| "Error encountered processing TM_SCHED FSM" |
| " - BAD EVENT ()\n"); |
| |
| return ret; |
| } |
| |
| /*****************************************************************************/ |
| /** |
| * @brief A function to process a tm sched object event received |
| * from one of the BAL apps. |
| * |
| * @param msg_payload A pointer to the util message |
| * |
| * @returns bcmos_errno |
| *****************************************************************************/ |
| bcmos_errno process_tm_sched_util_msg(void *msg_payload) |
| { |
| |
| |
| bcmos_errno ret = BCM_ERR_OK; |
| bcmbal_msg_type type; |
| bcmbal_tm_sched_key key; |
| tm_sched_inst *p_tm_sched_inst; |
| tm_sched_fsm_event tm_sched_event; |
| |
| |
| BUG_ON(NULL == msg_payload); |
| do |
| { |
| type = bcmbal_type_minor_get(msg_payload); |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, |
| "Processing a tm sched %s util message from %s\n", |
| bcmbal_msg_t_str[type], |
| subsystem_str[bcmbal_sender_get(msg_payload)]); |
| |
| if(BAL_MSG_TYPE_IND == type) |
| { |
| |
| /* recover the key from the message */ |
| key = ((bal_util_msg_ind *)msg_payload)->obj_key.tm_sched_key; |
| |
| |
| /* |
| * Get the sub_term instance that's being referenced |
| */ |
| p_tm_sched_inst = tm_sched_inst_get(key, TM_SCHED_FLAG_ACTIVE); |
| |
| if(NULL == p_tm_sched_inst) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "invalid tm sched (dir %s id %d) found while processing a util message type %s from %s\n", |
| TM_SCHED_DIR_TO_STR(key.dir), |
| key.id, |
| bcmbal_msg_t_str[type], |
| subsystem_str[bcmbal_sender_get(msg_payload)]); |
| ret = BCM_ERR_INTERNAL; |
| break; |
| } |
| tm_sched_event.msg = msg_payload; |
| |
| tm_sched_event.event_type = TM_SCHED_FSM_EVENT_TYPE_UTIL_MSG; |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, "p_tm_sched_inst->fsm_state=%d, tm_sched_event.event_type = %d\n", |
| p_tm_sched_inst->fsm_state, tm_sched_event.event_type); |
| /*Run the tm sched FSM to process this event */ |
| if(BCM_ERR_OK == ret) |
| { |
| ret = tm_sched_fsm_exec(p_tm_sched_inst, &tm_sched_event); |
| } |
| } |
| |
| else |
| { |
| ret = BCM_ERR_NOT_SUPPORTED; |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "Unknown message type received from the APP (not one of RSP:ACK:IND:AUTO_IND) (type:%d)\n", |
| type); |
| } |
| }while(0); |
| return ret; |
| } |
| |
| /*****************************************************************************/ |
| /** |
| * @brief The tm sched FSM state processing for a tm sched create command received |
| * from the BAL Public API. |
| * |
| * @param p_tm_sched_inst Pointer to a tm sched instance |
| * @param msg Pointer to a BAL message received from the BAL Public API |
| * @param p_event Pointer to a tm sched event structure |
| * |
| * @returns bcmos_errno |
| *****************************************************************************/ |
| static bcmos_errno tm_sched_fsm_create(tm_sched_inst *p_tm_sched_inst, |
| void *msg, |
| tm_sched_fsm_event *p_event) |
| { |
| |
| bcmos_errno ret = BCM_ERR_OK; |
| p_tm_sched_inst->fsm_state = TM_SCHED_FSM_STATE_INACTIVE; |
| |
| if(BCMBAL_CFG_PROP_IS_SET(&p_tm_sched_inst->req_tm_sched_info, tm_sched,owner)) |
| { |
| ret = bcmbal_tm_sched_set_owner(p_tm_sched_inst); |
| } |
| |
| return ret; |
| } |
| |
| bcmos_errno bcmbal_tm_sched_set_owner(tm_sched_inst *p_tm_sched_inst) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| bcmbal_tm_sched_owner owner; |
| bcmbal_tm_queue_key tm_queue_key; |
| bcmbal_tm_sched_key tm_sched_key = p_tm_sched_inst->req_tm_sched_info.key; |
| queue_entry *current_queue_entry; |
| |
| |
| BUG_ON(NULL == p_tm_sched_inst); |
| do |
| { |
| if( BCMBAL_CFG_PROP_IS_SET(&p_tm_sched_inst->req_tm_sched_info, tm_sched,owner)) |
| { |
| p_tm_sched_inst->fsm_state = TM_SCHED_FSM_STATE_ASSIGNED; |
| owner = p_tm_sched_inst->req_tm_sched_info.data.owner; |
| switch(owner.type) |
| { |
| case BCMBAL_TM_SCHED_OWNER_TYPE_INTERFACE: |
| case BCMBAL_TM_SCHED_OWNER_TYPE_SUB_TERM: |
| case BCMBAL_TM_SCHED_OWNER_TYPE_UNI: |
| { |
| /*no need to validate owner attributes as these are read only and set by VALID internal objects*/ |
| if(BCM_ERR_OK != (ret = sw_util_tm_sched_set(p_tm_sched_inst))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "error %s detected by switch util while adding tm sched\n", bcmos_strerror(ret)); |
| break; |
| } |
| /* The hardware has properly accepted the object info, so the request object becomes the current state. */ |
| bcmbal_tm_sched_object_overlay_w_src_priority(&p_tm_sched_inst->current_tm_sched_info, |
| &p_tm_sched_inst->req_tm_sched_info); |
| p_tm_sched_inst->fsm_state = TM_SCHED_FSM_STATE_ACTIVE; |
| /*configure all assigned queues*/ |
| |
| TAILQ_FOREACH(current_queue_entry, |
| &p_tm_sched_inst->queues_list, |
| next) |
| { |
| tm_queue_key.id = current_queue_entry->queue_id; |
| tm_queue_key.sched_id = tm_sched_key.id; |
| tm_queue_key.sched_dir = tm_sched_key.dir; |
| if(BCM_ERR_OK != (ret = bcmbal_tm_queue_set_owner(tm_queue_key))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Could not set queue sched id = %d sched dir = %s queue id = %d of the tm sched (%s)\n", |
| tm_queue_key.sched_id, TM_SCHED_DIR_TO_STR(tm_queue_key.sched_dir), tm_queue_key.id, bcmos_strerror(ret)); |
| break; |
| } |
| } |
| BCMBAL_OBJ_IN_PROGRESS_SET(&(p_tm_sched_inst->current_tm_sched_info), BCMOS_FALSE); |
| p_tm_sched_inst->current_tm_sched_info.hdr.hdr.status = ret; |
| |
| } |
| break; |
| |
| case BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT: |
| { |
| bcmbal_interface_key intf_key = {.intf_type = BCMBAL_INTF_TYPE_PON, .intf_id = owner.u.agg_port.intf_id}; |
| bcmbal_subscriber_terminal_key sub_key = {.sub_term_id = owner.u.agg_port.sub_term_id, .intf_id = intf_key.intf_id}; |
| /*for agg port, should validate intf and sub term validity*/ |
| if(NULL == sub_term_inst_get(&sub_key, SUB_TERM_FLAG_ACTIVE)) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Can not set an agg port for onu (if-%d id-%d) which does not exist\n", intf_key.intf_id, sub_key.sub_term_id); |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, "Getting a new ALLOC ID from resource manager\n"); |
| |
| owner.u.agg_port.agg_port_id = 0; /* 0 is a magic number telling the resource manager that it should provide the initial allocation of the ALLOC ID */ |
| ret = rsc_mgr_alloc_id_alloc(intf_key.intf_id, &owner.u.agg_port.agg_port_id, 1, NULL); |
| |
| if(BCM_ERR_OK != ret) |
| { |
| /* An error has occurred trying to get mandatory data */ |
| BCM_LOG(ERROR, log_id_tm_sched, "Failed to get ALLOC ID from resource manager\n"); |
| ret = BCM_ERR_NORES; |
| break; |
| } |
| /*set the agg port id into the inst*/ |
| BCMBAL_CFG_PROP_SET(&p_tm_sched_inst->req_tm_sched_info, tm_sched, owner, owner); |
| |
| ret = mac_util_agg_port_set(p_tm_sched_inst, BAL_UTIL_OPER_AGG_PORT_ADD); |
| if(BCM_ERR_OK != ret) |
| { |
| /* An error has occurred trying to configure mac*/ |
| BCM_LOG(ERROR, log_id_tm_sched, "Failed to configure ALLOC ID at mac (%s)\n",bcmos_strerror(ret)); |
| break; |
| } |
| } |
| break; |
| |
| case BCMBAL_TM_SCHED_OWNER_TYPE_VIRTUAL: |
| default: |
| BCM_LOG(ERROR, log_id_tm_sched, "nothing to do with owner type %d \n", p_tm_sched_inst->current_tm_sched_info.data.owner.type); |
| return BCM_ERR_PARM; |
| break; |
| } |
| } |
| }while(0); |
| |
| return ret; |
| } |
| |
| |
| bcmos_errno bcmbal_tm_sched_unset_owner(tm_sched_inst *p_tm_sched_inst) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| bcmbal_tm_sched_owner *owner; |
| bcmbal_tm_queue_key tm_queue_key; |
| queue_entry *current_queue_entry; |
| tm_sched_inst *p_parent_tm_sched_inst; |
| |
| BUG_ON(NULL == p_tm_sched_inst); |
| |
| tm_queue_key.sched_id = p_tm_sched_inst->req_tm_sched_info.key.id; |
| tm_queue_key.sched_dir = p_tm_sched_inst->req_tm_sched_info.key.dir; |
| |
| do |
| { |
| if( BCMBAL_CFG_PROP_IS_SET(&p_tm_sched_inst->req_tm_sched_info, tm_sched, owner)) |
| { |
| owner = &(p_tm_sched_inst->req_tm_sched_info.data.owner); |
| switch(owner->type) |
| { |
| case BCMBAL_TM_SCHED_OWNER_TYPE_INTERFACE: |
| { |
| /*remove all assigned queues*/ |
| TAILQ_FOREACH(current_queue_entry, |
| &p_tm_sched_inst->queues_list, |
| next) |
| { |
| tm_queue_key.id = current_queue_entry->queue_id; |
| if(BCM_ERR_OK != (ret = bcmbal_tm_queue_unset_owner(tm_queue_key))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Could not unset queue sched id = %d sched dir = %s queue id = %d of the tm sched (%s) \n", |
| tm_queue_key.sched_id, TM_SCHED_DIR_TO_STR(tm_queue_key.sched_dir), tm_queue_key.id, bcmos_strerror(ret)); |
| break; |
| } |
| } |
| /*unset from parent scheduler*/ |
| if(BCMBAL_CFG_PROP_IS_SET(&(p_tm_sched_inst->req_tm_sched_info), tm_sched, sched_parent)) |
| { |
| if(BCM_ERR_OK == (ret = bcmbal_tm_sched_validate_sched_parent(&(p_tm_sched_inst->req_tm_sched_info), &p_parent_tm_sched_inst))) |
| { |
| if(BCM_ERR_OK == (ret = bcmbal_tm_sched_sub_scheds_list_entry_remove(p_parent_tm_sched_inst, p_tm_sched_inst->req_tm_sched_info.key.id))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "could not remove scheduler dir = %s id = %d as parent of sched dir = %s id = %d (err= %s)\n", |
| TM_SCHED_DIR_TO_STR(p_tm_sched_inst->req_tm_sched_info.key.dir), p_tm_sched_inst->req_tm_sched_info.data.sched_parent.sched_id, |
| TM_SCHED_DIR_TO_STR(p_tm_sched_inst->req_tm_sched_info.key.dir), p_tm_sched_inst->req_tm_sched_info.key.id, bcmos_strerror(ret)); |
| } |
| } |
| else |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "could not validate scheduler dir = %s id = %d as parent of sched dir = %s id = %d (err= %s)\n", |
| TM_SCHED_DIR_TO_STR(p_tm_sched_inst->req_tm_sched_info.key.dir), p_tm_sched_inst->req_tm_sched_info.data.sched_parent.sched_id, |
| TM_SCHED_DIR_TO_STR(p_tm_sched_inst->req_tm_sched_info.key.dir), p_tm_sched_inst->req_tm_sched_info.key.id, bcmos_strerror(ret)); |
| } |
| } |
| |
| /*no need to validate owner attributes as these are read only and set by VALID internal objects*/ |
| if(BCM_ERR_OK != (ret = sw_util_tm_sched_clear(p_tm_sched_inst))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "error %s detected by switch util while clearing tm sched\n", bcmos_strerror(ret)); |
| break; |
| } |
| p_tm_sched_inst->fsm_state = TM_SCHED_FSM_STATE_INACTIVE; |
| |
| } |
| break; |
| |
| case BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT: |
| case BCMBAL_TM_SCHED_OWNER_TYPE_SUB_TERM: |
| case BCMBAL_TM_SCHED_OWNER_TYPE_UNI: |
| case BCMBAL_TM_SCHED_OWNER_TYPE_VIRTUAL: |
| default: |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "nothing to do with unsetting owner type %d \n", |
| p_tm_sched_inst->current_tm_sched_info.data.owner.type); |
| ret = BCM_ERR_PARM; |
| } |
| break; |
| } |
| } |
| }while(0); |
| return ret; |
| |
| } |
| |
| /*for the auto create, only key dir is set, id will be allocated from rsc mgr*/ |
| bcmos_errno bcmbal_tm_sched_auto_create(bcmbal_tm_sched_cfg cfg, tm_sched_inst **p_tm_sched_inst) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| do |
| { |
| cfg.key.id = 0; /* 0 is a magic number telling the resource manager that it should provide the initial allocation of the tm sched id*/ |
| if(BCM_ERR_OK != (ret = _rsc_mgr_tm_sched_auto_id_alloc(&cfg.key.id))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched,"Could not allocate a tm sched auto id \n"); |
| break; |
| } |
| *p_tm_sched_inst = tm_sched_inst_get(cfg.key, TM_SCHED_FLAG_FREE); |
| if(NULL == p_tm_sched_inst) |
| { |
| /* This is a fatal error condition */ |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "ERROR - could not allocate tm sched No further processing\n"); |
| ret = BCM_ERR_NOMEM; |
| break; |
| } |
| BCM_LOG(DEBUG, log_id_tm_sched, |
| "\n Tm Sched id %d dir %s was created \n", cfg.key.id, TM_SCHED_DIR_TO_STR(cfg.key.dir)); |
| |
| (*p_tm_sched_inst)->req_tm_sched_info = cfg; |
| ret = tm_sched_fsm_create(*p_tm_sched_inst, NULL,NULL); |
| }while(0); |
| return ret; |
| } |
| |
| static bcmos_errno bcmbal_tm_sched_queues_list_entry_add(tm_sched_inst *p_tm_sched_inst, bcmbal_tm_queue_key queue_key) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| queue_entry *current_entry; |
| |
| do |
| { |
| /* Check if the id is already on the list before adding it */ |
| TAILQ_FOREACH(current_entry, |
| &p_tm_sched_inst->queues_list, |
| next) |
| { |
| if(current_entry->queue_id == queue_key.id) |
| { |
| return BCM_ERR_ALREADY; |
| } |
| } |
| |
| /* Get a new entry and configure it */ |
| current_entry = bcmos_calloc(sizeof(queue_entry)); |
| |
| if(NULL == current_entry) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "No memory available to add queue\n"); |
| ret = BCM_ERR_NOMEM; |
| break; |
| } |
| |
| current_entry->queue_id = queue_key.id; |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, |
| "adding queue id %u to tm sched %u\n", queue_key.id, p_tm_sched_inst->req_tm_sched_info.key.id); |
| |
| /* Save the entry on the list of queues ids on this sched*/ |
| TAILQ_INSERT_TAIL(&p_tm_sched_inst->queues_list, |
| current_entry, next); |
| (p_tm_sched_inst->num_queues_on_node)++; |
| } while(0); |
| return ret; |
| } |
| |
| static bcmos_errno bcmbal_tm_sched_queues_list_entry_remove(tm_sched_inst *p_tm_sched_inst, bcmbal_tm_queue_key queue_key) |
| { |
| bcmos_errno ret = BCM_ERR_NOENT; |
| queue_entry *current_entry, *p_temp_entry; |
| |
| do |
| { |
| |
| /* Check if the id is on the list */ |
| TAILQ_FOREACH_SAFE(current_entry, |
| &p_tm_sched_inst->queues_list, |
| next, |
| p_temp_entry) |
| { |
| if(current_entry->queue_id == queue_key.id) |
| { |
| /* Remove it from the list of queues ids on this sched*/ |
| TAILQ_REMOVE(&p_tm_sched_inst->queues_list, |
| current_entry, next); |
| |
| bcmos_free(current_entry); |
| |
| (p_tm_sched_inst->num_queues_on_node)--; |
| ret = BCM_ERR_OK; |
| break; |
| |
| } |
| } |
| } while(0); |
| |
| return ret; |
| } |
| |
| static bcmos_errno queues_list_fill(tm_sched_inst *p_tm_sched_inst, |
| bcmbal_tm_queue_id_list_u8 *queues_list) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| queue_entry *current_entry = NULL; |
| int ii = 0; |
| |
| do |
| { |
| |
| /* Traverse the list of queues recorded and fill in the list to be returned */ |
| queues_list->len = p_tm_sched_inst->num_queues_on_node; |
| queues_list->val = bcmos_calloc(sizeof(bcmbal_tm_queue_id) * queues_list->len); |
| |
| if(NULL == queues_list->val) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "No memory available\n"); |
| ret = BCM_ERR_NOMEM; |
| break; |
| } |
| |
| TAILQ_FOREACH(current_entry, |
| &p_tm_sched_inst->queues_list, |
| next) |
| { |
| BCM_LOG(DEBUG, log_id_tm_sched, |
| "adding queue %d to response at array location %d\n", |
| current_entry->queue_id, |
| ii); |
| queues_list->val[ii++] = current_entry->queue_id; |
| } |
| } while(0); |
| return ret; |
| } |
| |
| static bcmos_errno bcmbal_tm_sched_sub_scheds_list_entry_add(tm_sched_inst *p_tm_sched_inst, bcmbal_tm_sched_id sched_id) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| sub_sched_entry *current_entry; |
| |
| BUG_ON(NULL == p_tm_sched_inst); |
| |
| do |
| { |
| /* Check if the id is already on the list before adding it */ |
| TAILQ_FOREACH(current_entry, |
| &p_tm_sched_inst->sub_scheds_list, |
| next) |
| { |
| if(current_entry->sched_id == sched_id) |
| { |
| return BCM_ERR_ALREADY; |
| } |
| } |
| |
| /* Get a new entry and configure it */ |
| current_entry = bcmos_calloc(sizeof(sub_sched_entry)); |
| |
| if(NULL == current_entry) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "No memory available to add sub sched\n"); |
| ret = BCM_ERR_NOMEM; |
| break; |
| } |
| |
| current_entry->sched_id = sched_id; |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, |
| "adding sub sched id %u to tm sched dir = %s id = %u\n", |
| sched_id, TM_SCHED_DIR_TO_STR(p_tm_sched_inst->req_tm_sched_info.key.dir), p_tm_sched_inst->req_tm_sched_info.key.id); |
| |
| /* Save the entry on the list of sub_scheds on that tm sched */ |
| TAILQ_INSERT_TAIL(&p_tm_sched_inst->sub_scheds_list, |
| current_entry, next); |
| (p_tm_sched_inst->num_sub_scheds_on_node)++; |
| |
| } while(0); |
| return ret; |
| } |
| |
| static bcmos_errno bcmbal_tm_sched_sub_scheds_list_entry_remove(tm_sched_inst *p_tm_sched_inst, bcmbal_tm_sched_id sched_id) |
| { |
| bcmos_errno ret = BCM_ERR_NOENT; |
| sub_sched_entry *current_entry, *p_temp_entry; |
| |
| do |
| { |
| |
| /* Check if the id is on the list */ |
| TAILQ_FOREACH_SAFE(current_entry, |
| &p_tm_sched_inst->sub_scheds_list, |
| next, |
| p_temp_entry) |
| { |
| if(current_entry->sched_id == sched_id) |
| { |
| /* Remove it from the list of sub_scheds ids on this sched*/ |
| TAILQ_REMOVE(&p_tm_sched_inst->sub_scheds_list, |
| current_entry, next); |
| |
| bcmos_free(current_entry); |
| |
| (p_tm_sched_inst->num_sub_scheds_on_node)--; |
| ret = BCM_ERR_OK; |
| break; |
| |
| } |
| } |
| } while(0); |
| |
| return ret; |
| } |
| |
| static bcmos_errno sub_scheds_list_fill(tm_sched_inst *p_tm_sched_inst, |
| bcmbal_tm_sched_id_list_u8 *sub_scheds_list) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| sub_sched_entry *current_entry = NULL; |
| int ii = 0; |
| |
| do |
| { |
| |
| /* Traverse the list of sub_scheds_ids recorded and fill in the list to be returned */ |
| sub_scheds_list->len = p_tm_sched_inst->num_sub_scheds_on_node; |
| sub_scheds_list->val = bcmos_calloc(sizeof(bcmbal_tm_sched_id) * sub_scheds_list->len); |
| |
| if(NULL == sub_scheds_list->val) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "No memory available\n"); |
| ret = BCM_ERR_NOMEM; |
| break; |
| } |
| |
| TAILQ_FOREACH(current_entry, |
| &p_tm_sched_inst->sub_scheds_list, |
| next) |
| { |
| BCM_LOG(DEBUG, log_id_tm_sched, |
| "adding sub sched %d to response at array location %d\n", |
| current_entry->sched_id, |
| ii); |
| sub_scheds_list->val[ii++] = current_entry->sched_id; |
| } |
| |
| } while(0); |
| |
| return ret; |
| } |
| |
| bcmos_errno bcmbal_tm_sched_set_queue(tm_queue_inst *p_tm_queue_inst) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| tm_sched_inst *p_tm_sched_inst = NULL; |
| bcmbal_tm_sched_key tm_sched_key; |
| BUG_ON(NULL == p_tm_queue_inst); |
| do |
| { |
| tm_sched_key.id = p_tm_queue_inst->api_req_tm_queue_info.key.sched_id; |
| tm_sched_key.dir= p_tm_queue_inst->api_req_tm_queue_info.key.sched_dir; |
| p_tm_sched_inst = tm_sched_inst_get(tm_sched_key, TM_SCHED_FLAG_ACTIVE); |
| |
| if(NULL == p_tm_sched_inst) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "ERROR - could not find an active tm sched (dir = %s id = %d) to attach the queue (id = %d)\n", |
| TM_SCHED_DIR_TO_STR(tm_sched_key.dir), tm_sched_key.id,p_tm_queue_inst->api_req_tm_queue_info.key.id); |
| ret = BCM_ERR_NOENT; |
| break; |
| } |
| ret = bcmbal_tm_sched_queues_list_entry_add(p_tm_sched_inst, p_tm_queue_inst->api_req_tm_queue_info.key); |
| if(BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "ERROR - could not add the queue entry to the sched\n"); |
| break; |
| } |
| if(TM_SCHED_FSM_STATE_ACTIVE == p_tm_sched_inst->fsm_state) |
| { |
| if(BCM_ERR_OK != (ret = bcmbal_tm_queue_activate(p_tm_queue_inst))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "ERROR - could not activate the newly added queue \n"); |
| break; |
| } |
| } |
| }while(0); |
| return ret; |
| } |
| |
| bcmos_errno bcmbal_tm_sched_remove_queue(tm_queue_inst *p_tm_queue_inst) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| tm_sched_inst *p_tm_sched_inst = NULL; |
| bcmbal_tm_sched_key tm_sched_key; |
| BUG_ON(NULL == p_tm_queue_inst); |
| do |
| { |
| tm_sched_key.id = p_tm_queue_inst->api_req_tm_queue_info.key.sched_id; |
| tm_sched_key.dir= p_tm_queue_inst->api_req_tm_queue_info.key.sched_dir; |
| p_tm_sched_inst = tm_sched_inst_get(tm_sched_key, TM_SCHED_FLAG_ACTIVE); |
| |
| if(NULL == p_tm_sched_inst) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "ERROR - could not find an active tm sched (dir = %s id = %d) to attach the queue (id = %d)\n", |
| TM_SCHED_DIR_TO_STR(tm_sched_key.dir), tm_sched_key.id,p_tm_queue_inst->api_req_tm_queue_info.key.id); |
| ret = BCM_ERR_NOENT; |
| break; |
| } |
| if(BCM_ERR_OK != (ret = bcmbal_tm_sched_queues_list_entry_remove(p_tm_sched_inst, p_tm_queue_inst->api_req_tm_queue_info.key))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "ERROR - could not remove the queue entry from the sched\n"); |
| break; |
| } |
| |
| }while(0); |
| return ret; |
| } |
| |
| /*tm_sched_find_by_owner - currently might be called for agg port and uni port only*/ |
| static tm_sched_inst* tm_sched_find_by_owner(bcmbal_tm_sched_owner owner) |
| { |
| tm_sched_inst *current_entry = NULL; |
| |
| TAILQ_FOREACH(current_entry, |
| &TM_SCHED_FSM_TM_SCHED_LIST_CTX_PTR->active_tm_sched_list, |
| tm_sched_inst_next) |
| { |
| if(BCMBAL_CFG_PROP_IS_SET(¤t_entry->req_tm_sched_info, tm_sched,owner)) |
| { |
| switch(current_entry->req_tm_sched_info.data.owner.type) |
| { |
| case BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT: |
| { |
| if((owner.u.agg_port.intf_id == current_entry->req_tm_sched_info.data.owner.u.agg_port.intf_id) |
| && (owner.u.agg_port.agg_port_id == current_entry->req_tm_sched_info.data.owner.u.agg_port.agg_port_id)) |
| { |
| BCM_LOG(DEBUG, log_id_tm_sched, "Found active tm_sched dir = us id= %d for agg_port_id %d intf_id %d\n", |
| current_entry->req_tm_sched_info.key.id, owner.u.agg_port.agg_port_id, owner.u.agg_port.intf_id); |
| return current_entry; |
| } |
| } |
| break; |
| |
| case BCMBAL_TM_SCHED_OWNER_TYPE_UNI: |
| { |
| if((owner.u.uni.intf_id == current_entry->req_tm_sched_info.data.owner.u.uni.intf_id) |
| && (owner.u.uni.sub_term_id == current_entry->req_tm_sched_info.data.owner.u.uni.sub_term_id) |
| && (owner.u.uni.idx == current_entry->req_tm_sched_info.data.owner.u.uni.idx)) |
| { |
| BCM_LOG(DEBUG, log_id_tm_sched, "Found active tm_sched id = %d for uni intf_id = %d sub_id = %d uni_id = %d\n", |
| current_entry->req_tm_sched_info.key.id, owner.u.uni.intf_id, owner.u.uni.sub_term_id, owner.u.uni.idx); |
| return current_entry; |
| } |
| } |
| |
| default: |
| break; |
| } |
| } |
| } |
| return current_entry; |
| } |
| |
| tm_sched_inst* tm_sched_find_agg_port_node(uint8_t intf_id, bcmbal_aggregation_port_id agg_port_id) |
| { |
| bcmbal_tm_sched_owner owner; |
| owner.type = BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT; |
| owner.u.agg_port.intf_id = intf_id; |
| owner.u.agg_port.agg_port_id = agg_port_id; |
| |
| return tm_sched_find_by_owner(owner); |
| } |
| |
| |
| |
| static bcmos_errno tm_sched_fsm_assigned_process_util_msg(tm_sched_inst *p_tm_sched_inst, void *msg, tm_sched_fsm_event *p_event) |
| { |
| |
| bcmos_errno ret; |
| bal_util_msg_ind *ind_msg; |
| |
| /* Parameter checks */ |
| BUG_ON(NULL == p_tm_sched_inst); |
| BUG_ON(NULL == msg); |
| BUG_ON(NULL == p_event); |
| |
| ind_msg = (bal_util_msg_ind *)msg; |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, |
| " Received a IND message from BAL UTIL (%s) during %s state\n", |
| subsystem_str[bcmbal_sender_get(msg)], |
| tm_sched_state_name_get(p_tm_sched_inst->fsm_state)); |
| |
| /* Handle response */ |
| ret = ind_msg->status; |
| |
| if(BCM_ERR_OK == ret) |
| { |
| p_tm_sched_inst->fsm_state = TM_SCHED_FSM_STATE_ACTIVE; |
| bcmbal_tm_sched_object_overlay_w_src_priority(&p_tm_sched_inst->current_tm_sched_info, |
| &p_tm_sched_inst->req_tm_sched_info); |
| } |
| else |
| { |
| /* Error */ |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "Failed in state %s;%s\n", |
| tm_sched_state_name_get(p_tm_sched_inst->fsm_state), |
| bcmos_strerror(ret)); |
| } |
| |
| mgmt_msg_send_balapi_ind(ret, |
| (void *)&p_tm_sched_inst->current_tm_sched_info.hdr, |
| log_id_tm_sched); |
| |
| return ret; |
| } |
| |
| /*currently handling util msg of alloc id setting complete only for agg port tm sched only*/ |
| static bcmos_errno tm_sched_fsm_deleting_process_util_msg(tm_sched_inst *p_tm_sched_inst, |
| void *msg, |
| tm_sched_fsm_event *p_event) |
| { |
| bcmos_errno ret; |
| bal_util_msg_ind *ind_msg; |
| |
| /* Parameter checks */ |
| BUG_ON(NULL == p_tm_sched_inst); |
| BUG_ON(NULL == msg); |
| BUG_ON(NULL == p_event); |
| |
| do |
| { |
| ind_msg = (bal_util_msg_ind *)msg; |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, |
| " Received a IND message from BAL UTIL (%s) during %s state\n", |
| subsystem_str[bcmbal_sender_get(msg)], |
| tm_sched_state_name_get(p_tm_sched_inst->fsm_state)); |
| |
| /* Handle response */ |
| ret = ind_msg->status; |
| |
| if(BCM_ERR_OK == ret) |
| { |
| ret = tm_sched_fsm_destroy(p_tm_sched_inst); |
| } |
| else |
| { |
| /* Error */ |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "Failed in state %s;%s\n", |
| tm_sched_state_name_get(p_tm_sched_inst->fsm_state), |
| bcmos_strerror(ret)); |
| } |
| }while(0); |
| return ret; |
| } |
| |
| static bcmos_errno tm_sched_fsm_destroy(tm_sched_inst *p_tm_sched_inst) |
| { |
| queue_entry *current_entry = NULL; |
| bcmos_errno ret = BCM_ERR_OK; |
| bcmbal_tm_queue_key tm_queue_key; |
| tm_queue_inst *p_tm_queue_inst; |
| int i=0; |
| bcmbal_tm_sched_owner owner; |
| |
| do |
| { |
| switch(p_tm_sched_inst->req_tm_sched_info.data.owner.type) |
| { |
| case BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT: |
| { |
| p_tm_sched_inst->fsm_state = TM_SCHED_FSM_STATE_NULL; |
| owner = p_tm_sched_inst->req_tm_sched_info.data.owner; |
| |
| ret = rsc_mgr_alloc_id_free(owner.u.agg_port.intf_id, owner.u.agg_port.agg_port_id, NULL); |
| if(BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "Failed to free alloc id if=%d id=%d at resource manager", |
| owner.u.agg_port.intf_id, owner.u.agg_port.agg_port_id); |
| break; |
| } |
| ret = tm_sched_fsm_destroy(p_tm_sched_inst); |
| if(BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "Failed to free auto created tm sched id, id=%d at resource manager", |
| p_tm_sched_inst->req_tm_sched_info.key.id); |
| break; |
| } |
| break; |
| } |
| case BCMBAL_TM_SCHED_OWNER_TYPE_INTERFACE: |
| { |
| tm_queue_key.sched_id = p_tm_sched_inst->req_tm_sched_info.key.id; |
| tm_queue_key.sched_dir = p_tm_sched_inst->req_tm_sched_info.key.dir; |
| |
| /*delete all attached queues*/ |
| TAILQ_FOREACH(current_entry, |
| &p_tm_sched_inst->queues_list, |
| next) |
| { |
| |
| BCM_LOG(DEBUG, log_id_tm_sched, |
| "deleting queue %u (location %u)\n", |
| current_entry->queue_id, |
| i); |
| tm_queue_key.id = current_entry->queue_id; |
| |
| p_tm_queue_inst = tm_queue_inst_get(tm_queue_key, TM_QUEUE_FLAG_ACTIVE); |
| if(NULL == p_tm_queue_inst) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched,"ERROR - tm queue not found. No further processing\n"); |
| ret = BCM_ERR_NOENT; |
| break; |
| } |
| |
| ret = bcmbal_tm_queue_destroy(p_tm_queue_inst, BCMOS_FALSE); |
| if(BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched,"ERROR - could not destroy tm queue %d .No further processing\n", |
| tm_queue_key.id); |
| ret = BCM_ERR_NOENT; |
| break; |
| } |
| |
| bcmos_free(current_entry); |
| i++; |
| } |
| } |
| break; |
| |
| default: |
| break; |
| } |
| if(p_tm_sched_inst->req_tm_sched_info.data.creation_mode == BCMBAL_TM_CREATION_MODE_AUTO) |
| { |
| ret = _rsc_mgr_tm_sched_auto_id_free(p_tm_sched_inst->req_tm_sched_info.key.id); |
| if(BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "Failed to free auto created tm sched id, id=%d at resource manager ", |
| p_tm_sched_inst->req_tm_sched_info.key.id); |
| break; |
| } |
| } |
| |
| mgmt_msg_send_balapi_ind(ret, |
| (void *)&p_tm_sched_inst->req_tm_sched_info.hdr, |
| log_id_tm_sched); |
| |
| ret = tm_sched_free_by_entry(p_tm_sched_inst); |
| if(BCM_ERR_OK != ret) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "Failed to free tm sched id=%d dir = %s",p_tm_sched_inst->req_tm_sched_info.key.id, |
| TM_SCHED_DIR_TO_STR(p_tm_sched_inst->req_tm_sched_info.key.dir)); |
| break; |
| } |
| }while(0); |
| return ret; |
| |
| } |
| |
| static bcmos_errno tm_sched_fsm_inactive_destroy(tm_sched_inst *p_tm_sched_inst, void *msg, tm_sched_fsm_event *p_event) |
| { |
| return tm_sched_fsm_destroy(p_tm_sched_inst); |
| } |
| |
| static bcmos_errno tm_sched_fsm_active_destroy(tm_sched_inst *p_tm_sched_inst, void *msg, tm_sched_fsm_event *p_event) |
| { |
| return bcmbal_tm_sched_fsm_active_destroy(p_tm_sched_inst); |
| } |
| |
| static bcmos_errno tm_sched_fsm_assigned_destroy(tm_sched_inst *p_tm_sched_inst, void *msg, tm_sched_fsm_event *p_event) |
| { |
| bcmos_errno ret = bcmbal_tm_sched_fsm_active_destroy(p_tm_sched_inst); |
| if (BCM_ERR_OK == ret) |
| ret = tm_sched_fsm_destroy(p_tm_sched_inst); |
| |
| return ret; |
| |
| } |
| bcmos_errno bcmbal_tm_sched_fsm_active_destroy(tm_sched_inst *p_tm_sched_inst) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| bcmbal_tm_sched_owner owner = p_tm_sched_inst->req_tm_sched_info.data.owner; |
| bcmbal_interface_key intf_key; |
| |
| |
| switch(owner.type) |
| { |
| case BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT: |
| { |
| uint32_t ref_count; |
| ret = rsc_mgr_alloc_id_get_ref_count(p_tm_sched_inst->req_tm_sched_info.data.owner.u.agg_port.intf_id, |
| p_tm_sched_inst->req_tm_sched_info.data.owner.u.agg_port.agg_port_id, &ref_count); |
| if(1!= ref_count) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "Cant destroy tm sched owned by agg port (if %d id %d) " |
| "with reference count %d (greated than 1)\n", |
| p_tm_sched_inst->req_tm_sched_info.data.owner.u.agg_port.intf_id, |
| p_tm_sched_inst->req_tm_sched_info.data.owner.u.agg_port.agg_port_id, ref_count); |
| ret = BCM_ERR_INTERNAL; |
| break; |
| |
| } |
| ret = mac_util_agg_port_set(p_tm_sched_inst, BAL_UTIL_OPER_AGG_PORT_REMOVE); |
| if(BCM_ERR_OK != ret) |
| { |
| /* An error has occurred trying to configure mac*/ |
| BCM_LOG(ERROR, log_id_tm_sched, "Failed to remove ALLOC ID at mac (%s)\n",bcmos_strerror(ret)); |
| break; |
| } |
| else |
| { |
| p_tm_sched_inst->fsm_state = TM_SCHED_FSM_STATE_DELETING; |
| } |
| break; |
| } |
| case BCMBAL_TM_SCHED_OWNER_TYPE_INTERFACE: |
| { |
| /*remove the setting of the sched from the owner configuration*/ |
| intf_key.intf_type = owner.u.interface.intf_type; |
| intf_key.intf_id = owner.u.interface.intf_id; |
| ret = interface_tm_sched_unset(intf_key, p_tm_sched_inst->req_tm_sched_info.key); |
| tm_sched_fsm_destroy(p_tm_sched_inst); |
| break; |
| } |
| |
| default: |
| break; |
| } |
| return ret; |
| |
| } |
| |
| /*****************************************************************************/ |
| /** |
| * @brief A function to set an interface as a tm sched owner |
| * |
| * @param interface_key the interface to become the owner |
| * @param p_tm_sched_inst the tm sched instance to be set |
| * |
| * @returns bcmos_errno |
| *****************************************************************************/ |
| bcmos_errno bcmbal_tm_sched_set_interface_owner(bcmbal_interface_key interface_key, tm_sched_inst *p_tm_sched_inst) |
| { |
| BUG_ON(NULL == p_tm_sched_inst); |
| |
| bcmos_errno ret = BCM_ERR_OK; |
| bcmbal_tm_sched_owner owner; |
| do |
| { |
| if(BCMBAL_CFG_PROP_IS_SET(&p_tm_sched_inst->req_tm_sched_info, tm_sched, owner)) |
| { |
| owner = p_tm_sched_inst->req_tm_sched_info.data.owner; |
| if (BCMBAL_TM_SCHED_OWNER_TYPE_INTERFACE!= owner.type ) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "tm sched %s%d is already assigned with an owner of type %d", |
| p_tm_sched_inst->current_tm_sched_info.key.dir == BCMBAL_TM_SCHED_DIR_US ? "us" : "ds", |
| p_tm_sched_inst->current_tm_sched_info.key.id, owner.type ); |
| break; |
| } |
| if(owner.u.interface.intf_type != interface_key.intf_type |
| || owner.u.interface.intf_id != interface_key.intf_id) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, "tm sched %s%d is already assigned with an interface owner", |
| p_tm_sched_inst->current_tm_sched_info.key.dir == BCMBAL_TM_SCHED_DIR_US ? "us" : "ds", |
| p_tm_sched_inst->current_tm_sched_info.key.id); |
| |
| ret = BCM_ERR_ALREADY; |
| break; |
| } |
| } |
| else |
| { |
| owner.type = BCMBAL_TM_SCHED_OWNER_TYPE_INTERFACE; |
| owner.u.interface.intf_type = interface_key.intf_type; |
| owner.u.interface.intf_id = interface_key.intf_id; |
| BCMBAL_CFG_PROP_SET(&p_tm_sched_inst->req_tm_sched_info, tm_sched, owner, owner); |
| ret = bcmbal_tm_sched_set_owner(p_tm_sched_inst); |
| } |
| }while(0); |
| return ret; |
| } |
| |
| #define BCMBAL_INTERFACE_DEFAULT_NUM_OF_TM_QUEUES 4 |
| #define BCMBAL_INTERFACE_DEFAULT_SCHED_TYPE BCMBAL_TM_SCHED_TYPE_SP_WFQ |
| #define BCMBAL_INTERFACE_DEFAULT_SCHED_CHILD_TYPE BCMBAL_TM_SCHED_CHILD_TYPE_QUEUE |
| |
| #define BCMBAL_TM_QUEUE_AUTO_DEFAULT_SIZE 128 |
| #define BCMBAL_TM_QUEUE_AUTO_DEFAULT_SBR 128 |
| #define BCMBAL_TM_QUEUE_AUTO_DEFAULT_PBR 128 |
| #define BCMBAL_TM_QUEUE_AUTO_DEFAULT_BURST_SIZE 128 |
| |
| bcmos_errno bcmbal_tm_sched_interface_tm_auto_create(bcmbal_interface_cfg *p_interface_info) |
| { |
| |
| bcmos_errno ret = BCM_ERR_OK; |
| tm_sched_inst *p_tm_sched_inst = NULL; |
| bcmbal_tm_sched_cfg tm_sched_default_cfg; |
| bcmbal_tm_queue_cfg tm_queue_default_cfg; |
| bcmbal_tm_shaping default_shaping; |
| bcmbal_tm_sched_key tm_sched_key; |
| bcmbal_tm_queue_key tm_queue_key; |
| int i; |
| |
| do |
| { |
| /*create the auto tm sched*/ |
| tm_sched_key.dir = p_interface_info->key.intf_type == BCMBAL_INTF_TYPE_PON ? BCMBAL_TM_SCHED_DIR_DS : BCMBAL_TM_SCHED_DIR_US; |
| BCMBAL_CFG_INIT(&tm_sched_default_cfg, tm_sched, tm_sched_key); |
| BCMBAL_CFG_PROP_SET(&tm_sched_default_cfg, tm_sched, sched_type, BCMBAL_INTERFACE_DEFAULT_SCHED_TYPE); |
| BCMBAL_CFG_PROP_SET(&tm_sched_default_cfg, tm_sched, sched_child_type, BCMBAL_INTERFACE_DEFAULT_SCHED_CHILD_TYPE); |
| BCMBAL_CFG_PROP_SET(&tm_sched_default_cfg, tm_sched, num_priorities, BCMBAL_INTERFACE_DEFAULT_NUM_OF_TM_QUEUES); |
| BCMBAL_CFG_PROP_SET(&tm_sched_default_cfg, tm_sched, creation_mode, BCMBAL_TM_CREATION_MODE_AUTO); |
| |
| if (BCM_ERR_OK != (ret = bcmbal_tm_sched_auto_create(tm_sched_default_cfg, &p_tm_sched_inst))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched,"Could not create the auto tm sched \n"); |
| break; |
| } |
| if (tm_sched_key.dir == BCMBAL_TM_SCHED_DIR_US) |
| { |
| BCMBAL_CFG_PROP_SET(p_interface_info, interface, us_tm, p_tm_sched_inst->req_tm_sched_info.key.id); |
| } |
| else |
| { |
| BCMBAL_CFG_PROP_SET(p_interface_info, interface, ds_tm, p_tm_sched_inst->req_tm_sched_info.key.id); |
| } |
| |
| /*SET THE DEFAULT ATTRIBUTES FOR AUTO CREATED QUEUE*/ |
| tm_queue_key.sched_id = p_tm_sched_inst->req_tm_sched_info.key.id; |
| tm_queue_key.sched_dir = p_tm_sched_inst->req_tm_sched_info.key.dir; |
| default_shaping.sbr = (uint8_t)BCMBAL_TM_QUEUE_AUTO_DEFAULT_SBR; |
| default_shaping.pbr = (uint8_t)BCMBAL_TM_QUEUE_AUTO_DEFAULT_PBR; |
| default_shaping.burst = (uint8_t)BCMBAL_TM_QUEUE_AUTO_DEFAULT_BURST_SIZE; |
| BCMBAL_CFG_PROP_SET(&tm_queue_default_cfg, tm_queue, rate, default_shaping); |
| BCMBAL_CFG_PROP_SET(&tm_sched_default_cfg, tm_queue, creation_mode, BCMBAL_TM_CREATION_MODE_AUTO); |
| |
| /*create its queues*/ |
| for(i=0; i<BCMBAL_INTERFACE_DEFAULT_NUM_OF_TM_QUEUES; i++) |
| { |
| tm_queue_key.id = i; |
| BCMBAL_CFG_INIT(&tm_queue_default_cfg, tm_queue, tm_queue_key); |
| |
| BCMBAL_CFG_PROP_SET(&tm_queue_default_cfg, tm_queue, priority, i); |
| BCMBAL_CFG_PROP_SET(&tm_queue_default_cfg, tm_queue, rate, default_shaping); |
| if (BCM_ERR_OK != (ret = bcmbal_tm_queue_auto_create(tm_queue_default_cfg))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched,"Could not create the %d tm queue\n", i); |
| break; |
| } |
| } |
| |
| ret = bcmbal_tm_sched_set_interface_owner(p_interface_info->key, p_tm_sched_inst); |
| |
| }while(0); |
| |
| return ret; |
| } |
| |
| bcmos_errno bcmbal_tm_sched_set_sub_term_owner( bcmbal_tm_sched_key tm_sched_key, const bcmbal_subscriber_terminal_cfg *p_sub_term_cfg) |
| { |
| bcmos_errno ret = BCM_ERR_OK; |
| tm_sched_inst *p_tm_sched_inst; |
| bcmbal_tm_sched_owner owner; |
| |
| do |
| { |
| p_tm_sched_inst = tm_sched_inst_get(tm_sched_key, TM_SCHED_FLAG_ACTIVE); |
| if (NULL == p_tm_sched_inst) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "tm sched dir = %s id = %d which is set as the subscriber tm does not exist \n", |
| TM_SCHED_DIR_TO_STR(tm_sched_key.dir), tm_sched_key.id); |
| ret = BCM_ERR_NOENT; |
| break; |
| } |
| if(BCMBAL_CFG_PROP_IS_SET(&p_tm_sched_inst->req_tm_sched_info, tm_sched, owner)) |
| { |
| /*check if it is already owned by that sub term*/ |
| owner = p_tm_sched_inst->req_tm_sched_info.data.owner; |
| if (owner.type != BCMBAL_TM_SCHED_OWNER_TYPE_SUB_TERM) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "tm sched dir = %s id = %d which is set as the subscriber tm already owned with owner type %d\n", |
| TM_SCHED_DIR_TO_STR(tm_sched_key.dir), tm_sched_key.id, owner.type); |
| ret = BCM_ERR_PARM; |
| break; |
| |
| } |
| if (owner.u.sub_term.intf_id != p_sub_term_cfg->key.intf_id |
| || owner.u.sub_term.sub_term_id != p_sub_term_cfg->key.sub_term_id) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "tm sched dir = %s id = %d which is set as the subscriber tm already owned by sub_term intf_id = %d sub_term_id = %d\n", |
| TM_SCHED_DIR_TO_STR(tm_sched_key.dir), tm_sched_key.id, owner.u.sub_term.intf_id, owner.u.sub_term.sub_term_id); |
| ret = BCM_ERR_PARM; |
| break; |
| } |
| } |
| else |
| { |
| owner.type = BCMBAL_TM_SCHED_OWNER_TYPE_SUB_TERM; |
| owner.u.sub_term.intf_id = p_sub_term_cfg->key.intf_id; |
| owner.u.sub_term.sub_term_id = p_sub_term_cfg->key.sub_term_id; |
| BCMBAL_CFG_PROP_SET(&p_tm_sched_inst->req_tm_sched_info, tm_sched, owner, owner); |
| |
| if (BCM_ERR_OK!= (ret = bcmbal_tm_sched_set_owner(p_tm_sched_inst))) |
| { |
| BCM_LOG(ERROR, log_id_tm_sched, |
| "could not set sub term intf_id = %d sub_term_id = %d as the owner of tm sched dir = %s id = %d which is set as the subscriber tm \n", |
| owner.u.sub_term.intf_id, owner.u.sub_term.sub_term_id, TM_SCHED_DIR_TO_STR(tm_sched_key.dir), tm_sched_key.id); |
| break; |
| } |
| } |
| }while (0); |
| return ret; |
| } |
| |
| /*@}*/ |