blob: 97b0a4521adb29e09ed013c693329b663ac59b7a [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 group_fsm.c
* @brief Code to support the BAL group FSM
*
*
*/
/*@{*/
#include <bcmos_system.h>
#include <group_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 "rsc_mgr.h"
#include <bal_objs.h>
#include <fsm_common.h>
#ifdef ENABLE_LOG
#include <bcm_dev_log.h>
/*
* @brief The logging device id for group
*/
static dev_log_id log_id_group;
#endif
/* local function declarations */
static bcmos_errno group_fsm_create(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event);
static bcmos_errno group_fsm_destroy(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event);
static bcmos_errno group_fsm_add(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event);
static bcmos_errno group_fsm_remove(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event);
static bcmos_errno group_fsm_set(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event);
static bcmos_errno group_fsm_configuring_util_msg(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event);
static bcmos_errno group_fsm_deleting_util_msg(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event);
static bcmos_errno group_fsm_ignore_api_msg(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event);
static bcmos_errno group_fsm_state_err(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event);
static bcmos_errno group_fsm_exec(group_inst *p_group_inst, group_fsm_event *p_event);
static group_inst *group_inst_get(bcmbal_group_key *key, group_flag search_flag);
static bcmos_errno group_free_by_entry(group_inst *p_entry);
static bcmos_errno bcmbal_group_object_member_remove(bcmbal_group_cfg *p_req_group,
bcmbal_group_cfg *p_cur_group);
static bcmos_errno bcmbal_group_object_member_add(bcmbal_group_cfg *p_req_group,
bcmbal_group_cfg *p_cur_group);
static bcmos_errno bcmbal_group_object_member_replace(bcmbal_group_cfg *p_req_group,
bcmbal_group_cfg *p_cur_group);
static bcmos_errno bcmbal_group_object_overlay(bcmbal_group_cfg *p_req_group,
bcmbal_group_cfg *p_cur_group);
/*
* @brief The Global group fsm context data structure
*/
static group_fsm_ctx g_group_fsm_group_list_ctx;
/*
* Macros for group ctx access
*/
#define GROUP_FSM_GROUP_LIST_CTX (g_group_fsm_group_list_ctx)
#define GROUP_FSM_GROUP_LIST_CTX_PTR (&g_group_fsm_group_list_ctx)
/*
* @brief The definition of a group FSM state processing function
*/
typedef bcmos_errno (* group_fsm_state_processor)(group_inst *, void *, group_fsm_event *);
/*
* @brief The Group FSM state processing array
*/
static group_fsm_state_processor group_states[GROUP_FSM_STATE__NUM_OF][GROUP_FSM_EVENT_TYPE__NUM_OF] =
{
[GROUP_FSM_STATE_NULL] =
{
/*
* Next state: COMFIGURING
*/
[GROUP_FSM_EVENT_TYPE_CREATE] = group_fsm_create,
/*
* Next state: NULL
*/
[GROUP_FSM_EVENT_TYPE_DESTROY] = group_fsm_ignore_api_msg,
/*
* Next state: CONFIGURING
*/
[GROUP_FSM_EVENT_TYPE_ADD] = group_fsm_add,
/*
* Next state: NULL
*/
[GROUP_FSM_EVENT_TYPE_REMOVE] = group_fsm_ignore_api_msg,
/*
* Next state: CONFIGURING
*/
[GROUP_FSM_EVENT_TYPE_SET] = group_fsm_set,
},
[GROUP_FSM_STATE_CONFIGURING] =
{
/*
* Next state: COMFIGURING
*/
[GROUP_FSM_EVENT_TYPE_CREATE] = group_fsm_ignore_api_msg,
/*
* Next state: COMFIGURING
*/
[GROUP_FSM_EVENT_TYPE_DESTROY] = group_fsm_ignore_api_msg,
/*
* Next state: CONFIGURING
*/
[GROUP_FSM_EVENT_TYPE_ADD] = group_fsm_ignore_api_msg,
/*
* Next state: CONFIGURING
*/
[GROUP_FSM_EVENT_TYPE_REMOVE] = group_fsm_ignore_api_msg,
/*
* Next state: CONFIGURING
*/
[GROUP_FSM_EVENT_TYPE_SET] = group_fsm_ignore_api_msg,
/*
* Next state: CONFIGURED
*/
[GROUP_FSM_EVENT_TYPE_UTIL_MSG] = group_fsm_configuring_util_msg,
},
[GROUP_FSM_STATE_CONFIGURED] =
{
/*
* Next state: COMFIGURING
*/
[GROUP_FSM_EVENT_TYPE_CREATE] = group_fsm_ignore_api_msg,
/*
* Next state: DELETING
*/
[GROUP_FSM_EVENT_TYPE_DESTROY] = group_fsm_destroy,
/*
* Next state: CONFIGURING
*/
[GROUP_FSM_EVENT_TYPE_ADD] = group_fsm_add,
/*
* Next state: CONFIGURING
*/
[GROUP_FSM_EVENT_TYPE_REMOVE] = group_fsm_remove,
/*
* Next state: CONFIGURING
*/
[GROUP_FSM_EVENT_TYPE_SET] = group_fsm_set,
},
[GROUP_FSM_STATE_DELETING] =
{
/*
* Next state: DELETING
*/
[GROUP_FSM_EVENT_TYPE_CREATE] = group_fsm_ignore_api_msg,
/*
* Next state: DELETING
*/
[GROUP_FSM_EVENT_TYPE_DESTROY] = group_fsm_ignore_api_msg,
/*
* Next state: DELETING
*/
[GROUP_FSM_EVENT_TYPE_ADD] = group_fsm_ignore_api_msg,
/*
* Next state: DELETING
*/
[GROUP_FSM_EVENT_TYPE_REMOVE] = group_fsm_ignore_api_msg,
/*
* Next state: DELETING
*/
[GROUP_FSM_EVENT_TYPE_SET] = group_fsm_ignore_api_msg,
/*
* Next state: NULL
*/
[GROUP_FSM_EVENT_TYPE_UTIL_MSG] = group_fsm_deleting_util_msg,
},
};
static char *state_name_str[] =
{
"GROUP_FSM_STATE_NULL",
"GROUP_FSM_STATE_CONFIGURING",
"GROUP_FSM_STATE_CONFIGURED",
"GROUP_FSM_STATE_DELETING",
};
/* Ensure that the name array size matches the associated enum */
BAL_STATIC_ASSERT (GROUP_FSM_STATE__LAST == (sizeof (state_name_str) / sizeof (char *)), group_fsm_state);
static char *group_state_name_get(group_fsm_state state)
{
if(state < GROUP_FSM_STATE__LAST)
{
return state_name_str[state];
}
else
{
return "GROUP_UNKNOWN";
}
}
static char *event_name_str[] =
{
"GROUP_FSM_CREATE_EVENT",
"GROUP_FSM_DESTROY_EVENT",
"GROUP_FSM_ADD_EVENT",
"GROUP_FSM_REMOVE_EVENT",
"GROUP_FSM_SET_EVENT",
"GROUP_FSM_UTIL_MSG_EVENT",
};
/* Ensure that the name array size matches the associated enum */
BAL_STATIC_ASSERT (GROUP_FSM_EVENT_TYPE__LAST == (sizeof (event_name_str) / sizeof (char *)), group_fsm_event_type);
static char *group_event_name_get(group_fsm_event_type event)
{
if(event < GROUP_FSM_EVENT_TYPE__LAST)
{
return event_name_str[event];
}
else
{
return "GROUP_EVT_UNKNOWN";
}
}
/*****************************************************************************/
/**
* @brief A function to initialize the current_group_info object of the
* supplied entry.
*
* @param p_entry A pointer to the entry to be initialized
*
*
* @returns void
*****************************************************************************/
static void group_inst_entry_obj_init(group_inst *p_entry)
{
/* The actual key content is irrelevant for free groups */
bcmbal_group_key key = { .group_id = 0 };
BCMBAL_CFG_INIT(&p_entry->current_group_info,
group,
key);
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_entry->current_group_info), BCMOS_FALSE);
}
/*****************************************************************************/
/**
* @brief A function to initialize the Group FSM infrastructure.
*
* NOTE: This is called once on startup and NOT for each FSM instance.
*
* @returns bcmos_errno
*****************************************************************************/
bcmos_errno group_fsm_init(void)
{
int ii;
group_inst *new_entry;
bcmos_errno ret = BCM_ERR_OK;
#ifdef ENABLE_LOG
log_id_group = bcm_dev_log_id_register("GROUP", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
BUG_ON(log_id_group == DEV_LOG_INVALID_ID);
#endif
/* Initialize all of the group queues */
TAILQ_INIT(&GROUP_FSM_GROUP_LIST_CTX_PTR->free_group_list);
TAILQ_INIT(&GROUP_FSM_GROUP_LIST_CTX_PTR->active_group_list);
/* Populate the free list with it's initial set of groups
*/
for(ii=0; ii<GROUP_ALLOCATION_BLOCK_SIZE; ii++)
{
new_entry = bcmos_calloc(sizeof(group_inst));
if (NULL == new_entry)
{
BCM_LOG(FATAL, log_id_group, "Failed to initialize the group free list - FATAL\n");
ret = BCM_ERR_NOMEM;
break;
}
group_free_by_entry(new_entry);
}
return ret;
}
/*****************************************************************************/
/**
* @brief A function to un-initialize the Group FSM infrastructure.
*
* NOTE: This is called once on shutdown and NOT for each FSM instance.
*
* @returns bcmos_errno
*****************************************************************************/
bcmos_errno group_fsm_finish(void)
{
group_inst *current_entry, *p_temp_entry;
/* Free all the entries on the active list */
TAILQ_FOREACH_SAFE(current_entry,
&GROUP_FSM_GROUP_LIST_CTX_PTR->active_group_list,
group_inst_next,
p_temp_entry)
{
/* free up the internal allocated member info */
if(current_entry->current_group_info.data.members.val)
{
bcmos_free(current_entry->current_group_info.data.members.val);
}
/* Remove it from the active list */
TAILQ_REMOVE(&GROUP_FSM_GROUP_LIST_CTX_PTR->active_group_list, current_entry, group_inst_next);
bcmos_free(current_entry);
}
/* Free all the entries on the free list */
TAILQ_FOREACH_SAFE(current_entry,
&GROUP_FSM_GROUP_LIST_CTX_PTR->free_group_list,
group_inst_next,
p_temp_entry)
{
/* Remove it from the active list */
TAILQ_REMOVE(&GROUP_FSM_GROUP_LIST_CTX_PTR->free_group_list, current_entry, group_inst_next);
bcmos_free(current_entry);
}
return BCM_ERR_OK;
}
/*****************************************************************************/
/**
* @brief The Group FSM state processing executive function
*
* @param p_group_inst Pointer to a group instance
* @param p_event Pointer to a group event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno group_fsm_exec(group_inst *p_group_inst, group_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
group_fsm_state pre_state;
group_fsm_state_processor group_state_processor;
/* Parameter checks */
BUG_ON(NULL == p_group_inst);
BUG_ON(NULL == p_event);
/* Record the present state for debug printing
*/
pre_state = p_group_inst->fsm_state;
/*
* Get the state processing function
*/
group_state_processor = group_states[p_group_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 (group_state_processor)
{
ret = group_state_processor(p_group_inst, p_event->msg, p_event);
} else
{
group_fsm_state_err(p_group_inst, p_event->msg, p_event);
}
if(BCM_ERR_OK != ret)
{
BCM_LOG(ERROR, log_id_group, "*** Error detected during state processing\n");
p_group_inst->fsm_state = pre_state;
}
BCM_LOG(DEBUG, log_id_group, "*** Event %s, State: %s --> %s\n\n",
group_event_name_get(p_event->event_type),
group_state_name_get(pre_state),
group_state_name_get(p_group_inst->fsm_state));
return ret;
}
/*****************************************************************************/
/**
* @brief The Group FSM state processing for a group create command received
* from the BAL Public API.
*
* @param p_group_inst Pointer to a group instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to a group event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno group_fsm_create(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
group_fsm_state pre_fsm_state;
BCM_LOG(INFO, log_id_group, "Got SET request from BAL API - create group \n");
do
{
/* save the current state */
pre_fsm_state = p_group_inst->fsm_state;
/* change Group state to CONFIGURING */
p_group_inst->fsm_state = GROUP_FSM_STATE_CONFIGURING;
/*– Core calls Switch Utils to add applicable CMDs */
if(BCM_ERR_OK != (ret = sw_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_CREATE)))
{
BCM_LOG(ERROR, log_id_group, "error %s detected by switch util while create group\n", bcmos_strerror(ret));
break;
}
/*– Core calls Mac Utils create applicable CMDs */
if(BCM_ERR_OK != (ret = mac_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_CREATE, BCMOS_TRUE)))
{
BCM_LOG(ERROR, log_id_group, "error %s detected by mac util\n", bcmos_strerror(ret));
/* Reverse the (just create) group in the switch, otherwise the switch utils
* will be out of sync with Core and Mac. There's not
* much we can do about it if reversing this group fails.
*/
if(BCM_ERR_OK != sw_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_DESTROY))
{
BCM_LOG(ERROR, log_id_group,
"error detected by switch util while reversing create group\n");
}
else
{
/* restore the original state */
p_group_inst->fsm_state = pre_fsm_state;
}
break;
}
/* The hardware has properly accepted the object info, so copy object to
* the current state.
*/
bcmbal_group_object_overlay(&p_group_inst->api_req_group_info,
&p_group_inst->current_group_info);
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_group_inst->current_group_info), BCMOS_TRUE);
}while(0);
/* If there were errors during processing, then report the error to the API */
if(BCM_ERR_OK != ret)
{
mgmt_msg_send_balapi_ind(ret,
msg,
log_id_group);
}
return ret;
}
/*****************************************************************************/
/**
* @brief The Group FSM state processing for a group destroy command received
* from the BAL Public API.
*
* @param p_group_inst Pointer to a group instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to a group event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno group_fsm_destroy(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
group_fsm_state sav_state = p_group_inst->fsm_state;
bcmbal_group_cfg *p_group_cfg;
int i;
BCM_LOG(INFO, log_id_group, "Got CLEAR request from BAL API - destroy group \n");
do
{
/* change Group state to CONFIGURING */
p_group_inst->fsm_state = GROUP_FSM_STATE_DELETING;
/* Destroy operation is best effort, as it is unlikely to fail */
/*– Core calls Switch Utils to add applicable CMDs */
if(BCM_ERR_OK != (ret = sw_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_DESTROY)))
{
BCM_LOG(ERROR, log_id_group, "error %s detected by switch util while destroy group\n", bcmos_strerror(ret));
/* if the group is busy, some flow still reference this group, skip the MAC and return error
no member has been clean up */
if(ret == BCM_ERR_INVALID_OP)
{
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_group_inst->current_group_info), BCMOS_TRUE);
p_group_inst->fsm_state = sav_state;
mgmt_msg_send_balapi_ind(ret, msg, log_id_group);
return ret;
}
break;
}
/*– Core calls Mac Utils create applicable CMDs */
if(BCM_ERR_OK != (ret = mac_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_DESTROY, BCMOS_TRUE)))
{
BCM_LOG(ERROR, log_id_group, "error %s detected by mac util\n", bcmos_strerror(ret));
break;
}
/* The hardware has properly accepted the object info, so copy object to
* the current state.
*/
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_group_inst->current_group_info), BCMOS_TRUE);
}while(0);
/* If there were errors during processing, then report the error to the API */
if(BCM_ERR_OK != ret)
{
mgmt_msg_send_balapi_ind(ret,
msg,
log_id_group);
/* TBD, need logic to perform error recovery if SwitchUtil success and MacUtil failed */
}
else
{
/* update resource manager on svc_port_id usage - keep going as the Mac and Switch already clean up */
p_group_cfg = &p_group_inst->current_group_info;
for(i=0; i<p_group_cfg->data.members.len; i++)
{
if(BCM_ERR_OK != rsc_mgr_gem_free(p_group_cfg->data.members.val[i].intf_id,
p_group_cfg->data.members.val[i].svc_port_id,
NULL) )
{
BCM_LOG(ERROR, log_id_group,
" error encountered during destroy of group resources (gem_id: %d, intf_id:%d\n",
p_group_cfg->data.members.val[i].svc_port_id,
p_group_cfg->data.members.val[i].intf_id);
}
}
}
return ret;
}
/*****************************************************************************/
/**
* @brief The Group FSM state processing for a group set command received
* from the BAL Public API.
*
* @param p_group_inst Pointer to a group instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to a group event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno group_fsm_set(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
group_inst group_inst_rvt;
bcmbal_group_cfg *p_group_cfg;
int i;
BCM_LOG(INFO, log_id_group, "Got SET request from BAL API - replace group members\n");
do
{
/* save the current state */
group_inst_rvt.fsm_state = p_group_inst->fsm_state;
/* change Group state to CONFIGURING */
p_group_inst->fsm_state = GROUP_FSM_STATE_CONFIGURING;
/*– Core calls Switch Utils to add applicable CMDs */
if(BCM_ERR_OK != (ret = sw_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_SET)))
{
BCM_LOG(ERROR, log_id_group, "error %s detected by switch util while set group members\n", bcmos_strerror(ret));
break;
}
/*– Core calls Mac Utils add applicable CMDs */
if(BCM_ERR_OK != (ret = mac_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_SET, BCMOS_TRUE)))
{
BCM_LOG(ERROR, log_id_group, "error %s detected by mac util\n", bcmos_strerror(ret));
group_inst_rvt.current_group_info = p_group_inst->api_req_group_info;
group_inst_rvt.api_req_group_info = p_group_inst->current_group_info;
/* Reverse the (just set) group from the switch otherwise the switch utils
* will be out of sync with Core and Mac. There's not
* much we can do about it if reversing this group fails.
*/
if(BCM_ERR_OK != sw_util_group_set(&group_inst_rvt, BAL_UTIL_OPER_GROUP_SET))
{
BCM_LOG(ERROR, log_id_group,
"error detected by switch util while reversing group\n");
}
else
{
/* restore the original state */
p_group_inst->fsm_state = group_inst_rvt.fsm_state;
}
break;
}
/* update resource manager on svc_port_id usage - free the gem on old members */
p_group_cfg = &p_group_inst->current_group_info;
for(i=0; i<p_group_cfg->data.members.len; i++)
{
if(BCM_ERR_OK != rsc_mgr_gem_free(p_group_cfg->data.members.val[i].intf_id,
p_group_cfg->data.members.val[i].svc_port_id,
NULL) )
{
BCM_LOG(ERROR, log_id_group,
" error encountered during release of group resources (gem_id: %d, intf_id:%d\n",
p_group_cfg->data.members.val[i].svc_port_id,
p_group_cfg->data.members.val[i].intf_id);
}
}
/* set operation can be made without CREATE, so fill in the non-member info */
bcmbal_group_object_overlay(&p_group_inst->api_req_group_info,
&p_group_inst->current_group_info);
/* The hardware has properly accepted the object info, so the request object becomes
* the current state.
*/
bcmbal_group_object_member_replace(&p_group_inst->api_req_group_info,
&p_group_inst->current_group_info);
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_group_inst->current_group_info), BCMOS_TRUE);
}while(0);
/* If there were errors during processing, then report the error to the API */
if(BCM_ERR_OK != ret)
{
mgmt_msg_send_balapi_ind(ret,
msg,
log_id_group);
}
return ret;
}
/*****************************************************************************/
/**
* @brief The Group FSM state processing for a group add command received
* from the BAL Public API.
*
* @param p_group_inst Pointer to a group instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to a group event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno group_fsm_add(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
group_fsm_state pre_fsm_state;
BCM_LOG(INFO, log_id_group, "Got SET request from BAL API - add group members\n");
do
{
/* save the current state */
pre_fsm_state = p_group_inst->fsm_state;
/* change Group state to CONFIGURING */
p_group_inst->fsm_state = GROUP_FSM_STATE_CONFIGURING;
/*– Core calls Switch Utils to add applicable CMDs */
if(BCM_ERR_OK != (ret = sw_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_ADD)))
{
BCM_LOG(ERROR, log_id_group, "error %s detected by switch util while add group members\n", bcmos_strerror(ret));
break;
}
/*– Core calls Mac Utils add applicable CMDs */
if(BCM_ERR_OK != (ret = mac_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_ADD, BCMOS_TRUE)))
{
BCM_LOG(ERROR, log_id_group, "error %s detected by mac util\n", bcmos_strerror(ret));
/* Reverse the (just add) group member from the switch, otherwise the switch utils
* will be out of sync with Core and Mac. There's not
* much we can do about it if reversing this group fails.
*/
if(BCM_ERR_OK != sw_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_REMOVE))
{
BCM_LOG(ERROR, log_id_group,
"error detected by switch util while reversing add group\n");
}
else
{
/* restore the original state */
p_group_inst->fsm_state = pre_fsm_state;
}
break;
}
/* add operation can be made without CREATE, so fill in the non-member info */
bcmbal_group_object_overlay(&p_group_inst->api_req_group_info,
&p_group_inst->current_group_info);
/* The hardware has properly accepted the object info, so add object members to
* the current state.
*/
bcmbal_group_object_member_add(&p_group_inst->api_req_group_info,
&p_group_inst->current_group_info);
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_group_inst->current_group_info), BCMOS_TRUE);
}while(0);
/* If there were errors during processing, then report the error to the API */
if(BCM_ERR_OK != ret)
{
mgmt_msg_send_balapi_ind(ret,
msg,
log_id_group);
}
return ret;
}
/*****************************************************************************/
/**
* @brief The Group FSM state processing for a group remove command received
* from the BAL Public API.
*
* @param p_group_inst Pointer to a group instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to a group event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno group_fsm_remove(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
group_fsm_state pre_fsm_state;
bcmbal_group_cfg *p_group_cfg;
int i;
BCM_LOG(INFO, log_id_group, "Got SET request from BAL API - remove group members\n");
do
{
/* save the current state */
pre_fsm_state = p_group_inst->fsm_state;
/* change Group state to CONFIGURING */
p_group_inst->fsm_state = GROUP_FSM_STATE_CONFIGURING;
/*– Core calls Switch Utils to add applicable CMDs */
if(BCM_ERR_OK != (ret = sw_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_REMOVE)))
{
BCM_LOG(ERROR, log_id_group, "error %s detected by switch util while remove group members\n", bcmos_strerror(ret));
break;
}
/*– Core calls Mac Utils add applicable CMDs */
if(BCM_ERR_OK != (ret = mac_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_REMOVE, BCMOS_TRUE)))
{
BCM_LOG(ERROR, log_id_group, "error %s detected by mac util\n", bcmos_strerror(ret));
/* Reverse the (just remove) group member from the switch, otherwise the switch utils
* will be out of sync with Core and Mac. There's not
* much we can do about it if reversing this group fails.
*/
if(BCM_ERR_OK != sw_util_group_set(p_group_inst, BAL_UTIL_OPER_GROUP_ADD))
{
BCM_LOG(ERROR, log_id_group,
"error detected by switch util while reversing remove group\n");
}
else
{
/* restore the original state */
p_group_inst->fsm_state = pre_fsm_state;
}
break;
}
/* update resource manager on svc_port_id usage */
p_group_cfg = &p_group_inst->api_req_group_info;
for(i=0; i<p_group_cfg->data.members.len; i++)
{
/* if interface is not a member (e.g. already removed), skip it */
if(p_group_cfg->data.members.val[i].svc_port_id == 0)
{
continue;
}
if(BCM_ERR_OK != rsc_mgr_gem_free(p_group_cfg->data.members.val[i].intf_id,
p_group_cfg->data.members.val[i].svc_port_id,
NULL) )
{
BCM_LOG(ERROR, log_id_group,
" error encountered during release of group resources (gem_id: %d, intf_id:%d\n",
p_group_cfg->data.members.val[i].svc_port_id,
p_group_cfg->data.members.val[i].intf_id);
}
}
/* The hardware has properly accepted the object info, so remove object members from
* the current state.
*/
bcmbal_group_object_member_remove(&p_group_inst->api_req_group_info,
&p_group_inst->current_group_info);
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_group_inst->current_group_info), BCMOS_TRUE);
}while(0);
/* If there were errors during processing, then report the error to the API */
if(BCM_ERR_OK != ret)
{
mgmt_msg_send_balapi_ind(ret,
msg,
log_id_group);
}
return ret;
}
/*****************************************************************************/
/**
* @brief The Group FSM state processing function to ignore a received message.
*
* @param p_group_inst Pointer to a group instance
* @param msg Pointer to a BAL message received from the BAL Public API
* @param p_event Pointer to a group event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno group_fsm_ignore_api_msg(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
BCM_LOG(WARNING, log_id_group, "Ignoring message from BAL API when in %s state \n", group_state_name_get(p_group_inst->fsm_state));
return ret;
}
/*****************************************************************************/
/**
* @brief The Group FSM state processing function to process a message from
* one of the BAL apps received when the specified group instance FSM
* is in the CONFIGURING state.
*
* @param p_group_inst Pointer to a group instance
* @param msg Pointer to a BAL message received from one of
* the BAL apps.
* @param p_event Pointer to a group event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno group_fsm_configuring_util_msg(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event)
{
bcmos_errno ret;
bal_util_msg_ind *ind_msg;
/* Parameter checks */
BUG_ON(NULL == p_group_inst);
BUG_ON(NULL == msg);
BUG_ON(NULL == p_event);
ind_msg = (bal_util_msg_ind *)msg;
BCM_LOG(DEBUG, log_id_group,
" Received an IND message from BAL UTIL (%s) during CONFIGURING state\n",
subsystem_str[bcmbal_sender_get(msg)]);
BCM_LOG(DEBUG, log_id_group,
"%s, thread %s, module %d\n", __FUNCTION__, bcmos_task_current()->name, bcmos_module_current());
/* Handle indication */
ret = ind_msg->status;
/* Reflect the execution status in the object being returned in the indication
*/
if(BCM_ERR_OK == ret)
{
/*
* The group has been successfully configured
*/
p_group_inst->fsm_state = GROUP_FSM_STATE_CONFIGURED;
}
else
{
/* Error */
BCM_LOG(ERROR, log_id_group, "Group %d: Failed in state %s. Error %s\n\n",
p_group_inst->api_req_group_info.key.group_id,
group_state_name_get(p_group_inst->fsm_state),
bcmos_strerror(ret));
}
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_group_inst->current_group_info), BCMOS_FALSE);
p_group_inst->current_group_info.hdr.hdr.status = ret;
/*
* Send the indication back to the BAL public API here
*/
mgmt_msg_send_balapi_ind(ret,
&p_group_inst->current_group_info.hdr,
log_id_group);
return ret;
}
/*****************************************************************************/
/**
* @brief The Group FSM state processing function to process a
* message from one of the BAL apps received when the specified
* group instance FSM is in the DELETING state.
*
* @param p_group_inst Pointer to an group instance
* @param msg Pointer to a BAL message received from one of
* the BAL apps.
* @param p_event Pointer to a group event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno group_fsm_deleting_util_msg(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_OK;
bal_util_msg_ind *ind_msg;
/* Parameter checks */
BUG_ON(NULL == p_group_inst);
BUG_ON(NULL == msg);
BUG_ON(NULL == p_event);
ind_msg = (bal_util_msg_ind *)msg;
BCM_LOG(DEBUG, log_id_group,
" Received an IND message from BAL UTIL (%s) during DELETING state\n",
subsystem_str[bcmbal_sender_get(msg)]);
/* Handle indication */
ret = ind_msg->status;
/* Reflect the execution status in the object being returned in the indication
*/
if(BCM_ERR_OK == ret)
{
p_group_inst->current_group_info.hdr.hdr.status = ret;
/*
* The group has been successfully destroy
*/
p_group_inst->fsm_state = GROUP_FSM_STATE_NULL;
BCMBAL_OBJ_IN_PROGRESS_SET(&(p_group_inst->current_group_info), BCMOS_FALSE);
/*
* Send the indication back to the BAL public API
*/
mgmt_msg_send_balapi_ind(ret,
&p_group_inst->current_group_info.hdr,
log_id_group);
/* free up the member memory */
if( p_group_inst->current_group_info.data.members.val)
{
bcmos_free(p_group_inst->current_group_info.data.members.val);
p_group_inst->current_group_info.data.members.val = NULL;
p_group_inst->current_group_info.data.members.len = 0;
}
/* Return the group to the free pool */
group_free_by_entry(p_group_inst);
}
else
{
/* Error */
BCM_LOG(ERROR, log_id_group, "Group %d: Failed in state %s. Error %s\n\n",
p_group_inst->current_group_info.key.group_id,
group_state_name_get(p_group_inst->fsm_state),
bcmos_strerror(ret));
p_group_inst->fsm_state = GROUP_FSM_STATE_CONFIGURED;
}
return ret;
}
/*****************************************************************************/
/**
* @brief The Group FSM function which is executed when an error
* is encountered during FSM processing.
*
* @param p_group_inst Pointer to a group instance
* @param msg Pointer to a BAL message received from one of
* the BAL apps.
* @param p_event Pointer to a group event structure
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno group_fsm_state_err(group_inst *p_group_inst,
void *msg,
group_fsm_event *p_event)
{
bcmos_errno ret = BCM_ERR_INVALID_OP;
BCM_LOG(DEBUG, log_id_group,
"Error encountered processing GROUP FSM"
" - BAD EVENT ()\n");
return ret;
}
/*****************************************************************************/
/**
* @brief A function called by the core worker thread to process an
* group 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_group_object(void *msg_payload)
{
bcmos_errno ret = BCM_ERR_OK, rsp_ret = BCM_ERR_OK;
bcmbal_group_cfg *p_group_cfg = (bcmbal_group_cfg *)msg_payload;
group_inst *p_group_inst = NULL;
group_fsm_event fsm_event;
bcmbal_group_key *p_group_key;
bcmbal_obj_msg_type oper_type;
int i, j, num_svc_port_allocated = 0;
BUG_ON(NULL == msg_payload);
BCM_LOG(DEBUG, log_id_group, "Processing a group object\n");
p_group_key = &p_group_cfg->key;
oper_type = p_group_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):
{
bcmos_bool b_generate_event = BCMOS_FALSE;
BCM_LOG(DEBUG, log_id_group,
"Processing a group SET REQ mgmt message\n");
do
{
if(BCMBAL_STATUS_UP != acc_term_status_get())
{
BCM_LOG(ERROR, log_id_group,
"ERROR - Access-terminal is not UP. No further processing\n");
ret = BCM_ERR_STATE;
break;
}
/*
* Find or create the specified group instance
*/
p_group_inst = group_inst_get(p_group_key, GROUP_FLAG_ANY);
if(NULL == p_group_inst)
{
/* This is a fatal error condition
*/
BCM_LOG(ERROR, log_id_group,
"ERROR - Group not found. No further processing\n");
ret = BCM_ERR_NOMEM;
break;
}
/* If the state of this group is in flux, then reject the SET request */
if(BCMOS_TRUE == BCMBAL_OBJ_IN_PROGRESS_GET(&(p_group_inst->current_group_info)))
{
ret = BCM_ERR_IN_PROGRESS;
break;
}
/* if needed, request/validate svc_port_id from resource manager - before validation */
if (BCMBAL_CFG_PROP_IS_SET(p_group_cfg, group, members_cmd) )
{
if(p_group_cfg->data.members_cmd == BCMBAL_GROUP_MEMBER_CMD_REM_MEMBERS)
{
/* if service id is not specified, filled in with current config info */
for(i=0; i<p_group_cfg->data.members.len; i++)
{
int req_intf = p_group_cfg->data.members.val[i].intf_id;
if(p_group_cfg->data.members.val[i].svc_port_id == 0)
{
for(j=0; j<p_group_inst->current_group_info.data.members.len; j++)
{
int cur_intf = p_group_inst->current_group_info.data.members.val[j].intf_id;
if( cur_intf == req_intf)
{
p_group_cfg->data.members.val[i].svc_port_id = p_group_inst->current_group_info.data.members.val[j].svc_port_id;
break;
}
}
}
}
}
else
{
/* if the group already has owner, alloc the svc_port for addition or replacement members */
if(BCMBAL_GROUP_OWNER_NONE != p_group_inst->current_group_info.data.owner )
{
/* copy the owner to the request */
BCMBAL_CFG_PROP_SET(p_group_cfg, group, owner, p_group_inst->current_group_info.data.owner);
/* allocate GEM */
for(i=0; i<p_group_cfg->data.members.len; i++)
{
if (BCMBAL_GROUP_OWNER_MULTICAST != p_group_inst->current_group_info.data.owner)
{
ret = rsc_mgr_gem_alloc_multicast(p_group_cfg->data.members.val[i].intf_id,
&p_group_cfg->data.members.val[i].svc_port_id,
1, /* request gem range */
NULL);
}
else if (BCMBAL_GROUP_OWNER_UNICAST != p_group_inst->current_group_info.data.owner)
{
ret = rsc_mgr_gem_alloc_broadcast(p_group_cfg->data.members.val[i].intf_id,
&p_group_cfg->data.members.val[i].svc_port_id,
1, /* request gem range */
NULL);
}
else
{
ret = BCM_ERR_PARM;
}
if(BCM_ERR_OK != ret)
{
break;
}
}
/* remember how many service port request been made to resource manager */
num_svc_port_allocated = i;
if(BCM_ERR_OK != ret)
{
BCM_LOG(ERROR, log_id_group,
" error encountered during allocate of group resources (intf_id:%d)\n",
p_group_cfg->data.members.val[i].intf_id);
break;
}
}
}
}
/*
* Fill in the local group info data structure
* Notice that any memory allocated in the request message will be free in
* process_mgmt_msg() of worker thread. If needed, GROUP FSM need to clone any
* request info into p_group_inst->current_group_info before return
*/
p_group_inst->api_req_group_info = *p_group_cfg;
/*
* Process the request
*/
/*
* Perform the validation check(s) that the utils require
*/
if(BCM_ERR_OK != (ret = mac_util_group_info_validate(&p_group_inst->api_req_group_info)))
{
BCM_LOG(ERROR, log_id_group, "Failed GROUP mac validation\n");
break;
}
if(BCM_ERR_OK != (ret = sw_util_group_info_validate(&p_group_inst->api_req_group_info)))
{
BCM_LOG(ERROR, log_id_group, "Failed switch group validation\n");
break;
}
/* set the event based on request command */
b_generate_event = BCMOS_TRUE;
if ( BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(&p_group_inst->api_req_group_info, group, members_cmd) )
{
switch(p_group_inst->api_req_group_info.data.members_cmd)
{
case BCMBAL_GROUP_MEMBER_CMD_ADD_MEMBERS:
fsm_event.event_type = GROUP_FSM_EVENT_TYPE_ADD;
break;
case BCMBAL_GROUP_MEMBER_CMD_REM_MEMBERS:
fsm_event.event_type = GROUP_FSM_EVENT_TYPE_REMOVE;
break;
case BCMBAL_GROUP_MEMBER_CMD_SET_MEMBERS:
fsm_event.event_type = GROUP_FSM_EVENT_TYPE_SET;
break;
default:
fsm_event.event_type = GROUP_FSM_EVENT_TYPE_NONE;
b_generate_event = BCMOS_FALSE;
break;
}
}
else
{
fsm_event.event_type = GROUP_FSM_EVENT_TYPE_CREATE;
}
}while(0);
/* if anything go wrong, inform resource manager to free up the service port */
if (BCM_ERR_OK != ret &&
BCMBAL_CFG_PROP_IS_SET(p_group_cfg, group, members_cmd) &&
p_group_cfg->data.members_cmd != BCMBAL_GROUP_MEMBER_CMD_REM_MEMBERS)
{
for(i=0; i<num_svc_port_allocated; i++)
{
rsp_ret = rsc_mgr_gem_free(p_group_cfg->data.members.val[i].intf_id,
p_group_cfg->data.members.val[i].svc_port_id,
NULL);
/* best effort to free up */
if(BCM_ERR_OK != rsp_ret)
{
BCM_LOG(ERROR, log_id_group,
" error encountered during allocate of group resources (intf_id:%d)\n",
p_group_cfg->data.members.val[i].intf_id);
}
}
}
/* 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_group);
if(BCM_ERR_OK != rsp_ret || BCM_ERR_OK != ret)
{
/* the mgmt_msg_send_balapi_rsp function above logs any errors that occur there */
ret = (BCM_ERR_OK != rsp_ret) ? rsp_ret : ret;
break;
}
/* If there was an event generated, call the state machine exec */
if(BCMOS_TRUE == b_generate_event)
{
/*
* Run the group FSM to process this event
*/
ret = group_fsm_exec(p_group_inst, &fsm_event);
}
break;
}
case (BCMBAL_OBJ_MSG_TYPE_GET):
{
BCM_LOG(DEBUG, log_id_group, "Processing a group GET REQ mgmt message\n");
do
{
if(BCMBAL_STATUS_UP != acc_term_status_get())
{
BCM_LOG(ERROR, log_id_group,
"ERROR - Access-terminal is not UP. No further processing\n");
ret = BCM_ERR_STATE;
}
else
{
/*
* Find the specified group instance
*/
p_group_inst = group_inst_get(p_group_key, GROUP_FLAG_ACTIVE);
}
if(NULL == p_group_inst)
{
if(BCM_ERR_STATE != ret)
{
/* This is not a fatal error condition
*/
BCM_LOG(ERROR, log_id_group, "ERROR - Specified group (%d) not found\n",
p_group_key->group_id);
ret = BCM_ERR_NOENT;
}
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_group_inst->current_group_info.hdr.hdr.comm_hdr = ((bcmbal_obj *)msg_payload)->comm_hdr;
*((bcmbal_group_cfg *)msg_payload) = p_group_inst->current_group_info;
} while (0);
mgmt_msg_send_balapi_rsp(ret, msg_payload, oper_type, log_id_group);
}
break;
case (BCMBAL_OBJ_MSG_TYPE_CLEAR):
{
BCM_LOG(DEBUG, log_id_group, "Processing a group CLEAR REQ mgmt message\n");
do
{
if(BCMBAL_STATUS_UP != acc_term_status_get())
{
BCM_LOG(ERROR, log_id_group,
"ERROR - Access-terminal is not UP. No further processing\n");
ret = BCM_ERR_STATE;
break;
}
/*
* Find the specified group instance
*/
p_group_inst = group_inst_get(p_group_key, GROUP_FLAG_ACTIVE);
if(NULL == p_group_inst)
{
/* This is a fatal error condition
*/
BCM_LOG(ERROR, log_id_group, "ERROR - Specified group (%d: not found\n",
p_group_key->group_id);
ret = BCM_ERR_NOENT;
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_group);
if(BCM_ERR_OK != rsp_ret || BCM_ERR_OK != ret)
{
/* the mgmt_msg_send_balapi_rsp function above logs any errors that occur there */
ret = (BCM_ERR_OK != rsp_ret) ? rsp_ret : ret;
break;
}
/*
* Run the group FSM to process this event
*/
if(BCM_ERR_OK == ret)
{
fsm_event.event_type = GROUP_FSM_EVENT_TYPE_DESTROY;
ret = group_fsm_exec(p_group_inst, &fsm_event);
}
break;
}
default:
{
BCM_LOG(ERROR, log_id_group, "Unsupported operation on group object (%d)\n",
oper_type );
ret = BCM_ERR_NOT_SUPPORTED;
/* 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.
*/
mgmt_msg_send_balapi_rsp(ret, msg_payload, oper_type, log_id_group);
break;
}
}
BCM_LOG(DEBUG, log_id_group, "%s returns\n", __FUNCTION__);
return ret;
}
/*****************************************************************************/
/**
* @brief A function to process a group object event received
* from one of the BAL apps.
*
* @param msg_payload A pointer to the util message
*
* @returns bcmos_errno
*****************************************************************************/
bcmos_errno process_group_util_msg(void *msg_payload)
{
bcmos_errno ret = BCM_ERR_OK;
group_inst *p_group_inst;
group_fsm_event fsm_event;
bcmbal_msg_type type;
bcmbal_group_key key;
type = bcmbal_type_minor_get(msg_payload);
BCM_LOG(DEBUG, log_id_group, "processing a group %s util message from %s\n",
bcmbal_msg_t_str[type],
subsystem_str[bcmbal_sender_get(msg_payload)]);
/* recover the key from the message */
key = ((bal_util_msg_ind *)msg_payload)->obj_key.group_key;
do
{
BCM_LOG(DEBUG, log_id_group, "Got group key id (%d) from util message\n", key.group_id);
/*
* Get the group instance that's being referenced
*/
if(NULL == (p_group_inst = group_inst_get(&key, GROUP_FLAG_ACTIVE)))
{
BCM_LOG(ERROR, log_id_group, "invalid group (%d) found while processing a util message from %s\n",
key.group_id,
subsystem_str[bcmbal_sender_get(msg_payload)]);
ret = BCM_ERR_INTERNAL;
break;
}
/*
* Record the msg for further processing access
*/
fsm_event.msg = msg_payload;
if (BAL_MSG_TYPE_IND == type)
{
fsm_event.event_type = GROUP_FSM_EVENT_TYPE_UTIL_MSG;
}
else
{
ret = BCM_ERR_NOT_SUPPORTED;
BCM_LOG(ERROR, log_id_group,
"Unknown message type received from the UTIL"
" (not IND) (type:%d)\n",
type);
break;
}
/*
* Run the Group FSM to process this event
*/
if(BCM_ERR_OK == ret)
{
ret = group_fsm_exec(p_group_inst, &fsm_event);
}
}
while(0);
return ret;
}
/*
* Helper functions
*/
/*****************************************************************************/
/**
* @brief A function to retrieve a group instance of the specified
* class.
*
* @param key A pointer to the key of the group being
* referenced
* @param search_flag A flag specifying the type of group
* instance to be retrieved
*
* @returns group_inst_t* A pointer to the found group instance,
* or NULL if one is not found
*****************************************************************************/
static group_inst *group_inst_get(bcmbal_group_key *key, group_flag search_flag)
{
group_inst *current_entry = NULL;
/*
* First, check the active list if the caller has chosen to do so
*/
if(GROUP_FLAG_ACTIVE & search_flag)
{
TAILQ_FOREACH(current_entry,
&GROUP_FSM_GROUP_LIST_CTX_PTR->active_group_list,
group_inst_next)
{
if(current_entry->api_req_group_info.key.group_id == key->group_id)
{
BCM_LOG(DEBUG, log_id_group, "Found active group\n");
/* The group instance pointer is in current_entry */
break;
}
}
}
/*
* Next, check the free list if the caller has chosen to do so
*/
if((GROUP_FLAG_FREE & search_flag) && (NULL == current_entry))
{
/* Now check the free list */
if(!TAILQ_EMPTY(&GROUP_FSM_GROUP_LIST_CTX_PTR->free_group_list))
{
/* Just grab the first entry */
current_entry = TAILQ_FIRST(&GROUP_FSM_GROUP_LIST_CTX_PTR->free_group_list);
/* Remove it from the free list */
TAILQ_REMOVE(&GROUP_FSM_GROUP_LIST_CTX_PTR->free_group_list, current_entry, group_inst_next);
/* And add it to the active list */
TAILQ_INSERT_TAIL(&GROUP_FSM_GROUP_LIST_CTX_PTR->active_group_list, current_entry, group_inst_next);
/*
* Initialize the fsm state
*/
current_entry->fsm_state = GROUP_FSM_STATE_NULL;
BCM_LOG(DEBUG, log_id_group, "Using new group\n");
}
}
if((GROUP_FLAG_ANY & search_flag) && (NULL == current_entry))
{
/*A group was not found on either list*/
BCM_LOG(DEBUG, log_id_group, "************** ERROR: no group found\n");
}
return current_entry;
}
#ifdef GET_GROUP_CFG_BY_KEY_SUPPORTED
/*****************************************************************************/
/**
* @brief A function to retrieve the current group info for the specified
* group instance.
*
* @param key A group key
*
* @returns bcmbal_group_cfg* A pointer to the current group info for the
* specified group, or NULL if the group is not found
*****************************************************************************/
static bcmbal_group_cfg *group_get_current_info_by_key(bcmbal_group_key key)
{
group_inst *current_entry = NULL;
/*
* Check the active list
*/
TAILQ_FOREACH(current_entry,
&GROUP_FSM_GROUP_LIST_CTX_PTR->active_group_list,
group_inst_next)
{
if(current_entry->current_group_info.key.group_id == key.group_id)
{
/* The group instance pointer is in current_entry */
break;
}
}
if(current_entry)
{
return &(current_entry->current_group_info);
}
else
{
return NULL;
}
}
#endif
/*****************************************************************************/
/**
* @brief A function to free a group 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 group_free_by_entry(group_inst *p_entry)
{
bcmos_errno ret = BCM_ERR_OK;
group_inst *current_entry;
group_inst *p_temp_entry;
/*
* First, check the active list (an active group can be in the adding or removing state)
*/
TAILQ_FOREACH_SAFE(current_entry,
&GROUP_FSM_GROUP_LIST_CTX_PTR->active_group_list,
group_inst_next,
p_temp_entry)
{
if(current_entry == p_entry)
{
/* Remove it from the active list */
TAILQ_REMOVE(&GROUP_FSM_GROUP_LIST_CTX_PTR->active_group_list, current_entry, group_inst_next);
break;
}
}
/* And add it to the free list */
p_entry->fsm_state = GROUP_FSM_STATE_NULL;
/* And initialize the current object in the group instance */
group_inst_entry_obj_init(p_entry);
TAILQ_INSERT_TAIL(&GROUP_FSM_GROUP_LIST_CTX_PTR->free_group_list, p_entry, group_inst_next);
return ret;
}
/*****************************************************************************/
/**
* @brief A function to remove group members specified in a requested group
* from a target group
*
* @param p_req_group A pointer to the group config that holds the members to be removed
* @param p_cur_group A pointer to the group config that holds the current members
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno bcmbal_group_object_member_remove(bcmbal_group_cfg *p_req_group,
bcmbal_group_cfg *p_cur_group)
{
int i, j, k, num_members, member_match;
bcmbal_group_member_info *p_new_member_info;
bcmbal_group_member_info_list_u16 new_members;
num_members = 0;
/* first calculate the final number of members */
for(i = 0; i < p_cur_group->data.members.len; i++)
{
member_match = 0;
/* check if it is in the remove list */
for(j = 0; j < p_req_group->data.members.len; j++)
{
if( p_cur_group->data.members.val[i].intf_id == p_req_group->data.members.val[j].intf_id)
{
member_match = 1;
break;
}
}
/* no match, we need to keep it */
if(!member_match)
{
num_members++;
}
}
/* if all requested members already been removed, no change, just return */
if( num_members == p_cur_group->data.members.len)
{
return BCM_ERR_OK;
}
/* if no member left, just clean up and leave */
if(num_members == 0)
{
bcmos_free(p_cur_group->data.members.val);
BCMBAL_CFG_PROP_CLEAR(p_cur_group, group, members);
return BCM_ERR_OK;
}
/* alloc memory for new list */
p_new_member_info = bcmos_calloc( num_members * sizeof(bcmbal_group_member_info));
if(p_new_member_info == NULL)
{
BCM_LOG(ERROR, log_id_group, "calloc failed when remove members from group object\n");
return BCM_ERR_NORES;
}
/* fill in the new list */
k=0;
for(i = 0; i < p_cur_group->data.members.len; i++)
{
member_match = 0;
/* check if it is in the remove list */
for(j = 0; j < p_req_group->data.members.len; j++)
{
if( p_cur_group->data.members.val[i].intf_id == p_req_group->data.members.val[j].intf_id)
{
member_match = 1;
break;
}
}
/* no match, we need to keep it */
if(!member_match)
{
p_new_member_info[k++] = p_cur_group->data.members.val[i];
}
}
/* free up the old list */
bcmos_free(p_cur_group->data.members.val);
/* assign new list */
new_members.val = p_new_member_info;
new_members.len = num_members;
BCMBAL_CFG_PROP_SET(p_cur_group, group, members, new_members);
return BCM_ERR_OK;
}
/*****************************************************************************/
/**
* @brief A function to add group members specified in a requested group
* to a target group
*
* @param p_req_group A pointer to the group config that holds the members to be added
* @param p_cur_group A pointer to the group config that holds the current members
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno bcmbal_group_object_member_add(bcmbal_group_cfg *p_req_group,
bcmbal_group_cfg *p_cur_group)
{
int i, j, k, num_members, member_match;
bcmbal_group_member_info *p_new_member_info;
bcmbal_group_member_info_list_u16 new_members;
num_members = 0;
/* first calculate the final number of members */
for(i = 0; i < p_req_group->data.members.len; i++)
{
member_match = 0;
/* check if it is in the current list */
for(j = 0; j < p_cur_group->data.members.len; j++)
{
if( p_req_group->data.members.val[i].intf_id == p_cur_group->data.members.val[j].intf_id)
{
member_match = 1;
break;
}
}
/* no match, we need to add it */
if(!member_match)
{
num_members++;
}
}
/* if all requested members already in the list, no change, just return */
if( num_members == 0)
{
return BCM_ERR_OK;
}
/* alloc memory for new list */
p_new_member_info = bcmos_calloc( (num_members + p_cur_group->data.members.len) * sizeof(bcmbal_group_member_info) );
if(p_new_member_info == NULL)
{
BCM_LOG(ERROR, log_id_group, "calloc failed when add members to group object\n");
return BCM_ERR_NORES;
}
/* fill in the new list */
k=0;
for(j = 0; j < p_cur_group->data.members.len; j++)
{
p_new_member_info[k++] = p_cur_group->data.members.val[j];
}
for(i = 0; i < p_req_group->data.members.len; i++)
{
member_match = 0;
/* check if it is in the current list */
for(j = 0; j < p_cur_group->data.members.len; j++)
{
if( p_req_group->data.members.val[i].intf_id == p_cur_group->data.members.val[j].intf_id)
{
member_match = 1;
break;
}
}
/* no match, we need to add it */
if(!member_match)
{
p_new_member_info[k++] = p_req_group->data.members.val[i];
}
}
/* free up the old list */
bcmos_free(p_cur_group->data.members.val);
/* assign new list */
new_members.val = p_new_member_info;
new_members.len = k;
BCMBAL_CFG_PROP_SET(p_cur_group, group, members, new_members);
return BCM_ERR_OK;
}
/*****************************************************************************/
/**
* @brief A function to replace group members specified in a targeted group
* with a requested group
*
* @param p_req_group A pointer to the group config that holds the members to be replaced
* @param p_cur_group A pointer to the group config that holds the current members
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno bcmbal_group_object_member_replace(bcmbal_group_cfg *p_req_group,
bcmbal_group_cfg *p_cur_group)
{
int j, k;
bcmbal_group_member_info *p_new_member_info;
bcmbal_group_member_info_list_u16 new_members;
/* alloc memory for new list */
p_new_member_info = bcmos_calloc( p_req_group->data.members.len * sizeof(bcmbal_group_member_info) );
if(p_new_member_info == NULL)
{
BCM_LOG(ERROR, log_id_group, "calloc failed when replace members to group object\n");
return BCM_ERR_NORES;
}
/* fill in the new list */
k=0;
for(j = 0; j < p_req_group->data.members.len; j++)
{
p_new_member_info[k++] = p_req_group->data.members.val[j];
}
/* free up the old list */
bcmos_free(p_cur_group->data.members.val);
/* assign new list */
new_members.val = p_new_member_info;
new_members.len = k;
BCMBAL_CFG_PROP_SET(p_cur_group, group, members, new_members);
return BCM_ERR_OK;
}
/*****************************************************************************/
/**
* @brief A function to overlay group info specified in a requested group
* to a target group ( exclude the member info as it will be managed by
bcmbal_group_object_member_xxx functions)
*
* @param p_req_group A pointer to the requested group config
* @param p_cur_group A pointer to the group config that to be overlay
*
* @returns bcmos_errno
*****************************************************************************/
static bcmos_errno bcmbal_group_object_overlay(bcmbal_group_cfg *p_req_group,
bcmbal_group_cfg *p_cur_group)
{
BUG_ON(NULL == p_cur_group);
BUG_ON(NULL == p_req_group);
bcmbal_presence_mask cur_presence_mask;
/* First, copy the common object and keys in their entirety, except for preserving the presence_mask */
cur_presence_mask = p_cur_group->hdr.hdr.presence_mask;
p_cur_group->hdr = p_req_group->hdr;
p_cur_group->key = p_req_group->key;
p_cur_group->hdr.hdr.presence_mask = cur_presence_mask;
/* Now copy only the fields that have been specified in the request object */
if(BCMBAL_CFG_PROP_IS_SET(p_req_group, group, members_cmd))
{
BCMBAL_CFG_PROP_SET(p_cur_group, group, members_cmd, p_req_group->data.members_cmd);
}
if(BCMBAL_CFG_PROP_IS_SET(p_req_group, group, cookie))
{
BCMBAL_CFG_PROP_SET(p_cur_group, group, cookie, p_req_group->data.cookie);
}
if(BCMBAL_CFG_PROP_IS_SET(p_req_group, group, owner))
{
BCMBAL_CFG_PROP_SET(p_cur_group, group, owner, p_req_group->data.owner);
}
return BCM_ERR_OK;
}
/*****************************************************************************/
/**
* @brief A function to test if the specified group is active
*
* @param p_group_key A pointer to the group key to be tested
*
* @returns bcmos_bool BCMOS_TRUE if specified group is active
*****************************************************************************/
bcmos_bool group_is_active(bcmbal_group_key *p_group_key)
{
return (NULL == group_inst_get(p_group_key, GROUP_FLAG_ACTIVE)) ? BCMOS_FALSE : BCMOS_TRUE;
}
/*****************************************************************************/
/**
* @brief A function to retrive the group owner
*
* @param group_key the group key
* @param p_group_owner A pointer to store the retrieve owner
*
* @returns bcmos_errno
*****************************************************************************/
bcmos_errno group_owner_get(bcmbal_group_key group_key, bcmbal_group_owner *p_group_owner)
{
group_inst *p_group;
p_group = group_inst_get(&group_key, GROUP_FLAG_ACTIVE);
if (p_group)
{
*p_group_owner = p_group->current_group_info.data.owner;
return BCM_ERR_OK;
}
else
{
return BCM_ERR_NOENT;
}
}
/*****************************************************************************/
/**
* @brief A function to set the group owner
* When the owner is set, the service port of the member is also allocated
*
* @param group_key group key
* @param grp_owner owner
*
* @returns bcmos_errno
*****************************************************************************/
bcmos_errno group_owner_set(bcmbal_group_key group_key, bcmbal_group_owner grp_owner)
{
bcmos_errno ret = BCM_ERR_OK;
/* if group has no owner, set the GROUP owner and allocate the GEM for each GROUP member
1. flip the current info with request info
2. allocate GEM for each group member
3. Call switch_util to update the group (SET with new GEM info)
4. Call mac_util to update the group (SET with new GEM info)
5. flip back the current info
else
do nothing and let util validate the group owner
end-if
later, follow the regular FLOW fsm to SET FLOW in switch_util and Mac_util
*/
group_inst *p_group;
p_group = group_inst_get(&group_key, GROUP_FLAG_ACTIVE);
if (p_group == NULL)
{
BCM_LOG(ERROR, log_id_group, "Failed to get group instance, group_id %d\n", group_key.group_id);
return BCM_ERR_INTERNAL;
}
if ( BCMBAL_GROUP_OWNER_NONE == p_group->current_group_info.data.owner)
{
int i;
bcmbal_group_cfg *p_group_req = &(p_group->api_req_group_info);
bcmbal_group_cfg *p_group_cur = &(p_group->current_group_info);
do
{
/* step 1 */
BCMBAL_CFG_PROP_SET(p_group_req, group, owner, grp_owner);
BCMBAL_CFG_PROP_SET(p_group_req, group, members_cmd, BAL_UTIL_OPER_GROUP_SET);
p_group_req->data.members.len = p_group_cur->data.members.len;
p_group_req->data.members.val = p_group_cur->data.members.val;
p_group_cur->data.members.len = 0;
p_group_cur->data.members.val = NULL;
/* step 2 */
for(i=0; i<p_group_req->data.members.len; i++)
{
if(grp_owner == BCMBAL_GROUP_OWNER_UNICAST )
{
ret = rsc_mgr_gem_alloc_broadcast(p_group_req->data.members.val[i].intf_id,
&p_group_req->data.members.val[i].svc_port_id,
1, /* request gem range */
NULL);
}
else if (grp_owner == BCMBAL_GROUP_OWNER_MULTICAST)
{
ret = rsc_mgr_gem_alloc_multicast(p_group_req->data.members.val[i].intf_id,
&p_group_req->data.members.val[i].svc_port_id,
1, /* request gem range */
NULL);
}
else
{
ret = BCM_ERR_PARM;
}
if(BCM_ERR_OK != ret)
{
break;
}
}
if(BCM_ERR_OK != ret)
{
BCM_LOG(ERROR, log_id_group, "Failed to alloc group GEM, interface=%d\n", p_group_req->data.members.val[i].intf_id);
break;
}
/* step 3 */
if(BCM_ERR_OK != (ret = sw_util_group_set(p_group, BAL_UTIL_OPER_GROUP_SET)))
{
BCM_LOG(ERROR, log_id_group,
"error %s while updating group GEM in switch\n", bcmos_strerror(ret));
break;
}
/* step 4 - request no indicaiton send back */
if(BCM_ERR_OK != (ret = mac_util_group_set(p_group, BAL_UTIL_OPER_GROUP_SET, BCMOS_FALSE)))
{
BCM_LOG(ERROR, log_id_group,
"error %s while updating group GEM in mac \n", bcmos_strerror(ret));
break;
}
/* step 5 - flip back */
BCMBAL_CFG_PROP_SET(p_group_cur, group, owner, grp_owner);
BCMBAL_CFG_PROP_SET(p_group_cur, group, members_cmd, BAL_UTIL_OPER_GROUP_SET);
p_group_cur->data.members.len = p_group_req->data.members.len;
p_group_cur->data.members.val = p_group_req->data.members.val;
p_group_req->data.members.len = 0;
p_group_req->data.members.val = NULL;
}while(0);
}
else
{
/* if GROUP already has owner , make sure it is the same type */
if ( grp_owner != p_group->current_group_info.data.owner)
{
BCM_LOG(ERROR, log_id_group,
" group already has owner %d, can not reassign to %d \n", p_group->current_group_info.data.owner, grp_owner);
ret = BCM_ERR_INTERNAL;
}
}
return ret;
}
/*@}*/