| /****************************************************************************** |
| * |
| * <: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 */ |
| |
| /*@}*/ |