blob: bd8afec2bf50b376b9a97f7488291cfa0ae374e7 [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.
*
* :>
*
*****************************************************************************/
#include <bcmolt_host_api.h>
#include <bcm_dev_log.h>
#include <bal_objs.h>
#include <bal_api.h>
#include <bal_cli.h>
#include <bcmolt_math.h>
#include <bcm_topo.h>
#include "rsc_mgr_common.h"
#include "rsc_mgr.h"
#define GPON_NUM_OF_ALLOC_IDS 1024
#define XGPON_NUM_OF_ALLOC_IDS 2048
#define GPON_NUM_OF_GEM_PORT_IDS_PER_PON 4096
#define XGPON_NUM_OF_GEM_PORT_IDS_PER_PON 8192
#define RSC_MGR_ALLOC_ID_LAST_DATA(pon_id, first_data_alloc_id) \
((first_data_alloc_id) + (bcmolt_pon_alloc_id)(RSC_MGR_PON_TOPO_CONTEXT(pon_id)->num_of_alloc_ids - 1))
#define RSC_MGR_ALLOC_ID_IS_VALID_DATA(pon_id, alloc_id, first_data_alloc_id) ( \
((alloc_id) >= (first_data_alloc_id) && (alloc_id) <= RSC_MGR_ALLOC_ID_LAST_DATA(pon_id, first_data_alloc_id)))
#define RSC_MGR_ALLOC_ID_IS_VALID(pon_id, alloc_id, first_data_alloc_id) ( \
((alloc_id) <= RSC_MGR_ALLOC_ID_LAST_DEFAULT(pon_id)) || \
RSC_MGR_ALLOC_ID_IS_VALID_DATA(pon_id, alloc_id, first_data_alloc_id))
#define RSC_MGR_GEM_PORT_ID_LAST_DEFAULT(pon_id) ((bcmolt_pon_gem_port_id)(bcm_topo_pon_get_max_num_of_onus(pon_id) - 1))
#define RSC_MGR_GEM_PORT_ID_LAST_DATA(pon_id, first_data_port_id) \
((first_data_port_id) + (bcmolt_pon_gem_port_id)(RSC_MGR_PON_TOPO_CONTEXT(pon_id)->num_of_gem_ports - bcm_topo_pon_get_max_num_of_onus(pon_id) - 1))
#define RSC_MGR_GEM_PORT_ID_IS_VALID_DATA(pon_id, gem_port_id, first_data_port_id) ( \
((gem_port_id) >= (first_data_port_id) && (gem_port_id) <= RSC_MGR_GEM_PORT_ID_LAST_DATA(pon_id, first_data_port_id)))
#define RSC_MGR_GEM_PORT_ID_IS_VALID(pon_id, gem_port_id, first_data_port_id) ( \
((gem_port_id) <= RSC_MGR_GEM_PORT_ID_LAST_DEFAULT(pon_id)) || \
RSC_MGR_GEM_PORT_ID_IS_VALID_DATA(pon_id, gem_port_id, first_data_port_id))
#define RSC_MGR_FOR_EACH_ALLOC_INDEX(pon_id, alloc_index) \
for (alloc_index = (bcmolt_pon_alloc_index)0; alloc_index < (bcmolt_pon_alloc_index)RSC_MGR_PON_TOPO_CONTEXT(pon_id)->num_of_alloc_ids; alloc_index++)
#define RSC_MGR_FOR_EACH_GEM_INDEX(pon_id, gem_port_index) \
for (gem_port_index = 0; (bcmolt_pon_gem_port_index)gem_port_index < (bcmolt_pon_gem_port_index)RSC_MGR_PON_TOPO_CONTEXT(pon_id)->num_of_gem_ports; gem_port_index++)
#define RSC_MGR_FOR_EACH_TM_SCHED_AUTO_INDEX(tm_sched_auto_index) \
for (tm_sched_auto_index = 0; (bcmbal_tm_sched_id_index)tm_sched_auto_index < (bcmbal_tm_sched_id_index)tm_context.num_of_tm_sched_auto_key_ids; tm_sched_auto_index++)
/* Because GEM port 0 .. 127 are used for OMCI, we can start allocating from 128. But due to a bug in Maple A0, 128 .. 159 must not be used. So we start from 256. */
#define MIN_BASE_GEM_PORT_ID_GPON 256
#define NUM_OF_TM_SCHED_AUTO_KEY_IDS 2048
#define MIN_BASE_TM_SCHED_AUTO_ID 2048
rsc_mgr_context_t rsc_mgr_context;
rsc_mgr_tm_context tm_context;
static bcmos_errno rsc_mgr_alloc_validate_common(bcmbal_intf_id access_int_id);
static bcmos_errno rsc_mgr_obj_get(bcmbal_intf_id access_int_id, rsc_mgr_obj_id obj_id, rsc_mgr_obj_rsc *obj_rsc, rsc_mgr_obj **obj, dev_log_id log_id);
static bcmos_errno rsc_mgr_obj_store_user_data(rsc_mgr_obj *obj, void *user_data);
static bcmos_errno rsc_mgr_obj_remove_user_data(rsc_mgr_obj *obj, void *user_data);
static bcmos_bool rsc_mgr_is_valid_data_alloc_id_cb(bcmolt_pon_ni pon_id, rsc_mgr_obj_id id, rsc_mgr_obj_id min_data_obj_id)
{
return (bcm_topo_pon_is_valid(pon_id) && RSC_MGR_ALLOC_ID_IS_VALID_DATA(pon_id, id, min_data_obj_id));
}
static rsc_mgr_obj_id rsc_mgr_get_last_data_alloc_id_cb(bcmolt_pon_ni pon_id, rsc_mgr_obj_id min_data_obj_id)
{
return (rsc_mgr_obj_id)(bcmolt_pon_alloc_id)RSC_MGR_ALLOC_ID_LAST_DATA(pon_id, min_data_obj_id);
}
static bcmos_bool rsc_mgr_is_valid_data_gem_cb(bcmolt_pon_ni pon_id, rsc_mgr_obj_id id, rsc_mgr_obj_id min_data_obj_id)
{
return (bcm_topo_pon_is_valid(pon_id) && RSC_MGR_GEM_PORT_ID_IS_VALID_DATA(pon_id, id, min_data_obj_id));
}
static rsc_mgr_obj_id rsc_mgr_get_last_data_gem_cb(bcmolt_pon_ni pon_id, rsc_mgr_obj_id min_data_obj_id)
{
return (rsc_mgr_obj_id)(bcmolt_pon_gem_port_id)RSC_MGR_GEM_PORT_ID_LAST_DATA(pon_id, min_data_obj_id);
}
static bcmos_bool rsc_mgr_is_valid_data_tm_sched_auto_id(rsc_mgr_obj_id id)
{
return (id >= MIN_BASE_TM_SCHED_AUTO_ID && id < MIN_BASE_TM_SCHED_AUTO_ID + NUM_OF_TM_SCHED_AUTO_KEY_IDS);
}
static bcmos_bool rsc_mgr_is_valid_data_tm_sched_auto_id_cb(bcmolt_pon_ni pon_id, rsc_mgr_obj_id id, rsc_mgr_obj_id min_data_obj_id)
{
return rsc_mgr_is_valid_data_tm_sched_auto_id(id);
}
static rsc_mgr_obj_id rsc_mgr_get_last_data_tm_sched_auto_id_cb(bcmolt_pon_ni pon_id, rsc_mgr_obj_id min_data_obj_id)
{
return (rsc_mgr_obj_id)(min_data_obj_id + NUM_OF_TM_SCHED_AUTO_KEY_IDS - 1);
}
static bcmos_errno rsc_mgr_obj_alloc(bcmbal_intf_id access_int_id, rsc_mgr_obj_id *obj_id, uint32_t range_size, rsc_mgr_obj_type type, rsc_mgr_obj_rsc *obj_rsc, void *user_data, dev_log_id log_id)
{
rsc_mgr_obj *obj;
bcmos_errno rc;
if (range_size < RSC_MGR_MIN_RANGE_SIZE || range_size > RSC_MGR_MAX_RANGE_SIZE)
{
BCM_LOG(ERROR, log_id, "Range size must be in the range %u .. %u\n", RSC_MGR_MIN_RANGE_SIZE, RSC_MGR_MAX_RANGE_SIZE);
return BCM_ERR_PARM;
}
if (*obj_id)
{
rc = rsc_mgr_obj_get(access_int_id, *obj_id, obj_rsc, &obj, log_id);
if (rc != BCM_ERR_OK)
return rc;
if (obj->range_size != range_size)
{
BCM_LOG(ERROR, log_id, "When reusing a range of %ss, range size (%d) must be exactly the same as the range from creation (%u)\n",
obj_rsc->obj_name, range_size, obj->range_size);
return BCM_ERR_PARM;
}
if (obj->type != type)
{
BCM_LOG(ERROR, log_id, "When reusing %ss, type (%d) must be exactly the same as the type from creation (%u)\n",
obj_rsc->obj_name, type, obj->type);
return BCM_ERR_PARM;
}
}
else
{
rsc_mgr_obj *base_obj;
rsc_mgr_obj *last_obj;
rsc_mgr_obj *obj_iter;
/* Find the first free range that fits ("first-fit" algorithm). */
TAILQ_FOREACH(obj_iter, &obj_rsc->free_objs, list)
{
if (range_size <= obj_iter->range_size)
break;
}
if (!obj_iter)
{
BCM_LOG(ERROR, log_id, "No free %ss\n", obj_rsc->obj_name);
return BCM_ERR_NORES;
}
*obj_id = obj_iter->id;
if (range_size < obj_iter->range_size)
{
/* Insert a smaller range (decrease by 'range_size') to the list of free objects. It will replace the old free range. */
base_obj = &obj_iter[range_size];
last_obj = &obj_iter[obj_iter->range_size - 1];
TAILQ_INSERT_HEAD(&obj_rsc->free_objs, base_obj, list);
base_obj->range_size = obj_iter->range_size - range_size;
last_obj->base_obj = base_obj;
}
/* Move 'range_size' objects from the list of free objects to the list of allocated objects. */
base_obj = obj_iter;
last_obj = &obj_iter[range_size - 1];
TAILQ_REMOVE(&obj_rsc->free_objs, base_obj, list);
TAILQ_INSERT_HEAD(&obj_rsc->allocated_objs, base_obj, list);
base_obj->range_size = range_size;
base_obj->type = type;
last_obj->base_obj = base_obj;
obj = obj_iter;
/* since new object, initialize the user data list */
TAILQ_INIT(&obj->user_data_list);
}
obj->ref_count++;
/** store user data (flow entry pointer) in a linked list inside the object */
rsc_mgr_obj_store_user_data(obj, user_data);
return BCM_ERR_OK;
}
static bcmos_errno rsc_mgr_obj_free(bcmbal_intf_id access_int_id, rsc_mgr_obj_id obj_id, rsc_mgr_obj_rsc *obj_rsc, void *user_data, dev_log_id log_id)
{
rsc_mgr_obj *obj;
rsc_mgr_obj *last_obj;
bcmos_errno rc;
rc = rsc_mgr_obj_get(access_int_id, obj_id, obj_rsc, &obj, log_id);
if (rc != BCM_ERR_OK)
return rc;
obj->ref_count--;
/** remove user data (flow entry pointer) from the linked list inside the object */
rsc_mgr_obj_remove_user_data(obj, user_data);
if (!obj->ref_count)
{
rsc_mgr_obj *next_obj = NULL;
rsc_mgr_obj *prev_obj = NULL;
/* Validate that going to the next object won't overflow the array. */
if (obj < &obj_rsc->objs[obj_rsc->num_of_objs - 1] && &obj[obj->range_size] <= &obj_rsc->objs[obj_rsc->num_of_objs - 1])
{
/* Check if the next ID is in the free list (according to its reference count).
* If true -> we can merge obj's range with the next range. */
if (!obj[obj->range_size].ref_count)
next_obj = &obj[obj->range_size];
}
/* Validate that going to the base of the previous range won't underflow the array. */
if (obj > obj_rsc->objs)
{
/* Check if the base ID of the previous range is in the free list (according to the base ID's reference count).
* If true -> we can merge obj's range with the previous range. */
if (obj[-1].base_obj && !obj[-1].base_obj->ref_count)
prev_obj = obj[-1].base_obj;
}
/* First remove the object from the allocated linked list. */
TAILQ_REMOVE(&obj_rsc->allocated_objs, obj, list);
last_obj = &obj[obj->range_size - 1];
obj->type = RSC_MGR_OBJ_TYPE_INVALID; /* Clear type. */
if (next_obj && !prev_obj)
{
/* Merge only with next range. */
TAILQ_INSERT_BEFORE(next_obj, obj, list);
TAILQ_REMOVE(&obj_rsc->free_objs, next_obj, list);
obj->range_size += next_obj->range_size;
last_obj->base_obj = NULL;
next_obj->range_size = 0;
last_obj = &obj[obj->range_size - 1];
last_obj->base_obj = obj;
}
else if (!next_obj && prev_obj)
{
/* Merge only with previous range. */
prev_obj->range_size += obj->range_size;
obj->range_size = 0;
last_obj->base_obj = prev_obj;
}
else if (next_obj && prev_obj)
{
/* Merge with both next and previous ranges. */
prev_obj->range_size += obj->range_size + next_obj->range_size;
obj->range_size = 0;
next_obj->range_size = 0;
TAILQ_REMOVE(&obj_rsc->free_objs, next_obj, list);
last_obj->base_obj = NULL;
last_obj = &prev_obj[prev_obj->range_size - 1];
last_obj->base_obj = prev_obj;
}
else
{
/* No merge at all. */
TAILQ_INSERT_TAIL(&obj_rsc->free_objs, obj, list);
}
}
return BCM_ERR_OK;
}
static bcmos_errno rsc_mgr_obj_get(bcmbal_intf_id access_int_id, rsc_mgr_obj_id obj_id, rsc_mgr_obj_rsc *obj_rsc, rsc_mgr_obj **obj, dev_log_id log_id)
{
bcmos_errno rc;
rc = rsc_mgr_alloc_validate_common(access_int_id);
if (BCM_ERR_OK != rc)
return rc;
if (!obj_rsc->is_valid_data_obj_id_cb(access_int_id, obj_id, obj_rsc->min_data_obj_id))
{
BCM_LOG(ERROR, log_id, "%s must be in the range %u .. %u\n",
obj_rsc->obj_name, obj_rsc->min_data_obj_id, obj_rsc->get_last_data_obj_id_cb(access_int_id, obj_rsc->min_data_obj_id));
return BCM_ERR_PARM;
}
*obj = &obj_rsc->objs[obj_id - obj_rsc->min_data_obj_id];
/* Only base object must have its reference count > 0. */
if (!(*obj)->ref_count)
{
BCM_LOG(ERROR, log_id, "%s hasn't been allocated before\n", obj_rsc->obj_name);
return BCM_ERR_PARM;
}
return BCM_ERR_OK;
}
/** @brief stores user passed in data in the linked list inside the obj */
static bcmos_errno rsc_mgr_obj_store_user_data(rsc_mgr_obj *obj, void *user_data)
{
rsc_mgr_user_data_entry *user_data_entry = NULL;
if (NULL == user_data)
return BCM_ERR_OK;
user_data_entry = bcmos_calloc(sizeof(rsc_mgr_user_data_entry));
user_data_entry->user_data = user_data;
TAILQ_INSERT_HEAD(&obj->user_data_list, user_data_entry, next);
return BCM_ERR_OK;
}
/** @brief removes user data from the linked list inside the obj */
static bcmos_errno rsc_mgr_obj_remove_user_data(rsc_mgr_obj *obj, void *user_data)
{
rsc_mgr_user_data_entry *user_data_entry = NULL, *user_data_entry_tmp;
if (NULL == user_data)
return BCM_ERR_OK;
TAILQ_FOREACH_SAFE(user_data_entry, &obj->user_data_list, next, user_data_entry_tmp)
{
if (user_data == user_data_entry->user_data)
break;
}
TAILQ_REMOVE(&obj->user_data_list, user_data_entry, next);
user_data_entry->user_data = NULL;
bcmos_free(user_data_entry);
return BCM_ERR_OK;
}
/** @brief iterator to iterate through the user data list in obj
* @note the assumption is if a NULL is returned, then caller code stop the iteration.
* */
static void *rsc_mgr_obj_get_next_user_data(rsc_mgr_obj *obj, void **curr_user_data_entry, void **next_user_data_entry)
{
if (NULL == *curr_user_data_entry)
{
*curr_user_data_entry = TAILQ_FIRST(&obj->user_data_list);
if (*curr_user_data_entry)
{
*next_user_data_entry = TAILQ_NEXT(((rsc_mgr_user_data_entry *)*curr_user_data_entry), next);
return ((rsc_mgr_user_data_entry *)(*curr_user_data_entry))->user_data;
}
}
else
{
*curr_user_data_entry = *next_user_data_entry;
if (*next_user_data_entry)
{
*next_user_data_entry = TAILQ_NEXT(((rsc_mgr_user_data_entry *)*next_user_data_entry), next);
return ((rsc_mgr_user_data_entry *)(*curr_user_data_entry))->user_data;
}
}
return NULL;
}
/* Alloc ID (aggregation port ID) */
static bcmos_errno _rsc_mgr_access_int_base_alloc_id_set(bcmbal_intf_id access_int_id, bcmbal_aggregation_port_id min_data_agg_port_id)
{
bcmolt_pon_alloc_index alloc_index;
rsc_mgr_topo_pon_context *topo_context = RSC_MGR_PON_TOPO_CONTEXT(access_int_id);
if (bcm_topo_pon_get_pon_mode(access_int_id) == BCM_TOPO_PON_MODE_GPON)
{
bcmolt_gpon_ni_cfg gpon_ni_cfg = {};
bcmolt_gpon_ni_cfg_id failed_prop;
BCMOLT_CFG_PROP_SET(&gpon_ni_cfg, gpon_ni, min_data_alloc_id, min_data_agg_port_id);
if (!bcmolt_gpon_ni_cfg_data_bounds_check(&gpon_ni_cfg.data, (1ULL << BCMOLT_GPON_NI_CFG_ID_MIN_DATA_ALLOC_ID), &failed_prop))
{
BCM_LOG(ERROR, topo_context->log_id, "Minimal data alloc ID is not in the allowed range\n");
return BCM_ERR_PARM;
}
}
else
{
bcmolt_xgpon_ni_cfg xgpon_ni_cfg = {};
bcmolt_xgpon_ni_cfg_id failed_prop;
BCMOLT_CFG_PROP_SET(&xgpon_ni_cfg, xgpon_ni, min_data_alloc_id, min_data_agg_port_id);
if (!bcmolt_xgpon_ni_cfg_data_bounds_check(&xgpon_ni_cfg.data, (1ULL << BCMOLT_XGPON_NI_CFG_ID_MIN_DATA_ALLOC_ID), &failed_prop))
{
BCM_LOG(ERROR, topo_context->log_id, "Minimal data alloc ID is not in the allowed range\n");
return BCM_ERR_PARM;
}
}
if (!TAILQ_EMPTY(&topo_context->alloc_ids.allocated_objs))
{
BCM_LOG(ERROR, topo_context->log_id, "Minimal alloc ID cannot be set when there are allocated alloc IDs\n");
return BCM_ERR_STATE;
}
topo_context->alloc_ids.min_data_obj_id = (rsc_mgr_obj_id)min_data_agg_port_id;
RSC_MGR_FOR_EACH_ALLOC_INDEX(access_int_id, alloc_index)
topo_context->alloc_ids.objs[alloc_index].id = topo_context->alloc_ids.min_data_obj_id + alloc_index;
return BCM_ERR_OK;
}
bcmos_errno rsc_mgr_access_int_base_alloc_id_set(bcmbal_intf_id access_int_id, bcmbal_aggregation_port_id min_data_agg_port_id)
{
bcmos_errno rc;
rc = rsc_mgr_alloc_validate_common(access_int_id);
if (BCM_ERR_OK != rc)
return rc;
return _rsc_mgr_access_int_base_alloc_id_set(access_int_id, min_data_agg_port_id);
}
static bcmos_errno rsc_mgr_alloc_validate_common(bcmbal_intf_id access_int_id)
{
bcmos_errno rc;
rc = rsc_mgr_init_validate();
if (rc != BCM_ERR_OK)
{
BCM_LOG(ERROR, rsc_mgr_log_id, "Resource manager is uninitialized\n");
return rc;
}
if (!bcm_topo_pon_is_valid(access_int_id))
return BCM_ERR_PARM;
return BCM_ERR_OK;
}
static bcmos_errno rsc_mgr_alloc_validate_non_unicast(bcmbal_intf_id access_int_id, bcmbal_service_port_id topo_context_gem_port,
bcmbal_service_port_id req_gem_port, uint32_t range_size, rsc_mgr_obj_type type,
dev_log_id log_id)
{
if (topo_context_gem_port != BCMOLT_PON_GEM_PORT_ID_INVALID && req_gem_port && req_gem_port != topo_context_gem_port)
{
BCM_LOG(ERROR, log_id, "Access interface already has %s service port ID=%u configured\n", RSC_MGR_OBJ_TYPE_STR(type), topo_context_gem_port);
return BCM_ERR_ALREADY;
}
if (range_size > 1)
{
BCM_LOG(ERROR, log_id, "Range bigger than 1 for %s GEM port is not allowed\n", RSC_MGR_OBJ_TYPE_STR(type));
return BCM_ERR_PARM;
}
return BCM_ERR_OK;
}
bcmos_errno rsc_mgr_alloc_id_alloc(bcmbal_intf_id access_int_id, bcmbal_aggregation_port_id *agg_port_id, uint32_t range_size, void *user_data)
{
bcmos_errno rc;
rsc_mgr_obj_id obj_id = *agg_port_id;
rsc_mgr_topo_pon_context *topo_context = RSC_MGR_PON_TOPO_CONTEXT(access_int_id);
rc = rsc_mgr_alloc_validate_common(access_int_id);
if (BCM_ERR_OK != rc)
return rc;
rc = rsc_mgr_obj_alloc(access_int_id, &obj_id, range_size, RSC_MGR_OBJ_TYPE_ALLOC_ID, &topo_context->alloc_ids, user_data, topo_context->log_id);
*agg_port_id = obj_id;
return rc;
}
bcmos_errno rsc_mgr_alloc_id_free(bcmbal_intf_id access_int_id, bcmbal_aggregation_port_id agg_port_id, void *user_data)
{
rsc_mgr_topo_pon_context *topo_context = RSC_MGR_PON_TOPO_CONTEXT(access_int_id);
if (!bcm_topo_pon_is_valid(access_int_id))
return BCM_ERR_PARM;
return rsc_mgr_obj_free(access_int_id, (rsc_mgr_obj_id)agg_port_id, &topo_context->alloc_ids, user_data, topo_context->log_id);
}
bcmos_errno rsc_mgr_alloc_id_get_ref_count(bcmbal_intf_id access_int_id, bcmbal_aggregation_port_id agg_port_id, uint32_t *ref_count)
{
rsc_mgr_obj *obj;
bcmos_errno rc;
rsc_mgr_topo_pon_context *topo_context = RSC_MGR_PON_TOPO_CONTEXT(access_int_id);
rc = rsc_mgr_obj_get(access_int_id, (rsc_mgr_obj_id)agg_port_id, &topo_context->alloc_ids, &obj, topo_context->log_id);
if (rc != BCM_ERR_OK)
return rc;
*ref_count = obj->ref_count;
return BCM_ERR_OK;
}
/** @brief iterates through user data list of an alloc id object */
void *rsc_mgr_alloc_id_get_next_user_data(bcmbal_intf_id access_int_id, bcmbal_aggregation_port_id agg_port_id, void **curr_user_data_entry, void **next_user_data_entry)
{
rsc_mgr_obj *obj;
bcmos_errno rc;
rsc_mgr_topo_pon_context *topo_context = RSC_MGR_PON_TOPO_CONTEXT(access_int_id);
rc = rsc_mgr_obj_get(access_int_id, (rsc_mgr_obj_id)agg_port_id, &topo_context->alloc_ids, &obj, topo_context->log_id);
if (rc != BCM_ERR_OK)
return NULL;
return rsc_mgr_obj_get_next_user_data(obj, curr_user_data_entry, next_user_data_entry);
}
/* GEM (service port ID) */
static bcmos_errno _rsc_mgr_access_int_base_gem_set(bcmbal_intf_id access_int_id, bcmbal_service_port_id min_data_svc_port_id)
{
bcmolt_pon_gem_port_index gem_index;
rsc_mgr_topo_pon_context *topo_context = RSC_MGR_PON_TOPO_CONTEXT(access_int_id);
if (bcm_topo_pon_get_pon_mode(access_int_id) == BCM_TOPO_PON_MODE_GPON)
{
bcmolt_gpon_gem_port_cfg gpon_gem_port_cfg = { .key.gem_port_id = min_data_svc_port_id };
bcmolt_gpon_gem_port_key_id failed_prop;
if (!bcmolt_gpon_gem_port_key_bounds_check(&gpon_gem_port_cfg.key, 1ULL << BCMOLT_GPON_GEM_PORT_KEY_ID_GEM_PORT_ID, &failed_prop) ||
min_data_svc_port_id < MIN_BASE_GEM_PORT_ID_GPON)
{
BCM_LOG(ERROR, topo_context->log_id, "Minimal data GEM port is not in the allowed range\n");
return BCM_ERR_PARM;
}
}
else
{
bcmolt_xgpon_ni_cfg xgpon_ni_cfg = {};
bcmolt_xgpon_ni_cfg_id failed_prop;
BCMOLT_CFG_PROP_SET(&xgpon_ni_cfg, xgpon_ni, min_data_gem_port_id, min_data_svc_port_id);
if (!bcmolt_xgpon_ni_cfg_data_bounds_check(&xgpon_ni_cfg.data, 1ULL << BCMOLT_XGPON_NI_CFG_ID_MIN_DATA_GEM_PORT_ID, &failed_prop))
{
BCM_LOG(ERROR, topo_context->log_id, "Minimal data GEM port is not in the allowed range\n");
return BCM_ERR_PARM;
}
}
if (!TAILQ_EMPTY(&topo_context->gems.allocated_objs))
{
BCM_LOG(ERROR, topo_context->log_id, "Minimal GEM port cannot be set when there are allocated GEM ports\n");
return BCM_ERR_STATE;
}
topo_context->gems.min_data_obj_id = (rsc_mgr_obj_id)min_data_svc_port_id;
RSC_MGR_FOR_EACH_GEM_INDEX(access_int_id, gem_index)
topo_context->gems.objs[gem_index].id = topo_context->gems.min_data_obj_id + gem_index;
return BCM_ERR_OK;
}
bcmos_errno rsc_mgr_access_int_base_gem_set(bcmbal_intf_id access_int_id, bcmbal_service_port_id min_data_svc_port_id)
{
bcmos_errno rc;
rc = rsc_mgr_alloc_validate_common(access_int_id);
if (BCM_ERR_OK != rc)
return rc;
return _rsc_mgr_access_int_base_gem_set(access_int_id, min_data_svc_port_id);
}
static bcmos_errno _rsc_mgr_base_tm_sched_auto_id_set (bcmbal_tm_sched_id min_tm_sched_auto_id)
{
bcmbal_tm_sched_id_index i;
if (!TAILQ_EMPTY(&tm_context.tm_sched_auto_key_ids.allocated_objs))
{
BCM_LOG(ERROR, tm_context.log_id, "Minimal tm node auto id cannot be set when there are allocated ids \n");
return BCM_ERR_STATE;
}
tm_context.tm_sched_auto_key_ids.min_data_obj_id = (rsc_mgr_obj_id)min_tm_sched_auto_id;
RSC_MGR_FOR_EACH_TM_SCHED_AUTO_INDEX(i)
{
tm_context.tm_sched_auto_key_ids.objs[i].id = tm_context.tm_sched_auto_key_ids.min_data_obj_id + i;
}
return BCM_ERR_OK;
}
bcmos_errno rsc_mgr_gem_alloc_unicast(bcmbal_intf_id access_int_id, bcmbal_service_port_id *svc_port_id, uint32_t range_size, void *user_data)
{
bcmos_errno rc;
rsc_mgr_topo_pon_context *topo_context = NULL;
rsc_mgr_obj_id obj_id = *svc_port_id;
rc = rsc_mgr_alloc_validate_common(access_int_id);
if (BCM_ERR_OK != rc)
return rc;
topo_context = RSC_MGR_PON_TOPO_CONTEXT(access_int_id);
rc = rsc_mgr_obj_alloc(access_int_id, &obj_id, range_size, RSC_MGR_OBJ_TYPE_GEM_PORT_UNICAST, &topo_context->gems, user_data, topo_context->log_id);
*svc_port_id = obj_id;
return rc;
}
bcmos_errno rsc_mgr_gem_alloc_multicast(bcmbal_intf_id access_int_id, bcmbal_service_port_id *svc_port_id, uint32_t range_size, void *user_data)
{
bcmos_errno rc;
rsc_mgr_topo_pon_context *topo_context = NULL;
rsc_mgr_obj_id obj_id = *svc_port_id;
rc = rsc_mgr_alloc_validate_common(access_int_id);
if (BCM_ERR_OK != rc)
return rc;
topo_context = RSC_MGR_PON_TOPO_CONTEXT(access_int_id);
#ifndef MULTIPLE_MULTICAST_GEM_PORTS_PER_PON
rc = rsc_mgr_alloc_validate_non_unicast(access_int_id, topo_context->multicast_gem_port, *svc_port_id, range_size, RSC_MGR_OBJ_TYPE_GEM_PORT_MULTICAST, topo_context->log_id);
if (topo_context->multicast_gem_port != BCMOLT_PON_GEM_PORT_ID_INVALID)
obj_id = topo_context->multicast_gem_port; /* This will cause the reference count of the multicast GEM to increase. */
#endif
rc = rsc_mgr_obj_alloc(access_int_id, &obj_id, range_size, RSC_MGR_OBJ_TYPE_GEM_PORT_MULTICAST, &topo_context->gems, user_data, topo_context->log_id);
*svc_port_id = obj_id;
#ifndef MULTIPLE_MULTICAST_GEM_PORTS_PER_PON
if (!rc)
RSC_MGR_PON_TOPO_CONTEXT(access_int_id)->multicast_gem_port = *svc_port_id;
#endif
return rc;
}
bcmos_errno rsc_mgr_gem_alloc_broadcast(bcmbal_intf_id access_int_id, bcmbal_service_port_id *svc_port_id, uint32_t range_size, void *user_data)
{
bcmos_errno rc;
rsc_mgr_topo_pon_context *topo_context = NULL;
rsc_mgr_obj_id obj_id = *svc_port_id;
rc = rsc_mgr_alloc_validate_common(access_int_id);
if (BCM_ERR_OK != rc)
return rc;
topo_context = RSC_MGR_PON_TOPO_CONTEXT(access_int_id);
#ifndef MULTIPLE_BROADCAST_GEM_PORTS_PER_PON
rc = rsc_mgr_alloc_validate_non_unicast(access_int_id, topo_context->broadcast_gem_port, *svc_port_id, range_size, RSC_MGR_OBJ_TYPE_GEM_PORT_BROADCAST, topo_context->log_id);
if (topo_context->broadcast_gem_port != BCMOLT_PON_GEM_PORT_ID_INVALID)
obj_id = topo_context->broadcast_gem_port; /* This will cause the reference count of the broadcast GEM to increase. */
#endif
rc = rsc_mgr_obj_alloc(access_int_id, &obj_id, range_size, RSC_MGR_OBJ_TYPE_GEM_PORT_BROADCAST, &topo_context->gems, user_data, topo_context->log_id);
*svc_port_id = obj_id;
#ifndef MULTIPLE_BROADCAST_GEM_PORTS_PER_PON
if (!rc)
RSC_MGR_PON_TOPO_CONTEXT(access_int_id)->broadcast_gem_port = *svc_port_id;
#endif
return rc;
}
bcmos_errno rsc_mgr_gem_free(bcmbal_intf_id access_int_id, bcmbal_service_port_id svc_port_id, void *user_data)
{
bcmos_errno rc;
#ifndef MULTIPLE_MULTICAST_GEM_PORTS_PER_PON
rsc_mgr_topo_pon_context *topo_context;
#endif
if (!bcm_topo_pon_is_valid(access_int_id))
return BCM_ERR_PARM;
#ifndef MULTIPLE_MULTICAST_GEM_PORTS_PER_PON
topo_context = RSC_MGR_PON_TOPO_CONTEXT(access_int_id);
#endif
rc = rsc_mgr_obj_free(access_int_id, (rsc_mgr_obj_id)svc_port_id, &topo_context->gems, user_data, topo_context->log_id);
#ifndef MULTIPLE_MULTICAST_GEM_PORTS_PER_PON
if (!rc && topo_context->multicast_gem_port == svc_port_id)
RSC_MGR_PON_TOPO_CONTEXT(access_int_id)->multicast_gem_port = BCMOLT_PON_GEM_PORT_ID_INVALID;
#endif
return rc;
}
bcmos_errno rsc_mgr_gem_get_ref_count(bcmbal_intf_id access_int_id, bcmbal_service_port_id svc_port_id, uint32_t *ref_count)
{
rsc_mgr_obj *obj;
bcmos_errno rc;
rsc_mgr_topo_pon_context *topo_context = RSC_MGR_PON_TOPO_CONTEXT(access_int_id);
rc = rsc_mgr_obj_get(access_int_id, (rsc_mgr_obj_id)svc_port_id, &topo_context->gems, &obj, topo_context->log_id);
if (rc != BCM_ERR_OK)
return rc;
*ref_count = obj->ref_count;
return BCM_ERR_OK;
}
/** @brief iterates through user data list of a gem object */
void *rsc_mgr_gem_get_next_user_data(bcmbal_intf_id access_int_id, bcmbal_service_port_id svc_port_id, void **curr_user_data_entry, void **next_user_data_entry)
{
rsc_mgr_obj *obj;
bcmos_errno rc;
rsc_mgr_topo_pon_context *topo_context = RSC_MGR_PON_TOPO_CONTEXT(access_int_id);
rc = rsc_mgr_obj_get(access_int_id, (rsc_mgr_obj_id)svc_port_id, &topo_context->gems, &obj, topo_context->log_id);
if (rc != BCM_ERR_OK)
return NULL;
return rsc_mgr_obj_get_next_user_data(obj, curr_user_data_entry, next_user_data_entry);
}
bcmos_errno _rsc_mgr_tm_sched_auto_id_alloc(bcmbal_tm_sched_id *tm_sched_id)
{
bcmos_errno rc;
rsc_mgr_obj_id obj_id = *tm_sched_id;
rc = rsc_mgr_init_validate();
if (rc != BCM_ERR_OK)
{
BCM_LOG(ERROR, rsc_mgr_log_id, "Resource manager is uninitialized\n");
return rc;
}
/* Allocate a new object. */
rc = rsc_mgr_obj_alloc(0, &obj_id, 1, RSC_MGR_OBJ_TYPE_TM_SCHED, &tm_context.tm_sched_auto_key_ids, NULL, tm_context.log_id);
*tm_sched_id = obj_id;
return rc;
}
bcmos_errno _rsc_mgr_tm_sched_auto_id_free(bcmbal_tm_sched_id tm_sched_id)
{
bcmos_errno rc;
rc = rsc_mgr_obj_free(0, (rsc_mgr_obj_id)tm_sched_id, &tm_context.tm_sched_auto_key_ids, NULL, tm_context.log_id);
return rc;
}
bcmos_errno _rsc_mgr_tm_sched_auto_id_get_ref_count(bcmbal_tm_sched_id tm_sched_id, uint32_t *ref_count)
{
rsc_mgr_obj *obj;
bcmos_errno rc;
rc = rsc_mgr_obj_get(0, (rsc_mgr_obj_id)tm_sched_id, &tm_context.tm_sched_auto_key_ids, &obj, tm_context.log_id);
if (rc != BCM_ERR_OK)
return rc;
*ref_count = obj->ref_count;
return BCM_ERR_OK;
}
bcmos_bool _rsc_mgr_tm_sched_id_validate(bcmbal_tm_sched_id tm_sched_key_id)
{
return (!rsc_mgr_is_valid_data_tm_sched_auto_id(tm_sched_key_id));
}
static void rsc_mgr_init_obj_rsc(rsc_mgr_obj_rsc *obj_rsc, rsc_mgr_is_valid_data_obj_id_cb_t is_valid_data_obj_id_cb,
rsc_mgr_get_last_data_obj_id_cb_t get_last_data_obj_id_cb, uint32_t num_of_objs, const char *obj_name)
{
rsc_mgr_obj *obj;
obj_rsc->obj_name = obj_name;
obj_rsc->is_valid_data_obj_id_cb = is_valid_data_obj_id_cb;
obj_rsc->get_last_data_obj_id_cb = get_last_data_obj_id_cb;
TAILQ_INIT(&obj_rsc->free_objs);
TAILQ_INIT(&obj_rsc->allocated_objs);
obj_rsc->objs = bcmos_calloc(num_of_objs * sizeof(*obj_rsc->objs));
obj_rsc->num_of_objs = num_of_objs;
/* Insert a first entry to the list of free objects. */
obj = &obj_rsc->objs[0];
obj->range_size = num_of_objs;
TAILQ_INSERT_HEAD(&obj_rsc->free_objs, obj, list);
}
static void rsc_mgr_uninit_obj_rsc(rsc_mgr_obj_rsc *obj_rsc)
{
bcmos_free(obj_rsc->objs);
}
bcmos_errno rsc_mgr_mac_init(void)
{
bcmos_errno rc = BCM_ERR_OK;
bcmolt_devid device_id;
uint32_t pon_id;
rsc_mgr_topo_pon_context *topo_context, *old_topo_context;
do
{
rc = rsc_mgr_init_validate();
if (rc != BCM_ERR_OK)
{
BCM_LOG(INFO, rsc_mgr_log_id, "Resource Manager was not initialized");
break;
}
BCM_TOPO_FOR_EACH_PON(device_id, pon_id)
{
old_topo_context = bcm_topo_pon_get_context(pon_id, BCM_TOPO_PON_CONTEXT_ID_RSC_MGR);
if (old_topo_context)
{
bcmos_free(old_topo_context);
}
topo_context = bcmos_calloc(sizeof(*topo_context));
if (bcm_topo_pon_get_pon_mode(pon_id) == BCM_TOPO_PON_MODE_GPON)
{
topo_context->num_of_alloc_ids = GPON_NUM_OF_ALLOC_IDS;
topo_context->num_of_gem_ports = GPON_NUM_OF_GEM_PORT_IDS_PER_PON;
}
else
{
topo_context->num_of_alloc_ids = XGPON_NUM_OF_ALLOC_IDS;
topo_context->num_of_gem_ports = XGPON_NUM_OF_GEM_PORT_IDS_PER_PON;
}
topo_context->multicast_gem_port = BCMOLT_PON_GEM_PORT_ID_INVALID;
topo_context->broadcast_gem_port = BCMOLT_PON_GEM_PORT_ID_INVALID;
bcm_topo_pon_set_context(pon_id, BCM_TOPO_PON_CONTEXT_ID_RSC_MGR, topo_context);
#ifdef ENABLE_LOG
snprintf(topo_context->log_id_name, sizeof(topo_context->log_id_name), "RSC_MGR%u", pon_id);
topo_context->log_id = bcm_dev_log_id_register(topo_context->log_id_name, DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
BUG_ON(topo_context->log_id == DEV_LOG_INVALID_ID);
#endif
rsc_mgr_init_obj_rsc(&topo_context->alloc_ids, rsc_mgr_is_valid_data_alloc_id_cb, rsc_mgr_get_last_data_alloc_id_cb,
RSC_MGR_PON_TOPO_CONTEXT(pon_id)->num_of_alloc_ids, "alloc ID");
rsc_mgr_init_obj_rsc(&topo_context->gems, rsc_mgr_is_valid_data_gem_cb, rsc_mgr_get_last_data_gem_cb,
RSC_MGR_PON_TOPO_CONTEXT(pon_id)->num_of_gem_ports, "GEM port");
if (bcm_topo_pon_get_pon_mode(pon_id) == BCM_TOPO_PON_MODE_GPON)
{
bcmolt_gpon_ni_cfg gpon_ni_cfg = {};
bcmolt_gpon_ni_cfg_data_set_default(&gpon_ni_cfg.data, 1 << BCMOLT_GPON_NI_CFG_ID_MIN_DATA_ALLOC_ID);
_rsc_mgr_access_int_base_alloc_id_set(pon_id, gpon_ni_cfg.data.min_data_alloc_id);
_rsc_mgr_access_int_base_gem_set(pon_id, MIN_BASE_GEM_PORT_ID_GPON);
}
else
{
bcmolt_xgpon_ni_cfg xgpon_ni_cfg = {};
bcmolt_xgpon_ni_cfg_data_set_default(&xgpon_ni_cfg.data, 1 << BCMOLT_XGPON_NI_CFG_ID_MIN_DATA_ALLOC_ID);
_rsc_mgr_access_int_base_alloc_id_set(pon_id, xgpon_ni_cfg.data.min_data_alloc_id);
bcmolt_xgpon_ni_cfg_data_set_default(&xgpon_ni_cfg.data, 1 << BCMOLT_XGPON_NI_CFG_ID_MIN_DATA_GEM_PORT_ID);
_rsc_mgr_access_int_base_gem_set(pon_id, xgpon_ni_cfg.data.min_data_gem_port_id);
}
}
}while(0);
return rc;
}
bcmos_errno rsc_mgr_init(void)
{
if (rsc_mgr_init_validate() == BCM_ERR_OK)
{
BCM_LOG(INFO, rsc_mgr_log_id, "Resource Manager was already initialized");
return BCM_ERR_OK;
}
#ifdef ENABLE_LOG
if (rsc_mgr_log_id == DEV_LOG_INVALID_ID)
{
rsc_mgr_log_id = bcm_dev_log_id_register("RSC_MGR", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
BUG_ON(rsc_mgr_log_id == DEV_LOG_INVALID_ID);
}
#endif
/*Init the tm object*/
tm_context.num_of_tm_sched_auto_key_ids = NUM_OF_TM_SCHED_AUTO_KEY_IDS;
snprintf(tm_context.log_id_name , sizeof(tm_context.log_id_name) , "RSC_MGR_TM");
tm_context.log_id = bcm_dev_log_id_register(tm_context.log_id_name, DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
BUG_ON(tm_context.log_id == DEV_LOG_INVALID_ID);
rsc_mgr_init_obj_rsc(&tm_context.tm_sched_auto_key_ids, rsc_mgr_is_valid_data_tm_sched_auto_id_cb, rsc_mgr_get_last_data_tm_sched_auto_id_cb,
tm_context.num_of_tm_sched_auto_key_ids, "TM node auto id");
_rsc_mgr_base_tm_sched_auto_id_set(MIN_BASE_TM_SCHED_AUTO_ID);
rsc_mgr_context.is_initialized = BCMOS_TRUE;
return BCM_ERR_OK;
}
void rsc_mgr_uninit(void)
{
bcmolt_devid device_id;
uint32_t pon_id;
if (!rsc_mgr_context.is_initialized)
return;
BCM_TOPO_FOR_EACH_PON(device_id, pon_id)
{
rsc_mgr_topo_pon_context *topo_context = RSC_MGR_PON_TOPO_CONTEXT(pon_id);
rsc_mgr_uninit_obj_rsc(&topo_context->gems);
rsc_mgr_uninit_obj_rsc(&topo_context->alloc_ids);
}
rsc_mgr_context.is_initialized = BCMOS_FALSE;
}