blob: 50424cb4b789c134fa1001e9ab7ed3d32d6f6106 [file] [log] [blame]
/******************************************************************************
*
* <:copyright-BRCM:2016:DUAL/GPL:standard
*
* Copyright (c) 2016 Broadcom
* All Rights Reserved
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed
* to you under the terms of the GNU General Public License version 2
* (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
* with the following added to such license:
*
* As a special exception, the copyright holders of this software give
* you permission to link this software with independent modules, and
* to copy and distribute the resulting executable under terms of your
* choice, provided that you also meet, for each linked independent
* module, the terms and conditions of the license of that module.
* An independent module is a module which is not derived from this
* software. The special exception does not apply to any modifications
* of the software.
*
* Not withstanding the above, under no circumstances may you combine
* this software in any way with any other Broadcom software provided
* under a license other than the GPL, without Broadcom's express prior
* written consent.
*
* :>
*
*****************************************************************************/
/**
* @file 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(&current_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;
}
/*@}*/