blob: d667f2ecb7d39d4810428d9848dc7a591a51a45b [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 bal_dpp_qos.c
* @brief BAL Switch Util QoS configuration API
*
* This file contains the data structures and functions for
* configuring and managing Quality of Service (QoS) for services on
* DUNE Pack Processor (DPP).
*
* The scheduler setup is presented below. In addition to setting up
* the scheduling elements (SEs), the BAL_DPP_QOS configures an egress
* port shaper on each PON-side port, as well as a per-Access Link (GEMID/LLID)
* shaper to implement the downstream SLA for the subscriber service.
*
* Currently the BAL_DPP_QOS configures downstream QoS only (over the
* PON). Maple PON Link SLAs are used to implement upstream SLAs for
* the subscriber service in the BAL+Maple+DPP
* architecture. Additional upstream QoS for TM within DPP (over the
* NNIs) are considered an OEM System vendor responsibility. No
* implementation for upstream QoS is provided by the BAL_DPP_QOS.
*
*
* ********************************************************************************
*
*/
/*@{*/
#ifndef TEST_SW_UTIL_LOOPBACK
#define BCM_PETRA_SUPPORT 1 /* TBD - this should be define in the Makefile of the ~/dpp directory */
#define LINK_ARAD_LIBRARIES 1 /* SDK Make.config - BCM_88650_A0 */
#define LINK_PPD_LIBRARIES 1 /* SDK Make.config - BCM_88650_A0 */
#define INCLUDE_L3 1 /* bcm/l3.h support */
#include <stdint.h> /* for compiler defined int64_t and uint64_t */
#include "phymod_custom_config.h" /* resolve PHYMOD_xxx in phymod_system.h */
#include "bcm/debug.h"
#include "bcm/error.h"
#include "bcm/l2.h"
#include "bcm/mpls.h"
#include "bcm/qos.h"
#include "bcm/vlan.h"
#include "bcm/vswitch.h"
#include <soc/mcm/allenum.h>
#include "bcm/field.h"
#include <bcm/cosq.h>
#include <bcm/stack.h>
#include <bcm_int/dpp/alloc_mngr.h>
#include <bcm_int/dpp/qos.h>
#include <bcm_int/dpp/error.h>
#include <bcm_int/dpp/utils.h>
#include <bcm_int/dpp/qos.h>
#include <soc/dpp/PPD/ppd_api_eg_vlan_edit.h>
#include "bcm_dev_log.h"
#include "bcmos_errno.h"
#include "bal_switch_acc_term.h"
#include "bal_switch_flow.h"
#include "bal_switch_util.h"
#include "bal_dpp_qos.h"
/** @brief A global QoS configuration context */
bal_sw_qos_cfg g_bal_bcm_qos_cfg = {0};
/** @brief Pointer to global QoS configuration context */
bal_sw_qos_cfg *gp_bal_bcm_qos_cfg = &g_bal_bcm_qos_cfg;
/**
* @brief Number of traffic classes
*/
#define BAL_BCM_QOS_TC_NUM 8
/**
* @brief PCP/CoS mapping to internal Traffic Class (TC)
*
* The mapping is as follows, where TC 0 maps to the lowest priority
* and TC 3 maps to the highest priority.
*
* PCP/DEI TC
* ------- --
* 0/0 0
* 0/1 0
* 1/0 0
* 1/1 0
* 2/0 1
* 2/1 1
* 3/0 1
* 3/1 1
* 4/0 2
* 4/1 2
* 5/0 2
* 5/1 2
* 6/0 3
* 6/1 3
* 7/0 3
* 7/1 3
*
* PCP values: 0 1 2 3 4 5 6 7
*/
const int g_bal_bcm_qos_tc_map[BAL_BCM_QOS_TC_NUM] = {0, 0, 1, 1, 2, 2, 3, 3};
/**************************************************************************/
/**
// * @brief Initialize the QOS Flow/VOQ ID resource pool
*
* This function initializes the QOS Flow/VOQ ID resource pool, which
* consists of an attribute representing the next ID value to allocate
* and a table containing free voq ID values.
*
* The BAL_DPP_QOS assumes four queues are assigned to each access port (GEMID/LLID) in
* the downstream direction. Four queues per access port is the smallest
* value of queues per access port supported by the DPP device.
*
* Note, in the BAL_DPP_QOS, the qos Flow and VOQ ID are set to the
* same value.
*
* @param p_pool Pointer to a voq ID pool
* @param init_value The initial value to use during voq ID allocation
* @param max_value The maximum value assigned by this pool
*
**************************************************************************/
static void bal_sw_dpp_init_flow_id_pool(bal_sw_dpp_qos_flowid_pool *p_pool, uint32_t init_value, uint32_t max_value)
{
/* Parameter checks */
BUG_ON(p_pool == NULL);
/* Initialize the data structure */
memset(p_pool, 0, sizeof(bal_sw_dpp_qos_flowid_pool));
/* Store the first value to be used as the voq ID */
p_pool->next_flow_id_value = init_value;
/* Store the maximum value assigned by the pool */
p_pool->max_value = max_value;
/* Initialize the free pool table */
TAILQ_INIT(&p_pool->free_table);
}
/**************************************************************************/
/**
* @brief Clean up the qos Flow/VOQ ID resource pool
*
* This function cleans up the qos Flow/VOQ ID resource pool. It frees all
* of the memory used for bal_sw_dpp_qos_flowid_pool_entry_t's
*
* @param p_pool Pointer to a voq ID pool
*
**************************************************************************/
static void bal_sw_dpp_cleanup_flow_id_pool(bal_sw_dpp_qos_flowid_pool *p_pool)
{
bal_sw_dpp_qos_flowid_pool_entry *p_pool_entry = NULL;
/* Parameter checks */
BUG_ON(p_pool == NULL);
while ((p_pool_entry = TAILQ_FIRST(&p_pool->free_table)) != NULL)
{
/* Remove the entry from the free pool table. */
TAILQ_REMOVE(&p_pool->free_table, p_pool_entry, entry);
/* Free the entry */
sal_free(p_pool_entry);
}
}
/**************************************************************************/
/**
* @brief Allocate a qos Flow/VOQ ID from the pool
*
* This function allocates a Flow/VOQ ID from the resource pool. If
* there is a free voq ID entry in the free pool, the voq ID from
* the entry is used (i.e., returned to the caller) and the entry is
* freed. Otherwise, a new voq ID value is allocated and
* returned. This function returns an error if there are no voq IDs
* available.
*
* @param p_pool Pointer to a voq ID pool
* @param p_flow_id Pointer to the voq ID (value returned to caller)
*
* @return bcmos_errno
*
**************************************************************************/
static bcmos_errno bal_sw_dpp_qos_alloc_flow_id(bal_sw_dpp_qos_flowid_pool *p_pool, int *p_flow_id)
{
bcmos_errno rc = BCM_ERR_OK;
bal_sw_dpp_qos_flowid_pool_entry *p_pool_entry = NULL;
uint32_t flow_id = 0;
/* Parameter checks */
BUG_ON(p_pool == NULL);
BUG_ON(p_flow_id == NULL);
/* Get an entry from the free pool */
p_pool_entry = TAILQ_FIRST(&p_pool->free_table);
/* If an entry exists from the free pool, use the voq ID from the
* entry.
*/
if (p_pool_entry != NULL)
{
/* Remove the entry from the free pool. */
TAILQ_REMOVE(&p_pool->free_table, p_pool_entry, entry);
/* Use the voq ID from the entry */
flow_id = p_pool_entry->flow_id;
/* Free the entry */
sal_free(p_pool_entry);
}
else
{
/* Otherwise, use the next voq ID value (if available) */
if (p_pool->next_flow_id_value <= p_pool->max_value)
{
/* Use the next available voq ID value */
flow_id = p_pool->next_flow_id_value;
/* Increment the next_flow_id_value parameter */
p_pool->next_flow_id_value += BAL_BCM_QOS_QUEUES_PER_LLID;
}
}
/* Check to see if a voq ID value was available. */
if (flow_id == 0)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util, "%s(): No voq IDs available\n",
__FUNCTION__);
*p_flow_id = 0;
rc = BCM_ERR_NORES;
}
else
{
*p_flow_id = flow_id;
}
return rc;
}
/**************************************************************************/
/**
* @brief Free a qos Flow/VOQ ID and return it to the resource pool
*
* This function "frees" a Flow/VOQ ID and returns it to the free
* pool. The free pool consists of a linked list of voq ID values
* that are available for reuse. When a voq ID is freed, memory is
* allocated to store the free voq ID value, which is appended to the
* link list used to implement the free pool.
*
* @param p_pool Pointer to a voq ID pool
* @param p_flow_id Pointer to the voq ID to free
*
* @return bcmos_errno
*
**************************************************************************/
static bcmos_errno bal_sw_dpp_qos_free_flow_id(bal_sw_dpp_qos_flowid_pool *p_pool, int *p_flow_id)
{
bcmos_errno rc = BCM_ERR_OK;
bal_sw_dpp_qos_flowid_pool_entry *p_pool_entry = NULL;
/* Parameter checks */
BUG_ON(p_pool == NULL);
BUG_ON(p_flow_id == NULL);
/* Make sure there is something to free */
if (*p_flow_id == 0)
{
/* Nothing to free - just return */
return BCM_ERR_OK;
}
/* Allocate memory for a free pool entry */
p_pool_entry = sal_alloc(sizeof(bal_sw_dpp_qos_flowid_pool_entry), "voq ID Free Pool Entry");
if (p_pool_entry == NULL)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): No memory for bal_sw_dpp_qos_flowid_pool_entry_t for voq ID %u\n",
__FUNCTION__, *p_flow_id);
rc = BCM_ERR_NORES;
}
else
{
/* Initialize the entry */
memset(p_pool_entry, 0, sizeof(bal_sw_dpp_qos_flowid_pool_entry));
/* Store the voq ID */
p_pool_entry->flow_id = *p_flow_id;
/* Add the service entry to the table */
TAILQ_INSERT_TAIL(&p_pool->free_table, p_pool_entry, entry);
/* Clear the voq ID entry */
*p_flow_id = 0;
}
return rc;
}
/**************************************************************************/
/**
* @brief Create the PCP and DEI to Traffic Class (TC) mapping
*
* This function creates the mapping from PCP/CoS and DEI bits in the
* frames received by DPP to the internal traffic class (TC) in
* DPP. The TC is used to determine the destination VOQ for the
* frame.
*
* Please see comments for @ref g_bal_bcm_qos_tc_map for a description of
* mapping.
*
* @param unit SDK unit number
* @param p_tc_map Pointer to PCP/DEI to TC map array
*
* @return bcmos_errno
*
**************************************************************************/
static bcmos_errno bal_sw_dpp_qos_tc_map_create(int unit, const int *p_tc_map)
{
bcm_error_t sdk_rc = BCM_E_NONE;
bcm_qos_map_t l2_in_map;
int pcp = 0;
int dei = 0;
int32_t qos_map_id;
/* Parameter checks */
BUG_ON(p_tc_map == NULL);
/* Create the TC map object */
sdk_rc = bcm_qos_map_create(unit, BCM_QOS_MAP_INGRESS, &qos_map_id);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_qos_map_create failed with %s\n",
__FUNCTION__, bcm_errmsg(sdk_rc));
return BCM_ERR_INTERNAL;
}
/* Create a mapping for each PCP/CoS and DEI bit value. */
for (pcp = 0; pcp < BAL_BCM_QOS_TC_NUM; pcp++)
{
for (dei = 0; dei < 2; dei++)
{
bcm_qos_map_t_init(&l2_in_map);
/* Ingress PCP/CoS value */
l2_in_map.pkt_pri = pcp;
/* DEI Bit */
l2_in_map.pkt_cfi = dei;
/* Set internal priority for this ingress pri */
l2_in_map.int_pri = p_tc_map[pcp];
/* Set color for this ingress Priority */
l2_in_map.color = bcmColorGreen;
sdk_rc = bcm_qos_map_add(unit, BCM_QOS_MAP_L2, &l2_in_map, qos_map_id);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_qos_map_add failed with %s, for pcp %d, dei %d\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pcp, dei);
return BCM_ERR_INTERNAL;
}
}
}
gp_bal_bcm_qos_cfg->qos_port_map_id = qos_map_id;
return BCM_ERR_OK;
}
/**************************************************************************/
/**
* @brief Clean up the PCP and DEI to Traffic Class (TC) map
*
* @param unit SDK unit number
*
**************************************************************************/
static void bal_sw_dpp_qos_tc_map_cleanup(int unit)
{
bcm_error_t sdk_rc = BCM_E_NONE;
bcm_qos_map_t l2_in_map;
int pcp = 0;
int dei = 0;
/* Delete all mapping entries */
for (pcp = 0; pcp < BAL_BCM_QOS_TC_NUM; pcp++)
{
for (dei = 0; dei < 2; dei++)
{
bcm_qos_map_t_init(&l2_in_map);
/* Ingress PCP/CoS value */
l2_in_map.pkt_pri = pcp;
/* DEI Bit */
l2_in_map.pkt_cfi = dei;
sdk_rc = bcm_qos_map_delete(unit, BCM_QOS_MAP_L2, &l2_in_map, gp_bal_bcm_qos_cfg->qos_port_map_id);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_qos_map_delete failed with %s, for pcp %d, dei %d\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pcp, dei);
/* Continue processing - don't halt because of errors during clearn up */
}
}
}
/* Delete the TC map object */
sdk_rc = bcm_qos_map_destroy(unit, gp_bal_bcm_qos_cfg->qos_port_map_id);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_qos_map_destroy failed with %s\n",
__FUNCTION__, bcm_errmsg(sdk_rc));
/* Continue processing - don't halt because of errors during clearn up */
}
}
/**************************************************************************/
/**
* @brief Initialize the BAL DPP QoS Module
*
* This function initializes the QoS module for the BAL BCM Switch Util.
* This function initializes the global QoS context, and
* sets up downstream scheduling hierarchy on each channelized
* PON-side port. Scheduling/QoS is applied to packets that egress the
* port.
*
* @param unit SDK unit number
* @param pon_mode pon interface mode
*
* @return bcmos_errno
*
**************************************************************************/
bcmos_errno bal_sw_dpp_qos_init(int unit, bal_swapp_port_map_indx pon_mode)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_error_t sdk_rc = BCM_E_NONE;
bal_sw_dpp_qos_sched_pon_chan pon_chan;
uint32_t port_rate, pri_channel_rate, sec_channel_rate;
int ii, port_num;
/* Initialization */
memset(gp_bal_bcm_qos_cfg, 0, sizeof(*gp_bal_bcm_qos_cfg));
do /* Exception Block Start */
{
rc = bal_sw_dpp_qos_tc_map_create(unit, g_bal_bcm_qos_tc_map);
if (rc != BCM_ERR_OK)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"Failed to create the default QoS TC map\n");
rc = BCM_ERR_INTERNAL;
break;
}
/* Get this module ID for this ARAD device. This is used by
* several of the bcm API calls during QoS setups.
*/
sdk_rc = bcm_stk_modid_get(unit, &gp_bal_bcm_qos_cfg->mod_id);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_stk_modid_get failed with %s\n",
__FUNCTION__, bcm_errmsg(sdk_rc));
rc = BCM_ERR_INTERNAL;
break;
}
/* set the port rate based on board type */
switch(pon_mode)
{
case BAL_SWAPP_PORT_MAP_GPON:
case BAL_SWAPP_PORT_MAP_GPON_V3:
port_rate = 2500000; /* 2.5G */
pri_channel_rate = 2500000; /* 2.5G */
sec_channel_rate = 0;
gp_bal_bcm_qos_cfg->num_channels_per_pon = 1;
break;
case BAL_SWAPP_PORT_MAP_EXP:
case BAL_SWAPP_PORT_MAP_EXP2:
case BAL_SWAPP_PORT_MAP_SVK4:
port_rate = 10000000; /* 10G */
pri_channel_rate = 10000000; /* 10G */
sec_channel_rate = 0;
gp_bal_bcm_qos_cfg->num_channels_per_pon = 1;
break;
case BAL_SWAPP_PORT_MAP_EPON_TDMA:
port_rate = BAL_BCM_QOS_DEFAULT_PORT_RATE; /* 12.5G */
pri_channel_rate = BAL_BCM_QOS_DEFAULT_10G_CHAN_RATE; /* 10.25G */
sec_channel_rate = BAL_BCM_QOS_DEFAULT_1G_CHAN_RATE; /* 2.25G */
gp_bal_bcm_qos_cfg->num_channels_per_pon = 2;
break;
case BAL_SWAPP_PORT_MAP_EPON_1G:
port_rate = 2500000; /* 2.5G */
pri_channel_rate = BAL_BCM_QOS_DEFAULT_1G_CHAN_RATE; /* 2.25G */
sec_channel_rate = 0;
gp_bal_bcm_qos_cfg->num_channels_per_pon = 1;
break;
case BAL_SWAPP_PORT_MAP_EPON_10G:
port_rate = BAL_BCM_QOS_DEFAULT_PORT_RATE; /* 12.5G */
pri_channel_rate = BAL_BCM_QOS_DEFAULT_10G_CHAN_RATE; /* 10.25G */
sec_channel_rate = 0;
gp_bal_bcm_qos_cfg->num_channels_per_pon = 1;
break;
default:
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): pon mode %d not supported\n",
__FUNCTION__, pon_mode);
return BCM_ERR_INTERNAL;
}
/*
* Initialize the egress scheduling for downstream QoS on each
* PON-side port.
*/
ii = 0; /* Start with the first PON logical interface */
/* loop through all pon port, -1 indicate end of table */
while(-1 != (port_num = bal_bcm_pon_inf_pbm_get(ii)))
{
/*
* Default port settings
*
* Set the port shaper to rate based on physical layout on each board.
* On Epon, there are 2 channels on each port.
* The channel interface shapers are set to 10G and 2G for the 10G and 1G
* channels respectively. DPP will rely on flow control from
* Maple for back pressure.
*/
bal_sw_dpp_qos_set_port_bandwidth(unit, port_num,
port_rate, BAL_BCM_QOS_DEFAULT_MAX_BURST);
bal_sw_dpp_qos_set_portchan_bandwidth(unit, port_num, BAL_BCM_SCHED_PON_CHAN_10G,
pri_channel_rate, BAL_BCM_QOS_DEFAULT_MAX_BURST);
if(gp_bal_bcm_qos_cfg->num_channels_per_pon > 1)
{
bal_sw_dpp_qos_set_portchan_bandwidth(unit, port_num, BAL_BCM_SCHED_PON_CHAN_1G,
sec_channel_rate, BAL_BCM_QOS_DEFAULT_MAX_BURST);
}
for (pon_chan = 0; pon_chan < gp_bal_bcm_qos_cfg->num_channels_per_pon; pon_chan++)
{
/* pass the logical port number - ii, to the port qos init function,
* the logical port number and the channel number will be mapped to
* packet process port number that used in qos configuration
*/
rc = bal_sw_dpp_port_qos_init(unit, ii, pon_chan);
if (rc != BCM_ERR_OK)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"QoS setup failed for port %u pon_chan %u\n",
port_num, pon_chan);
rc = BCM_ERR_INTERNAL;
break;
}
}
/* Exception Block - check for errors from the previous loop */
if (rc != BCM_ERR_OK)
{
/* Error */
break;
}
ii++;
}
/* Check for errors */
if (rc != BCM_ERR_OK)
{
break;
}
/* Initialize the Flow/VOQ ID pools */
bal_sw_dpp_init_flow_id_pool(&gp_bal_bcm_qos_cfg->flow_id_pool_10g,
DEFAULT_QOS_VOQ_BASE_10G,
DEFAULT_QOS_VOQ_MAX_10G);
bal_sw_dpp_init_flow_id_pool(&gp_bal_bcm_qos_cfg->flow_id_pool_1g,
DEFAULT_QOS_VOQ_BASE_1G,
DEFAULT_QOS_VOQ_MAX_1G);
} while(0); /* Exception Block - End */
/* Check for errors */
if (rc != BCM_ERR_OK)
{
/* Failure */
BCM_LOG(ERROR, log_id_sw_util,
"BAL BCM App not initialized, failed setting up the QoS module\n");
/* Cleanup */
bal_sw_dpp_qos_cleanup(unit);
}
else
{
/* Success */
BCM_LOG(INFO, log_id_sw_util,
"Successfully initialized the QoS module\n");
}
return rc;
}
/**************************************************************************/
/**
* @brief Cleanup the BAL BCM APP QoS Module
*
* @param unit SDK unit number
*
**************************************************************************/
void bal_sw_dpp_qos_cleanup(int unit)
{
bcm_port_t port_num;
bal_sw_dpp_qos_sched_pon_chan pon_chan;
int ii;
/*
* Cleanup the egress scheduling for downstream QoS on each
* PON-side port.
*/
ii = 0; /* Start with the first PON logical interface */
/* loop through all pon port, -1 indicate end of table */
while(-1 != (port_num = bal_bcm_pon_inf_pbm_get(ii)))
{
/* Clean up each channelized port */
for (pon_chan = 0; pon_chan < gp_bal_bcm_qos_cfg->num_channels_per_pon; pon_chan++)
{
bal_sw_dpp_port_qos_cleanup(unit, ii, pon_chan);
}
ii++;
}
/* Clean up the TC map */
bal_sw_dpp_qos_tc_map_cleanup(unit);
/* Free memory that was used for the Flow/VOQ ID pools */
bal_sw_dpp_cleanup_flow_id_pool(&gp_bal_bcm_qos_cfg->flow_id_pool_10g);
bal_sw_dpp_cleanup_flow_id_pool(&gp_bal_bcm_qos_cfg->flow_id_pool_1g);
}
/**************************************************************************/
/**
* @brief Configure the rate shaper for a PON port
*
* This function configures the rate shaper (i.e., rate limit) for a
* PON side port. The rate limit and maximum burst size is set to the
* value specified in the function call. The maximum burst size is
* only set for max_burst values greater than '0'.
*
* @param unit SDK unit number
* @param pon_port PON port number
* @param bandwidth Shaper data rate in kbps
* @param max_burst Shaper maximum burst size in bytes
*
* @return bcmos_errno
*
**************************************************************************/
bcmos_errno bal_sw_dpp_qos_set_port_bandwidth(int unit, bcm_port_t pon_port,
uint32_t bandwidth, uint32_t max_burst)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_error_t sdk_rc = BCM_E_NONE;
bcm_gport_t e2e_pon_gport;
bcm_gport_t e2e_parent_gport;
/* Parameter checks */
BUG_ON(pon_port > BAL_BCM_MAX_PON_NUM);
/* Get the gport object for the E2E interface for the specified
* pon_port
*/
BCM_COSQ_GPORT_E2E_PORT_SET(e2e_pon_gport, pon_port);
do /* Exception Block Start */
{
/*
* Get the gport for the E2E Interface
*/
sdk_rc = bcm_fabric_port_get(unit,
e2e_pon_gport,
0,
&e2e_parent_gport);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_fabric_port_get for Egress Port failed with %s for pon %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port);
rc = BCM_ERR_INTERNAL;
break;
}
/*
* Set rate on the E2E Interface
*/
sdk_rc = bcm_cosq_gport_bandwidth_set(unit,
e2e_parent_gport,
0,
0,
bandwidth,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_bandwidth_set for Egress Port failed with %s for pon %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port);
rc = BCM_ERR_INTERNAL;
break;
}
/* Set the Burst */
if (max_burst > 0)
{
sdk_rc = bcm_cosq_control_set(unit,
e2e_parent_gport,
0,
bcmCosqControlBandwidthBurstMax,
max_burst);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_control_set for MaxBurst failed with %s for pon %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port);
rc = BCM_ERR_INTERNAL;
break;
}
}
} while(0); /* Exception Block - End */
return rc;
}
/**************************************************************************/
/**
* @brief Configure the rate shaper for a PON channel
*
* This function configures the rate shaper (i.e., rate limit) for a
* PON channel 10G. vs. 1G. The rate limit and maximum burst size is
* set to the value specified in the function call. The maximum burst
* size is only set for max_burst values greater than '0'.
*
* @param unit SDK unit number
* @param pon_port PON port number
* @param pon_chan PON channel (10G vs. 1G)
* @param bandwidth Shaper data rate in kbps
* @param max_burst Shaper maximum burst size in bytes
*
* @return bcmos_errno
*
**************************************************************************/
bcmos_errno bal_sw_dpp_qos_set_portchan_bandwidth(int unit, bcm_port_t pon_port,
bal_sw_dpp_qos_sched_pon_chan pon_chan,
uint32_t bandwidth, uint32_t max_burst)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_error_t sdk_rc = BCM_E_NONE;
bcm_port_t pp_port;
bcm_gport_t e2e_gport;
bcm_gport_t local_gport;
bcm_gport_t e2e_tc_gport;
bcm_gport_t local_tc_gport;
uint32_t adj_bandwidth;
/* Parameter checks */
BUG_ON(pon_port > BAL_BCM_MAX_PON_NUM);
BUG_ON(pon_chan >= BAL_BCM_SCHED_PON_CHAN_NUM);
/* Get the local port number for the specified device PON port number and channel */
pp_port = BAL_BCM_GET_PP_PORT(pon_port, pon_chan);
do /* Exception Block Start */
{
/* Apply a rate adjustment to the credit generator */
adj_bandwidth = bandwidth + ((uint32_t)(bandwidth * BAL_BCM_QOS_CREDIT_RATE_ADJ));
BCM_COSQ_GPORT_E2E_PORT_SET(e2e_gport, pp_port);
sdk_rc = bcm_cosq_gport_bandwidth_set(unit, e2e_gport, 0, 0, adj_bandwidth, 0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_bandwidth_set for e2e_gport failed with %s for pon %u chan %u pp_port %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan, pp_port);
rc = BCM_ERR_INTERNAL;
break;
}
/* Apply a rate adjustment to the shaper */
adj_bandwidth = bandwidth + ((uint32_t)(bandwidth * BAL_BCM_QOS_SHAPER_RATE_ADJ));
BCM_GPORT_LOCAL_SET(local_gport, pp_port);
sdk_rc = bcm_cosq_gport_bandwidth_set(unit, local_gport, 0, 0, adj_bandwidth, 0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_bandwidth_set for local_gport failed with %s for pon %u chan %u pp_port %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan, pp_port);
rc = BCM_ERR_INTERNAL;
break;
}
BCM_COSQ_GPORT_E2E_PORT_TC_SET(e2e_tc_gport, pp_port);
sdk_rc = bcm_cosq_gport_bandwidth_set(unit, e2e_tc_gport, 0, 0, bandwidth, 0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_bandwidth_set for e2e_tc_gport failed with %s for pon %u chan %u pp_port %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan, pp_port);
rc = BCM_ERR_INTERNAL;
break;
}
BCM_COSQ_GPORT_PORT_TC_SET(local_tc_gport, pp_port);
sdk_rc = bcm_cosq_gport_bandwidth_set(unit, local_tc_gport, 0, 0, bandwidth, 0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_bandwidth_set for local_tc_gport failed with %s for pon %u chan %u pp_port %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan, pp_port);
rc = BCM_ERR_INTERNAL;
break;
}
} while(0); /* Exception Block - End */
return rc;
}
/**************************************************************************/
/**
* @brief Configure SP or WFQ scheduling for a PON channel
*
* This function configures scheduling for a PON channel (10G
* vs. 1G). If all of the specified weight values are non-zero, then
* WFQ is enabled on the PON channel. Otherwise, if one or more of the
* weight values is zero, strict priority (SP) scheduling will be used
* on this port.
*
* @param unit SDK unit number
* @param pon_port PON port number
* @param pon_chan PON channel (10G vs. 1G)
* @param p_wfq_cfg Pointer to the WFQ scheduler configuration
*
* @return bcmos_errno
*
**************************************************************************/
bcmos_errno bal_sw_dpp_qos_set_ponchan_wfq_cfg(int unit, bcm_port_t pon_port,
bal_sw_dpp_qos_sched_pon_chan pon_chan, bal_sw_dpp_qos_wfq_cfg *p_wfq_cfg)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_error_t sdk_rc = BCM_E_NONE;
bal_sw_dpp_port_qos_cfg *p_port_qos = NULL;
uint8_t wfq_lvl;
uint32_t weight;
/* Parameter checks */
BUG_ON(pon_port >= BAL_BCM_QOS_NUM_PON_PORTS);
BUG_ON(pon_chan >= BAL_BCM_SCHED_PON_CHAN_NUM);
/* Get the scheduler configuration for the port. */
p_port_qos = &gp_bal_bcm_qos_cfg->pon[pon_port][pon_chan];
/* Assume WFQ is used until a zero weight value is encountered. */
p_port_qos->sched_type = BAL_BCM_SCHED_TYPE_WFQ;
for (wfq_lvl=0; wfq_lvl<BAL_BCM_SCHED_WFQ_PRI_NUM; wfq_lvl++)
{
if (p_wfq_cfg->weights[wfq_lvl] == 0)
{
/* Use strict priority */
memset(&p_port_qos->pon_chan_weight_cfg, 0, sizeof(p_port_qos->pon_chan_weight_cfg));
p_port_qos->sched_type = BAL_BCM_SCHED_TYPE_SP;
break;
}
else
{
p_port_qos->pon_chan_weight_cfg[wfq_lvl] = p_wfq_cfg->weights[wfq_lvl];
}
}
/* If WFQ is being used, update the weight values in the PON
* channel's SE. Otherwise, the scheduling type is SP and there is
* nothing else to do.
*/
if (p_port_qos->sched_type == BAL_BCM_SCHED_TYPE_WFQ)
{
/* Apply the weight configuration for each WFQ scheduling
* level to the hardware.
*/
for (wfq_lvl=0; wfq_lvl<BAL_BCM_SCHED_WFQ_PRI_NUM; wfq_lvl++)
{
/* The weight cannot exceed 4K on ARAD */
weight = p_port_qos->pon_chan_weight_cfg[wfq_lvl];
if (weight > BAL_BCM_SCHED_WFQ_MAX_WEIGHT)
{
BCM_LOG(WARNING, log_id_sw_util,
"Configured weight value %u is larger than the maximum supported by ARAD, capping value to %u, pon %u, chan %u, wfq_lvl %u\n",
weight, BAL_BCM_SCHED_WFQ_MAX_WEIGHT, pon_port, pon_chan, wfq_lvl);
/* If the weight value exceeds max, cap that value at 4K. */
weight = BAL_BCM_SCHED_WFQ_MAX_WEIGHT;
}
/* Configure the hardware */
sdk_rc = bcm_cosq_gport_sched_set(unit,
p_port_qos->wfq_scheduler[wfq_lvl],
0,
BCM_COSQ_SP3,
weight);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_sched_set for PON Channel WFQ SE failed with %s for pon %u, chan %u, wfq_lvl %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan, wfq_lvl);
rc = BCM_ERR_INTERNAL;
break;
}
}
}
return rc;
}
/**************************************************************************/
/**
* @brief Initialize downstream QoS for a channelized PON port
*
* This function initializes downstream QoS for a channelized PON
* port, where scheduling/QoS is applied to packets that egress the
* port. Please refer to the "SCHEDULER MODEL" diagram at the top of
* this file.
*
* This function configures the Port-related scheduling elements
* (SEs), including the PON channel (10G vs. 1G) High Resolution
* Diff-serve (HR) SE. CIR flows are attached directly to the channel
* HR. Strict Priority (SP) and Weighted-Fair Queue (WFQ) SEs are
* created to implement DOCSIS Traffic Priority for EIR flows. After
* creating the SEs, each SE is connected to the hierarchy as shown in
* the diagram.
*
* @param unit SDK unit number
* @param log_pon logical PON port number
* @param pon_chan PON channel (10G vs. 1G)
*
* @return bcmos_errno
*
**************************************************************************/
bcmos_errno bal_sw_dpp_port_qos_init(int unit, bcm_port_t log_pon, bal_sw_dpp_qos_sched_pon_chan pon_chan)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_error_t sdk_rc = BCM_E_NONE;
bal_sw_dpp_port_qos_cfg *p_port_qos = NULL;
bcm_gport_t mod_gport;
int flags = 0;
int wfq_lvl;
bcm_port_t pp_port, pon_port;
/* Parameter checks */
BUG_ON(log_pon >= BAL_BCM_QOS_NUM_PON_PORTS);
BUG_ON(pon_chan >= BAL_BCM_SCHED_PON_CHAN_NUM);
BCM_LOG(DEBUG, log_id_sw_util,
"%s(): initializing QoS on port %d, %s channel w sche mode %s\n",
__FUNCTION__, log_pon, (pon_chan == BAL_BCM_SCHED_PON_CHAN_10G) ? "10G" : "1G",
(bal_bcm_ds_sched_mode_get()) ? "WFQ" : "SP");
/* Retrieve the QoS configuration for the specified channel, index by logical pon number */
p_port_qos = &gp_bal_bcm_qos_cfg->pon[log_pon][pon_chan];
/* Get Max rate scheduling mode from global setting */
/* TBD - the scheduling mode can be different for each port */
p_port_qos->sched_type = bal_bcm_ds_sched_mode_get();
/* get the pp port from the device port number */
pon_port = bal_bcm_pon_inf_pbm_get(log_pon);
pp_port = BAL_BCM_GET_PP_PORT(pon_port, pon_chan);
/*
* Setup downstream scheduling this channelized port
*/
do /* Exception Block Start */
{
/*
* Get the mod port for this channel.
*/
BCM_GPORT_MODPORT_SET(mod_gport, gp_bal_bcm_qos_cfg->mod_id, pp_port);
p_port_qos->mod_gport = mod_gport;
/* Initialize the channel weights to defaults values.
*
* By default strict priority is used, so these weight values
* are not "active". However, we need to set the weights to
* something non-zero during initialization.
*
* The default channel weights are...
* 32, 64, 128, 256, 512, 1024, 2048, 4096
*/
p_port_qos->pon_chan_weight_cfg[0] = 32;
for (wfq_lvl=1; wfq_lvl<BAL_BCM_SCHED_WFQ_PRI_NUM; wfq_lvl++)
{
p_port_qos->pon_chan_weight_cfg[wfq_lvl] = 2 * p_port_qos->pon_chan_weight_cfg[wfq_lvl-1];
}
/*
* Channel HR (level 1)
*
* Get the OTM port HR for this PON channel. The rest of
* the downstream scheduling hierarchy is attached to this
* HR.
*
* The 'BCM_COSQ_GPORT_REPLACE' flag is passed into the
* bcm_cosq_gport_add() function call, which changes the
* scheduling type from the default mode to a SINGLE_WFQ
* mode.
*/
BCM_COSQ_GPORT_E2E_PORT_SET(p_port_qos->pon_chan_scheduler, pp_port);
flags = BCM_COSQ_GPORT_SCHEDULER | BCM_COSQ_GPORT_SCHEDULER_HR_SINGLE_WFQ | BCM_COSQ_GPORT_REPLACE;
sdk_rc = bcm_cosq_gport_add(unit, pp_port, 1, flags, &p_port_qos->pon_chan_scheduler);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_add (with REPLACE) for PON Channel HR failed with %s for pon %u chan %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan);
rc = BCM_ERR_INTERNAL;
break;
}
else
{
BCM_LOG(DEBUG, log_id_sw_util,
"%s(): bcm_cosq_gport_add (with REPLACE) for PON Channel HR - gport 0x%x\n",
__FUNCTION__, p_port_qos->pon_chan_scheduler);
}
/*
* Strict Priority HR (level 2)
*
* Set up a Strict Priority HR scheduler for EIR (MAX Rate)
* flows. This SE is only used when the PON channel is running
* in Strict Priority mode.
*/
/* Create the scheduler object */
flags = BCM_COSQ_GPORT_SCHEDULER | BCM_COSQ_GPORT_SCHEDULER_HR_ENHANCED;
sdk_rc = bcm_cosq_gport_add(unit, 0, 1, flags, &p_port_qos->sp_scheduler);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_add for MAX Rate SP HR failed with %s for pon %u chan %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan);
rc = BCM_ERR_INTERNAL;
break;
}
else
{
BCM_LOG(DEBUG, log_id_sw_util,
"%s(): bcm_cosq_gport_add for MAX Rate SP HR - gport 0x%x\n",
__FUNCTION__, p_port_qos->sp_scheduler);
}
/* Configure the priority for this scheduler. The SP SE is
* attached at priority '2'.
*/
sdk_rc = bcm_cosq_gport_sched_set(unit,
p_port_qos->sp_scheduler,
0,
BCM_COSQ_SP2,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_sched_set for MAX Rate SP HR failed with %s for pon %u chan %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan);
rc = BCM_ERR_INTERNAL;
break;
}
/* Attach the SP scheduler to the Channel HR. */
sdk_rc = bcm_cosq_gport_attach(unit,
p_port_qos->pon_chan_scheduler,
p_port_qos->sp_scheduler,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_attach for MAX Rate SP HR failed with %s for pon %u chan %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan);
rc = BCM_ERR_INTERNAL;
break;
}
/*
* WFQ (level 2)
*
* Create FQ scheduling elements and attach one to each
* WFQ level. This is used to schedule EIR (MAX Rate)
* flows when the PON channel is running in WFQ mode.
*/
/* Create a FQ scheduler for each WFQ level */
for (wfq_lvl=0; wfq_lvl<BAL_BCM_SCHED_WFQ_PRI_NUM; wfq_lvl++)
{
/* Create the scheduler object */
flags = BCM_COSQ_GPORT_SCHEDULER | BCM_COSQ_GPORT_SCHEDULER_FQ;
sdk_rc = bcm_cosq_gport_add(unit, 0, 1, flags, &p_port_qos->wfq_scheduler[wfq_lvl]);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_add for MAX Rate WFQ failed with %s for pon %u chan %u wfq_lvl %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan, wfq_lvl);
rc = BCM_ERR_INTERNAL;
break;
}
/* Configure the priority for this SE. (WFQ is SP3 on
* the Channel HR.)
*/
sdk_rc = bcm_cosq_gport_sched_set(unit,
p_port_qos->wfq_scheduler[wfq_lvl],
0,
BCM_COSQ_SP3,
p_port_qos->pon_chan_weight_cfg[wfq_lvl]);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_sched_set for MAX Rate WFQ failed with %s for pon %u chan %u wfq_lvl %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan, wfq_lvl);
rc = BCM_ERR_INTERNAL;
break;
}
/* Attach the FQ scheduler the WFQ on the Channel HR. */
sdk_rc = bcm_cosq_gport_attach(unit,
p_port_qos->pon_chan_scheduler,
p_port_qos->wfq_scheduler[wfq_lvl],
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_attach for MAX Rate WFQ failed with %s for pon %u chan %u wfq_lvl %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan, wfq_lvl);
rc = BCM_ERR_INTERNAL;
break;
}
}
} while(0); /* Exception Block - End */
return rc;
}
/**************************************************************************/
/**
* @brief Clean up QoS for a PON-side port
*
* Each SE must be disconnected from the hierarchy before freeing the
* SE.
*
* @param unit SDK unit number
* @param pon_port PON port number
* @param pon_chan PON channel (10G vs. 1G)
*
**************************************************************************/
void bal_sw_dpp_port_qos_cleanup(int unit, bcm_port_t pon_port, bal_sw_dpp_qos_sched_pon_chan pon_chan)
{
bcm_error_t sdk_rc = BCM_E_NONE;
bal_sw_dpp_port_qos_cfg *p_port_qos = NULL;
int wfq_lvl;
/* Parameter checks */
BUG_ON(pon_port >= BAL_BCM_QOS_NUM_PON_PORTS);
BUG_ON(pon_chan >= BAL_BCM_SCHED_PON_CHAN_NUM);
/* Retrieve the QoS configuration for the specified port */
p_port_qos = &gp_bal_bcm_qos_cfg->pon[pon_port][pon_chan];
/*
* Clean up WFQ
*/
for (wfq_lvl=0; wfq_lvl<BAL_BCM_SCHED_WFQ_PRI_NUM; wfq_lvl++)
{
/* Disconnect the scheduler from the one above */
sdk_rc = bcm_cosq_gport_detach(unit,
p_port_qos->pon_chan_scheduler,
p_port_qos->wfq_scheduler[wfq_lvl],
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_detach for MAX Rate WFQ failed with %s for pon %u pon_chan %u wfq_lvl %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan, wfq_lvl);
/* Continue cleanup, don't halt processing because of this error */
}
sdk_rc = bcm_cosq_gport_delete(unit, p_port_qos->wfq_scheduler[wfq_lvl]);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_delete for MAX Rate WFQ failed with %s for pon %u pon_chan %u wfq_lvl %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan, wfq_lvl);
/* Continue cleanup, don't halt processing because of this error */
}
}
/*
* Clean up SP HR
*/
/* Disconnect the scheduler from the one above */
sdk_rc = bcm_cosq_gport_detach(unit,
p_port_qos->pon_chan_scheduler,
p_port_qos->sp_scheduler,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_detach for MAX Rate SP HR failed with %s for pon %u pon_chan %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan);
/* Continue cleanup, don't halt processing because of this error */
}
sdk_rc = bcm_cosq_gport_delete(unit, p_port_qos->sp_scheduler);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_delete for MAX Rate SP HR failed with %s for pon %u pon_chan %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), pon_port, pon_chan);
/* Continue cleanup, don't halt processing because of this error */
}
}
/**************************************************************************/
/**
* @brief Configure a rate shaper and maximum burst size for a PON Link
*
* This function configures the rate and maximum burst size for the
* specified shaper (MIN Rate vs. MAX Rate) for a PON Link (LLID).
*
* @param unit SDK unit number
* @param p_service_cfg Pointer to the service configuration entry
* @param sla_type Shaper type (MIN vs. MAX)
* @param bandwidth Data rate in Kbps (i.e., token bucket fill rate)
* @param max_burst Maximum burst size in bytes (i.e., token bucket size)
*
* @return bcmos_errno
*
**************************************************************************/
bcmos_errno bal_sw_dpp_qos_set_llid_bandwidth(int unit, bal_sw_dpp_qos_service_cfg *p_service_cfg,
bal_sw_dpp_qos_sched_sla_type sla_type, uint32_t bandwidth, uint32_t max_burst)
{
bcm_error_t sdk_rc = BCM_E_NONE;
bcm_gport_t scheduler_gport;
/* Parameter checks */
BUG_ON(p_service_cfg == NULL);
/* Get the scheduler gport that the VOQs are attached to (MIN vs. MAX) */
if (sla_type == BAL_BCM_SCHED_SLA_MIN_RATE)
{
scheduler_gport = p_service_cfg->ds_qos.min.scheduler_gport;
}
else
{
scheduler_gport = p_service_cfg->ds_qos.max.scheduler_gport;
}
/* Set the Rate - drain rate */
sdk_rc = bcm_cosq_gport_bandwidth_set(unit,
scheduler_gport,
0,
0,
bandwidth,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_bandwidth_set failed with %s for %s gport 0x%x\n",
__FUNCTION__, bcm_errmsg(sdk_rc), (sla_type == BAL_BCM_SCHED_SLA_MIN_RATE)? "SLA_MIN_RATE":"SLA_MAX_RATE", scheduler_gport);
return BCM_ERR_INTERNAL;
}
else
{
BCM_LOG(INFO, log_id_sw_util,
"%s() set gport 0x%x with %s of %d\n",
__FUNCTION__, scheduler_gport,(sla_type == BAL_BCM_SCHED_SLA_MIN_RATE)? "SLA_MIN_RATE":"SLA_MAX_RATE", bandwidth);
}
/* Set the Burst - bucket size that hold the incoming frames */
sdk_rc = bcm_cosq_control_set(unit,
scheduler_gport,
0,
bcmCosqControlBandwidthBurstMax,
max_burst);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_control_set for MaxBurst failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
return BCM_ERR_INTERNAL;
}
return BCM_ERR_OK;
}
/**************************************************************************/
/**
* @brief Configure downstream QoS for a PON Link (LLID)
*
* This function configures downstream QoS for a PON Link (LLID),
* which is represented by a tunnel ID in ARAD. Please refer to the
* "SCHEDULER MODEL" diagram at the top of this file. This function
* configures the PON Link SE and queues (VOQ + VOQ Connector) for the
* Link. The PON Link scheduler processes queues using strict
* priority. This function configures four queues for the Link, which
* is the smallest number of queues per LLID supported by
* ARAD. However, the BAL BCM App currently only makes use of a single
* queue.
*
* This function configures MIN (CIR) and MAX (EIR) rate shapers. If
* the MIN rate is disabled (i.e., bandwidth configured with a value
* of '0' kbps), the shaper is not "connected" to the port's MIN Rate
* SE.
*
* @param unit SDK unit number
* @param p_service_cfg Pointer to the service configuration entry
*
* @return bcmos_errno
*
**************************************************************************/
bcmos_errno bal_sw_dpp_llid_qos_config(int unit, bal_sw_dpp_qos_service_cfg *p_service_cfg)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_error_t sdk_rc = BCM_E_NONE;
bal_sw_dpp_port_qos_cfg *p_port_qos = NULL;
int flags = 0;
int cosq;
bcm_cosq_gport_connection_t connection;
bal_sw_dpp_qos_sched_pon_chan ds_pon_chan;
bcm_gport_t scheduler_gport;
/* Parameter checks */
BUG_ON(p_service_cfg == NULL);
/* Store the downstream PON rate, which will be used in several
* places throughout this function.
*/
ds_pon_chan = p_service_cfg->ds_qos.pon_chan;
/* Retrieve the QoS configuration for the specified port */
p_port_qos = &gp_bal_bcm_qos_cfg->pon[p_service_cfg->pon_port][ds_pon_chan];
do /* Exception Block Start */
{
/* Allocate the voq ID from the free pool */
if (ds_pon_chan == BAL_BCM_SCHED_PON_CHAN_10G)
{
rc = bal_sw_dpp_qos_alloc_flow_id(&gp_bal_bcm_qos_cfg->flow_id_pool_10g, &p_service_cfg->ds_qos.voq_flow_id);
}
else
{
rc = bal_sw_dpp_qos_alloc_flow_id(&gp_bal_bcm_qos_cfg->flow_id_pool_1g, &p_service_cfg->ds_qos.voq_flow_id);
}
if (rc != BCM_ERR_OK)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): Unable to allocate voq ID for pon %u tid %u\n",
__FUNCTION__, p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* In the BAL BCM App, the VOQ ID is equal to the voq ID */
p_service_cfg->ds_qos.voq_id = p_service_cfg->ds_qos.voq_flow_id;
/*
* PON Link scheduler (level 2)
*/
if (p_service_cfg->ds_qos.min.rate > 0)
{
/* Create a composite, strict priority scheduler for this PON
* Link. This is used to schedule between the queues assigned to
* this PON Link.
*/
flags = BCM_COSQ_GPORT_SCHEDULER | BCM_COSQ_GPORT_SCHEDULER_CLASS_MODE1_4SP | BCM_COSQ_GPORT_COMPOSITE;
sdk_rc = bcm_cosq_gport_add(unit,
0,
1, /* Number of CoS levels */
flags,
&p_service_cfg->ds_qos.min.scheduler_gport);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_add for PON Link SE failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* A single priority on the Channel HR handles all MIN Rates (CIRs). */
sdk_rc = bcm_cosq_gport_sched_set(unit,
p_service_cfg->ds_qos.min.scheduler_gport,
0,
BCM_COSQ_SP1,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_sched_set for Min Rate SE failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* Attach the PON Link scheduler to the Channel HR. */
sdk_rc = bcm_cosq_gport_attach(unit,
p_port_qos->pon_chan_scheduler,
p_service_cfg->ds_qos.min.scheduler_gport,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_attach for Min Rate SE failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* Save the gport of the parent SE (used for cleanup) */
p_service_cfg->ds_qos.min.parent_gport = p_port_qos->pon_chan_scheduler;
/* Configure the MIN Rate shaper */
rc = bal_sw_dpp_qos_set_llid_bandwidth(unit,
p_service_cfg,
BAL_BCM_SCHED_SLA_MIN_RATE,
p_service_cfg->ds_qos.min.rate,
p_service_cfg->ds_qos.min.burst);
if (rc != BCM_ERR_OK)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): Set MIN Rate shaper failed for pon %u tid %u\n",
__FUNCTION__, p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* Set the gport for the MAX Rate scheduler */
BCM_COSQ_GPORT_COMPOSITE_SF2_SET(p_service_cfg->ds_qos.max.scheduler_gport, p_service_cfg->ds_qos.min.scheduler_gport);
/* Set the scheduler gport that the VOQs are attached to */
scheduler_gport = p_service_cfg->ds_qos.min.scheduler_gport;
}
else
{
/*
* MAX Rate only (level 2)
*/
flags = BCM_COSQ_GPORT_SCHEDULER | BCM_COSQ_GPORT_SCHEDULER_CLASS_MODE1_4SP;
sdk_rc = bcm_cosq_gport_add(unit,
0,
1, /* Number of CoS levels */
flags,
&p_service_cfg->ds_qos.max.scheduler_gport);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_add for PON Link SE failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* Set the scheduler gport that the VOQs are attached to */
scheduler_gport = p_service_cfg->ds_qos.max.scheduler_gport;
}
/* The type of MAX Rate scheduling depends on what scheduling
* mode is configured on the PON channel (SP vs. WFQ).
*/
if (p_port_qos->sched_type == BAL_BCM_SCHED_TYPE_SP)
{
/*
* Strict Priority (SP) scheduling is being used
*/
/* Set the priority used for the attachment to the SP HR */
sdk_rc = bcm_cosq_gport_sched_set(unit,
p_service_cfg->ds_qos.max.scheduler_gport,
0,
BCM_COSQ_SP0 + p_service_cfg->ds_qos.max.traffic_priority,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_sched_set for Max Rate SE failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* Attach the PON Link scheduler to the SP HR. */
sdk_rc = bcm_cosq_gport_attach(unit,
p_port_qos->sp_scheduler,
p_service_cfg->ds_qos.max.scheduler_gport,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_attach for Max Rate SE failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* Save the gport of the parent SE (used for cleanup) */
p_service_cfg->ds_qos.max.parent_gport = p_port_qos->sp_scheduler;
}
else
{
/*
* Weighted Fair Queuing (WFQ) scheduling is being used
*/
/* Set the priority used for the attachment to the FQ. */
sdk_rc = bcm_cosq_gport_sched_set(unit,
p_service_cfg->ds_qos.max.scheduler_gport,
0,
BCM_COSQ_SP0,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_sched_set for Max Rate SE failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* Attach the PON Link scheduler to the FQ. */
sdk_rc = bcm_cosq_gport_attach(unit,
p_port_qos->wfq_scheduler[p_service_cfg->ds_qos.max.traffic_priority],
p_service_cfg->ds_qos.max.scheduler_gport,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_attach for Max Rate SE failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* Save the gport of the parent SE (used for cleanup) */
p_service_cfg->ds_qos.max.parent_gport = p_port_qos->wfq_scheduler[p_service_cfg->ds_qos.max.traffic_priority];
}
/* Configure the MAX Rate shaper */
rc = bal_sw_dpp_qos_set_llid_bandwidth(unit,
p_service_cfg,
BAL_BCM_SCHED_SLA_MAX_RATE,
p_service_cfg->ds_qos.max.rate,
p_service_cfg->ds_qos.max.burst);
if (rc != BCM_ERR_OK)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): Set MAX Rate shaper failed for pon %u tid %u\n",
__FUNCTION__, p_service_cfg->pon_port, p_service_cfg->tunnel_id);
break;
}
/*
* Create a VOQ connector (level 3)
*/
/* Create the VOQ connector object for a bundle of four queues */
flags = BCM_COSQ_GPORT_VOQ_CONNECTOR | BCM_COSQ_GPORT_WITH_ID;
BCM_COSQ_GPORT_VOQ_CONNECTOR_SET(p_service_cfg->ds_qos.voq_connector_gport, p_service_cfg->ds_qos.voq_flow_id);
sdk_rc = bcm_cosq_gport_add(unit,
p_port_qos->mod_gport,
BAL_BCM_QOS_QUEUES_PER_LLID,
flags,
&p_service_cfg->ds_qos.voq_connector_gport);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_add for VOQ Connector failed with %s for pon %u tid %u voq ID %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc),
p_service_cfg->pon_port,
p_service_cfg->tunnel_id,
p_service_cfg->ds_qos.voq_flow_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* Set the traffic class for each queue and attach the VOQ
* connector to the PON Link scheduler.
*/
for (cosq = 0; cosq < BAL_BCM_QOS_QUEUES_PER_LLID; cosq++)
{
/* Set the traffic class for the queue */
sdk_rc = bcm_cosq_gport_sched_set(unit,
p_service_cfg->ds_qos.voq_connector_gport,
cosq,
BCM_COSQ_SP3 - cosq,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_sched_set for VOQ Connector failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* Attach the connection for each queue to the PON Link
* scheduler, based on the traffic class.
*/
sdk_rc = bcm_cosq_gport_attach(unit,
scheduler_gport,
p_service_cfg->ds_qos.voq_connector_gport,
cosq);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_attach for VOQ Connector failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
}
/* Exception Block - check for errors from the previous loop */
if (rc != BCM_ERR_OK)
{
/* Error */
break;
}
/*
* Create a VOQ (level 3)
*/
flags = BCM_COSQ_GPORT_UCAST_QUEUE_GROUP | BCM_COSQ_GPORT_TM_FLOW_ID | BCM_COSQ_GPORT_WITH_ID;
BCM_GPORT_UNICAST_QUEUE_GROUP_SET(p_service_cfg->ds_qos.voq_gport, p_service_cfg->ds_qos.voq_id);
sdk_rc = bcm_cosq_gport_add(unit,
p_port_qos->mod_gport,
BAL_BCM_QOS_QUEUES_PER_LLID,
flags,
&p_service_cfg->ds_qos.voq_gport);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_add for VOQ failed with %s for voq id %u, voq gport 0x%x, pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->ds_qos.voq_id, p_service_cfg->ds_qos.voq_gport,
p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* QAX not support per Queue compensation */
#ifndef QAX_SWITCH
/* Start - header adjust */
{
/*
* If necessary, adjust the packet header overhead to match
* the configured value.
*/
int32_t val = 0;
int32_t cfg_dpp_hdr_size = 0;
/* Calculate the expected DPP header size, which depends on
* whether or not traffic is untagged, PB tagged, ICT
* tagged, or Shared Vlan tagged. If the traffic is tagged
* (either PB, ICT, or Shared Vlan), there are five fewer
* bytes in the DPP header.
*/
cfg_dpp_hdr_size = DEFAULT_QOS_DPP_PKT_HDR_SIZE;
if (p_service_cfg->service_type != BAL_BCM_SVC_TYPE_IP)
{
cfg_dpp_hdr_size -= BAL_BCM_DPP_FLOWID_HDR_SIZE;
}
/* If the traffic is ICT stack mode or Shared Vlan tagged, we
* need to exclude the Vlan tag overhead from the bandwidth
* calculation (i.e., add four bytes of overhead).
*/
if (((p_service_cfg->service_type == BAL_BCM_SVC_TYPE_ICT) /*&& (p_service_cfg->ictStkType != BAL_BCM_ICT_STACK_TYPE_NONE)*/)||
(p_service_cfg->service_type == BAL_BCM_SVC_TYPE_SHVLAN))
{
cfg_dpp_hdr_size += BAL_BCM_QOS_SINGLE_VLAN_TAG_HDR_SIZE;
}
/* Get the header length */
sdk_rc = bcm_cosq_control_get(unit,
p_service_cfg->ds_qos.voq_gport,
0,
bcmCosqControlPacketLengthAdjust,
&val);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_control_get for bcmCosqControlPacketLengthAdjust failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* If current length does not match the configured length,
* configure it now.
*/
if (val != cfg_dpp_hdr_size)
{
/* Debug */
BCM_LOG(INFO, log_id_sw_util,
"%s(): modifying value of bcmCosqControlPacketLengthAdjust from %u to %u for pon %u tid %u\n",
__FUNCTION__,
val,
cfg_dpp_hdr_size,
p_service_cfg->pon_port,
p_service_cfg->tunnel_id);
/* Adjust the packet length calculated above. This has to
* be configured for each queue (cosq) in the voq
* group.
*/
for (cosq = 0; cosq < BAL_BCM_QOS_QUEUES_PER_LLID; cosq++)
{
/* Adjust the packet length calculated above. */
sdk_rc = bcm_cosq_control_set(unit,
p_service_cfg->ds_qos.voq_gport,
cosq,
bcmCosqControlPacketLengthAdjust,
cfg_dpp_hdr_size);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_control_set for bcmCosqControlPacketLengthAdjust for cosq %d failed with %s for pon %u tid %u\n",
__FUNCTION__, cosq, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
}
/* Exception Block - check for errors from the previous loop */
if (rc != BCM_ERR_OK)
{
/* Error */
break;
}
}
} /* End - header adjustment */
#endif
/*
* Connect a VOQ to a VOQ connector
*/
/* Connect VOQ to the VOQ connector for the ingress direction */
connection.flags = BCM_COSQ_GPORT_CONNECTION_INGRESS;
connection.remote_modid = gp_bal_bcm_qos_cfg->mod_id;
connection.voq = p_service_cfg->ds_qos.voq_gport;
connection.voq_connector = p_service_cfg->ds_qos.voq_connector_gport;
sdk_rc = bcm_cosq_gport_connection_set(unit, &connection);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_connection_set for INGRESS failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
/* Connect VOQ to the VOQ connector for the egress direction */
connection.flags = BCM_COSQ_GPORT_CONNECTION_EGRESS;
connection.remote_modid = gp_bal_bcm_qos_cfg->mod_id;
connection.voq = p_service_cfg->ds_qos.voq_gport;
connection.voq_connector = p_service_cfg->ds_qos.voq_connector_gport;
sdk_rc = bcm_cosq_gport_connection_set(unit, &connection);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_cosq_gport_connection_set for EGRESS failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
rc = BCM_ERR_INTERNAL;
break;
}
} while(0); /* Exception Block - End */
/* Check for errors */
if (rc != BCM_ERR_OK)
{
/* Failure */
BCM_LOG(WARNING, log_id_sw_util,
"Downstream QoS setup failed for pon %u tid %u\n",
p_service_cfg->pon_port, p_service_cfg->tunnel_id);
/* Cleanup */
bal_sw_dpp_llid_qos_cleanup(unit, p_service_cfg);
}
return rc;
}
/**************************************************************************/
/**
* @brief Configure downstream QoS Port Map for a PON Link (LLID)
*
* This function configures downstream QoS Port Map for a PON Link
* (LLID), which is represented by a tunnel ID in ARAD. This sets the
* default traffic class (TC) value for VLAN tags being inserted or
* modified.
*
* @param unit SDK unit number
* @param p_service_cfg Pointer to the service configuration entry
*
* @return bcmos_errno
*
**************************************************************************/
bcmos_errno bal_sw_dpp_llid_set_qos_port_map(int unit, bal_sw_dpp_qos_service_cfg *p_service_cfg)
{
bcmos_errno rc = BCM_ERR_OK;
bcm_error_t sdk_rc = BCM_E_NONE;
int i;
/* Parameter checks */
BUG_ON(p_service_cfg == NULL);
/* Set the QoS Port Map for the NNI LIF */
for(i = 0; i < p_service_cfg->num_nni_gport; i++)
{
sdk_rc = bcm_qos_port_map_set(unit, p_service_cfg->nni_gport[i], gp_bal_bcm_qos_cfg->qos_port_map_id, -1);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(ERROR, log_id_sw_util,
"%s(): bcm_qos_port_map_set for nni_index %d returned with failure code '%s'\n",
__FUNCTION__, i, bcm_errmsg(sdk_rc));
rc = BCM_ERR_INTERNAL;
}
}
return rc;
}
/**************************************************************************/
/**
* @brief Clean up QoS for a PON Link (LLID)
*
* Each SE and VOQ must be disconnected from the hierarchy before
* freeing the SE and VOQ objects.
*
* @param unit SDK unit number
* @param p_service_cfg Pointer to the service configuration entry
*
**************************************************************************/
void bal_sw_dpp_llid_qos_cleanup(int unit, bal_sw_dpp_qos_service_cfg *p_service_cfg)
{
bcm_error_t sdk_rc = BCM_E_NONE;
int cosq;
bcm_cosq_gport_connection_t connection;
bal_sw_dpp_qos_sched_pon_chan ds_pon_chan;
bcm_gport_t scheduler_gport;
/* Parameter checks */
BUG_ON(p_service_cfg == NULL);
/* Store the downstream PON rate, which will be used in several
* places throughout this function.
*/
ds_pon_chan = p_service_cfg->ds_qos.pon_chan;
/* Get the scheduler gport that the VOQs are attached to */
if (p_service_cfg->ds_qos.min.rate > 0)
{
scheduler_gport = p_service_cfg->ds_qos.min.scheduler_gport;
}
else
{
scheduler_gport = p_service_cfg->ds_qos.max.scheduler_gport;
}
/* Disconnect VOQ from the VOQ connector for the egress direction */
connection.flags = BCM_COSQ_GPORT_CONNECTION_EGRESS | BCM_COSQ_GPORT_CONNECTION_INVALID;
connection.remote_modid = gp_bal_bcm_qos_cfg->mod_id;
connection.voq = p_service_cfg->ds_qos.voq_gport;
connection.voq_connector = p_service_cfg->ds_qos.voq_connector_gport;
sdk_rc = bcm_cosq_gport_connection_set(unit, &connection);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(WARNING, log_id_sw_util,
"%s(): bcm_cosq_gport_connection_set for DISCONNECT EGRESS failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
/* Continue cleanup, don't halt processing because of this error */
}
/* Disconnect VOQ from the VOQ connector for the ingress direction */
connection.flags = BCM_COSQ_GPORT_CONNECTION_INGRESS | BCM_COSQ_GPORT_CONNECTION_INVALID;
connection.remote_modid = gp_bal_bcm_qos_cfg->mod_id;
connection.voq = p_service_cfg->ds_qos.voq_gport;
connection.voq_connector = p_service_cfg->ds_qos.voq_connector_gport;
sdk_rc = bcm_cosq_gport_connection_set(unit, &connection);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(WARNING, log_id_sw_util,
"%s(): bcm_cosq_gport_connection_set for DISCONNECT INGRESS failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
/* Continue cleanup, don't halt processing because of this error */
}
/* Delete the VOQ */
sdk_rc = bcm_cosq_gport_delete(unit, p_service_cfg->ds_qos.voq_gport);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(WARNING, log_id_sw_util,
"%s(): bcm_cosq_gport_delete for VOQ failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
/* Continue cleanup, don't halt processing because of this error */
}
/* Disconnect the VOQ connector */
for (cosq = 0; cosq < BAL_BCM_QOS_QUEUES_PER_LLID; cosq++)
{
sdk_rc = bcm_cosq_gport_detach(unit,
scheduler_gport,
p_service_cfg->ds_qos.voq_connector_gport,
cosq);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(WARNING, log_id_sw_util,
"%s(): bcm_cosq_gport_detach for VOQ Connector failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
/* Continue cleanup, don't halt processing because of this error */
}
}
/* Delete the VOQ connector */
sdk_rc = bcm_cosq_gport_delete(unit, p_service_cfg->ds_qos.voq_connector_gport);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(WARNING, log_id_sw_util,
"%s(): bcm_cosq_gport_delete for VOQ Connector failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
/* Continue cleanup, don't halt processing because of this error */
}
/* If a MIN rate was configured for this PON Link, disconnect the
* PON Link scheduler from the MIN Rate scheduler.
*/
if (p_service_cfg->ds_qos.min.rate > 0)
{
/* Detach from the parent SE */
sdk_rc = bcm_cosq_gport_detach(unit,
p_service_cfg->ds_qos.min.parent_gport,
p_service_cfg->ds_qos.min.scheduler_gport,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(WARNING, log_id_sw_util,
"%s(): bcm_cosq_gport_detach for MIN Rate SE failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
/* Continue cleanup, don't halt processing because of this error */
}
}
/* Disconnect the PON Link scheduler from the MAX Rate scheduler. */
sdk_rc = bcm_cosq_gport_detach(unit,
p_service_cfg->ds_qos.max.parent_gport,
p_service_cfg->ds_qos.max.scheduler_gport,
0);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(WARNING, log_id_sw_util,
"%s(): bcm_cosq_gport_detach for MAX Rate SE failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
/* Continue cleanup, don't halt processing because of this error */
}
/* Delete the PON Link scheduler */
sdk_rc = bcm_cosq_gport_delete(unit, scheduler_gport);
if (sdk_rc != BCM_E_NONE)
{
/* Error */
BCM_LOG(WARNING, log_id_sw_util,
"%s(): bcm_cosq_gport_delete for PON Link SE failed with %s for pon %u tid %u\n",
__FUNCTION__, bcm_errmsg(sdk_rc), p_service_cfg->pon_port, p_service_cfg->tunnel_id);
/* Continue cleanup, don't halt processing because of this error */
}
/* Free the voq ID to the free pool */
if (ds_pon_chan == BAL_BCM_SCHED_PON_CHAN_10G)
{
bal_sw_dpp_qos_free_flow_id(&gp_bal_bcm_qos_cfg->flow_id_pool_10g, &p_service_cfg->ds_qos.voq_flow_id);
}
else
{
bal_sw_dpp_qos_free_flow_id(&gp_bal_bcm_qos_cfg->flow_id_pool_1g, &p_service_cfg->ds_qos.voq_flow_id);
}
}
/**
* @brief Clear statistics for a VOQ
*
* This function is used to clear VOQ counters
*
* @param unit SDK unit number
* @param gport VOQ gport PON port number
*
*/
void bal_sw_dpp_qos_clear_voq_stats(int unit, bcm_gport_t gport)
{
int cosq;
/* Clear all VOQ counters for the VOQ group */
for (cosq = 0; cosq < BAL_BCM_QOS_QUEUES_PER_LLID; cosq++)
{
bcm_cosq_gport_stat_set(unit, gport, cosq, bcmCosqGportReceivedBytes, 0);
bcm_cosq_gport_stat_set(unit, gport, cosq, bcmCosqGportReceivedPkts, 0);
bcm_cosq_gport_stat_set(unit, gport, cosq, bcmCosqGportEnqueuedBytes, 0);
bcm_cosq_gport_stat_set(unit, gport, cosq, bcmCosqGportEnqueuedPkts, 0);
bcm_cosq_gport_stat_set(unit, gport, cosq, bcmCosqGportDroppedBytes, 0);
bcm_cosq_gport_stat_set(unit, gport, cosq, bcmCosqGportDroppedPkts, 0);
}
}
/**
* @brief Display the qos configuration for each on the console (stdout)
*/
void bal_sw_dpp_print_all_port_qos(int unit)
{
bal_sw_dpp_port_qos_cfg *p_port_qos = NULL;
uint8_t port_num;
uint8_t pon_chan;
bcm_gport_t e2e_pon_gport;
bcm_gport_t e2e_parent_gport;
uint32_t min, flags;
uint32_t bandwidth;
int32_t max_burst;
int32_t mode;
int32_t weight;
uint8_t wfq_lvl;
/* Display header */
printf("Port\\Chan\tgport\t\tRate (kbps)\tMaxBurst (bytes)\tWeight\n");
printf("---------\t-----\t\t-----------\t----------------\t------\n");
for (port_num=BAL_PON_PORT_START; port_num<=BAL_PON_PORT_END; port_num++)
{
/* Display Port info */
BCM_COSQ_GPORT_E2E_PORT_SET(e2e_pon_gport, port_num);
if (BCM_E_NONE == bcm_fabric_port_get(unit,
e2e_pon_gport,
0,
&e2e_parent_gport))
{
bandwidth = 0;
max_burst = 0;
weight = 0;
bcm_cosq_gport_bandwidth_get(unit,
e2e_parent_gport,
0,
&min,
&bandwidth,
&flags);
printf("Port %u\t0x%08X\t%11u\t%16d\t%6d\n",
port_num,
0,
bandwidth,
0,
0);
}
/* Display PON channel configuration */
for (pon_chan = 0; pon_chan < BAL_BCM_SCHED_PON_CHAN_NUM; pon_chan++)
{
p_port_qos = &gp_bal_bcm_qos_cfg->pon[port_num][pon_chan];
bandwidth = 0;
max_burst = 0;
weight = 0;
/* Bandwidth (rate) */
bcm_cosq_gport_bandwidth_get(unit,
p_port_qos->pon_chan_scheduler,
0,
0,
&bandwidth,
0);
/* Max Burst */
bcm_cosq_control_get(unit,
p_port_qos->pon_chan_scheduler,
0,
bcmCosqControlBandwidthBurstMax,
&max_burst);
printf("%9s\t0x%08X\t%11u\t%16d\t%6d\n",
(pon_chan == BAL_BCM_SCHED_PON_CHAN_10G) ? "10G" : "1G",
p_port_qos->pon_chan_scheduler,
bandwidth,
max_burst,
weight);
printf("%9s\t0x%08X\t%11u\t%16d\t%6d\n",
"MIN",
p_port_qos->pon_chan_scheduler,
0,
0,
0);
if (p_port_qos->sched_type == BAL_BCM_SCHED_TYPE_SP)
{
printf("%9s\t0x%08X\t%11u\t%16d\t%6d\n",
" MAX (SP)",
p_port_qos->sp_scheduler,
0,
0,
0);
}
else
{
printf("%9s\t0x%08X\t%11u\t%16d\t%6d\n",
" MAX (WFQ)",
0,
0,
0,
0);
printf(" WFQ weight [");
for (wfq_lvl=0; wfq_lvl<BAL_BCM_SCHED_WFQ_PRI_NUM; wfq_lvl++)
{
bcm_cosq_gport_sched_get(unit,
p_port_qos->wfq_scheduler[wfq_lvl],
0,
&mode,
&weight);
printf("w%u=%u(%u)", wfq_lvl, p_port_qos->pon_chan_weight_cfg[wfq_lvl], weight);
if (wfq_lvl != BAL_BCM_SCHED_WFQ_PRI_NUM - 1)
{
printf(", ");
}
}
printf("]\n");
printf(" WFQ gports [");
for (wfq_lvl=0; wfq_lvl<BAL_BCM_SCHED_WFQ_PRI_NUM; wfq_lvl++)
{
printf("w%u=0x%08X", wfq_lvl, p_port_qos->wfq_scheduler[wfq_lvl]);
if (wfq_lvl != BAL_BCM_SCHED_WFQ_PRI_NUM - 1)
{
printf(", ");
}
}
printf("]\n");
}
}
printf("\n");
}
}
/**
* @brief Display the Flow/VOQ ID pool information
*/
void bal_sw_dpp_qos_print_flowid_pool(int unit)
{
bal_sw_dpp_qos_flowid_pool_entry *p_pool_entry = NULL;
uint8_t count, free_count;
int sdkVal;
printf("\nvoq ID Information:\n");
printf(" Min 10G voq ID = %u\n", DEFAULT_QOS_VOQ_BASE_10G);
printf(" Max 10G voq ID = %u\n", DEFAULT_QOS_VOQ_MAX_10G);
printf(" Min 1G voq ID = %u\n", DEFAULT_QOS_VOQ_BASE_1G);
printf(" Max 1G voq ID = %u\n", DEFAULT_QOS_VOQ_MAX_1G);
bcm_fabric_control_get(unit, bcmFabricQueueMin, &sdkVal);
printf(" Min VOQ ID = %d\n", sdkVal);
bcm_fabric_control_get(unit ,bcmFabricQueueMax, &sdkVal);
printf(" Max VOQ ID = %d\n", sdkVal);
printf("\n10G voq ID Table Info:\n");
printf(" next_flow_id_value = %u\n", gp_bal_bcm_qos_cfg->flow_id_pool_10g.next_flow_id_value);
printf(" max_value = %u\n", gp_bal_bcm_qos_cfg->flow_id_pool_10g.max_value);
printf(" Free 10g voq IDs = ");
printf(" ");
count = 0;
free_count = 0;
TAILQ_FOREACH(p_pool_entry, &gp_bal_bcm_qos_cfg->flow_id_pool_10g.free_table, entry)
{
printf("%d, ", p_pool_entry->flow_id);
if (count < 15)
{
count++;
}
else
{
printf("\n ");
count = 0;
}
free_count++;
}
printf("\n");
printf(" Number of Free 10g voq IDs = %d\n", free_count);
printf("\n1G voq ID Table Info:\n");
printf(" next_flow_id_value = %u\n", gp_bal_bcm_qos_cfg->flow_id_pool_1g.next_flow_id_value);
printf(" max_value = %u\n", gp_bal_bcm_qos_cfg->flow_id_pool_1g.max_value);
printf(" Free 1g voq IDs = ");
printf(" ");
count = 0;
free_count = 0;
TAILQ_FOREACH(p_pool_entry, &gp_bal_bcm_qos_cfg->flow_id_pool_1g.free_table, entry)
{
printf("%d, ", p_pool_entry->flow_id);
if (count < 15)
{
count++;
}
else
{
printf("\n ");
count = 0;
}
free_count++;
}
printf("\n");
printf(" Number of Free 1g voq IDs = %d\n", free_count);
}
#endif /* TEST_SW_UTIL_LOOPBACK */
/*@}*/