openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

cosq.c (212175B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  */
      7 
      8 #include <soc/defs.h>
      9 
     10 #include <assert.h>
     11 
     12 #include <sal/core/libc.h>
     13 #if defined(BCM_GREYHOUND2_SUPPORT)
     14 #include <shared/util.h>
     15 #include <soc/mem.h>
     16 #include <soc/cm.h>
     17 #include <soc/drv.h>
     18 #include <soc/scache.h>
     19 #include <soc/register.h>
     20 #include <soc/memory.h>
     21 #include <soc/greyhound2.h>
     22 #include <bcm_int/esw/port.h>
     23 #include <bcm_int/esw/cosq.h>
     24 #include <bcm_int/esw/ecn.h>
     25 #include <bcm_int/esw/tas.h>
     26 #include <bcm_int/esw/firebolt.h>
     27 #include <bcm_int/esw/greyhound2.h>
     28 #include <bcm_int/esw_dispatch.h>
     29 
     30 #ifdef BCM_WARM_BOOT_SUPPORT
     31 #include <bcm_int/esw/switch.h>
     32 #endif /* BCM_WARM_BOOT_SUPPORT */
     33 
     34 #define GH2_DRR_KBYTES   (1)
     35 #define GH2_DRR_WEIGHT_MAX       0x7f
     36 #define GH2_WRR_WEIGHT_MAX       0x7f
     37 
     38 #define GH2_MTU_QUANTA_ID_COUNT 4
     39 #define GH2_COS_WEIGHT_MAX      0x7f
     40 
     41 static int MTU_GH2_Quanta[GH2_MTU_QUANTA_ID_COUNT] = {
     42     2 *  GH2_DRR_KBYTES,     /* Quanta of 2048 bytes */
     43     4 *  GH2_DRR_KBYTES,     /* Quanta of 4096 bytes */
     44     8 *  GH2_DRR_KBYTES,     /* Quanta of 8192 bytes */
     45    16 *  GH2_DRR_KBYTES      /* Quanta of 16384 bytes */
     46 };
     47 
     48 
     49 /* COS Map profile entries per set */
     50 #define GH2_COS_MAP_ENTRIES_PER_SET    16
     51 
     52 #define GH2_BURST_GRANULARITY         64 /* 64bytes */
     53 #define GH2_BURST_GRANULARITY_DEFAULT GH2_BURST_GRANULARITY
     54 #define GH2_BURST_GRANULARITY_128B    128 /* 128 bytes */
     55 #define GH2_BW_FIELD_MAX              0x3FFFF
     56 
     57 /* Cache of COS_MAP Profile Table */
     58 STATIC soc_profile_mem_t *gh2_cos_map_profile[BCM_MAX_NUM_UNITS] = {NULL};
     59 
     60 /* WRED definition */
     61 /* WRED update interval unit : us */
     62 STATIC int gh2_wred_update_interval[BCM_MAX_NUM_UNITS];
     63 STATIC soc_profile_mem_t *gh2_wred_profile[BCM_MAX_NUM_UNITS];
     64 
     65 #define GH2_CELL_FIELD_MAX       0x7fff
     66 
     67 /* MMU cell size in bytes */
     68 #define GH2_BYTES_PER_CELL 144   /* bytes */
     69 #define GH2_BYTES_TO_CELLS(_byte_)  \
     70             (((_byte_) + GH2_BYTES_PER_CELL - 1) / GH2_BYTES_PER_CELL)
     71 
     72 #define GH2_PORT_LVL_SCHEDULER_PER_PORT 1
     73 #define GH2_QGROUP_LVL_SCHEDULER_PER_PORT 1
     74 #define GH2_QLAYER_LVL_SCHEDULER_PER_PORT 8
     75 /* 8 ports support 2 level scheduling */
     76 #define GH2_NUM_TWO_LEVEL_SCHEDULER_PORT \
     77             (SOC_GH2_64Q_MMU_PORT_IDX_MAX - SOC_GH2_64Q_MMU_PORT_IDX_MIN + 1)
     78 /* 10 Scheduler node per port */
     79 #define GH2_NUM_SCHEDULERS_PER_PORT \
     80             (GH2_PORT_LVL_SCHEDULER_PER_PORT + \
     81              GH2_QGROUP_LVL_SCHEDULER_PER_PORT + \
     82              GH2_QLAYER_LVL_SCHEDULER_PER_PORT)
     83 
     84 /*
     85  * The first 8 Scheduler nodes are reserved for PORT_LEVEL scheduler of
     86  * the 8 MMU port .
     87  * The other 72 Scheduler nodes are for QGROUP and QLAYER schedulers
     88  * of the MMU ports.
     89  */
     90 /* 8/80 Schedulres node for PORT_LEVEL */
     91 #define GH2_NUM_PORT_SCHEDULERS 8
     92 /* 8/80 Schedulres node for QGROUP */
     93 #define GH2_NUM_QGROUP_SCHEDULERS \
     94             (GH2_QGROUP_LVL_SCHEDULER_PER_PORT * \
     95              GH2_NUM_TWO_LEVEL_SCHEDULER_PORT)
     96 /* 64/80 Schedulres node for QLAYER */
     97 #define GH2_NUM_QLAYER_SCHEDULERS \
     98             (GH2_QLAYER_LVL_SCHEDULER_PER_PORT * \
     99              GH2_NUM_TWO_LEVEL_SCHEDULER_PORT)
    100 /* 80 Scheduler node total */
    101 #define GH2_NUM_TOTAL_SCHEDULERS (GH2_NUM_PORT_SCHEDULERS + \
    102                                   GH2_NUM_QGROUP_SCHEDULERS + \
    103                                   GH2_NUM_QLAYER_SCHEDULERS)
    104 
    105 /* Queue node total */
    106 #define GH2_NUM_TOTAL_QUEUES (GH2_NUM_TWO_LEVEL_SCHEDULER_PORT * \
    107                               SOC_GH2_QLAYER_COSQ_PER_PORT_NUM)
    108 
    109 
    110 typedef enum {
    111     GH2_COSQ_LEVEL_PORT = 0, /* port level */
    112     GH2_COSQ_LEVEL_QGROUP,   /* QGroup level (L0) */
    113     GH2_COSQ_LEVEL_QLAYER,   /* QLayer level (L1) */
    114     GH2_COSQ_LEVEL_QUEUE     /* Queue level (L2)*/
    115 } gh2_cosq_level_type_t;
    116 
    117 typedef struct gh2_cosq_node_s {
    118     int in_use;
    119     int node_id; /* internal node id */
    120     bcm_gport_t node_gport; /* node gport id */
    121     gh2_cosq_level_type_t node_level; /* QGROUP, QLAYER, QUEUE */
    122     int max_num_child;
    123 
    124     /* parameters for node_level = QGROUP, QLAYER, QUEUE */
    125     bcm_gport_t parent_gport; /* parent node's gport id */
    126 
    127     /* parameters for node_level = PORT, QGROUP, QLAYER */
    128     /* number of child, value 0~8 */
    129     int num_child;
    130     /* all childrens' gport id */
    131     bcm_gport_t child_gport[GH2_QLAYER_LVL_SCHEDULER_PER_PORT];
    132 
    133     /* parameters for node_level = QLAYER, QUEUE */
    134     /* the X-st child of parent node, valid X is 0-7 */
    135     int child_idx;
    136 
    137     /* QLAYER's queue range's min, value=child_idx * 8 */
    138     int qlayer_cosq_min;
    139     /* QLAYER's queue range's max, value=(child_idx+1)*8-1 */
    140     int qlayer_cosq_max;
    141 } gh2_cosq_node_t;
    142 
    143 typedef struct gh2_mmu_info_s {
    144     /* scheduler nodes */
    145     gh2_cosq_node_t sched_node[GH2_NUM_TOTAL_SCHEDULERS];
    146     /* queue nodes */
    147     gh2_cosq_node_t queue_node[GH2_NUM_TOTAL_QUEUES];
    148 } gh2_mmu_info_t;
    149 
    150 /* MMU info of scheduler and queue nodes */
    151 STATIC gh2_mmu_info_t *gh2_mmu_info[BCM_MAX_NUM_UNITS];
    152 
    153 /* Number of COSQs configured for this device */
    154 STATIC int gh2_num_cosq[SOC_MAX_NUM_DEVICES];
    155 
    156 #ifdef BCM_WARM_BOOT_SUPPORT
    157 
    158 #define BCM_WB_VERSION_1_0                SOC_SCACHE_VERSION(1, 0)
    159 #define BCM_WB_DEFAULT_VERSION            BCM_WB_VERSION_1_0
    160 
    161 /*
    162  * Function:
    163  *      bcmi_gh2_cosq_sync
    164  * Purpose:
    165  *      Record COSQ module persistent info for Level 2 Warm Boot.
    166  * Parameters:
    167  *      unit - Unit number.
    168  * Returns:
    169  *      BCM_E_XXX
    170  */
    171 int
    172 bcmi_gh2_cosq_sync(int unit)
    173 {
    174     soc_scache_handle_t scache_handle;
    175     uint8               *cosq_scache_ptr;
    176     uint32              num_cosq;
    177     gh2_mmu_info_t *mmu_info;
    178 
    179     mmu_info = gh2_mmu_info[unit];
    180 
    181     if (!mmu_info) {
    182         return BCM_E_INIT;
    183     }
    184 
    185     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0);
    186     BCM_IF_ERROR_RETURN
    187         (_bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
    188                                  0, &cosq_scache_ptr,
    189                                  BCM_WB_DEFAULT_VERSION, NULL));
    190     /* Number COSQ */
    191     num_cosq = gh2_num_cosq[unit];
    192     sal_memcpy(cosq_scache_ptr, &num_cosq, sizeof(num_cosq));
    193 
    194     /* 2-level scheduling scheduler nodes */
    195     cosq_scache_ptr += sizeof(num_cosq);
    196     sal_memcpy(cosq_scache_ptr,
    197                gh2_mmu_info[unit], sizeof(gh2_mmu_info_t));
    198     return BCM_E_NONE;
    199 }
    200 
    201 /*
    202  * Function:
    203  *      bcmi_gh2_cosq_reinit
    204  * Purpose:
    205  *      Recover COSQ software state.
    206  * Parameters:
    207  *      unit - Unit number.
    208  * Returns:
    209  *      BCM_E_XXX
    210  */
    211 STATIC int
    212 bcmi_gh2_cosq_reinit(int unit)
    213 {
    214     int                 rv;
    215     soc_scache_handle_t scache_handle;
    216     uint8               *cosq_scache_ptr;
    217     uint32              num_cosq;
    218     int i, profile_index;
    219     mmu_wred_config_entry_t qentry;
    220     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0);
    221     rv = _bcm_esw_scache_ptr_get(unit, scache_handle, FALSE,
    222                                  0, &cosq_scache_ptr,
    223                                  BCM_WB_DEFAULT_VERSION, NULL);
    224 
    225     if (rv == BCM_E_NOT_FOUND) {
    226         cosq_scache_ptr = NULL;
    227     } else if (BCM_FAILURE(rv)) {
    228         return rv;
    229     }
    230 
    231     if (cosq_scache_ptr != NULL) {
    232         /* Number COSQ */
    233         sal_memcpy(&num_cosq, cosq_scache_ptr, sizeof(num_cosq));
    234         gh2_num_cosq[unit] = num_cosq;
    235 
    236         cosq_scache_ptr += sizeof(num_cosq);
    237 
    238         /* 2-level scheduling scheduler nodes */
    239         if (gh2_mmu_info[unit] != NULL) {
    240             sal_memcpy(gh2_mmu_info[unit], cosq_scache_ptr,
    241                        sizeof(gh2_mmu_info_t));
    242         }
    243     } else {
    244         gh2_num_cosq[unit] = _bcm_esw_cosq_config_property_get(unit);
    245     }
    246 
    247     if (soc_feature(unit, soc_feature_discard_ability)) {
    248         for (i = soc_mem_index_min(unit, MMU_WRED_CONFIGm);
    249              i <= soc_mem_index_max(unit, MMU_WRED_CONFIGm); i++) {
    250             BCM_IF_ERROR_RETURN(
    251                   soc_mem_read(unit, MMU_WRED_CONFIGm,
    252                                MEM_BLOCK_ALL, i, &qentry));
    253 
    254             profile_index = soc_mem_field32_get(unit, MMU_WRED_CONFIGm,
    255                                                 &qentry, PROFILE_INDEXf);
    256 
    257             BCM_IF_ERROR_RETURN
    258                 (soc_profile_mem_reference(unit, gh2_wred_profile[unit],
    259                                            profile_index, 1));
    260         }
    261 
    262         for (i = soc_mem_index_min(unit, MMU_WRED_CONFIG_QGROUPm);
    263              i <= soc_mem_index_max(unit, MMU_WRED_CONFIG_QGROUPm); i++) {
    264             BCM_IF_ERROR_RETURN(
    265                   soc_mem_read(unit, MMU_WRED_CONFIG_QGROUPm,
    266                                MEM_BLOCK_ALL, i, &qentry));
    267 
    268             profile_index = soc_mem_field32_get(unit, MMU_WRED_CONFIG_QGROUPm,
    269                                                 &qentry, PROFILE_INDEXf);
    270 
    271             BCM_IF_ERROR_RETURN
    272                 (soc_profile_mem_reference(unit, gh2_wred_profile[unit],
    273                                            profile_index, 1));
    274         }
    275     }
    276 
    277     return BCM_E_NONE;
    278 }
    279 
    280 #endif /* BCM_WARM_BOOT_SUPPORT */
    281 
    282 /*
    283  * Function:
    284  *     bcmi_gh2_cosq_node_t_init
    285  * Purpose:
    286  *     Initialize node information
    287  * Parameters:
    288  *     node       - (IN) node structure
    289  * Returns:
    290  *     BCM_E_XXX
    291  */
    292 STATIC void
    293 bcmi_gh2_cosq_node_t_init(gh2_cosq_node_t *node)
    294 {
    295     int i;
    296 
    297     node->in_use            = FALSE;
    298     node->node_id           = -1;
    299     node->node_gport        = -1;
    300     node->node_level        = -1;
    301     node->parent_gport      = -1;
    302     node->max_num_child     = 0;
    303     node->num_child         = 0;
    304     node->child_idx         = -1;
    305     node->qlayer_cosq_min   = -1;
    306     node->qlayer_cosq_max   = -1;
    307     for (i = 0; i < GH2_QLAYER_LVL_SCHEDULER_PER_PORT; i++) {
    308         node->child_gport[i] = BCM_GPORT_INVALID;
    309     }
    310 }
    311 
    312 /*
    313  * Function:
    314  *     bcmi_gh2_cosq_node_get
    315  * Purpose:
    316  *     Get internal information of scheduler type GPORT
    317  * Parameters:
    318  *     unit       - (IN) unit number
    319  *     gport      - (IN) queue group/scheduler GPORT identifier
    320  *     modid      - (OUT) module identifier
    321  *     port       - (OUT) port number
    322  *     id         - (OUT) queue group or scheduler identifier
    323  *     node       - (OUT) node structure for the specified GPORT
    324  * Returns:
    325  *     BCM_E_XXX
    326  */
    327 STATIC int
    328 bcmi_gh2_cosq_node_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq,
    329                        bcm_module_t *modid, bcm_port_t *port,
    330                        int *id, gh2_cosq_node_t **node)
    331 {
    332     gh2_mmu_info_t *mmu_info;
    333     gh2_cosq_node_t *node_base = NULL;
    334     bcm_module_t modid_out = 0;
    335     bcm_port_t port_out = 0;
    336     uint32 encap_id = -1;
    337     int index;
    338 
    339     if ((mmu_info = gh2_mmu_info[unit]) == NULL) {
    340         return BCM_E_INIT;
    341     }
    342 
    343     if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) {
    344         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid_out));
    345         port_out = BCM_GPORT_UCAST_QUEUE_GROUP_SYSPORTID_GET(gport);
    346     } else if (BCM_GPORT_IS_SCHEDULER(gport)) {
    347         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid_out));
    348         port_out = BCM_GPORT_SCHEDULER_GET(gport) & 0xff;
    349     } else {
    350         return BCM_E_PORT;
    351     }
    352 
    353     if (!SOC_PORT_VALID(unit, port_out)) {
    354         return BCM_E_PORT;
    355     }
    356 
    357     if (port != NULL) {
    358         *port = port_out;
    359     }
    360 
    361     if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) {
    362         encap_id = BCM_GPORT_UCAST_QUEUE_GROUP_QID_GET(gport);
    363         index = encap_id;
    364         node_base = mmu_info->queue_node;
    365     } else { /* scheduler */
    366         encap_id = (BCM_GPORT_SCHEDULER_GET(gport) >> 8) & 0x3fff;
    367         index = encap_id;
    368         node_base = mmu_info->sched_node;
    369     }
    370 
    371     if (node_base[index].in_use == FALSE) {
    372         return BCM_E_NOT_FOUND;
    373     }
    374 
    375     if (modid != NULL) {
    376         *modid = modid_out;
    377     }
    378     if (id != NULL) {
    379         *id = encap_id;
    380     }
    381     if (node != NULL) {
    382         *node = &node_base[index];
    383     }
    384 
    385     return BCM_E_NONE;
    386 }
    387 
    388 /*
    389  * Function:
    390  *     bcmi_gh2_cosq_index_resolve
    391  * Purpose:
    392  *     Find hardware index for the given gport
    393  * Parameters:
    394  *     unit      - (IN) unit number
    395  *     gport     - (IN) GPORT identifier
    396  *     cosq      - (OUT) result cosq of hw index
    397  * Returns:
    398  *     BCM_E_XXX
    399  */
    400 int
    401 bcmi_gh2_cosq_index_resolve(int unit, bcm_gport_t gport, int *cosq)
    402 {
    403     gh2_cosq_node_t *node, *parent_node;
    404     int cosq_base;
    405     int cosq_offset;
    406 
    407     if (gh2_mmu_info[unit] == NULL) {
    408         return BCM_E_INIT;
    409     }
    410 
    411     if (cosq == NULL) {
    412         return BCM_E_PARAM;
    413     }
    414 
    415     if (!BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) {
    416         /* HW cosq index is only available Queue node */
    417         return BCM_E_PORT;
    418     }
    419 
    420     BCM_IF_ERROR_RETURN
    421         (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL,
    422                                 NULL, NULL, &node));
    423 
    424     if (node != NULL) {
    425         cosq_offset = node->child_idx;
    426         BCM_IF_ERROR_RETURN
    427             (bcmi_gh2_cosq_node_get(unit, node->parent_gport, 0, NULL,
    428                                     NULL, NULL, &parent_node));
    429         cosq_base = parent_node->qlayer_cosq_min;
    430         *cosq = cosq_base + cosq_offset;
    431     } else {
    432         return BCM_E_NOT_FOUND;
    433     }
    434 
    435     return BCM_E_NONE;
    436 }
    437 
    438 /*
    439  * Function:
    440  *     bcmi_gh2_cosq_port_resolve
    441  * Purpose:
    442  *     Resolve gport and get IDs
    443  * Parameters:
    444  *     unit      - (IN) unit number
    445  *     gport     - (IN) GPORT identifier
    446  *     modid     - (OUT) module id
    447  *     port      - (OUT) local port id
    448  *     trunk_id  - (OUT) trunk id
    449  *     id        - (OUT) Queue node or scheduler identifier
    450  * Returns:
    451  *     BCM_E_XXX
    452  */
    453 int
    454 bcmi_gh2_cosq_port_resolve(int unit, bcm_gport_t gport, bcm_module_t *modid,
    455                            bcm_port_t *port, bcm_trunk_t *trunk_id, int *id)
    456 {
    457     gh2_cosq_node_t *node;
    458 
    459     BCM_IF_ERROR_RETURN
    460         (bcmi_gh2_cosq_node_get(unit, gport, 0, modid, port, id, &node));
    461     *trunk_id = -1;
    462 
    463     return BCM_E_NONE;
    464 }
    465 
    466 /*
    467  * Function:
    468  *     bcmi_gh2_cosq_localport_resolve
    469  * Purpose:
    470  *     Resolve GRPOT if it is a local port
    471  * Parameters:
    472  *     unit       - (IN) unit number
    473  *     gport      - (IN) GPORT identifier
    474  *     local_port - (OUT) local port number
    475  * Returns:
    476  *     BCM_E_XXX
    477  */
    478 STATIC int
    479 bcmi_gh2_cosq_localport_resolve(int unit, bcm_gport_t gport,
    480                                 bcm_port_t *local_port)
    481 {
    482     bcm_module_t module;
    483     bcm_port_t port;
    484     bcm_trunk_t trunk;
    485     int id, result;
    486 
    487     if (!BCM_GPORT_IS_SET(gport)) {
    488         if (!SOC_PORT_VALID(unit, gport)) {
    489             return BCM_E_PORT;
    490         }
    491         *local_port = gport;
    492         return BCM_E_NONE;
    493     }
    494 
    495     BCM_IF_ERROR_RETURN
    496         (_bcm_esw_gport_resolve(unit, gport, &module,
    497                                 &port, &trunk, &id));
    498     BCM_IF_ERROR_RETURN(
    499         _bcm_esw_modid_is_local(unit, module, &result));
    500 
    501     if (TRUE != result) {
    502         return BCM_E_PARAM;
    503     }
    504 
    505     *local_port = port;
    506     return BCM_E_NONE;
    507 }
    508 
    509 /*
    510  * Function:
    511  *     bcmi_gh2_cosq_gport_bandwidth_port_resolve
    512  * Purpose:
    513  *     Resolve GRPOT and cosq to get the cosq range for programming
    514  * Parameters:
    515  *     unit       - (IN) unit number
    516  *     gport      - (IN) GPORT identifier
    517  *     cosq       - (IN) cosq id
    518  *     local_port - (OUT) local port number
    519  *     cosq_start - (OUT) start index
    520  *     cosq_end   - (OUT) end index
    521  * Returns:
    522  *     BCM_E_XXX
    523  */
    524 STATIC int
    525 bcmi_gh2_cosq_gport_bandwidth_port_resolve(int unit, bcm_gport_t gport,
    526                                            bcm_cos_queue_t cosq,
    527                                            bcm_port_t *local_port,
    528                                            bcm_cos_queue_t *cosq_start,
    529                                            bcm_cos_queue_t *cosq_end)
    530 {
    531     int is_64q;
    532     gh2_cosq_node_t *node = NULL;
    533 
    534     if (gh2_mmu_info[unit] == NULL) {
    535         return BCM_E_INIT;
    536     }
    537 
    538     if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) {
    539         /* shaping is supported on scheduler node */
    540         return BCM_E_PORT;
    541     }
    542 
    543     /*
    544      * gport is local port:
    545      *     cosq range is 0~7
    546      * gport is GPORT_SCHEDULER QGROUP
    547      *     cosq(num of qlayer cosq of the qgroup) range is 0~7
    548      * gport is GPORT_SCHEDULER QLAYER
    549      *     cosq(num of qlayer cosq of the port) range is 0~7
    550      */
    551     if (BCM_GPORT_IS_SET(gport)) {
    552         if (BCM_GPORT_IS_SCHEDULER(gport)) {
    553             BCM_IF_ERROR_RETURN
    554                 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL,
    555                                         local_port, NULL, &node));
    556         } else {
    557             BCM_IF_ERROR_RETURN
    558                 (bcm_esw_port_local_get(unit, gport, local_port));
    559         }
    560     } else {
    561         *local_port = gport;
    562         if (!SOC_PORT_VALID(unit, gport)) {
    563             return BCM_E_PORT;
    564         }
    565     }
    566 
    567     if (node != NULL) {
    568         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, *local_port,
    569                                                    &is_64q));
    570         if (!is_64q) {
    571             return BCM_E_PORT;
    572         }
    573 
    574         if (cosq < -1) {
    575             return BCM_E_PARAM;
    576         }
    577         if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
    578             if (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM) {
    579                 return BCM_E_PARAM;
    580             } else if (cosq < 0) {
    581                 *cosq_start = 0;
    582                 *cosq_end = SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM - 1;
    583             } else {
    584                 *cosq_start = *cosq_end = cosq;
    585             }
    586         } else {
    587             /* node->node_level is GH2_COSQ_LEVEL_QLAYER */
    588             if (cosq >= gh2_num_cosq[unit]) {
    589                 return BCM_E_PARAM;
    590             } else if (cosq < 0) {
    591                 *cosq_start = 0;
    592                 *cosq_end = gh2_num_cosq[unit] - 1;
    593             } else {
    594                 *cosq_start = *cosq_end = cosq;
    595             }
    596         }
    597     } else {
    598         if (cosq < -1) {
    599             return BCM_E_PARAM;
    600         }
    601         if (cosq >= gh2_num_cosq[unit]) {
    602             return BCM_E_PARAM;
    603         } else if (cosq < 0) {
    604             *cosq_start = 0;
    605             *cosq_end = gh2_num_cosq[unit] - 1;
    606         } else {
    607             *cosq_start = *cosq_end = cosq;
    608         }
    609     }
    610 
    611     return BCM_E_NONE;
    612 }
    613 
    614 /*
    615  * Function:
    616  *     bcmi_gh2_cosq_qlayer_scheduler_resolve
    617  * Purpose:
    618  *     Find hardware cosq index and local port for the given gport
    619  *     The function only resolve QLayer scheduler gport type
    620  * Parameters:
    621  *     unit      - (IN) unit number
    622  *     gport     - (IN) GPORT identifier,
    623  *                 accept QLayer scheduler gport or local port id
    624  *     cosq      - (IN) cosq id or input id, valid 0~7
    625  *     out_port  - (OUT) local port id resolved
    626  *     out_hw_idx- (OUT) cosq of hw index resolved
    627  * Returns:
    628  *     BCM_E_XXX
    629  */
    630 STATIC int
    631 bcmi_gh2_cosq_qlayer_scheduler_resolve(int unit, bcm_gport_t gport,
    632                                        bcm_cos_queue_t cosq,
    633                                        bcm_port_t *out_port, int *out_hw_idx)
    634 {
    635     bcm_gport_t local_gport;
    636     int is_64q_port = 0;
    637     gh2_cosq_node_t *node = NULL;
    638 
    639     LOG_INFO(BSL_LS_BCM_COSQ,
    640              (BSL_META_U(unit,
    641                          "bcmi_gh2_cosq_qlayer_scheduler_resolve: unit=%d \
    642                           gport=0x%x cosq=%d\n"),
    643               unit, gport, cosq));
    644 
    645         /* Get the local port and cosq hw index */
    646         if (BCM_GPORT_IS_SCHEDULER(gport)) {
    647             /* The gport id is a Scheduler node */
    648             BCM_IF_ERROR_RETURN
    649                 (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, NULL, NULL,
    650                                         &node));
    651             /* Only accept QLAYER scheduler in this case */
    652             if (node->node_level != GH2_COSQ_LEVEL_QLAYER) {
    653                 return BCM_E_PORT;
    654             }
    655 
    656             /* Get the child gport of the QLAYER scheduler */
    657             BCM_IF_ERROR_RETURN
    658                 (bcmi_gh2_cosq_gport_child_get(unit, gport, cosq,
    659                                                &local_gport));
    660             /* Get the hw cosq index (0~63) */
    661             BCM_IF_ERROR_RETURN
    662                 (bcmi_gh2_cosq_index_resolve(unit, local_gport, out_hw_idx));
    663         } else {
    664             local_gport = gport;
    665             /* Get the hw cosq index (0~7) */
    666             *out_hw_idx = cosq;
    667         }
    668 
    669         /* Get the local port id */
    670         BCM_IF_ERROR_RETURN
    671             (bcmi_gh2_cosq_localport_resolve(unit, local_gport, out_port));
    672 
    673         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, *out_port,
    674                                                    &is_64q_port));
    675         if (is_64q_port) {
    676             if ((*out_hw_idx < 0) ||
    677                 (*out_hw_idx >= SOC_GH2_2LEVEL_QUEUE_NUM)) {
    678                 return BCM_E_PARAM;
    679             }
    680         } else {
    681             if ((*out_hw_idx < 0) ||
    682                 (*out_hw_idx >= SOC_GH2_LEGACY_QUEUE_NUM)) {
    683                 return BCM_E_PARAM;
    684             }
    685         }
    686 
    687     LOG_INFO(BSL_LS_BCM_COSQ,
    688              (BSL_META_U(unit,
    689                          "bcmi_gh2_cosq_qlayer_scheduler_resolve: unit=%d \
    690                           out_port=0x%x out_hw_idx=%d\n"),
    691               unit, *out_port, *out_hw_idx));
    692     return BCM_E_NONE;
    693 }
    694 
    695 STATIC int
    696 bcmi_gh2_cosq_perq_xmt_counter_base_init(int unit)
    697 {
    698     uint32 regval32 = 0;
    699     soc_port_t port = 0;
    700     int base_index = 0, max_index = 0;
    701 
    702     max_index = soc_mem_index_max(unit, EGR_PERQ_XMT_COUNTERSm);
    703 
    704     PBMP_ALL_ITER(unit, port) {
    705         /* Get the index of MMU_MAX/MIN_BUCKET_QLAYER table by (port, cosq) */
    706         BCM_IF_ERROR_RETURN(
    707             soc_gh2_mmu_bucket_qlayer_index(unit, port, 0, &base_index));
    708 
    709         if (base_index > max_index) {
    710             LOG_ERROR(BSL_LS_BCM_COSQ,
    711                       (BSL_META_U(unit,
    712                                   "bcmi_gh2_cosq_perq_xmt_counter_base_init "
    713                                   "error\n")));
    714             return BCM_E_RESOURCE;
    715         }
    716 
    717         BCM_IF_ERROR_RETURN(
    718             READ_PERQ_XMT_COUNTER_BASEr(unit, port, &regval32));
    719 
    720         soc_reg_field_set(unit, PERQ_XMT_COUNTER_BASEr,
    721                           &regval32, INDEXf, base_index);
    722 
    723         BCM_IF_ERROR_RETURN(
    724             WRITE_PERQ_XMT_COUNTER_BASEr(unit, port, regval32));
    725     }
    726 
    727     return BCM_E_NONE;
    728 }
    729 
    730 /* Function:
    731  *      bcmi_gh2_cosq_init
    732  * Purpose:
    733  *      Initialize (clear) all COS schedule/mapping state.
    734  * Parameters:
    735  *      unit - StrataSwitch unit number.
    736  * Returns:
    737  *      BCM_E_XXX
    738  */
    739 
    740 int
    741 bcmi_gh2_cosq_init(int unit)
    742 {
    743     STATIC int _gh2_max_cosq = -1;
    744     int num_cos = 0;
    745 #ifdef BCM_WARM_BOOT_SUPPORT
    746     int                 rv;
    747     soc_scache_handle_t scache_handle;
    748     uint32              cosq_scache_size;
    749     uint8               *cosq_scache_ptr;
    750 #endif /* BCM_WARM_BOOT_SUPPORT */
    751 
    752     static soc_mem_t wred_mems[6] = {
    753         MMU_WRED_DROP_PROFILE_GREENm,
    754         MMU_WRED_DROP_PROFILE_YELLOWm,
    755         MMU_WRED_DROP_PROFILE_REDm,
    756         MMU_WRED_MARK_PROFILE_GREENm,
    757         MMU_WRED_MARK_PROFILE_YELLOWm,
    758         MMU_WRED_MARK_PROFILE_REDm
    759     };
    760     uint32 interval;
    761     int entry_words[6];
    762     gh2_mmu_info_t *mmu_info;
    763     int alloc_size;
    764     int i;
    765 
    766     if (_gh2_max_cosq < 0) {
    767         _gh2_max_cosq = NUM_COS(unit);
    768         NUM_COS(unit) = 8;
    769     }
    770 
    771     if (!SOC_WARM_BOOT(unit)) {    /* Cold Boot */
    772         BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_detach(unit, 0));
    773         if (soc_feature(unit, soc_feature_discard_ability)) {
    774             BCM_IF_ERROR_RETURN(
    775                 soc_mem_clear(unit, MMU_WRED_CONFIGm, COPYNO_ALL, TRUE));
    776             BCM_IF_ERROR_RETURN(
    777                 soc_mem_clear(unit, MMU_WRED_CONFIG_QGROUPm, COPYNO_ALL, TRUE));
    778         }
    779     }
    780 
    781     num_cos = _bcm_esw_cosq_config_property_get(unit);
    782 
    783     alloc_size = sizeof(gh2_mmu_info_t) * 1;
    784     if (gh2_mmu_info[unit] == NULL) {
    785         gh2_mmu_info[unit] =
    786             sal_alloc(alloc_size, "gh2_mmu_info");
    787 
    788         if (gh2_mmu_info[unit] == NULL) {
    789             return BCM_E_MEMORY;
    790         }
    791 
    792         sal_memset(gh2_mmu_info[unit], 0, alloc_size);
    793     }
    794 
    795     mmu_info = gh2_mmu_info[unit];
    796 
    797     for (i = 0; i < GH2_NUM_TOTAL_SCHEDULERS; i++) {
    798         bcmi_gh2_cosq_node_t_init(&mmu_info->sched_node[i]);
    799     }
    800 
    801     for (i = 0; i < GH2_NUM_TOTAL_QUEUES; i++) {
    802         bcmi_gh2_cosq_node_t_init(&mmu_info->queue_node[i]);
    803     }
    804 
    805     if (soc_feature(unit, soc_feature_discard_ability)) {
    806         /* Create profile for MMU_WRED_DROP_CURVE_PROFILE_x tables */
    807         if (gh2_wred_profile[unit] == NULL) {
    808             gh2_wred_profile[unit] =
    809                 sal_alloc(sizeof(soc_profile_mem_t), "WRED Profile Mem");
    810             if (gh2_wred_profile[unit] == NULL) {
    811                 return BCM_E_MEMORY;
    812             }
    813             soc_profile_mem_t_init(gh2_wred_profile[unit]);
    814         } else {
    815             soc_profile_mem_destroy(unit, gh2_wred_profile[unit]);
    816         }
    817 
    818         entry_words[0] =
    819             sizeof(mmu_wred_drop_profile_green_entry_t) / sizeof(uint32);
    820         entry_words[1] =
    821             sizeof(mmu_wred_drop_profile_yellow_entry_t) / sizeof(uint32);
    822         entry_words[2] =
    823             sizeof(mmu_wred_drop_profile_red_entry_t) / sizeof(uint32);
    824         entry_words[3] =
    825             sizeof(mmu_wred_mark_profile_green_entry_t) / sizeof(uint32);
    826         entry_words[4] =
    827             sizeof(mmu_wred_mark_profile_yellow_entry_t) / sizeof(uint32);
    828         entry_words[5] =
    829             sizeof(mmu_wred_mark_profile_red_entry_t) / sizeof(uint32);
    830         BCM_IF_ERROR_RETURN
    831             (soc_profile_mem_create(unit, wred_mems, entry_words, 6,
    832                                     gh2_wred_profile[unit]));
    833 
    834         /*
    835          * WRED update inetrval
    836          * = 1040entries * core_clk_cycle_time * 1.125(sbus overhead),
    837          * = 1170 * core_clk_cycle_time
    838          * = 1170 / core_frequency
    839          *
    840          * GH2:
    841          * 200M : interval=5
    842          * 300M : interval=3
    843          * 400M : interval=2
    844          * 500M : interval=2
    845          * 600M : interval=1
    846          */
    847         interval =  1170 / SOC_INFO(unit).frequency;
    848         BCM_IF_ERROR_RETURN(
    849             soc_reg_field32_modify(unit, TIME_DOMAINr,
    850                                    REG_PORT_ANY, WRED_UPDATE_INTERVALf,
    851                                    interval));
    852         gh2_wred_update_interval[unit] = interval + 1;
    853     }
    854 
    855     /* Need to configure the base id within EGR_PERQ_XMT_COUNTERSm per port */
    856     BCM_IF_ERROR_RETURN(
    857         bcmi_gh2_cosq_perq_xmt_counter_base_init(unit));
    858 
    859 #ifdef BCM_WARM_BOOT_SUPPORT
    860     if (SOC_WARM_BOOT(unit)) {
    861         BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_reinit(unit));
    862         num_cos = gh2_num_cosq[unit];
    863     } else {
    864         /* Warm boot level 2 cache size */
    865         cosq_scache_size = sizeof(uint32); /* Number COSQ */
    866         cosq_scache_size += sizeof(gh2_mmu_info_t);
    867 
    868         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 0);
    869         rv = _bcm_esw_scache_ptr_get(unit, scache_handle,
    870                                     (0 == SOC_WARM_BOOT(unit)),
    871                                     cosq_scache_size, &cosq_scache_ptr,
    872                                     BCM_WB_DEFAULT_VERSION, NULL);
    873         if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
    874             return rv;
    875         }
    876     }
    877 #endif /* BCM_WARM_BOOT_SUPPORT */
    878 
    879     return bcmi_gh2_cosq_config_set(unit, num_cos);
    880 }
    881 
    882 /*
    883  * Function:
    884  *      bcmi_gh2_cosq_detach
    885  * Purpose:
    886  *      Discard all COS schedule/mapping state.
    887  * Parameters:
    888  *      unit - StrataSwitch unit number.
    889  * Returns:
    890  *      BCM_E_XXX
    891  */
    892 
    893 int
    894 bcmi_gh2_cosq_detach(int unit, int software_state_only)
    895 {
    896     bcm_port_t port;
    897     bcm_pbmp_t port_all;
    898     int weights[8];
    899     int cosq;
    900     int is_64q = 0;
    901     uint32 reg_val;
    902 
    903     if (gh2_mmu_info[unit]) {
    904         sal_free(gh2_mmu_info[unit]);
    905         gh2_mmu_info[unit] = NULL;
    906     }
    907 
    908     for (cosq = 0; cosq < 8; cosq++) {
    909         weights[cosq] = 0;
    910     }
    911 
    912     if (!software_state_only) {
    913         /* clear shaper tables */
    914         BCM_IF_ERROR_RETURN(
    915             soc_mem_clear(unit, MMU_MAX_BUCKET_QLAYERm, MEM_BLOCK_ALL, 0));
    916         BCM_IF_ERROR_RETURN(
    917             soc_mem_clear(unit, MMU_MIN_BUCKET_QLAYERm, MEM_BLOCK_ALL, 0));
    918         BCM_IF_ERROR_RETURN(
    919             soc_mem_clear(unit, MMU_MAX_BUCKET_QGROUPm, MEM_BLOCK_ALL, 0));
    920         BCM_IF_ERROR_RETURN(
    921             soc_mem_clear(unit, MMU_MIN_BUCKET_QGROUPm, MEM_BLOCK_ALL, 0));
    922 
    923         /* disable 2-level scheduling register */
    924         PBMP_ALL_ITER(unit, port) {
    925             BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port,
    926                                                        &is_64q));
    927             if (is_64q) {
    928                 READ_TWO_LAYER_SCH_MODEr(unit, port, &reg_val);
    929                 soc_reg_field_set(unit, TWO_LAYER_SCH_MODEr, &reg_val,
    930                                   SCH_MODEf,  0);
    931                 WRITE_TWO_LAYER_SCH_MODEr(unit, port, reg_val);
    932             }
    933         }
    934         /* Clear scheduling settings on port */
    935         port_all = PBMP_ALL(unit);
    936         BCM_IF_ERROR_RETURN
    937             (bcmi_gh2_cosq_port_sched_set(unit, port_all,
    938                                           BCM_COSQ_WEIGHTED_ROUND_ROBIN,
    939                                           weights, 0));
    940     }
    941 
    942     return BCM_E_NONE;
    943 }
    944 
    945 /*
    946  * Function:
    947  *      bcmi_gh2_cosq_config_set
    948  * Purpose:
    949  *      Set the number of COS queues
    950  * Parameters:
    951  *      unit - Unit number.
    952  *      numq - number of COS queues (1-8).
    953  * Returns:
    954  *      BCM_E_XXX
    955  */
    956 
    957 int
    958 bcmi_gh2_cosq_config_set(int unit, int numq)
    959 {
    960     int cos, prio, ratio, remain;
    961     uint32 index;
    962     soc_mem_t mem = PORT_COS_MAPm;
    963     int entry_words = sizeof(port_cos_map_entry_t) / sizeof(uint32);
    964     bcm_pbmp_t ports;
    965     bcm_port_t port;
    966     port_cos_map_entry_t cos_map_array[GH2_COS_MAP_ENTRIES_PER_SET];
    967     void *entries[GH2_COS_MAP_ENTRIES_PER_SET];
    968     static soc_mem_t wred_mems[6] = {
    969         MMU_WRED_DROP_PROFILE_GREENm,
    970         MMU_WRED_DROP_PROFILE_YELLOWm,
    971         MMU_WRED_DROP_PROFILE_REDm,
    972         MMU_WRED_MARK_PROFILE_GREENm,
    973         MMU_WRED_MARK_PROFILE_YELLOWm,
    974         MMU_WRED_MARK_PROFILE_REDm
    975     };
    976     int ii, wred_prof_count;
    977     uint32 profile_index;
    978     mmu_wred_drop_profile_green_entry_t entry_tcp_green;
    979     mmu_wred_drop_profile_yellow_entry_t entry_tcp_yellow;
    980     mmu_wred_drop_profile_red_entry_t entry_tcp_red;
    981     mmu_wred_mark_profile_green_entry_t entry_mark_green;
    982     mmu_wred_mark_profile_yellow_entry_t entry_mark_yellow;
    983     mmu_wred_mark_profile_red_entry_t entry_mark_red;
    984     void *wred_entries[6];
    985 
    986     /* Validate cosq num */
    987     if (numq < 1) {
    988         return BCM_E_PARAM;
    989     }
    990 
    991     /* Map the eight 802.1 priority levels to the active cosqs */
    992     if (numq > 8) {
    993         numq = 8;
    994     }
    995 
    996     sal_memset(cos_map_array, 0,
    997                GH2_COS_MAP_ENTRIES_PER_SET * sizeof(port_cos_map_entry_t));
    998 
    999     if (gh2_cos_map_profile[unit] == NULL) {
   1000         gh2_cos_map_profile[unit] = sal_alloc(sizeof(soc_profile_mem_t),
   1001                                               "COS_MAP Profile Mem");
   1002         if (gh2_cos_map_profile[unit] == NULL) {
   1003             return BCM_E_MEMORY;
   1004         }
   1005         soc_profile_mem_t_init(gh2_cos_map_profile[unit]);
   1006     }
   1007 
   1008     /* Create profile table cache (or re-init if it already exists) */
   1009     SOC_IF_ERROR_RETURN(soc_profile_mem_create(unit, &mem, &entry_words, 1,
   1010                                                gh2_cos_map_profile[unit]));
   1011 
   1012     if (SOC_WARM_BOOT(unit)) {    /* Warm Boot */
   1013         int     i;
   1014         uint32  val;
   1015 
   1016         /* Gather reference count for cosq map profile table */
   1017         BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit));
   1018         PBMP_ITER(ports, port) {
   1019             SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, port, &val));
   1020             index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf);
   1021             index *= GH2_COS_MAP_ENTRIES_PER_SET;
   1022             for (i = 0; i < GH2_COS_MAP_ENTRIES_PER_SET; i++) {
   1023                 SOC_PROFILE_MEM_REFERENCE(unit, gh2_cos_map_profile[unit],
   1024                                           index + i, 1);
   1025                 SOC_PROFILE_MEM_ENTRIES_PER_SET(unit,
   1026                                                 gh2_cos_map_profile[unit],
   1027                                                 index + i,
   1028                                                 GH2_COS_MAP_ENTRIES_PER_SET);
   1029             }
   1030 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE
   1031             if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) {
   1032                 SOC_IF_ERROR_RETURN(READ_ICOS_MAP_SELr(unit, port, &val));
   1033                 index = soc_reg_field_get(unit, ICOS_MAP_SELr, val, SELECTf);
   1034                 index *= GH2_COS_MAP_ENTRIES_PER_SET;
   1035                 for (i = 0; i < GH2_COS_MAP_ENTRIES_PER_SET; i++) {
   1036                     SOC_PROFILE_MEM_REFERENCE(unit, gh2_cos_map_profile[unit],
   1037                                               index + i, 1);
   1038                     SOC_PROFILE_MEM_ENTRIES_PER_SET(
   1039                         unit,
   1040                         gh2_cos_map_profile[unit],
   1041                         index + i,
   1042                         GH2_COS_MAP_ENTRIES_PER_SET);
   1043                 }
   1044             }
   1045 #endif /* BCM_COSQ_HIGIG_MAP_DISABLE */
   1046         }
   1047 
   1048         gh2_num_cosq[unit] = numq;
   1049 
   1050         return BCM_E_NONE;
   1051     }
   1052 
   1053     /* Cold Boot */
   1054     ratio = 8 / numq;
   1055     remain = 8 % numq;
   1056     cos = 0;
   1057     for (prio = 0; prio < 8; prio++) {
   1058         soc_mem_field32_set(unit, PORT_COS_MAPm,
   1059                             &cos_map_array[prio], COSf, cos);
   1060         if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) {
   1061             soc_mem_field32_set(unit, PORT_COS_MAPm,
   1062                                 &cos_map_array[prio], HG_COSf, 0);
   1063         }
   1064 
   1065         if ((prio + 1) == (((cos + 1) * ratio) +
   1066                            ((remain < (numq - cos)) ? 0 :
   1067                             (remain - (numq - cos) + 1)))) {
   1068             cos++;
   1069         }
   1070         entries[prio] = (void *) &cos_map_array[prio];
   1071     }
   1072 
   1073     /* Map remaining internal priority levels to highest priority cosq */
   1074     cos = numq - 1;
   1075     for (prio = 8; prio < 16; prio++) {
   1076         soc_mem_field32_set(unit, PORT_COS_MAPm,
   1077                             &cos_map_array[prio], COSf, cos);
   1078         if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) {
   1079             soc_mem_field32_set(unit, PORT_COS_MAPm,
   1080                                 &cos_map_array[prio], HG_COSf, 0);
   1081         }
   1082         entries[prio] = (void *) &cos_map_array[prio];
   1083     }
   1084 
   1085     /* Map internal priority levels to CPU CoS queues */
   1086     BCM_IF_ERROR_RETURN(_bcm_esw_cpu_cosq_mapping_default_set(unit, numq));
   1087 
   1088     /* Add a profile mem entry for each port */
   1089     BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit));
   1090     PBMP_ITER(ports, port) {
   1091         SOC_IF_ERROR_RETURN
   1092             (soc_profile_mem_add(unit, gh2_cos_map_profile[unit],
   1093                                  (void *) &entries,
   1094                                  GH2_COS_MAP_ENTRIES_PER_SET, &index));
   1095         SOC_IF_ERROR_RETURN
   1096             (soc_reg_field32_modify(unit, COS_MAP_SELr, port,
   1097                                     SELECTf,
   1098                                     (index / GH2_COS_MAP_ENTRIES_PER_SET)));
   1099 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE
   1100         if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) {
   1101             SOC_IF_ERROR_RETURN
   1102                 (soc_profile_mem_add(unit, gh2_cos_map_profile[unit],
   1103                                      (void *) &entries,
   1104                                      GH2_COS_MAP_ENTRIES_PER_SET, &index));
   1105             SOC_IF_ERROR_RETURN
   1106                 (soc_reg_field32_modify(unit, ICOS_MAP_SELr, port,
   1107                                         SELECTf,
   1108                                         (index / GH2_COS_MAP_ENTRIES_PER_SET)));
   1109         }
   1110 #endif
   1111     }
   1112 
   1113 #ifdef BCM_COSQ_HIGIG_MAP_DISABLE
   1114     /* identity mapping for higig ports */
   1115 
   1116     /* map prio0->cos0, prio1->cos1, ... , prio7->cos7 */
   1117     for (prio = 0; prio < 8; prio++) {
   1118         soc_mem_field32_set(unit, PORT_COS_MAPm,
   1119                             &cos_map_array[prio], COSf, prio);
   1120         if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) {
   1121             soc_mem_field32_set(unit, PORT_COS_MAPm,
   1122                                 &cos_map_array[prio], HG_COSf, 0);
   1123         }
   1124     }
   1125     /* Map remaining internal priority levels to highest priority cosq */
   1126     for (prio = 8; prio < 16; prio++) {
   1127         soc_mem_field32_set(unit, PORT_COS_MAPm,
   1128                             &cos_map_array[prio], COSf, 7);
   1129         if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) {
   1130             soc_mem_field32_set(unit, PORT_COS_MAPm,
   1131                                 &cos_map_array[prio], HG_COSf, 0);
   1132         }
   1133     }
   1134     PBMP_ITER(ports, port) {
   1135         if (IS_HG_PORT(unit, port) || port == CMIC_PORT(unit)) {
   1136             SOC_IF_ERROR_RETURN
   1137                 (soc_profile_mem_add(unit, gh2_cos_map_profile[unit],
   1138                                      (void *) &entries,
   1139                                      GH2_COS_MAP_ENTRIES_PER_SET, &index));
   1140             soc_reg_field32_modify(unit, ICOS_MAP_SELr, port,
   1141                                    SELECTf,
   1142                                    (index / GH2_COS_MAP_ENTRIES_PER_SET));
   1143         }
   1144     }
   1145 #endif
   1146 
   1147     gh2_num_cosq[unit] = numq;
   1148 
   1149     if (soc_feature(unit, soc_feature_discard_ability)) {
   1150       /* Add default entries for MMU_WRED_DROP_CURVE_PROFILE_x memory profile */
   1151         sal_memset(&entry_tcp_green, 0, sizeof(entry_tcp_green));
   1152         sal_memset(&entry_tcp_yellow, 0, sizeof(entry_tcp_yellow));
   1153         sal_memset(&entry_tcp_red, 0, sizeof(entry_tcp_red));
   1154         sal_memset(&entry_mark_green, 0, sizeof(entry_mark_green));
   1155         sal_memset(&entry_mark_yellow, 0, sizeof(entry_mark_yellow));
   1156         sal_memset(&entry_mark_red, 0, sizeof(entry_mark_red));
   1157         wred_entries[0] = &entry_tcp_green;
   1158         wred_entries[1] = &entry_tcp_yellow;
   1159         wred_entries[2] = &entry_tcp_red;
   1160         wred_entries[3] = &entry_mark_green;
   1161         wred_entries[4] = &entry_mark_yellow;
   1162         wred_entries[5] = &entry_mark_red;
   1163         for (ii = 0; ii < 6; ii++) {
   1164             soc_mem_field32_set(unit, wred_mems[ii], wred_entries[ii],
   1165                                 MIN_THDf, GH2_CELL_FIELD_MAX);
   1166             soc_mem_field32_set(unit, wred_mems[ii], wred_entries[ii],
   1167                                 MAX_THDf, GH2_CELL_FIELD_MAX);
   1168         }
   1169         profile_index = 0xffffffff;
   1170         wred_prof_count = soc_mem_index_count(unit, MMU_WRED_CONFIGm);
   1171         while (wred_prof_count) {
   1172             if (profile_index == 0xffffffff) {
   1173                 BCM_IF_ERROR_RETURN
   1174                     (soc_profile_mem_add(unit,
   1175                                          gh2_wred_profile[unit],
   1176                                          wred_entries, 1, &profile_index));
   1177             } else {
   1178                 BCM_IF_ERROR_RETURN
   1179                     (soc_profile_mem_reference(unit,
   1180                                                gh2_wred_profile[unit],
   1181                                                profile_index, 0));
   1182             }
   1183             wred_prof_count -= 1;
   1184         }
   1185         profile_index = 0xffffffff;
   1186         wred_prof_count =
   1187             soc_mem_index_count(unit, MMU_WRED_CONFIG_QGROUPm);
   1188         while (wred_prof_count) {
   1189             if (profile_index == 0xffffffff) {
   1190                 BCM_IF_ERROR_RETURN
   1191                     (soc_profile_mem_add(unit,
   1192                                          gh2_wred_profile[unit],
   1193                                          wred_entries, 1, &profile_index));
   1194             } else {
   1195                 BCM_IF_ERROR_RETURN
   1196                     (soc_profile_mem_reference(unit,
   1197                                                gh2_wred_profile[unit],
   1198                                                profile_index, 0));
   1199             }
   1200             wred_prof_count -= 1;
   1201         }
   1202 
   1203         BCM_IF_ERROR_RETURN(
   1204             _bcm_esw_ecn_init(unit));
   1205 
   1206     }
   1207 
   1208     return BCM_E_NONE;
   1209 }
   1210 
   1211 /*
   1212  * Function:
   1213  *      bcmi_gh2_cosq_config_get
   1214  * Purpose:
   1215  *      Get the number of cos queues
   1216  * Parameters:
   1217  *      unit - StrataSwitch unit number.
   1218  *      numq - (Output) number of cosq
   1219  * Returns:
   1220  *      BCM_E_XXX
   1221  */
   1222 
   1223 int
   1224 bcmi_gh2_cosq_config_get(int unit, int *numq)
   1225 {
   1226     if (gh2_num_cosq[unit] == 0) {
   1227         return BCM_E_INIT;
   1228     }
   1229 
   1230     if (numq != NULL) {
   1231         *numq = gh2_num_cosq[unit];
   1232     }
   1233 
   1234     return BCM_E_NONE;
   1235 }
   1236 
   1237 /*
   1238  * Function:
   1239  *      bcmi_gh2_cosq_port_bandwidth_set
   1240  * Purpose:
   1241  *      Set bandwidth values for given COS policy.
   1242  * Parameters:
   1243  *      unit - StrataSwitch unit number.
   1244  *      port - port to configure
   1245  *      cosq - COS queue to configure
   1246  *      kbits_sec_min - minimum bandwidth, kbits/sec.
   1247  *      kbits_sec_max - maximum bandwidth, kbits/sec.
   1248  *      flags
   1249  * Returns:
   1250  *      BCM_E_XXX
   1251  */
   1252 int
   1253 bcmi_gh2_cosq_port_bandwidth_set(int unit, bcm_gport_t gport,
   1254                                  bcm_cos_queue_t cosq,
   1255                                  uint32 kbits_sec_min,
   1256                                  uint32 kbits_sec_max,
   1257                                  uint32 kbits_sec_burst,
   1258                                  uint32 flags)
   1259 {
   1260     uint32 regval, rval = 0;
   1261     uint32 burst_size = 0;
   1262     uint32 refresh_rate, bucketsize, granularity = 3, meter_flags = 0;
   1263     int    refresh_bitsize, bucket_bitsize;
   1264     uint32 fval = 0;
   1265     uint32 eav_gran = GH2_BURST_GRANULARITY_DEFAULT;
   1266     int memidx;
   1267     soc_mem_t config_mem = INVALIDm;
   1268     soc_reg_t config_reg = INVALIDr;
   1269     uint32 entry[SOC_MAX_MEM_WORDS];
   1270     int is_64q;
   1271     int shift;
   1272     bcm_port_t local_port;
   1273     gh2_cosq_node_t *node = NULL;
   1274     int local_cosq;
   1275     soc_mem_t max_bucket_mem = INVALIDm;
   1276     soc_mem_t min_bucket_mem = INVALIDm;
   1277     soc_reg_t min_gran_reg = INVALIDr;
   1278     soc_reg_t max_gran_reg = INVALIDr;
   1279     int gran_shift = 0;
   1280     soc_reg_t eav_bucket_reg = INVALIDr;
   1281 
   1282     if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) {
   1283         /* shaping is supported on scheduler node */
   1284         return BCM_E_PORT;
   1285     }
   1286 
   1287     /*
   1288      * Parameter gport cases
   1289      * gport is local port:
   1290      *     parameter cosq valid : 0~7
   1291      * gport is GPORT_SCHEDULER QGROUP
   1292      *     parameter cosq valid : 0~7
   1293      * gport is GPORT_SCHEDULER QLAYER
   1294      *     parameter cosq valid : 0~7
   1295      */
   1296     if (BCM_GPORT_IS_SCHEDULER(gport)) {
   1297         BCM_IF_ERROR_RETURN
   1298             (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL,
   1299                                     &local_port, NULL, &node));
   1300         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   1301                                                    &is_64q));
   1302         if (!is_64q) {
   1303             return BCM_E_PORT;
   1304         }
   1305         if (node->node_level == GH2_COSQ_LEVEL_PORT) {
   1306             /* Shaper is not available on this level */
   1307             return BCM_E_UNAVAIL;
   1308         } else if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   1309             max_bucket_mem = MMU_MAX_BUCKET_QGROUPm;
   1310             min_bucket_mem = MMU_MIN_BUCKET_QGROUPm;
   1311             min_gran_reg = SHAPING_Q_GRAN_QGROUPr;
   1312             max_gran_reg = SHAPING_Q_GRAN_QGROUPr;
   1313             gran_shift = cosq;
   1314             eav_bucket_reg = EAVBUCKETCONFIG_EXT_QGROUPr;
   1315         } else {
   1316             max_bucket_mem = MMU_MAX_BUCKET_QLAYERm;
   1317             min_bucket_mem = MMU_MIN_BUCKET_QLAYERm;
   1318 
   1319             /* transfered to hw queue index (0~63) */
   1320             local_cosq = node->qlayer_cosq_min + cosq;
   1321             if (local_cosq < 32) {
   1322                 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN0r;
   1323                 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX0r;
   1324                 gran_shift = local_cosq;
   1325             } else {
   1326                 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN1r;
   1327                 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX1r;
   1328                 gran_shift = local_cosq - 32;
   1329             }
   1330 
   1331             eav_bucket_reg = EAVBUCKETCONFIG_EXT_QLAYERr;
   1332         }
   1333     } else {
   1334         BCM_IF_ERROR_RETURN
   1335             (bcmi_gh2_cosq_localport_resolve(unit, gport, &local_port));
   1336 
   1337         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   1338                                                    &is_64q));
   1339 
   1340         max_bucket_mem = MMU_MAX_BUCKET_QLAYERm;
   1341         min_bucket_mem = MMU_MIN_BUCKET_QLAYERm;
   1342 
   1343         if (is_64q) {
   1344             if (cosq < 32) {
   1345                 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN0r;
   1346                 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX0r;
   1347                 gran_shift = cosq;
   1348             } else {
   1349                 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN1r;
   1350                 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX1r;
   1351                 gran_shift = cosq - 32;
   1352             }
   1353             eav_bucket_reg = EAVBUCKETCONFIG_EXT_QLAYERr;
   1354         } else {
   1355             min_gran_reg = SHAPING_Q_GRANr;
   1356             max_gran_reg = SHAPING_Q_GRANr;
   1357             gran_shift = cosq;
   1358             eav_bucket_reg = EAVBUCKETCONFIG_EXTr;
   1359         }
   1360     }
   1361 
   1362     /*
   1363      * To set the new Bandwidth settings, the procedure adopted is
   1364      * a. reset MAXBUCKETCONFIG, MINBUCKETCONFIG, MAXBUCKET, MINBUCKET
   1365      * b. update MAXBUCKETCONFIG and MINBUCKETCONFIG with new values passed
   1366      * c. if MISCCONFIG.METERING_CLK_EN not set before, enable it.
   1367      */
   1368 
   1369     if (node) {
   1370         if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   1371             /*
   1372              * Get the hw index of MMU_MAX/MIN_BUCKET_QGROUP table by
   1373              * (port, cosq)
   1374              */
   1375             BCM_IF_ERROR_RETURN(
   1376                 soc_gh2_mmu_bucket_qgroup_index(unit,
   1377                                                 local_port,
   1378                                                 cosq,
   1379                                                 &memidx));
   1380         } else {
   1381             /* node->node_level is GH2_COSQ_LEVEL_QLAYER */
   1382             /*
   1383              * Get the hw index of MMU_MAX/MIN_BUCKET_QLAYER table by
   1384              * (port, cosq)
   1385              */
   1386             BCM_IF_ERROR_RETURN(
   1387                 soc_gh2_mmu_bucket_qlayer_index(unit,
   1388                                                 local_port,
   1389                                                 node->qlayer_cosq_min + cosq,
   1390                                                 &memidx));
   1391         }
   1392     } else {
   1393         /* Get the index of MMU_MAX/MIN_BUCKET_QLAYER table by (port, cosq) */
   1394         BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qlayer_index
   1395                             (unit, local_port, cosq, &memidx));
   1396     }
   1397 
   1398     /* Disable egress metering for this port */
   1399     config_mem = max_bucket_mem; /* MMU_MAX_BUCKET_QLAYERm; */
   1400     BCM_IF_ERROR_RETURN
   1401         (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1402     soc_mem_field32_set(unit, config_mem, &entry, REFRESHf, 0);
   1403     soc_mem_field32_set(unit, config_mem, &entry, THD_SELf, 0);
   1404     BCM_IF_ERROR_RETURN
   1405         (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1406 
   1407     config_mem = min_bucket_mem; /* MMU_MIN_BUCKET_QLAYERm; */
   1408     BCM_IF_ERROR_RETURN
   1409         (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1410     soc_mem_field32_set(unit, config_mem, &entry, REFRESHf, 0);
   1411     soc_mem_field32_set(unit, config_mem, &entry, THD_SELf, 0);
   1412     BCM_IF_ERROR_RETURN
   1413         (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1414 
   1415     /* reset the MAXBUCKET register */
   1416     config_mem = max_bucket_mem; /* MMU_MAX_BUCKET_QLAYERm; */
   1417     BCM_IF_ERROR_RETURN
   1418         (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1419     soc_mem_field32_set(unit, config_mem, &entry, BUCKETf, 0);
   1420     BCM_IF_ERROR_RETURN
   1421         (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1422 
   1423     /* reset the MINBUCKET register value */
   1424     config_mem = min_bucket_mem; /* MMU_MIN_BUCKET_QLAYERm; */
   1425     BCM_IF_ERROR_RETURN
   1426         (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1427     soc_mem_field32_set(unit, config_mem, &entry, BUCKETf, 0);
   1428     BCM_IF_ERROR_RETURN
   1429         (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1430 
   1431 
   1432     refresh_bitsize =
   1433         soc_mem_field_length(unit, MMU_MIN_BUCKET_QLAYERm, REFRESHf);
   1434     bucket_bitsize =
   1435         soc_mem_field_length(unit, MMU_MIN_BUCKET_QLAYERm, THD_SELf);
   1436 
   1437     meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY_SELECTIVE;
   1438     meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY_SELECT3;
   1439     meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY_SELECT5;
   1440     meter_flags |= _BCM_XGS_METER_FLAG_BUCKET_IN_8KB;
   1441 
   1442     BCM_IF_ERROR_RETURN
   1443         (_bcm_xgs_kbits_to_bucket_encoding(kbits_sec_min, kbits_sec_min,
   1444                                            meter_flags, refresh_bitsize,
   1445                                            bucket_bitsize,
   1446                                            &refresh_rate, &bucketsize,
   1447                                            &granularity));
   1448     config_reg = min_gran_reg;
   1449     shift = gran_shift;
   1450 
   1451     BCM_IF_ERROR_RETURN
   1452         (soc_reg32_get(unit, config_reg, local_port, 0, &regval));
   1453     fval = soc_reg_field_get(unit, config_reg,
   1454                              regval, MIN_Q_GRANf);
   1455     if (granularity == 5) {
   1456         fval |= (1 << shift);
   1457     } else {
   1458         fval &= ~(1 << shift);
   1459     }
   1460     soc_reg_field_set(unit, config_reg, &regval,
   1461                       MIN_Q_GRANf, fval);
   1462     BCM_IF_ERROR_RETURN
   1463         (soc_reg32_set(unit, config_reg, local_port, 0, regval));
   1464 
   1465     config_mem = min_bucket_mem; /* MMU_MIN_BUCKET_QLAYERm; */
   1466     BCM_IF_ERROR_RETURN
   1467         (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1468     soc_mem_field32_set(unit, config_mem, &entry, REFRESHf, refresh_rate);
   1469     soc_mem_field32_set(unit, config_mem, &entry, THD_SELf, bucketsize);
   1470     BCM_IF_ERROR_RETURN
   1471         (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1472 
   1473 
   1474     refresh_bitsize =
   1475         soc_mem_field_length(unit, MMU_MAX_BUCKET_QLAYERm, REFRESHf);
   1476     bucket_bitsize =
   1477         soc_mem_field_length(unit, MMU_MAX_BUCKET_QLAYERm, THD_SELf);
   1478 
   1479     BCM_IF_ERROR_RETURN
   1480         (_bcm_xgs_kbits_to_bucket_encoding(kbits_sec_max, kbits_sec_burst,
   1481                                            meter_flags, refresh_bitsize,
   1482                                            bucket_bitsize,
   1483                                            &refresh_rate, &bucketsize,
   1484                                            &granularity));
   1485     config_reg = max_gran_reg;
   1486     shift = gran_shift;
   1487 
   1488     BCM_IF_ERROR_RETURN
   1489         (soc_reg32_get(unit, config_reg, local_port, 0, &regval));
   1490     fval = soc_reg_field_get(unit, config_reg,
   1491                              regval, MAX_Q_GRANf);
   1492     if (granularity == 5) {
   1493         fval |= (1 << shift);
   1494     } else {
   1495         fval &= ~(1 << shift);
   1496     }
   1497     soc_reg_field_set(unit, config_reg, &regval,
   1498                       MAX_Q_GRANf, fval);
   1499     BCM_IF_ERROR_RETURN
   1500         (soc_reg32_set(unit, config_reg, local_port, 0, regval));
   1501 
   1502     config_mem = max_bucket_mem; /* MMU_MAX_BUCKET_QLAYERm; */
   1503     BCM_IF_ERROR_RETURN
   1504         (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1505 
   1506     soc_mem_field32_set(unit, config_mem, &entry, REFRESHf, refresh_rate);
   1507     if ((flags & (BCM_COSQ_BW_EAV_MODE | BCM_COSQ_BW_EAV_TAS_MODE)) ==
   1508         (BCM_COSQ_BW_EAV_MODE | BCM_COSQ_BW_EAV_TAS_MODE)) {
   1509         return BCM_E_CONFIG;
   1510     }
   1511     if ((flags & BCM_COSQ_BW_EAV_MODE) ||
   1512         (flags & BCM_COSQ_BW_EAV_TAS_MODE)) {
   1513         if (granularity == 5) {
   1514             eav_gran = GH2_BURST_GRANULARITY_128B;
   1515         } else {
   1516             eav_gran = GH2_BURST_GRANULARITY_DEFAULT;
   1517         }
   1518         burst_size = (((kbits_sec_burst * 1000) / 8) +
   1519                          (eav_gran - 1)) / eav_gran;
   1520         if (burst_size > GH2_BW_FIELD_MAX) {
   1521             burst_size = GH2_BW_FIELD_MAX;
   1522         }
   1523 
   1524         if (flags & BCM_COSQ_BW_EAV_MODE) {
   1525         soc_mem_field32_set(unit, config_mem, &entry, EAV_MODEf, 1);
   1526         } else {
   1527             soc_mem_field32_set(unit, config_mem, &entry, EAV_MODEf, 2);
   1528         }
   1529         config_reg = eav_bucket_reg;
   1530 
   1531         SOC_IF_ERROR_RETURN(soc_reg32_get(unit, config_reg,
   1532                                           local_port, cosq, &rval));
   1533         soc_reg_field_set(unit, config_reg, &rval, EAV_THD_SEL_6LSBf,
   1534                           burst_size & 0x3f);
   1535         SOC_IF_ERROR_RETURN(soc_reg32_set(unit, config_reg,
   1536                                           local_port, cosq, rval));
   1537 
   1538         soc_mem_field32_set(unit, config_mem, &entry, THD_SELf,
   1539                             (burst_size >> 6 & 0xFFF));
   1540     } else {
   1541         soc_mem_field32_set(unit, config_mem, &entry, EAV_MODEf, 0);
   1542         soc_mem_field32_set(unit, config_mem, &entry, THD_SELf,
   1543                             bucketsize);
   1544     }
   1545     BCM_IF_ERROR_RETURN
   1546         (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1547 
   1548     config_reg = eav_bucket_reg;
   1549     if (SOC_REG_FIELD_VALID(unit, config_reg, GATE_CLOSE_FREEZE_MODEf)) {
   1550         SOC_IF_ERROR_RETURN(soc_reg32_get(unit, config_reg,
   1551                                           local_port, cosq, &rval));
   1552         if (flags & BCM_COSQ_BW_TAS_TOKEN_FREEZE) {
   1553             soc_reg_field_set(unit, config_reg, &rval, GATE_CLOSE_FREEZE_MODEf,
   1554                               1);
   1555         } else {
   1556             soc_reg_field_set(unit, config_reg, &rval, GATE_CLOSE_FREEZE_MODEf,
   1557                               0);
   1558         }
   1559         SOC_IF_ERROR_RETURN(soc_reg32_set(unit, config_reg,
   1560                                           local_port, cosq, rval));
   1561     }
   1562 
   1563     /* MISCCONFIG.METERING_CLK_EN is set by chip init */
   1564 
   1565     return BCM_E_NONE;
   1566 }
   1567 
   1568 /*
   1569  * Function:
   1570  *      bcmi_gh2_cosq_port_bandwidth_get
   1571  * Purpose:
   1572  *      Retrieve bandwidth values for given COS policy.
   1573  * Parameters:
   1574  *      unit - StrataSwitch unit number.
   1575  *      port - port to configure
   1576  *      cosq - COS queue to configure
   1577  *      kbits_sec_min - (OUT) minimum bandwidth, kbits/sec.
   1578  *      kbits_sec_max - (OUT) maximum bandwidth, kbits/sec.
   1579  *      flags - (OUT)
   1580  * Returns:
   1581  *      BCM_E_XXX
   1582  */
   1583 int
   1584 bcmi_gh2_cosq_port_bandwidth_get(int unit, bcm_gport_t gport,
   1585                                  bcm_cos_queue_t cosq,
   1586                                  uint32 *kbits_sec_min,
   1587                                  uint32 *kbits_sec_max,
   1588                                  uint32 *kbits_sec_burst,
   1589                                  uint32 *flags)
   1590 {
   1591     uint32 regval;
   1592     uint32 refresh_rate = 0, bucketsize = 0,
   1593            granularity = 3, meter_flags = 0;
   1594     uint32 kbits_min_burst; /* Placeholder, since burst is unused for min */
   1595     uint32 rval = 0;
   1596     uint32 bucket_lo = 0;
   1597     uint32 eav_mode = 0;
   1598     uint32 fval = 0;
   1599     uint32 eav_gran = GH2_BURST_GRANULARITY_DEFAULT;
   1600     int memidx;
   1601     int is_64q;
   1602     int shift;
   1603     soc_mem_t config_mem = INVALIDm;
   1604     soc_reg_t config_reg = INVALIDr;
   1605     uint32 entry[SOC_MAX_MEM_WORDS];
   1606     bcm_port_t local_port;
   1607     gh2_cosq_node_t *node = NULL;
   1608     int local_cosq;
   1609     soc_mem_t max_bucket_mem = INVALIDm;
   1610     soc_mem_t min_bucket_mem = INVALIDm;
   1611     soc_reg_t min_gran_reg = INVALIDr;
   1612     soc_reg_t max_gran_reg = INVALIDr;
   1613     int gran_shift = 0;
   1614     soc_reg_t eav_bucket_reg = INVALIDr;
   1615 
   1616     if (BCM_GPORT_IS_SCHEDULER(gport)) {
   1617         BCM_IF_ERROR_RETURN
   1618             (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL,
   1619                                     &local_port, NULL, &node));
   1620         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   1621                                                    &is_64q));
   1622         if (!is_64q) {
   1623             return BCM_E_PORT;
   1624         }
   1625         if (node->node_level == GH2_COSQ_LEVEL_PORT) {
   1626             /* Shaper is not available on this level */
   1627             return BCM_E_UNAVAIL;
   1628         } else if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   1629             max_bucket_mem = MMU_MAX_BUCKET_QGROUPm;
   1630             min_bucket_mem = MMU_MIN_BUCKET_QGROUPm;
   1631             min_gran_reg = SHAPING_Q_GRAN_QGROUPr;
   1632             max_gran_reg = SHAPING_Q_GRAN_QGROUPr;
   1633             gran_shift = cosq;
   1634             eav_bucket_reg = EAVBUCKETCONFIG_EXT_QGROUPr;
   1635         } else {
   1636             max_bucket_mem = MMU_MAX_BUCKET_QLAYERm;
   1637             min_bucket_mem = MMU_MIN_BUCKET_QLAYERm;
   1638 
   1639             /* transfered to hw queue index (0~63) */
   1640             local_cosq = node->qlayer_cosq_min + cosq;
   1641             if (local_cosq < 32) {
   1642                 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN0r;
   1643                 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX0r;
   1644                 gran_shift = local_cosq;
   1645             } else {
   1646                 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN1r;
   1647                 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX1r;
   1648                 gran_shift = local_cosq - 32;
   1649             }
   1650             eav_bucket_reg = EAVBUCKETCONFIG_EXT_QLAYERr;
   1651         }
   1652     } else {
   1653         BCM_IF_ERROR_RETURN
   1654             (bcmi_gh2_cosq_localport_resolve(unit, gport, &local_port));
   1655         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   1656                                                    &is_64q));
   1657         max_bucket_mem = MMU_MAX_BUCKET_QLAYERm;
   1658         min_bucket_mem = MMU_MIN_BUCKET_QLAYERm;
   1659         if (is_64q) {
   1660             if (cosq < 32) {
   1661                 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN0r;
   1662                 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX0r;
   1663                 gran_shift = cosq;
   1664             } else {
   1665                 min_gran_reg = SHAPING_Q_GRAN_QLAYER_MIN1r;
   1666                 max_gran_reg = SHAPING_Q_GRAN_QLAYER_MAX1r;
   1667                 gran_shift = cosq - 32;
   1668             }
   1669             eav_bucket_reg = EAVBUCKETCONFIG_EXT_QLAYERr;
   1670         } else {
   1671             min_gran_reg = SHAPING_Q_GRANr;
   1672             max_gran_reg = SHAPING_Q_GRANr;
   1673             gran_shift = cosq;
   1674             eav_bucket_reg = EAVBUCKETCONFIG_EXTr;
   1675         }
   1676     }
   1677 
   1678     if (node) {
   1679         if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   1680             /*
   1681              * Get the hw index of MMU_MAX/MIN_BUCKET_QGROUP table by
   1682              * (port, cosq)
   1683              */
   1684             BCM_IF_ERROR_RETURN(
   1685                 soc_gh2_mmu_bucket_qgroup_index(unit,
   1686                                                 local_port,
   1687                                                 cosq,
   1688                                                 &memidx));
   1689         } else {
   1690             /* node->node_level is GH2_COSQ_LEVEL_QLAYER */
   1691             /*
   1692              * Get the hw index of MMU_MAX/MIN_BUCKET_QLAYER table by
   1693              * (port, cosq)
   1694              */
   1695             BCM_IF_ERROR_RETURN(
   1696                 soc_gh2_mmu_bucket_qlayer_index(unit,
   1697                                                 local_port,
   1698                                                 node->qlayer_cosq_min + cosq,
   1699                                                 &memidx));
   1700         }
   1701     } else {
   1702         /* Get the index of MMU_MAX/MIN_BUCKET_QLAYER table by (port, cosq) */
   1703         BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qlayer_index
   1704                             (unit, local_port, cosq, &memidx));
   1705     }
   1706 
   1707     if (!kbits_sec_min || !kbits_sec_max || !kbits_sec_burst || !flags) {
   1708         return (BCM_E_PARAM);
   1709     }
   1710 
   1711     *flags = 0;
   1712 
   1713     meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY;
   1714     granularity = 3; /* reset to default */
   1715 
   1716     config_reg = max_gran_reg;
   1717     shift = gran_shift;
   1718 
   1719     BCM_IF_ERROR_RETURN
   1720         (soc_reg32_get(unit, config_reg, local_port, 0, &regval));
   1721     if (soc_reg_field_valid(unit, config_reg, MAX_Q_GRANf)) {
   1722        fval = soc_reg_field_get(unit, config_reg,
   1723                                 regval, MAX_Q_GRANf);
   1724        if (fval & (1 << shift)) {
   1725            granularity = 5;
   1726        }
   1727     }
   1728 
   1729     config_mem = max_bucket_mem; /* MMU_MAX_BUCKET_QLAYERm; */
   1730     BCM_IF_ERROR_RETURN
   1731         (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1732     refresh_rate = soc_mem_field32_get(unit, config_mem,
   1733                                        &entry, REFRESHf);
   1734     bucketsize = soc_mem_field32_get(unit, config_mem,
   1735                                      &entry, THD_SELf);
   1736     eav_mode = soc_mem_field32_get(unit, config_mem,
   1737                                    &entry, EAV_MODEf);
   1738     BCM_IF_ERROR_RETURN
   1739         (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, bucketsize,
   1740                                            granularity, meter_flags,
   1741                                            kbits_sec_max, kbits_sec_burst));
   1742     if ((eav_mode == 1) || (eav_mode == 2)) {
   1743         *flags |= (eav_mode == 1) ? BCM_COSQ_BW_EAV_MODE :
   1744                   BCM_COSQ_BW_EAV_TAS_MODE;
   1745 
   1746         config_reg = eav_bucket_reg;
   1747 
   1748         SOC_IF_ERROR_RETURN(soc_reg32_get(unit, config_reg,
   1749                                           local_port, cosq, &rval));
   1750         bucket_lo = soc_reg_field_get(unit, config_reg,
   1751                                       rval, EAV_THD_SEL_6LSBf);
   1752         if (granularity == 5) {
   1753             eav_gran = GH2_BURST_GRANULARITY_128B;
   1754         } else {
   1755             eav_gran = GH2_BURST_GRANULARITY_DEFAULT;
   1756         }
   1757         *kbits_sec_burst = (((bucketsize << 6) | bucket_lo) *
   1758                                eav_gran * 8) / 1000;
   1759     }
   1760     config_reg = eav_bucket_reg;
   1761     if (SOC_REG_FIELD_VALID(unit, config_reg, GATE_CLOSE_FREEZE_MODEf)) {
   1762         SOC_IF_ERROR_RETURN(soc_reg32_get(unit, config_reg,
   1763                                           local_port, cosq, &rval));
   1764         if (soc_reg_field_get(unit, config_reg,
   1765                               rval, GATE_CLOSE_FREEZE_MODEf)) {
   1766             *flags |= BCM_COSQ_BW_TAS_TOKEN_FREEZE;
   1767         }
   1768     }
   1769 
   1770     config_mem = min_bucket_mem; /* MMU_MIN_BUCKET_QLAYERm; */
   1771     BCM_IF_ERROR_RETURN
   1772         (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry));
   1773     refresh_rate = soc_mem_field32_get(unit, config_mem,
   1774                                        &entry, REFRESHf);
   1775 
   1776     meter_flags = 0; /* reset to default */
   1777     granularity = 3; /* reset to default */
   1778     meter_flags |= _BCM_XGS_METER_FLAG_GRANULARITY;
   1779 
   1780     config_reg = min_gran_reg;
   1781     shift = gran_shift;
   1782 
   1783     BCM_IF_ERROR_RETURN
   1784         (soc_reg32_get(unit, config_reg, local_port, 0, &regval));
   1785     if (soc_reg_field_valid(unit, config_reg, MIN_Q_GRANf)) {
   1786         fval = soc_reg_field_get(unit, config_reg,
   1787                                  regval, MIN_Q_GRANf);
   1788         if (fval & (1 << shift)) {
   1789             granularity = 5;
   1790         }
   1791     }
   1792 
   1793     BCM_IF_ERROR_RETURN
   1794         (_bcm_xgs_bucket_encoding_to_kbits(refresh_rate, 0,
   1795                                            granularity, meter_flags,
   1796                                            kbits_sec_min, &kbits_min_burst));
   1797 
   1798 
   1799     return BCM_E_NONE;
   1800 }
   1801 
   1802 /*
   1803  * Function:
   1804  *      bcmi_gh2_cosq_sched_weight_max_get
   1805  * Purpose:
   1806  *      Retrieve maximum weights for given COS policy.
   1807  * Parameters:
   1808  *      unit - StrataSwitch unit number.
   1809  *      mode - Scheduling mode, one of BCM_COSQ_xxx
   1810  *      weight_max - (output) Maximum weight for COS queue.
   1811  *              For DRR mode Weight is specified in Kbytes
   1812  *              0 if mode is BCM_COSQ_STRICT.
   1813  *              1 if mode is BCM_COSQ_ROUND_ROBIN.
   1814  *              -1 if not applicable to mode.
   1815  * Returns:
   1816  *      BCM_E_XXX
   1817  */
   1818 
   1819 int
   1820 bcmi_gh2_cosq_sched_weight_max_get(int unit, int mode, int *weight_max)
   1821 {
   1822     switch (mode) {
   1823     case BCM_COSQ_STRICT:
   1824         *weight_max = BCM_COSQ_WEIGHT_STRICT;
   1825         break;
   1826     case BCM_COSQ_ROUND_ROBIN:
   1827         *weight_max = BCM_COSQ_WEIGHT_MIN;
   1828         break;
   1829     case BCM_COSQ_WEIGHTED_ROUND_ROBIN:
   1830         *weight_max = GH2_WRR_WEIGHT_MAX;
   1831         break;
   1832     case BCM_COSQ_DEFICIT_ROUND_ROBIN:
   1833         /* max weight in kb will be
   1834         max weight * max value of MTU quanta sel */
   1835         *weight_max = GH2_DRR_WEIGHT_MAX * \
   1836                       MTU_GH2_Quanta[GH2_MTU_QUANTA_ID_COUNT - 1];
   1837         break;
   1838     default:
   1839         *weight_max = BCM_COSQ_WEIGHT_UNLIMITED;
   1840         return BCM_E_PARAM;
   1841     }
   1842 
   1843     return BCM_E_NONE;
   1844 }
   1845 
   1846 /* Function:
   1847  *      bcmi_gh2_cos_max_weight
   1848  * Purpose:
   1849  *      Get the max weight from the input weights.
   1850  * Parameters:
   1851  *      weight - array of weight value.
   1852  * Returns:
   1853  *      BCM_E_XXX
   1854  */
   1855 static int
   1856 bcmi_gh2_cos_max_weight(const int weight[])
   1857 {
   1858     int i, max_weight = 0;
   1859 
   1860     /* find max weight */
   1861     for (i = 0; i < 8; i++) {
   1862         if (max_weight < weight[i]) {
   1863             max_weight = weight[i];
   1864         }
   1865     }
   1866     return max_weight;
   1867 }
   1868 
   1869 /*
   1870  * Calculates the Quanta needed for COS according to its weight
   1871  */
   1872 static int
   1873 bcmi_gh2_cos_drr_weights_to_quanta(const int weight[])
   1874 {
   1875     int i, max_weight = 0;
   1876 
   1877     max_weight = bcmi_gh2_cos_max_weight(weight);
   1878 
   1879     for (i = 0; i < GH2_MTU_QUANTA_ID_COUNT; i++) {
   1880         if (max_weight <= MTU_GH2_Quanta[i] * GH2_COS_WEIGHT_MAX) {
   1881             return i;   /* Right Quanta was found */
   1882         }
   1883     }
   1884     return -1;  /* In case of too big weight return negative value */
   1885 }
   1886 
   1887 /*
   1888  * Convert the encoded weights to number of kbytes that can transmtted
   1889  * in one run.
   1890  */
   1891 static int
   1892 bcmi_gh2_mtu_cos_drr_weight_to_kbytes(int weight, int MTUQuantaSel)
   1893 {
   1894     return (weight * MTU_GH2_Quanta[MTUQuantaSel]);
   1895 }
   1896 
   1897 /*
   1898  * Convert the number of kbytes (1024 bytes) that can transmtted in one run
   1899  * to weight encoding
   1900  */
   1901 static int
   1902 bcmi_gh2_mtu_cos_drr_kbytes_to_weight(int kbytes, int MTUQuantaSel)
   1903 {
   1904     int cos_weight = 0;
   1905     int weight_found = FALSE, low_weight_boundary, hi_weight_boundary;
   1906 
   1907     /* Search for right weight */
   1908     low_weight_boundary = 1;
   1909     hi_weight_boundary = GH2_COS_WEIGHT_MAX;
   1910 
   1911     /* Boundary conditions */
   1912     if (kbytes >= hi_weight_boundary * MTU_GH2_Quanta[MTUQuantaSel]) {
   1913         cos_weight = hi_weight_boundary;
   1914         weight_found = TRUE;
   1915     }
   1916     if (kbytes <= low_weight_boundary * MTU_GH2_Quanta[MTUQuantaSel]) {
   1917         cos_weight = low_weight_boundary;
   1918         weight_found = TRUE;
   1919     }
   1920     while (!weight_found) {
   1921         cos_weight =  (hi_weight_boundary + low_weight_boundary) / 2;
   1922         if (kbytes <= cos_weight * MTU_GH2_Quanta[MTUQuantaSel]) {
   1923            if (kbytes > ((cos_weight - 1) * MTU_GH2_Quanta[MTUQuantaSel])) {
   1924                weight_found = TRUE;
   1925            } else {
   1926                hi_weight_boundary = cos_weight;
   1927            }
   1928         } else {
   1929             if (kbytes <= ((cos_weight + 1) * MTU_GH2_Quanta[MTUQuantaSel])) {
   1930                 cos_weight++;
   1931                 weight_found = TRUE;
   1932             } else {
   1933                 low_weight_boundary = cos_weight;
   1934             }
   1935         }
   1936     } /* Here weight should be found */
   1937     return cos_weight;
   1938 }
   1939 
   1940 /*
   1941  * Function:
   1942  *      bcmi_gh2_cosq_port_sched_set
   1943  * Purpose:
   1944  *      Set class-of-service policy and corresponding weights and delay
   1945  * Parameters:
   1946  *      unit     - StrataSwitch unit number.
   1947  *      pbm      - port bitmap
   1948  *      mode     - (IN) Scheduling mode, one of BCM_COSQ_xxx
   1949  *      weights  - (IN) Weights for each COS queue
   1950  *                      Only for BCM_COSQ_WEIGHTED_ROUND_ROBIN and
   1951  *                      BCM_COSQ_DEFICIT_ROUND_ROBIN mode.
   1952  *                 For DRR Weight is specified in Kbytes
   1953  *      delay    - This parameter is not used
   1954  * Returns:
   1955  *      BCM_E_XXX
   1956  */
   1957 int
   1958 bcmi_gh2_cosq_port_sched_set(int unit, bcm_pbmp_t pbm,
   1959                              int mode, const int weights[], int delay)
   1960 {
   1961     uint32 wrr;
   1962     int    port;
   1963     uint32 cosarbsel;
   1964     int mbits = 0;
   1965     int i, max_weight;
   1966     int enc_weights[8];
   1967     int MTUQuantaSel = 0;
   1968     soc_reg_t config_reg = INVALIDr;
   1969     int is_64q_port;
   1970 
   1971     COMPILER_REFERENCE(delay);
   1972     mbcm_driver[unit]->mbcm_cosq_sched_weight_max_get(unit, mode, &max_weight);
   1973     if ((mode != BCM_COSQ_STRICT) && (mode != BCM_COSQ_ROUND_ROBIN) &&
   1974         (max_weight != BCM_COSQ_WEIGHT_UNLIMITED)) {
   1975         for (i = 0; i < NUM_COS(unit); i++) {
   1976             if ((weights[i] < 0) || (weights[i] > max_weight)) {
   1977                 return BCM_E_PARAM;
   1978             }
   1979         }
   1980     }
   1981 
   1982     /* Initialize all weights 0 (Strict Priority). */
   1983     for (i = 0; i < 8; i++) {
   1984         enc_weights[i] = 0;
   1985     }
   1986 
   1987     switch (mode) {
   1988     case BCM_COSQ_STRICT:
   1989         mbits = 0;
   1990         break;
   1991     case BCM_COSQ_ROUND_ROBIN:
   1992         mbits = 1;
   1993         break;
   1994     case BCM_COSQ_WEIGHTED_ROUND_ROBIN:
   1995         mbits = 2;
   1996         /*
   1997          * All weight values must fit within 7 bits.
   1998          * If weight is 0, this queue is run in strict mode,
   1999          * others run in WRR mode.
   2000          */
   2001 
   2002         for (i = 0; i < NUM_COS(unit); i++) {
   2003             enc_weights[i] = weights[i];
   2004         }
   2005         break;
   2006     case BCM_COSQ_DEFICIT_ROUND_ROBIN:
   2007         mbits = 3;
   2008         if (soc_feature(unit, soc_feature_linear_drr_weight)) {
   2009             MTUQuantaSel = bcmi_gh2_cos_drr_weights_to_quanta(weights);
   2010             if (MTUQuantaSel < 0) {
   2011                 return BCM_E_PARAM;
   2012             }
   2013             for (i = 0; i < NUM_COS(unit); i++) {
   2014                 if (weights[i]) {
   2015                     enc_weights[i] =
   2016                         bcmi_gh2_mtu_cos_drr_kbytes_to_weight(weights[i],
   2017                                                               MTUQuantaSel);
   2018                 } else {
   2019                     enc_weights[i] = weights[i];
   2020                 }
   2021             }
   2022         } /* soc_feature_linear_drr_weight */
   2023         break;
   2024     case BCM_COSQ_BOUNDED_DELAY:        /* not supported in xgs */
   2025     default:
   2026         return BCM_E_PARAM;
   2027     }
   2028 
   2029     PBMP_ITER(pbm, port) {
   2030         cosarbsel = 0;
   2031         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port));
   2032 
   2033         if (is_64q_port) {
   2034             config_reg = XQCOSARBSEL_QLAYERr;
   2035         } else {
   2036             config_reg = XQCOSARBSELr;
   2037         }
   2038         soc_reg_field_set(unit, config_reg, &cosarbsel, COSARBf, mbits);
   2039         if ((mode == BCM_COSQ_DEFICIT_ROUND_ROBIN) &&
   2040                 (soc_feature(unit, soc_feature_linear_drr_weight))) {
   2041             soc_reg_field_set(unit, config_reg, &cosarbsel,
   2042                               MTU_QUANTA_SELECTf, MTUQuantaSel);
   2043         }
   2044         BCM_IF_ERROR_RETURN
   2045             (soc_reg32_set(unit, config_reg, port, 0, cosarbsel));
   2046     }
   2047 
   2048     if ((mode == BCM_COSQ_WEIGHTED_ROUND_ROBIN) ||
   2049         (mode == BCM_COSQ_DEFICIT_ROUND_ROBIN)) {
   2050         /*
   2051          * Weighted Fair Queueing scheduling among vaild COSs
   2052          */
   2053         PBMP_ITER(pbm, port) {
   2054             if (soc_feature(unit, soc_feature_linear_drr_weight)) {
   2055                 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port,
   2056                                                            &is_64q_port));
   2057                 if (is_64q_port) {
   2058                     config_reg = WRRWEIGHT_COS_QLAYERr;
   2059                 } else {
   2060                     config_reg = WRRWEIGHT_COSr;
   2061                 }
   2062                 for (i = 0; i < NUM_COS(unit); i++) {
   2063                     BCM_IF_ERROR_RETURN
   2064                         (soc_reg32_get(unit, config_reg, port, i, &wrr));
   2065                     soc_reg_field_set(unit, config_reg, &wrr,
   2066                                       WEIGHTf, enc_weights[i]);
   2067                     BCM_IF_ERROR_RETURN
   2068                         (soc_reg32_set(unit, config_reg, port, i, wrr));
   2069                 }
   2070             }
   2071         }
   2072     }
   2073 
   2074     return BCM_E_NONE;
   2075 }
   2076 
   2077 /*
   2078  * Function:
   2079  *      bcmi_gh2_cosq_port_sched_get
   2080  * Purpose:
   2081  *      Retrieve class-of-service policy and corresponding weights and delay
   2082  * Parameters:
   2083  *      unit     - StrataSwitch unit number.
   2084  *      pbm      - port bitmap
   2085  *      mode     - (output) Scheduling mode, one of BCM_COSQ_xxx
   2086  *      weights  - (output) Weights for each COS queue
   2087  *                          Only for BCM_COSQ_WEIGHTED_ROUND_ROBIN and
   2088  *                          BCM_COSQ_DEFICIT_ROUND_ROBIN mode.
   2089  *                 For DRR Weight is specified in Kbytes
   2090  *      delay    - This parameter is not used
   2091  * Returns:
   2092  *      BCM_E_XXX
   2093  * Notes:
   2094  *      Actually just returns data for the first port in the bitmap
   2095  */
   2096 
   2097 int
   2098 bcmi_gh2_cosq_port_sched_get(int unit, bcm_pbmp_t pbm,
   2099                              int *mode, int weights[], int *delay)
   2100 {
   2101     uint32 cosarbsel, wrr;
   2102     int    mbits, port, i;
   2103     int    MTUQuantaSel = -1;
   2104     soc_reg_t config_reg = INVALIDr;
   2105     int is_64q_port;
   2106 
   2107     mbits = -1;
   2108     PBMP_ITER(pbm, port) {
   2109         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port));
   2110 
   2111         if (is_64q_port) {
   2112             config_reg = XQCOSARBSEL_QLAYERr;
   2113         } else {
   2114             config_reg = XQCOSARBSELr;
   2115         }
   2116 
   2117         BCM_IF_ERROR_RETURN
   2118             (soc_reg32_get(unit, config_reg, port, 0, &cosarbsel));
   2119         mbits = soc_reg_field_get(unit, config_reg, cosarbsel, COSARBf);
   2120         if (soc_feature(unit, soc_feature_linear_drr_weight)) {
   2121             MTUQuantaSel =
   2122                 soc_reg_field_get(unit, config_reg, cosarbsel,
   2123                                   MTU_QUANTA_SELECTf);
   2124         }
   2125         break;
   2126     }
   2127     switch (mbits) {
   2128     case 0:
   2129         *mode = BCM_COSQ_STRICT;
   2130         break;
   2131     case 1:
   2132         *mode = BCM_COSQ_ROUND_ROBIN;
   2133         break;
   2134     case 2:
   2135         *mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN;
   2136         break;
   2137     case 3:
   2138         *mode = BCM_COSQ_DEFICIT_ROUND_ROBIN;
   2139         break;
   2140     default:
   2141         return BCM_E_INTERNAL;
   2142     }
   2143     if ((mbits == 2) || (mbits == 3)) {
   2144         wrr = 0;
   2145         if (soc_feature(unit, soc_feature_linear_drr_weight)) {
   2146             PBMP_ITER(pbm, port) {
   2147                 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port,
   2148                                                            &is_64q_port));
   2149                 if (is_64q_port) {
   2150                     config_reg = WRRWEIGHT_COS_QLAYERr;
   2151                 } else {
   2152                     config_reg = WRRWEIGHT_COSr;
   2153                 }
   2154 
   2155 
   2156                 for (i = 0; i < NUM_COS(unit); i++) {
   2157                     BCM_IF_ERROR_RETURN
   2158                         (soc_reg32_get(unit, config_reg, port, i, &wrr));
   2159                     weights[i] = soc_reg_field_get(unit, config_reg,
   2160                                                    wrr, WEIGHTf);
   2161                 }
   2162             }
   2163         }
   2164         if (mbits == 3) {
   2165             int i;
   2166             for (i = 0; i < NUM_COS(unit); i++) {
   2167                 if (soc_feature(unit, soc_feature_linear_drr_weight)) {
   2168                         weights[i] =
   2169                             bcmi_gh2_mtu_cos_drr_weight_to_kbytes(
   2170                                 weights[i], MTUQuantaSel);
   2171                 }
   2172             }
   2173         }
   2174     }
   2175     if (delay) {
   2176         *delay = 0;
   2177     }
   2178     return BCM_E_NONE;
   2179 }
   2180 
   2181 /*
   2182  * Function:
   2183  *      bcmi_gh2_cosq_mapping_set
   2184  * Purpose:
   2185  *      Set which cosq a given priority should fall into
   2186  * Parameters:
   2187  *      unit - StrataSwitch unit number.
   2188  *      priority - Priority value to map
   2189  *      cosq - COS queue to map to
   2190  * Returns:
   2191  *      BCM_E_XXX
   2192  */
   2193 
   2194 int
   2195 bcmi_gh2_cosq_mapping_set(int unit, bcm_port_t port,
   2196                           bcm_cos_t priority, bcm_cos_queue_t cosq)
   2197 {
   2198     uint32 val, old_index, new_index;
   2199     int i;
   2200     port_cos_map_entry_t cos_map_array[GH2_COS_MAP_ENTRIES_PER_SET], *entry_p;
   2201     void *entries[GH2_COS_MAP_ENTRIES_PER_SET];
   2202     bcm_pbmp_t ports;
   2203     bcm_port_t local_port;
   2204 
   2205     if (priority < 0 || priority >= 16) {
   2206         return (BCM_E_PARAM);
   2207     }
   2208 
   2209     if (cosq < 0 || cosq >= 8) {
   2210         return (BCM_E_PARAM);
   2211     }
   2212 
   2213     if (port == -1) { /* all ports */
   2214         BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit));
   2215     } else {
   2216         if (BCM_GPORT_IS_SET(port)) {
   2217             BCM_IF_ERROR_RETURN(
   2218                 bcm_esw_port_local_get(unit, port, &local_port));
   2219         } else {
   2220             local_port = port;
   2221         }
   2222 
   2223         if (!SOC_PORT_VALID(unit, local_port) || \
   2224             !IS_ALL_PORT(unit, local_port)) {
   2225             return BCM_E_PORT;
   2226         }
   2227         BCM_PBMP_CLEAR(ports);
   2228         BCM_PBMP_PORT_ADD(ports, local_port);
   2229     }
   2230 
   2231     PBMP_ITER(ports, local_port) {
   2232         SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, local_port, &val));
   2233         old_index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf);
   2234         old_index *= GH2_COS_MAP_ENTRIES_PER_SET;
   2235 
   2236         /* get current mapping profile values */
   2237         for (i = 0; i < GH2_COS_MAP_ENTRIES_PER_SET; i++) {
   2238             entry_p = SOC_PROFILE_MEM_ENTRY(unit, gh2_cos_map_profile[unit],
   2239                                             port_cos_map_entry_t *,
   2240                                             (old_index + i));
   2241             memcpy(&cos_map_array[i], entry_p, sizeof(*entry_p));
   2242             entries[i] = (void *) &cos_map_array[i];
   2243         }
   2244         soc_mem_field32_set(unit, PORT_COS_MAPm,
   2245                             &cos_map_array[priority], COSf, cosq);
   2246         SOC_IF_ERROR_RETURN
   2247             (soc_profile_mem_add(unit, gh2_cos_map_profile[unit],
   2248                                  (void *) &entries,
   2249                                  GH2_COS_MAP_ENTRIES_PER_SET, &new_index));
   2250         SOC_IF_ERROR_RETURN
   2251             (soc_reg_field32_modify(unit, COS_MAP_SELr, local_port,
   2252                                     SELECTf,
   2253                                     new_index / GH2_COS_MAP_ENTRIES_PER_SET));
   2254         SOC_IF_ERROR_RETURN
   2255             (soc_profile_mem_delete(unit,
   2256                                     gh2_cos_map_profile[unit], old_index));
   2257 
   2258 #ifndef BCM_COSQ_HIGIG_MAP_DISABLE
   2259         if (IS_HG_PORT(unit, local_port) || local_port == CMIC_PORT(unit)) {
   2260             SOC_IF_ERROR_RETURN
   2261                 (soc_profile_mem_add(unit, gh2_cos_map_profile[unit],
   2262                                      (void *) &entries,
   2263                                      GH2_COS_MAP_ENTRIES_PER_SET, &new_index));
   2264             SOC_IF_ERROR_RETURN
   2265                 (soc_reg_field32_modify(unit, ICOS_MAP_SELr, local_port,
   2266                                         SELECTf,
   2267                                         new_index / GH2_COS_MAP_ENTRIES_PER_SET)
   2268                                         );
   2269             SOC_IF_ERROR_RETURN
   2270                 (soc_profile_mem_delete(unit,
   2271                                         gh2_cos_map_profile[unit], old_index));
   2272         }
   2273 #endif
   2274     }
   2275     return BCM_E_NONE;
   2276 }
   2277 
   2278 /*
   2279  * Function:
   2280  *      bcmi_gh2_cosq_mapping_get
   2281  * Purpose:
   2282  *      Determine which COS queue a given priority currently maps to.
   2283  * Parameters:
   2284  *      unit - StrataSwitch unit number.
   2285  *      priority - Priority value
   2286  *      cosq - (Output) COS queue number
   2287  * Returns:
   2288  *      BCM_E_XXX
   2289  */
   2290 
   2291 int
   2292 bcmi_gh2_cosq_mapping_get(int unit, bcm_port_t port,
   2293                           bcm_cos_t priority, bcm_cos_queue_t *cosq)
   2294 {
   2295     uint32 val;
   2296     int index;
   2297     port_cos_map_entry_t *entry_p;
   2298     bcm_port_t local_port;
   2299 
   2300     if (priority < 0 || priority >= 16) {
   2301         return (BCM_E_PARAM);
   2302     }
   2303 
   2304     if (port == -1) {
   2305         local_port = REG_PORT_ANY;
   2306     } else {
   2307         if (BCM_GPORT_IS_SET(port)) {
   2308             BCM_IF_ERROR_RETURN(
   2309                 bcm_esw_port_local_get(unit, port, &local_port));
   2310         } else {
   2311             local_port = port;
   2312         }
   2313 
   2314         if (!SOC_PORT_VALID(unit, local_port) || \
   2315             !IS_ALL_PORT(unit, local_port)) {
   2316             return BCM_E_PORT;
   2317         }
   2318     }
   2319 
   2320     SOC_IF_ERROR_RETURN(READ_COS_MAP_SELr(unit, local_port, &val));
   2321     index = soc_reg_field_get(unit, COS_MAP_SELr, val, SELECTf);
   2322     index *= GH2_COS_MAP_ENTRIES_PER_SET;
   2323 
   2324     entry_p = SOC_PROFILE_MEM_ENTRY(unit, gh2_cos_map_profile[unit],
   2325                                     port_cos_map_entry_t *,
   2326                                     (index + priority));
   2327     *cosq = soc_mem_field32_get(unit, PORT_COS_MAPm, entry_p, COSf);
   2328     return BCM_E_NONE;
   2329 }
   2330 
   2331 
   2332 /*
   2333  * Function:
   2334  *      bcmi_gh2_cosq_gport_bandwidth_set
   2335  * Purpose:
   2336  *
   2337  * Parameters:
   2338  *      unit - (IN) Unit number.
   2339  *      gport - (IN) GPORT ID.
   2340  *      cosq - (IN) COS queue to configure, -1 for all COS queues.
   2341  *      kbits_sec_min - (IN) minimum bandwidth, kbits/sec.
   2342  *      kbits_sec_max - (IN) maximum bandwidth, kbits/sec.
   2343  *      flags - (IN) BCM_COSQ_BW_*
   2344  * Returns:
   2345  *      BCM_E_XXX
   2346  */
   2347 int
   2348 bcmi_gh2_cosq_gport_bandwidth_set(int unit, bcm_gport_t gport,
   2349                                 bcm_cos_queue_t cosq, uint32 kbits_sec_min,
   2350                                 uint32 kbits_sec_max, uint32 flags)
   2351 {
   2352     bcm_port_t local_port;
   2353     int i;
   2354     bcm_cos_queue_t cosq_start = 0, cosq_end = 0;
   2355 
   2356     BCM_IF_ERROR_RETURN
   2357         (bcmi_gh2_cosq_gport_bandwidth_port_resolve(unit, gport, cosq,
   2358                                                     &local_port,
   2359                                                     &cosq_start, &cosq_end));
   2360 
   2361     for (i = cosq_start; i <= cosq_end; i++) {
   2362         BCM_IF_ERROR_RETURN
   2363             (bcmi_gh2_cosq_port_bandwidth_set(unit, gport, i,
   2364                                               kbits_sec_min,
   2365                                               kbits_sec_max,
   2366                                               kbits_sec_max,
   2367                                               flags));
   2368     }
   2369 
   2370     return BCM_E_NONE;
   2371 }
   2372 
   2373 /*
   2374  * Function:
   2375  *      bcmi_gh2_cosq_gport_bandwidth_get
   2376  * Purpose:
   2377  *
   2378  * Parameters:
   2379  *      unit - (IN) Unit number.
   2380  *      gport - (IN) GPORT ID.
   2381  *      cosq - (IN) COS queue to configure, -1 for all COS queues.
   2382  *      kbits_sec_min - (OUT) minimum bandwidth, kbits/sec.
   2383  *      kbits_sec_max - (OUT) maximum bandwidth, kbits/sec.
   2384  *      flags - (OUT) BCM_COSQ_BW_*
   2385  * Returns:
   2386  *      BCM_E_XXX
   2387  */
   2388 int
   2389 bcmi_gh2_cosq_gport_bandwidth_get(int unit, bcm_gport_t gport,
   2390                                   bcm_cos_queue_t cosq, uint32 *kbits_sec_min,
   2391                                   uint32 *kbits_sec_max, uint32 *flags)
   2392 {
   2393     bcm_port_t local_port;
   2394     bcm_cos_queue_t cosq_start = 0, cosq_end = 0;
   2395     uint32 kbits_sec_burst;    /* Dummy variable */
   2396 
   2397     *kbits_sec_min = *kbits_sec_max = *flags = 0;
   2398 
   2399     BCM_IF_ERROR_RETURN
   2400         (bcmi_gh2_cosq_gport_bandwidth_port_resolve(unit, gport, cosq,
   2401                                                     &local_port,
   2402                                                     &cosq_start, &cosq_end));
   2403     BCM_IF_ERROR_RETURN
   2404         (bcmi_gh2_cosq_port_bandwidth_get(unit, gport, cosq_start,
   2405                                           kbits_sec_min, kbits_sec_max,
   2406                                           &kbits_sec_burst, flags));
   2407     return BCM_E_NONE;
   2408 }
   2409 
   2410 /*
   2411  * Convert the number of kbytes (1024 bytes) that can transmtted in one run
   2412  * to weight encoding for
   2413  */
   2414 static int
   2415 bcmi_gh2_cos_drr_kbytes_to_weight(int kbytes, int MTUQuantaSel)
   2416 {
   2417     int cos_weight = 0;
   2418     int weight_found = FALSE, low_weight_boundary, hi_weight_boundary;
   2419 
   2420     /* Search for right weight */
   2421     low_weight_boundary = 1;
   2422     hi_weight_boundary = GH2_COS_WEIGHT_MAX;
   2423 
   2424     /* Boundary conditions */
   2425     if (kbytes >= hi_weight_boundary * MTU_GH2_Quanta[MTUQuantaSel]) {
   2426         cos_weight = hi_weight_boundary;
   2427         weight_found = TRUE;
   2428     }
   2429     if (kbytes <= low_weight_boundary * MTU_GH2_Quanta[MTUQuantaSel]) {
   2430         cos_weight = low_weight_boundary;
   2431         weight_found = TRUE;
   2432     }
   2433 
   2434     while (!weight_found) {
   2435         cos_weight =  (hi_weight_boundary + low_weight_boundary) / 2;
   2436         if (kbytes <= cos_weight * MTU_GH2_Quanta[MTUQuantaSel]) {
   2437            if (kbytes > ((cos_weight - 1) * MTU_GH2_Quanta[MTUQuantaSel])) {
   2438                weight_found = TRUE;
   2439            } else {
   2440                hi_weight_boundary = cos_weight;
   2441            }
   2442         } else {
   2443             if (kbytes <= ((cos_weight + 1) * MTU_GH2_Quanta[MTUQuantaSel])) {
   2444                 cos_weight++;
   2445                 weight_found = TRUE;
   2446             } else {
   2447                 low_weight_boundary = cos_weight;
   2448             }
   2449         }
   2450     } /* Here weight should be found */
   2451 
   2452     return cos_weight;
   2453 }
   2454 
   2455 /*
   2456  * Function:
   2457  *     bcmi_gh2_cosq_port_schedule_set
   2458  * Purpose:
   2459  *     Set scheduling mode
   2460  * Parameters:
   2461  *     unit                - (IN) unit number
   2462  *     config_reg          - (IN) register for configuration mode
   2463  *     weight_reg          - (IN) register for configuratin weight
   2464  *     port                - (IN) port number or GPORT identifier
   2465  *     qlayer_sch_id       - (IN) scheduler id
   2466  *     start_cosq          - (IN) COS queue number
   2467  *     num_weights         - (IN) number of entries in weights array
   2468  *     weights             - (IN) weights array
   2469  *     mode                - (IN) scheduling mode (BCM_COSQ_XXX)
   2470  * Returns:
   2471  *     BCM_E_XXX
   2472  */
   2473 STATIC int
   2474 bcmi_gh2_cosq_port_schedule_set(int unit, soc_reg_t config_reg,
   2475                                 soc_reg_t weight_reg, bcm_port_t port,
   2476                                 int qlayer_sch_id,
   2477                                 bcm_cos_queue_t start_cosq,
   2478                                 int num_weights, const int weights[],
   2479                                 int mode)
   2480 {
   2481     int t, i, cosq;
   2482     uint32 wrr;
   2483     uint32 reg_val;
   2484     int mbits = 0;
   2485     int enc_weights[8];
   2486     int MTUQuantaSel = 0;
   2487 
   2488     switch (mode) {
   2489     case BCM_COSQ_STRICT:
   2490         mbits = 0;
   2491         break;
   2492     case BCM_COSQ_ROUND_ROBIN:
   2493         mbits = 1;
   2494         break;
   2495     case BCM_COSQ_WEIGHTED_ROUND_ROBIN:
   2496         mbits = 2;
   2497         /*
   2498          * All weight values must fit within 7 bits.
   2499          * If weight is 0, this queue is run in strict mode,
   2500          * others run in WRR mode.
   2501          */
   2502         t = 0;
   2503         for (i = 0; i < num_weights; i++) {
   2504             t |= weights[i];
   2505         }
   2506         if ((t & ~0x7f) != 0) {
   2507             return BCM_E_PARAM;
   2508         }
   2509         for (i = 0; i < num_weights; i++) {
   2510             enc_weights[i] = weights[i];
   2511         }
   2512         break;
   2513     case BCM_COSQ_DEFICIT_ROUND_ROBIN:
   2514         mbits = 3;
   2515         MTUQuantaSel = bcmi_gh2_cos_drr_weights_to_quanta(weights);
   2516         if (MTUQuantaSel < 0) {
   2517             return BCM_E_PARAM;
   2518         }
   2519 
   2520         for (i = 0; i < num_weights; i++) {
   2521             if (weights[i]) {
   2522                 enc_weights[i] =
   2523                     bcmi_gh2_cos_drr_kbytes_to_weight(weights[i],
   2524                                                       MTUQuantaSel);
   2525             } else {
   2526                 enc_weights[i] = weights[i];
   2527             }
   2528 
   2529         }
   2530         break;
   2531     case BCM_COSQ_BOUNDED_DELAY:        /* not supported in xgs */
   2532     default:
   2533         return BCM_E_PARAM;
   2534     }
   2535 
   2536     /* Program the scheduling mode */
   2537     BCM_IF_ERROR_RETURN
   2538         (soc_reg32_get(unit, config_reg, port, qlayer_sch_id, &reg_val));
   2539     soc_reg_field_set(unit, config_reg, &reg_val, COSARBf, mbits);
   2540     if ((mode == BCM_COSQ_DEFICIT_ROUND_ROBIN) &&
   2541         (soc_feature(unit, soc_feature_linear_drr_weight))) {
   2542         soc_reg_field_set(unit, config_reg, &reg_val,
   2543                           MTU_QUANTA_SELECTf, MTUQuantaSel);
   2544     }
   2545     BCM_IF_ERROR_RETURN
   2546         (soc_reg32_set(unit, config_reg, port, qlayer_sch_id, reg_val));
   2547 
   2548     if ((mode == BCM_COSQ_WEIGHTED_ROUND_ROBIN) ||
   2549         (mode == BCM_COSQ_DEFICIT_ROUND_ROBIN)) {
   2550         /*
   2551          * Weighted Fair Queueing scheduling among vaild COSs
   2552          */
   2553         for (cosq = start_cosq, i = 0; i < num_weights; cosq++, i++) {
   2554             BCM_IF_ERROR_RETURN
   2555                 (soc_reg32_get(unit, weight_reg, port, cosq, &wrr));
   2556             soc_reg_field_set(unit, weight_reg, &wrr,
   2557                               WEIGHTf, enc_weights[i]);
   2558             BCM_IF_ERROR_RETURN
   2559                 (soc_reg32_set(unit, weight_reg, port, cosq, wrr));
   2560         }
   2561     }
   2562     return BCM_E_NONE;
   2563 }
   2564 
   2565 /*
   2566  * Function:
   2567  *      bcmi_gh2_cosq_gport_sched_set
   2568  * Purpose:
   2569  *
   2570  * Parameters:
   2571  *      unit - (IN) Unit number.
   2572  *      gport - (IN) GPORT ID.
   2573  *      cosq - (IN) COS queue to configure, -1 for all COS queues.
   2574  *      mode - (IN) Scheduling mode, one of BCM_COSQ_xxx
   2575  *      weight - (IN) Weight for the specified COS queue(s)
   2576  *               Unused if mode is BCM_COSQ_STRICT.
   2577  * Returns:
   2578  *      BCM_E_XXX
   2579  */
   2580 int
   2581 bcmi_gh2_cosq_gport_sched_set(int unit, bcm_gport_t gport,
   2582                               bcm_cos_queue_t cosq, int mode, int weight)
   2583 {
   2584     bcm_port_t local_port;
   2585     int i;
   2586     gh2_cosq_node_t *node = NULL;
   2587     int qlayer_sch_id = 0;
   2588     bcm_cos_queue_t cosq_start = 0;
   2589     int num_weights = 1, weights[8];
   2590     soc_reg_t config_reg = INVALIDr;
   2591     soc_reg_t weight_reg = INVALIDr;
   2592     int is_64q_port;
   2593 
   2594     if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) {
   2595         /* scheduling is supported on scheduler node */
   2596         return BCM_E_PORT;
   2597     }
   2598 
   2599     sal_memset(&weights, 0, sizeof(int) * 8);
   2600 
   2601     if (BCM_GPORT_IS_SCHEDULER(gport)) {
   2602         BCM_IF_ERROR_RETURN
   2603             (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL,
   2604                                     &local_port, NULL, &node));
   2605         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   2606                                                     &is_64q_port));
   2607         if (!is_64q_port) {
   2608             return BCM_E_PORT;
   2609         }
   2610 
   2611         if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   2612             config_reg = XQCOSARBSEL_QGROUPr;
   2613             weight_reg = WRRWEIGHT_COS_QGROUPr;
   2614         } else {
   2615             config_reg = XQCOSARBSEL_QLAYERr;
   2616             weight_reg = WRRWEIGHT_COS_QLAYERr;
   2617             qlayer_sch_id = node->child_idx;
   2618         }
   2619     } else {
   2620         BCM_IF_ERROR_RETURN
   2621             (bcmi_gh2_cosq_localport_resolve(unit, gport, &local_port));
   2622         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   2623                                                    &is_64q_port));
   2624 
   2625         if (is_64q_port) {
   2626             config_reg = XQCOSARBSEL_QLAYERr;
   2627             weight_reg = WRRWEIGHT_COS_QLAYERr;
   2628         } else {
   2629             config_reg = XQCOSARBSELr;
   2630             weight_reg = WRRWEIGHT_COSr;
   2631         }
   2632     }
   2633 
   2634     if (cosq >= gh2_num_cosq[unit]) {
   2635         return BCM_E_PARAM;
   2636     } else if (cosq < 0) {
   2637         if (node && (node->node_level == GH2_COSQ_LEVEL_QLAYER)) {
   2638             cosq_start = node->qlayer_cosq_min;
   2639         } else {
   2640             cosq_start = 0;
   2641         }
   2642         num_weights = 8;
   2643         for (i = 0; i < num_weights; i++) {
   2644             if (i < gh2_num_cosq[unit]) {
   2645                 weights[i] = weight;
   2646             } else {
   2647                 weights[i] = 0;
   2648             }
   2649         }
   2650     } else {
   2651         if (node && (node->node_level == GH2_COSQ_LEVEL_QLAYER)) {
   2652             cosq_start = node->qlayer_cosq_min + cosq;
   2653         } else {
   2654             cosq_start = cosq;
   2655         }
   2656         num_weights = 1;
   2657         weights[0] = weight;
   2658     }
   2659     BCM_IF_ERROR_RETURN
   2660         (bcmi_gh2_cosq_port_schedule_set(unit, config_reg, weight_reg,
   2661                                          local_port, qlayer_sch_id,
   2662                                          cosq_start, num_weights,
   2663                                          weights, mode));
   2664     return BCM_E_NONE;
   2665 }
   2666 
   2667 /*
   2668  * Function:
   2669  *     bcmi_gh2_cosq_port_schedule_get
   2670  * Purpose:
   2671  *     Set scheduling mode
   2672  * Parameters:
   2673  *     unit                - (IN) unit number
   2674  *     config_reg          - (IN) register for configuration mode
   2675  *     weight_reg          - (IN) register for configuratin weight
   2676  *     port                - (IN) port number or GPORT identifier
   2677  *     qlayer_sch_id       - (IN) scheduler id
   2678  *     start_cosq          - (IN) COS queue number
   2679  *     num_weights         - (IN) number of entries in weights array
   2680  *     weights             - (IN) weights array
   2681  *     mode                - (OUT) scheduling mode (BCM_COSQ_XXX)
   2682  * Returns:
   2683  *     BCM_E_XXX
   2684  */
   2685 STATIC int
   2686 bcmi_gh2_cosq_port_schedule_get(int unit, soc_reg_t config_reg,
   2687                                 soc_reg_t weight_reg, bcm_port_t port,
   2688                                 int qlayer_sch_id,
   2689                                 bcm_cos_queue_t start_cosq,
   2690                                 int num_weights, int weights[], int *mode)
   2691 {
   2692     uint32 escfg, wrr;
   2693     int mbits, i, cosq;
   2694     int MTUQuantaSel = -1;
   2695 
   2696     if (mode == NULL) {
   2697         return BCM_E_PARAM;
   2698     }
   2699 
   2700     BCM_IF_ERROR_RETURN
   2701         (soc_reg32_get(unit, config_reg, port, qlayer_sch_id, &escfg));
   2702     mbits = soc_reg_field_get(unit, config_reg, escfg, COSARBf);
   2703     MTUQuantaSel = soc_reg_field_get(unit, config_reg, escfg,
   2704                                      MTU_QUANTA_SELECTf);
   2705 
   2706     switch (mbits) {
   2707     case 0:
   2708         *mode = BCM_COSQ_STRICT;
   2709         break;
   2710     case 1:
   2711         *mode = BCM_COSQ_ROUND_ROBIN;
   2712         break;
   2713     case 2:
   2714         *mode = BCM_COSQ_WEIGHTED_ROUND_ROBIN;
   2715         break;
   2716     case 3:
   2717         *mode = BCM_COSQ_DEFICIT_ROUND_ROBIN;
   2718         break;
   2719     default:
   2720         return BCM_E_INTERNAL;
   2721     }
   2722 
   2723     if ((mbits == 2) || (mbits == 3)) {
   2724         wrr = 0;
   2725         for (cosq = start_cosq, i = 0; i < num_weights; cosq++, i++) {
   2726             BCM_IF_ERROR_RETURN
   2727                 (soc_reg32_get(unit, weight_reg, port, cosq, &wrr));
   2728             weights[i] = soc_reg_field_get(unit, weight_reg, wrr,
   2729                                            WEIGHTf);
   2730         }
   2731 
   2732         if (mbits == 3) {
   2733             int i;
   2734             for (i = 0; i < num_weights; i++) {
   2735                 weights[i] =
   2736                     bcmi_gh2_mtu_cos_drr_weight_to_kbytes(weights[i],
   2737                                                           MTUQuantaSel);
   2738             }
   2739         }
   2740     }
   2741     return BCM_E_NONE;
   2742 }
   2743 
   2744 /*
   2745  * Function:
   2746  *      bcmi_gh2_cosq_gport_sched_get
   2747  * Purpose:
   2748  *
   2749  * Parameters:
   2750  *      unit - (IN) Unit number.
   2751  *      gport - (IN) GPORT ID.
   2752  *      cosq - (IN) COS queue
   2753  *      mode - (OUT) Scheduling mode, one of BCM_COSQ_xxx
   2754  *      weight - (OUT) Weight for the specified COS queue(s)
   2755  *               Unused if mode is BCM_COSQ_STRICT.
   2756  * Returns:
   2757  *      BCM_E_XXX
   2758  */
   2759 int
   2760 bcmi_gh2_cosq_gport_sched_get(int unit, bcm_gport_t gport,
   2761                               bcm_cos_queue_t cosq, int *mode, int *weight)
   2762 {
   2763     bcm_port_t local_port;
   2764     soc_reg_t config_reg = INVALIDr;
   2765     soc_reg_t weight_reg = INVALIDr;
   2766     int is_64q_port;
   2767     gh2_cosq_node_t *node = NULL;
   2768     int qlayer_sch_id = 0;
   2769     bcm_cos_queue_t cosq_start = 0;
   2770 
   2771     if ((mode == NULL) || (weight == NULL)) {
   2772         return BCM_E_PARAM;
   2773     }
   2774 
   2775     if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) {
   2776         /* scheduling is supported on scheduler node */
   2777         return BCM_E_PORT;
   2778     }
   2779 
   2780     *mode = *weight = 0;
   2781 
   2782     if (BCM_GPORT_IS_SCHEDULER(gport)) {
   2783         BCM_IF_ERROR_RETURN
   2784             (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL,
   2785                                     &local_port, NULL, &node));
   2786         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   2787                                                    &is_64q_port));
   2788         if (!is_64q_port) {
   2789             return BCM_E_PORT;
   2790         }
   2791 
   2792         if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   2793             config_reg = XQCOSARBSEL_QGROUPr;
   2794             weight_reg = WRRWEIGHT_COS_QGROUPr;
   2795         } else {
   2796             config_reg = XQCOSARBSEL_QLAYERr;
   2797             weight_reg = WRRWEIGHT_COS_QLAYERr;
   2798             qlayer_sch_id = node->child_idx;
   2799         }
   2800     } else {
   2801         BCM_IF_ERROR_RETURN
   2802             (bcmi_gh2_cosq_localport_resolve(unit, gport, &local_port));
   2803         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   2804                                                    &is_64q_port));
   2805 
   2806         if (is_64q_port) {
   2807             config_reg = XQCOSARBSEL_QLAYERr;
   2808             weight_reg = WRRWEIGHT_COS_QLAYERr;
   2809         } else {
   2810             config_reg = XQCOSARBSELr;
   2811             weight_reg = WRRWEIGHT_COSr;
   2812         }
   2813     }
   2814 
   2815     if (cosq >= gh2_num_cosq[unit]) {
   2816         return BCM_E_PARAM;
   2817     } else if (cosq < 0) {
   2818         cosq = 0;
   2819     }
   2820 
   2821     if (node && (node->node_level == GH2_COSQ_LEVEL_QLAYER)) {
   2822         cosq_start = node->qlayer_cosq_min + cosq;
   2823     } else {
   2824         cosq_start = cosq;
   2825     }
   2826 
   2827     BCM_IF_ERROR_RETURN
   2828         (bcmi_gh2_cosq_port_schedule_get(unit, config_reg, weight_reg,
   2829                                          local_port, qlayer_sch_id,
   2830                                          cosq_start, 1,
   2831                                          weight, mode));
   2832     return BCM_E_NONE;
   2833 }
   2834 
   2835 /*
   2836  * Function:
   2837  *      bcmi_gh2_cosq_gport_bandwidth_burst_set
   2838  * Purpose:
   2839  *
   2840  * Parameters:
   2841  *      unit - (IN) Unit number.
   2842  *      gport - (IN) GPORT ID.
   2843  *      cosq - (IN) COS queue to configure, -1 for all COS queues.
   2844  *      kbits_burst - (IN) maximum burst, kbits.
   2845  * Returns:
   2846  *      BCM_E_XXX
   2847  */
   2848 int
   2849 bcmi_gh2_cosq_gport_bandwidth_burst_set(int unit, bcm_gport_t gport,
   2850                                         bcm_cos_queue_t cosq,
   2851                                         uint32 kbits_burst)
   2852 {
   2853     bcm_port_t local_port, port;
   2854     int i;
   2855     bcm_cos_queue_t cosq_start = 0, cosq_end = 0;
   2856     uint32 kbits_sec_min, kbits_sec_max, flags;
   2857     uint32 kbits_sec_burst; /* Dummy variable */
   2858 
   2859     if (gport < 0) {
   2860         PBMP_ALL_ITER(unit, port) {
   2861             BCM_IF_ERROR_RETURN
   2862                 (bcmi_gh2_cosq_gport_bandwidth_port_resolve(unit, port, cosq,
   2863                                                             &local_port,
   2864                                                             &cosq_start,
   2865                                                             &cosq_end));
   2866             for (i = cosq_start; i <= cosq_end; i++) {
   2867                 BCM_IF_ERROR_RETURN
   2868                     (bcmi_gh2_cosq_port_bandwidth_get(
   2869                         unit, local_port, i,
   2870                         &kbits_sec_min,
   2871                         &kbits_sec_max,
   2872                         &kbits_sec_burst, &flags));
   2873                 BCM_IF_ERROR_RETURN
   2874                     (bcmi_gh2_cosq_port_bandwidth_set(unit, local_port, i,
   2875                                                       kbits_sec_min,
   2876                                                       kbits_sec_max,
   2877                                                       kbits_burst,
   2878                                                       flags));
   2879             }
   2880         }
   2881         return BCM_E_NONE;
   2882     }
   2883 
   2884     BCM_IF_ERROR_RETURN
   2885         (bcmi_gh2_cosq_gport_bandwidth_port_resolve(unit, gport, cosq,
   2886                                                     &local_port,
   2887                                                     &cosq_start, &cosq_end));
   2888 
   2889     for (i = cosq_start; i <= cosq_end; i++) {
   2890         BCM_IF_ERROR_RETURN
   2891             (bcmi_gh2_cosq_port_bandwidth_get(unit, gport, cosq_start,
   2892                                              &kbits_sec_min, &kbits_sec_max,
   2893                                              &kbits_sec_burst, &flags));
   2894         BCM_IF_ERROR_RETURN
   2895             (bcmi_gh2_cosq_port_bandwidth_set(unit, gport, i,
   2896                                               kbits_sec_min,
   2897                                               kbits_sec_max,
   2898                                               kbits_burst,
   2899                                               flags));
   2900     }
   2901     return BCM_E_NONE;
   2902 }
   2903 
   2904 /*
   2905  * Function:
   2906  *      bcmi_gh2_cosq_gport_bandwidth_burst_get
   2907  * Purpose:
   2908  *
   2909  * Parameters:
   2910  *      unit - (IN) Unit number.
   2911  *      gport - (IN) GPORT ID.
   2912  *      cosq - (IN) COS queue to configure, -1 for all COS queues.
   2913  *      kbits_burst - (OUT) maximum burst, kbits.
   2914  * Returns:
   2915  *      BCM_E_XXX
   2916  */
   2917 int
   2918 bcmi_gh2_cosq_gport_bandwidth_burst_get(int unit, bcm_gport_t gport,
   2919                                         bcm_cos_queue_t cosq,
   2920                                         uint32 *kbits_burst)
   2921 {
   2922     bcm_port_t local_port, port;
   2923     bcm_cos_queue_t cosq_start = 0, cosq_end = 0;
   2924     uint32 kbits_sec_min, kbits_sec_max, flags;    /* Dummy variables */
   2925 
   2926     kbits_sec_min = kbits_sec_max = flags = 0;
   2927 
   2928     if (gport < 0) {
   2929         port = SOC_PORT_MIN(unit, all);
   2930 
   2931         BCM_IF_ERROR_RETURN
   2932             (bcmi_gh2_cosq_gport_bandwidth_port_resolve(
   2933                 unit, port, cosq,
   2934                 &local_port,
   2935                 &cosq_start, &cosq_end));
   2936         BCM_IF_ERROR_RETURN
   2937             (bcmi_gh2_cosq_port_bandwidth_get(unit, local_port, cosq_start,
   2938                                               &kbits_sec_min, &kbits_sec_max,
   2939                                               kbits_burst, &flags));
   2940     } else {
   2941         BCM_IF_ERROR_RETURN
   2942             (bcmi_gh2_cosq_gport_bandwidth_port_resolve(
   2943                 unit, gport, cosq,
   2944                 &local_port,
   2945                 &cosq_start, &cosq_end));
   2946         BCM_IF_ERROR_RETURN
   2947             (bcmi_gh2_cosq_port_bandwidth_get(unit, gport, cosq_start,
   2948                                               &kbits_sec_min, &kbits_sec_max,
   2949                                               kbits_burst, &flags));
   2950     }
   2951 
   2952     return BCM_E_NONE;
   2953 }
   2954 
   2955 /*
   2956  * Function:
   2957  *      bcmi_gh2_cosq_control_set
   2958  * Purpose:
   2959  *      Set specified feature configuration
   2960  *
   2961  * Parameters:
   2962  *      unit - (IN) Unit number.
   2963  *      port - (IN) GPORT ID.
   2964  *      cosq - (IN) COS queue.
   2965  *      type - (IN) feature
   2966  *      arg  - (IN) feature value
   2967  * Returns:
   2968  *      BCM_E_XXX
   2969  * Notes:
   2970  */
   2971 int
   2972 bcmi_gh2_cosq_control_set(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq,
   2973                           bcm_cosq_control_t type, int arg)
   2974 {
   2975     bcm_port_t port;
   2976     int is_64q_port;
   2977     soc_reg_t config_reg = INVALIDr;
   2978     uint32 rval;
   2979     uint32 fval = 0;
   2980     int offset = 0;
   2981     int hw_cosq_idx;
   2982 
   2983     LOG_INFO(BSL_LS_BCM_COSQ,
   2984              (BSL_META_U(unit,
   2985                          "bcmi_gh2_cosq_control_set: unit=%d gport=0x%x \
   2986                          cosq=%d type=%d arg=%d\n"),
   2987               unit, gport, cosq, type, arg));
   2988 
   2989     BCM_IF_ERROR_RETURN
   2990         (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport, cosq,
   2991                                                 &port, &hw_cosq_idx));
   2992     BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port));
   2993 
   2994     switch (type) {
   2995     case bcmCosqControlEEEQueueThresholdProfileSelect:
   2996         if (is_64q_port) {
   2997             config_reg = EEE_PROFILE_SEL_QLAYERr;
   2998         } else {
   2999             config_reg = EEE_PROFILE_SELr;
   3000         }
   3001 
   3002         BCM_IF_ERROR_RETURN(
   3003             soc_reg32_get(unit, config_reg, port, hw_cosq_idx, &rval));
   3004         soc_reg_field_set(unit, config_reg, &rval,
   3005                           EEE_THRESH_SELf, arg);
   3006         BCM_IF_ERROR_RETURN(
   3007             soc_reg32_set(unit, config_reg, port, hw_cosq_idx, rval));
   3008         return BCM_E_NONE;
   3009         break;
   3010     case bcmCosqControlEEEPacketLatencyProfileSelect:
   3011         if (is_64q_port) {
   3012             config_reg = EEE_PROFILE_SEL_QLAYERr;
   3013         } else {
   3014             config_reg = EEE_PROFILE_SELr;
   3015         }
   3016 
   3017         BCM_IF_ERROR_RETURN(
   3018             soc_reg32_get(unit, config_reg, port, hw_cosq_idx, &rval));
   3019         soc_reg_field_set(unit, config_reg, &rval,
   3020                           EEE_LATENCY_SELf, arg);
   3021         BCM_IF_ERROR_RETURN(
   3022             soc_reg32_set(unit, config_reg, port, hw_cosq_idx, rval));
   3023         return BCM_E_NONE;
   3024         break;
   3025     case bcmCosqControlAlternateStoreForward:
   3026         if (is_64q_port) {
   3027             if (hw_cosq_idx < 32) {
   3028                 config_reg = ASF_ENABLE_0_64Qr;
   3029             } else {
   3030                 config_reg = ASF_ENABLE_1_64Qr;
   3031             }
   3032             offset = hw_cosq_idx % 32;
   3033         } else {
   3034             config_reg = ASF_ENABLE_8Qr;
   3035             offset = hw_cosq_idx;
   3036         }
   3037 
   3038         BCM_IF_ERROR_RETURN(
   3039             soc_reg32_get(unit, config_reg, port, 0, &rval));
   3040         fval = soc_reg_field_get(unit, config_reg,
   3041                                  rval, ASF_ENABLEf);
   3042 
   3043         if (arg == bcmCosqAsfModeAlternateStoreForward) {
   3044             fval |= (1 << offset);
   3045         } else {
   3046             fval &= ~(1 << offset);
   3047         }
   3048         soc_reg_field_set(unit, config_reg, &rval,
   3049                           ASF_ENABLEf, fval);
   3050         BCM_IF_ERROR_RETURN(
   3051             soc_reg32_set(unit, config_reg, port, 0, rval));
   3052         return BCM_E_NONE;
   3053         break;
   3054     default:
   3055         break;
   3056     }
   3057 
   3058     return BCM_E_UNAVAIL;
   3059 }
   3060 
   3061 /*
   3062  * Function:
   3063  *      bcmi_gh2_cosq_control_get
   3064  * Purpose:
   3065  *      Get specified feature configuration
   3066  *
   3067  * Parameters:
   3068  *      unit - (IN) Unit number.
   3069  *      port - (IN) GPORT ID.
   3070  *      cosq - (IN) COS queue.
   3071  *      type - (IN) feature
   3072  *      arg  - (OUT) feature value
   3073  * Returns:
   3074  *      BCM_E_XXX
   3075  * Notes:
   3076  */
   3077 int
   3078 bcmi_gh2_cosq_control_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq,
   3079                           bcm_cosq_control_t type, int *arg)
   3080 {
   3081     bcm_port_t port;
   3082     int is_64q_port;
   3083     soc_reg_t config_reg = INVALIDr;
   3084     uint32 rval;
   3085     uint32 fval = 0;
   3086     int offset = 0;
   3087     int hw_cosq_idx;
   3088 
   3089     LOG_INFO(BSL_LS_BCM_COSQ,
   3090              (BSL_META_U(unit,
   3091                          "bcmi_gh2_cosq_control_get: unit=%d gport=0x%x \
   3092                          cosq=%d type=%d\n"),
   3093                          unit, gport, cosq, type));
   3094     if (arg == NULL) {
   3095         return BCM_E_PARAM;
   3096     }
   3097 
   3098     BCM_IF_ERROR_RETURN
   3099         (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport, cosq,
   3100                                                 &port, &hw_cosq_idx));
   3101     BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port));
   3102 
   3103     switch (type) {
   3104     case bcmCosqControlEEEQueueThresholdProfileSelect:
   3105         if (is_64q_port) {
   3106             config_reg = EEE_PROFILE_SEL_QLAYERr;
   3107         } else {
   3108             config_reg = EEE_PROFILE_SELr;
   3109         }
   3110 
   3111         BCM_IF_ERROR_RETURN(
   3112             soc_reg32_get(unit, config_reg, port, hw_cosq_idx, &rval));
   3113         *arg = soc_reg_field_get(unit, config_reg,
   3114                                  rval, EEE_THRESH_SELf);
   3115         return BCM_E_NONE;
   3116         break;
   3117     case bcmCosqControlEEEPacketLatencyProfileSelect:
   3118         if (is_64q_port) {
   3119             config_reg = EEE_PROFILE_SEL_QLAYERr;
   3120         } else {
   3121             config_reg = EEE_PROFILE_SELr;
   3122         }
   3123 
   3124         BCM_IF_ERROR_RETURN(
   3125             soc_reg32_get(unit, config_reg, port, hw_cosq_idx, &rval));
   3126         *arg = soc_reg_field_get(unit, config_reg,
   3127                                  rval, EEE_LATENCY_SELf);
   3128         return BCM_E_NONE;
   3129         break;
   3130     case bcmCosqControlAlternateStoreForward:
   3131         if (is_64q_port) {
   3132             if (hw_cosq_idx < 32) {
   3133                 config_reg = ASF_ENABLE_0_64Qr;
   3134             } else {
   3135                 config_reg = ASF_ENABLE_1_64Qr;
   3136             }
   3137             offset = hw_cosq_idx % 32;
   3138         } else {
   3139             config_reg = ASF_ENABLE_8Qr;
   3140             offset = hw_cosq_idx;
   3141         }
   3142 
   3143         BCM_IF_ERROR_RETURN(
   3144             soc_reg32_get(unit, config_reg, port, 0, &rval));
   3145         fval = soc_reg_field_get(unit, config_reg,
   3146                                  rval, ASF_ENABLEf);
   3147         if (fval & (1 << offset)) {
   3148             *arg = bcmCosqAsfModeAlternateStoreForward;
   3149         } else {
   3150             *arg = bcmCosqAsfModeDisabled;
   3151         }
   3152         return BCM_E_NONE;
   3153         break;
   3154     default:
   3155         break;
   3156     }
   3157 
   3158     return BCM_E_UNAVAIL;
   3159 }
   3160 
   3161 /*
   3162  * Function:
   3163  *      bcmi_gh2_cosq_num_validate
   3164  * Purpose:
   3165  *      validate cosq id
   3166  *
   3167  * Parameters:
   3168  *      unit - (IN) Unit number.
   3169  *      port - (IN) GPORT ID.
   3170  *      cosq - (IN) COS queue.
   3171  * Returns:
   3172  *      BCM_E_XXX
   3173  * Notes:
   3174  */
   3175 STATIC int
   3176 bcmi_gh2_cosq_num_validate(int unit, bcm_port_t port, int cosq)
   3177 {
   3178     int max_cosq_per_port;
   3179     int is_64q_port;
   3180 
   3181     BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port));
   3182 
   3183     if (is_64q_port) {
   3184         max_cosq_per_port = SOC_GH2_2LEVEL_QUEUE_NUM;
   3185     } else {
   3186         max_cosq_per_port = SOC_GH2_LEGACY_QUEUE_NUM;
   3187     }
   3188 
   3189     if (((cosq >= 0) && (cosq < max_cosq_per_port)) ||
   3190         (cosq == BCM_COS_INVALID)) {
   3191         return BCM_E_NONE;
   3192     }
   3193 
   3194     return BCM_E_PARAM;
   3195 }
   3196 
   3197 /*
   3198  * Function:
   3199  *      bcmi_gh2_cosq_stat_get
   3200  * Parameters:
   3201  *      unit  - (IN) Unit number
   3202  *      gport - (IN) GPORT ID
   3203  *      cosq  - (IN) COS queue.
   3204  *      stat  - (IN) Statistic to be retrieved.
   3205  *      value - (OUT) Returned statistic value.
   3206  * Returns:
   3207  *      BCM_E_XXX
   3208  */
   3209 int
   3210 bcmi_gh2_cosq_stat_get(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq,
   3211                        bcm_cosq_stat_t stat, int sync_mode, uint64 *value)
   3212 {
   3213     bcm_port_t local_port;
   3214     int (*counter_get) (int , soc_port_t , soc_reg_t , int , uint64 *);
   3215     uint64 val64;
   3216     int i, rv;
   3217     int is_64q_port = 0;
   3218     int total_cosq = 0;
   3219     int cosq_idx = 0;
   3220 
   3221     LOG_INFO(BSL_LS_BCM_COSQ,
   3222              (BSL_META_U(unit,
   3223                          "bcmi_gh2_cosq_stat_get: unit=%d gport=0x%x \
   3224                           cosq=%d stat=%d sync_mode=%d\n"),
   3225               unit, gport, cosq, stat, sync_mode));
   3226 
   3227     if (value == NULL) {
   3228         return BCM_E_PARAM;
   3229     }
   3230 
   3231     /*
   3232      * if sync-mode is set, update the software cached counter value,
   3233      * with the hardware count and then retrieve the count.
   3234      * else return the software cache counter value.
   3235      */
   3236     counter_get = (sync_mode == 1) ? soc_counter_sync_get : soc_counter_get;
   3237     COMPILER_64_ZERO(*value);
   3238     COMPILER_64_ZERO(val64);
   3239 
   3240     switch (stat) {
   3241     case bcmCosqStatDroppedPackets:
   3242         if (cosq == BCM_COS_INVALID) {
   3243             BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_localport_resolve(unit, gport,
   3244                                                                 &local_port));
   3245             /*
   3246              * SOC_COUNTER_NON_DMA_COSQ_DROP_PKT gets the
   3247              * EGRDROPPKTCOUNT_COSr which is a register array with
   3248              * 64 elements per-port.
   3249              */
   3250             for (i = 0; i < SOC_GH2_2LEVEL_QUEUE_NUM; i++) {
   3251                 rv = counter_get(unit, local_port,
   3252                                  SOC_COUNTER_NON_DMA_COSQ_DROP_PKT, i, &val64);
   3253                 if (SOC_SUCCESS(rv)) {
   3254                     COMPILER_64_ADD_64(*value, val64);
   3255                 } else {
   3256                     break;
   3257                 }
   3258             }
   3259         } else {
   3260             BCM_IF_ERROR_RETURN
   3261                 (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport,
   3262                                                         cosq,
   3263                                                         &local_port,
   3264                                                         &cosq_idx));
   3265 
   3266             SOC_IF_ERROR_RETURN(counter_get(unit, local_port,
   3267                                             SOC_COUNTER_NON_DMA_COSQ_DROP_PKT,
   3268                                             cosq_idx, value));
   3269         }
   3270         break;
   3271     case bcmCosqStatOutPackets:
   3272         if (cosq == BCM_COS_INVALID) {
   3273             BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_localport_resolve(unit, gport,
   3274                                                                 &local_port));
   3275             BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   3276                                                        &is_64q_port));
   3277             if (!is_64q_port) {
   3278                 total_cosq = SOC_GH2_LEGACY_QUEUE_NUM;
   3279             } else {
   3280                 total_cosq = SOC_GH2_2LEVEL_QUEUE_NUM;
   3281             }
   3282             for (i = 0; i < total_cosq; i++) {
   3283                 rv = counter_get(unit, local_port,
   3284                                  SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT,
   3285                                  i, &val64);
   3286                 if (SOC_SUCCESS(rv)) {
   3287                     COMPILER_64_ADD_64(*value, val64);
   3288                 } else {
   3289                     break;
   3290                 }
   3291             }
   3292         } else {
   3293             BCM_IF_ERROR_RETURN
   3294                 (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport,
   3295                                                         cosq,
   3296                                                         &local_port,
   3297                                                         &cosq_idx));
   3298             SOC_IF_ERROR_RETURN
   3299                 (counter_get(unit, local_port,
   3300                              SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT,
   3301                              cosq_idx, value));
   3302         }
   3303         break;
   3304     case bcmCosqStatOutBytes:
   3305         if (cosq == BCM_COS_INVALID) {
   3306             BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_localport_resolve(unit, gport,
   3307                                                                 &local_port));
   3308             BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   3309                                                        &is_64q_port));
   3310             if (!is_64q_port) {
   3311                 total_cosq = SOC_GH2_LEGACY_QUEUE_NUM;
   3312             } else {
   3313                 total_cosq = SOC_GH2_2LEVEL_QUEUE_NUM;
   3314             }
   3315             for (i = 0; i < total_cosq; i++) {
   3316                 rv = counter_get(unit, local_port,
   3317                                  SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE,
   3318                                  i, &val64);
   3319                 if (SOC_SUCCESS(rv)) {
   3320                     COMPILER_64_ADD_64(*value, val64);
   3321                 } else {
   3322                     break;
   3323                 }
   3324             }
   3325         } else {
   3326             BCM_IF_ERROR_RETURN
   3327                 (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport,
   3328                                                         cosq,
   3329                                                         &local_port,
   3330                                                         &cosq_idx));
   3331             SOC_IF_ERROR_RETURN
   3332                 (counter_get(unit, local_port,
   3333                              SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE,
   3334                              cosq_idx, value));
   3335         }
   3336         break;
   3337     case bcmCosqStatYellowCongestionDroppedPackets:
   3338         BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, gport,
   3339                                                          &local_port));
   3340         BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_num_validate(unit, local_port, cosq));
   3341         if (cosq != BCM_COS_INVALID) {
   3342            /* Yellow dropped packet counters are available only on a per
   3343             * port basis.
   3344             */
   3345            return BCM_E_UNAVAIL;
   3346         }
   3347         SOC_IF_ERROR_RETURN
   3348             (counter_get(unit, local_port,
   3349                          SOC_COUNTER_NON_DMA_PORT_DROP_PKT_YELLOW, 0, value));
   3350         break;
   3351     case bcmCosqStatRedCongestionDroppedPackets:
   3352         BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, gport,
   3353                                                          &local_port));
   3354         BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_num_validate(unit, local_port, cosq));
   3355         if (cosq != BCM_COS_INVALID) {
   3356             /* Red dropped packet counters are available only on a per
   3357              * port basis.
   3358              */
   3359             return BCM_E_UNAVAIL;
   3360         }
   3361         SOC_IF_ERROR_RETURN(counter_get(unit, local_port,
   3362                                         SOC_COUNTER_NON_DMA_PORT_DROP_PKT_RED,
   3363                                         0, value));
   3364         break;
   3365     case bcmCosqStatDiscardDroppedPackets:
   3366         if (soc_feature(unit, soc_feature_wred_drop_counter_per_port)) {
   3367             BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, gport,
   3368                                                              &local_port));
   3369             BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_num_validate(unit, local_port,
   3370                                                            cosq));
   3371             COMPILER_64_ZERO(*value);
   3372             if (cosq == BCM_COS_INVALID) {
   3373                 SOC_IF_ERROR_RETURN
   3374                     (soc_counter_get(unit, local_port,
   3375                                      SOC_COUNTER_NON_DMA_PORT_WRED_DROP_PKT,
   3376                                      0, value));
   3377             } else {
   3378                 return BCM_E_UNAVAIL;
   3379             }
   3380         }
   3381         break;
   3382     case bcmCosqStatTASTxOverrunPackets:
   3383         if (soc_feature(unit, soc_feature_tas)) {
   3384             BCM_IF_ERROR_RETURN(
   3385                 _bcm_esw_port_gport_validate(unit, gport, &local_port));
   3386             BCM_IF_ERROR_RETURN(
   3387                 bcmi_gh2_tas_port_validate(unit, local_port));
   3388             if (cosq != BCM_COS_INVALID) {
   3389                /* Only support per port basis */
   3390                return BCM_E_UNAVAIL;
   3391             }
   3392             COMPILER_64_ZERO(*value);
   3393             COMPILER_64_ZERO(val64);
   3394             SOC_IF_ERROR_RETURN(
   3395                 counter_get(unit, local_port,
   3396                             SOC_COUNTER_NON_DMA_TAS_TXOVERRUN_PREEMPT,
   3397                             0, &val64));
   3398             COMPILER_64_ADD_64(*value, val64);
   3399 
   3400             COMPILER_64_ZERO(val64);
   3401             SOC_IF_ERROR_RETURN(
   3402                 counter_get(unit, local_port,
   3403                             SOC_COUNTER_NON_DMA_TAS_TXOVERRUN_EXPRESS,
   3404                             0, &val64));
   3405             COMPILER_64_ADD_64(*value, val64);
   3406         }
   3407         break;
   3408     default:
   3409         return BCM_E_PARAM;
   3410     }
   3411 
   3412     return BCM_E_NONE;
   3413 }
   3414 
   3415 /*
   3416  * Function:
   3417  *      bcmi_gh2_cosq_stat_set
   3418  * Purpose:
   3419  *      Set statistics
   3420  * Parameters:
   3421  *      unit  - (IN) Unit number.
   3422  *      gport - (IN) GPORT ID
   3423  *      cosq  - (IN) COS queue.
   3424  *      stat  - (IN) Statistic to be set.
   3425  *      value - (IN) Statistic value to be set.
   3426  * Returns:
   3427  *      BCM_E_xxx
   3428  * Notes:
   3429  */
   3430 int
   3431 bcmi_gh2_cosq_stat_set(int unit, bcm_gport_t gport, bcm_cos_queue_t cosq,
   3432                        bcm_cosq_stat_t stat, uint64 value)
   3433 {
   3434     bcm_port_t local_port;
   3435     uint64 val64_zero;
   3436     int i, rv;
   3437     int is_64q_port = 0;
   3438     int total_cosq = 0;
   3439     int cosq_idx = 0;
   3440 
   3441     LOG_INFO(BSL_LS_BCM_COSQ,
   3442              (BSL_META_U(unit,
   3443                          "bcmi_gh2_cosq_stat_set: unit=%d gport=0x%x \
   3444                           cosq=%d stat=%d\n"),
   3445               unit, gport, cosq, stat));
   3446 
   3447     switch (stat) {
   3448     case bcmCosqStatOutPackets:
   3449         COMPILER_64_ZERO(val64_zero);
   3450         if (cosq == BCM_COS_INVALID) {
   3451             BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_localport_resolve(unit, gport,
   3452                                                                 &local_port));
   3453             BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   3454                                                        &is_64q_port));
   3455             if (!is_64q_port) {
   3456                 total_cosq = SOC_GH2_LEGACY_QUEUE_NUM;
   3457             } else {
   3458                 total_cosq = SOC_GH2_2LEVEL_QUEUE_NUM;
   3459             }
   3460             /* Write given value to first COS queue */
   3461             rv = soc_counter_set(unit, local_port,
   3462                                  SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT,
   3463                                  0, value);
   3464 
   3465             /* Write zero to all other COS queues */
   3466             for (i = 1; i < total_cosq; i++) {
   3467                 rv = soc_counter_set(unit, local_port,
   3468                                      SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT,
   3469                                      i, val64_zero);
   3470                 if (SOC_FAILURE(rv)) {
   3471                     break;
   3472                 }
   3473             }
   3474         } else {
   3475             BCM_IF_ERROR_RETURN
   3476                 (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport,
   3477                                                         cosq,
   3478                                                         &local_port,
   3479                                                         &cosq_idx));
   3480             SOC_IF_ERROR_RETURN
   3481                 (soc_counter_set(unit, local_port,
   3482                                  SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT,
   3483                                  cosq_idx, value));
   3484         }
   3485         break;
   3486     case bcmCosqStatOutBytes:
   3487         COMPILER_64_ZERO(val64_zero);
   3488         if (cosq == BCM_COS_INVALID) {
   3489             BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_localport_resolve(unit, gport,
   3490                                                                 &local_port));
   3491             BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   3492                                                        &is_64q_port));
   3493             if (!is_64q_port) {
   3494                 total_cosq = SOC_GH2_LEGACY_QUEUE_NUM;
   3495             } else {
   3496                 total_cosq = SOC_GH2_2LEVEL_QUEUE_NUM;
   3497             }
   3498 
   3499             /* Write given value to first COS queue */
   3500             rv = soc_counter_set(unit, local_port,
   3501                                  SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE,
   3502                                  0, value);
   3503 
   3504             /* Write zero to all other COS queues */
   3505             for (i = 1; i < total_cosq; i++) {
   3506                 rv = soc_counter_set(unit, local_port,
   3507                                      SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE,
   3508                                      i, val64_zero);
   3509                 if (SOC_FAILURE(rv)) {
   3510                     break;
   3511                 }
   3512             }
   3513         } else {
   3514             BCM_IF_ERROR_RETURN
   3515                 (bcmi_gh2_cosq_qlayer_scheduler_resolve(unit, gport,
   3516                                                         cosq,
   3517                                                         &local_port,
   3518                                                         &cosq_idx));
   3519             SOC_IF_ERROR_RETURN
   3520                 (soc_counter_set(unit, local_port,
   3521                                  SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE,
   3522                                  cosq_idx, value));
   3523         }
   3524         break;
   3525     case bcmCosqStatDiscardDroppedPackets:
   3526         if (soc_feature(unit, soc_feature_wred_drop_counter_per_port)) {
   3527              BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, gport,
   3528                                                               &local_port));
   3529             if (cosq == BCM_COS_INVALID) {
   3530                 SOC_IF_ERROR_RETURN
   3531                     (soc_counter_set(unit, local_port,
   3532                                      SOC_COUNTER_NON_DMA_PORT_WRED_DROP_PKT,
   3533                                      0, value));
   3534             } else {
   3535                 return BCM_E_UNAVAIL;
   3536             }
   3537         }
   3538         break;
   3539     case bcmCosqStatTASTxOverrunPackets:
   3540         if (soc_feature(unit, soc_feature_tas)) {
   3541             /* read-only register, only take value=0 to clear it */
   3542             if (!COMPILER_64_IS_ZERO(value)) {
   3543                 return BCM_E_UNAVAIL;
   3544             }
   3545             BCM_IF_ERROR_RETURN(
   3546                 _bcm_esw_port_gport_validate(unit, gport, &local_port));
   3547             if (cosq == BCM_COS_INVALID) {
   3548                 SOC_IF_ERROR_RETURN(
   3549                     soc_counter_set(unit, local_port,
   3550                                     SOC_COUNTER_NON_DMA_TAS_TXOVERRUN_EXPRESS,
   3551                                     0, value));
   3552             } else {
   3553                 return BCM_E_UNAVAIL;
   3554             }
   3555         }
   3556         break;
   3557     case bcmCosqStatDroppedPackets:
   3558     case bcmCosqStatYellowCongestionDroppedPackets:
   3559     case bcmCosqStatRedCongestionDroppedPackets:
   3560         /* registers are read-only */
   3561         return BCM_E_UNAVAIL;
   3562     default:
   3563         return BCM_E_PARAM;
   3564     }
   3565 
   3566     return BCM_E_NONE;
   3567 }
   3568 
   3569 /*
   3570  *  Convert HW drop probability to percent value
   3571  */
   3572 STATIC int
   3573 gh2_hw_drop_prob_to_percent[] = {
   3574     0,     /* 0  */
   3575     1,     /* 1  */
   3576     2,     /* 2  */
   3577     3,     /* 3  */
   3578     4,     /* 4  */
   3579     5,     /* 5  */
   3580     6,     /* 6  */
   3581     7,     /* 7  */
   3582     8,     /* 8  */
   3583     9,     /* 9  */
   3584     10,    /* 10 */
   3585     25,    /* 11 */
   3586     50,    /* 12 */
   3587     75,    /* 13 */
   3588     100,   /* 14 */
   3589     -1     /* 15 */
   3590 };
   3591 
   3592 STATIC int
   3593 bcmi_gh2_percent_to_drop_prob(int percent)
   3594 {
   3595    int i;
   3596 
   3597    for (i = 14; i > 0 ; i--) {
   3598       if (percent >= gh2_hw_drop_prob_to_percent[i]) {
   3599           break;
   3600       }
   3601    }
   3602    return i;
   3603 }
   3604 
   3605 STATIC int
   3606 bcmi_gh2_drop_prob_to_percent(int drop_prob) {
   3607    return (gh2_hw_drop_prob_to_percent[drop_prob]);
   3608 }
   3609 
   3610 /*
   3611  * index: degree, value: contangent(degree) * 100
   3612  * max value is 0x7fff (15-bit) at 0 degree
   3613  */
   3614 STATIC int
   3615 bcmi_gh2_cotangent_lookup_table[] =
   3616 {
   3617     /*  0.. 5 */  32767, 5728, 2863, 1908, 1430, 1143,
   3618     /*  6..11 */    951,  814,  711,  631,  567,  514,
   3619     /* 12..17 */    470,  433,  401,  373,  348,  327,
   3620     /* 18..23 */    307,  290,  274,  260,  247,  235,
   3621     /* 24..29 */    224,  214,  205,  196,  188,  180,
   3622     /* 30..35 */    173,  166,  160,  153,  148,  142,
   3623     /* 36..41 */    137,  132,  127,  123,  119,  115,
   3624     /* 42..47 */    111,  107,  103,  100,   96,   93,
   3625     /* 48..53 */     90,   86,   83,   80,   78,   75,
   3626     /* 54..59 */     72,   70,   67,   64,   62,   60,
   3627     /* 60..65 */     57,   55,   53,   50,   48,   46,
   3628     /* 66..71 */     44,   42,   40,   38,   36,   34,
   3629     /* 72..77 */     32,   30,   28,   26,   24,   23,
   3630     /* 78..83 */     21,   19,   17,   15,   14,   12,
   3631     /* 84..89 */     10,    8,    6,    5,    3,    1,
   3632     /* 90     */      0
   3633 };
   3634 
   3635 /*
   3636  * Given a slope (angle in degrees) from 0 to 90, return the number of cells
   3637  * in the range from 0% drop probability to 100% drop probability.
   3638  */
   3639 STATIC int
   3640 bcmi_gh2_angle_to_cells(int angle)
   3641 {
   3642     return (bcmi_gh2_cotangent_lookup_table[angle]);
   3643 }
   3644 
   3645 /*
   3646  * Given a number of packets in the range from 0% drop probability
   3647  * to 100% drop probability, return the slope (angle in degrees).
   3648  */
   3649 STATIC int
   3650 bcmi_gh2_cells_to_angle(int packets)
   3651 {
   3652     int angle;
   3653 
   3654     for (angle = 90; angle >= 0 ; angle--) {
   3655         if (packets <= bcmi_gh2_cotangent_lookup_table[angle]) {
   3656             break;
   3657         }
   3658     }
   3659     return angle;
   3660 }
   3661 
   3662 /*
   3663  * Function:
   3664  *     bcmi_gh2_cosq_wred_set
   3665  * Purpose:
   3666  *     Configure queue WRED setting
   3667  * Parameters:
   3668  *     unit                - (IN) unit number
   3669  *     port                - (IN) port number or GPORT identifier
   3670  *     cosq                - (IN) COS queue number
   3671  *     flags               - (IN) BCM_COSQ_DISCARD_XXX
   3672  *     min_thresh          - (IN)
   3673  *     max_thresh          - (IN)
   3674  *     drop_probablity     - (IN)
   3675  *     gain                - (IN)
   3676  *     ignore_enable_flags - (IN)
   3677  * Returns:
   3678  *     BCM_E_XXX
   3679  * Notes:
   3680  *     If port is any form of local port, cosq is the hardware queue index.
   3681  */
   3682 STATIC int
   3683 bcmi_gh2_cosq_wred_set(int unit, bcm_port_t port, bcm_cos_queue_t cosq,
   3684                        uint32 flags, uint32 min_thresh, uint32 max_thresh,
   3685                        int drop_probability, int gain, int ignore_enable_flags,
   3686                        uint32 lflags)
   3687 {
   3688     int index;
   3689     uint32 profile_index, old_profile_index;
   3690     mmu_wred_drop_profile_green_entry_t entry_tcp_green;
   3691     mmu_wred_drop_profile_yellow_entry_t entry_tcp_yellow;
   3692     mmu_wred_drop_profile_red_entry_t entry_tcp_red;
   3693     mmu_wred_mark_profile_green_entry_t entry_mark_green;
   3694     mmu_wred_mark_profile_yellow_entry_t entry_mark_yellow;
   3695     mmu_wred_mark_profile_red_entry_t entry_mark_red;
   3696     mmu_wred_config_entry_t qentry;
   3697     void *entries[6];
   3698     soc_mem_t mems[6];
   3699     int rate, i, exists = 0;
   3700     static soc_mem_t wred_mems[6] = {
   3701         MMU_WRED_DROP_PROFILE_GREENm,
   3702         MMU_WRED_DROP_PROFILE_YELLOWm,
   3703         MMU_WRED_DROP_PROFILE_REDm,
   3704         MMU_WRED_MARK_PROFILE_GREENm,
   3705         MMU_WRED_MARK_PROFILE_YELLOWm,
   3706         MMU_WRED_MARK_PROFILE_REDm
   3707     };
   3708     int is_64q_port = 0;
   3709     soc_mem_t config_mem = INVALIDm;
   3710     gh2_cosq_node_t *node;
   3711     bcm_port_t local_port;
   3712     int local_cosq = 0;
   3713 
   3714     /*
   3715      * if (port is GPORT scheduler)
   3716      *     cosq is the child index of the GPORT object (QGROUP or QLAYER)
   3717      *     valid value : 0~7
   3718      * otherwise (just resolve the local port id)
   3719      *     cosq is COSQ number, value 0~7 or 0~63
   3720      */
   3721     if (BCM_GPORT_IS_SCHEDULER(port)) {
   3722         BCM_IF_ERROR_RETURN
   3723             (bcmi_gh2_cosq_node_get(unit, port, 0, NULL,
   3724                                     &local_port, NULL, &node));
   3725         if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   3726             if ((cosq < 0) ||
   3727                 (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) {
   3728                 return BCM_E_PARAM;
   3729             }
   3730 
   3731             config_mem = MMU_WRED_CONFIG_QGROUPm;
   3732             /* Get the MMU_WRED_CONFIG_QGROUPm index by (port, cosq) */
   3733             BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qgroup_index
   3734                                 (unit, local_port, cosq, &index));
   3735         } else if (node->node_level == GH2_COSQ_LEVEL_QLAYER) {
   3736             if ((cosq < 0) ||
   3737                 (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) {
   3738                 return BCM_E_PARAM;
   3739             }
   3740             config_mem = MMU_WRED_CONFIGm;
   3741             local_cosq = node->qlayer_cosq_min + cosq;
   3742             /* Get the MMU_WRED_CONFIGm index by (port, cosq) */
   3743             BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qlayer_index
   3744                                 (unit, local_port, local_cosq, &index));
   3745         } else {
   3746             return BCM_E_PARAM;
   3747         }
   3748     } else {
   3749         BCM_IF_ERROR_RETURN
   3750             (bcmi_gh2_cosq_localport_resolve(unit, port, &local_port));
   3751 
   3752         if (!SOC_PORT_VALID(unit, local_port) ||
   3753             (CMIC_PORT(unit) == local_port)) {
   3754             return BCM_E_PORT;
   3755         }
   3756 
   3757         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   3758                                                    &is_64q_port));
   3759         /* cosq parameter is value */
   3760         if (is_64q_port) {
   3761             if ((cosq < 0) || cosq >= SOC_GH2_2LEVEL_QUEUE_NUM) {
   3762                 return BCM_E_PARAM;
   3763             }
   3764         } else {
   3765             if ((cosq < 0) || cosq >= SOC_GH2_LEGACY_QUEUE_NUM) {
   3766                 return BCM_E_PARAM;
   3767             }
   3768         }
   3769 
   3770         local_cosq = cosq;
   3771         config_mem = MMU_WRED_CONFIGm;
   3772         /* Get the MMU_WRED_CONFIGm index by (port, cosq) */
   3773         BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qlayer_index
   3774                             (unit, local_port, local_cosq, &index));
   3775     }
   3776 
   3777     if (index < 0) {
   3778         return BCM_E_PARAM;
   3779     }
   3780 
   3781     BCM_IF_ERROR_RETURN
   3782         (soc_mem_read(unit, config_mem, SOC_BLOCK_ALL, index, &qentry));
   3783 
   3784     old_profile_index = 0xffffffff;
   3785 
   3786     if (flags & BCM_COSQ_DISCARD_NONTCP) {
   3787         /* Greyhound-based WRED  doesnot support non-responsive dropping */
   3788         return BCM_E_UNAVAIL;
   3789     }
   3790 
   3791     if (flags & (BCM_COSQ_DISCARD_TCP | BCM_COSQ_DISCARD_COLOR_ALL |
   3792                 BCM_COSQ_DISCARD_MARK_CONGESTION)) {
   3793             old_profile_index = soc_mem_field32_get(unit, config_mem,
   3794                                                     &qentry, PROFILE_INDEXf);
   3795         entries[0] = &entry_tcp_green;
   3796         entries[1] = &entry_tcp_yellow;
   3797         entries[2] = &entry_tcp_red;
   3798         entries[3] = &entry_mark_green;
   3799         entries[4] = &entry_mark_yellow;
   3800         entries[5] = &entry_mark_red;
   3801         BCM_IF_ERROR_RETURN
   3802             (soc_profile_mem_get(unit, gh2_wred_profile[unit],
   3803                                  old_profile_index, 1, entries));
   3804         for (i = 0; i < 6; i++) {
   3805             mems[i] = INVALIDm;
   3806         }
   3807         if ((flags & BCM_COSQ_DISCARD_TCP) ||
   3808                   !(flags & BCM_COSQ_DISCARD_MARK_CONGESTION)) {
   3809             if (flags & BCM_COSQ_DISCARD_COLOR_GREEN) {
   3810                 mems[0] = MMU_WRED_DROP_PROFILE_GREENm;
   3811             }
   3812             if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) {
   3813                 mems[1] = MMU_WRED_DROP_PROFILE_YELLOWm;
   3814             }
   3815             if (flags & BCM_COSQ_DISCARD_COLOR_RED) {
   3816                 mems[2] = MMU_WRED_DROP_PROFILE_REDm;
   3817             }
   3818         }
   3819         if (flags & BCM_COSQ_DISCARD_MARK_CONGESTION) {
   3820             if (flags & BCM_COSQ_DISCARD_COLOR_GREEN) {
   3821                 mems[3] = MMU_WRED_MARK_PROFILE_GREENm;
   3822             }
   3823             if (flags & BCM_COSQ_DISCARD_COLOR_YELLOW) {
   3824                 mems[4] = MMU_WRED_MARK_PROFILE_YELLOWm;
   3825             }
   3826             if (flags & BCM_COSQ_DISCARD_COLOR_RED) {
   3827                 mems[5] = MMU_WRED_MARK_PROFILE_REDm;
   3828             }
   3829         }
   3830         rate = bcmi_gh2_percent_to_drop_prob(drop_probability);
   3831         for (i = 0; i < 6; i++) {
   3832             exists = 0;
   3833             if ((soc_mem_field32_get(unit, wred_mems[i], entries[i],
   3834                     MIN_THDf) != GH2_CELL_FIELD_MAX) && (mems[i] == INVALIDm)) {
   3835                 mems[i] = wred_mems[i];
   3836                 exists = 1;
   3837             } else {
   3838                 soc_mem_field32_set(unit, wred_mems[i], entries[i],
   3839                         MIN_THDf, (mems[i] == INVALIDm) ?
   3840                         GH2_CELL_FIELD_MAX : min_thresh);
   3841             }
   3842 
   3843             if ((soc_mem_field32_get(unit, wred_mems[i], entries[i],
   3844                         MAX_THDf) != GH2_CELL_FIELD_MAX) &&
   3845                         ((mems[i] == INVALIDm) || exists)) {
   3846                 mems[i] = wred_mems[i];
   3847                 exists = 1;
   3848             } else {
   3849                 soc_mem_field32_set(unit, wred_mems[i], entries[i],
   3850                         MAX_THDf, (mems[i] == INVALIDm) ?
   3851                         GH2_CELL_FIELD_MAX :max_thresh);
   3852             }
   3853 
   3854             if (!exists) {
   3855                 if (soc_mem_field_valid(unit, wred_mems[i],
   3856                                                         MAX_DROP_RATEf)) {
   3857                     soc_mem_field32_set(unit, wred_mems[i], entries[i],
   3858                         MAX_DROP_RATEf, (mems[i] == INVALIDm) ? 0 : rate);
   3859                 } else if (soc_mem_field_valid(unit, wred_mems[i],
   3860                                                         MAX_MARK_RATEf)) {
   3861                     soc_mem_field32_set(unit, wred_mems[i], entries[i],
   3862                         MAX_MARK_RATEf, (mems[i] == INVALIDm) ? 0 : rate);
   3863                 }
   3864             }
   3865         }
   3866         BCM_IF_ERROR_RETURN
   3867             (soc_profile_mem_add(unit, gh2_wred_profile[unit],
   3868                                              entries, 1, &profile_index));
   3869         soc_mem_field32_set(unit, config_mem,
   3870                     &qentry, PROFILE_INDEXf, profile_index);
   3871         soc_mem_field32_set(unit, config_mem, &qentry, WEIGHTf, gain);
   3872     }
   3873     /* Some APIs only modify profiles */
   3874     if (!ignore_enable_flags) {
   3875         soc_mem_field32_set(unit, config_mem, &qentry, CAP_AVGf,
   3876                           flags & BCM_COSQ_DISCARD_CAP_AVERAGE ? 1 : 0);
   3877         soc_mem_field32_set(unit, config_mem, &qentry, WRED_ENf,
   3878                           flags & BCM_COSQ_DISCARD_ENABLE ? 1 : 0);
   3879         soc_mem_field32_set(unit, config_mem, &qentry, ECN_MARKING_ENf,
   3880                           flags & BCM_COSQ_DISCARD_MARK_CONGESTION ?  1 : 0);
   3881     }
   3882 
   3883     BCM_IF_ERROR_RETURN(
   3884           soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, index, &qentry));
   3885 
   3886     if (old_profile_index != 0xffffffff) {
   3887         SOC_IF_ERROR_RETURN
   3888             (soc_profile_mem_delete(unit, gh2_wred_profile[unit],
   3889                                     old_profile_index));
   3890     }
   3891 
   3892     return BCM_E_NONE;
   3893 }
   3894 
   3895 /*
   3896  * Function:
   3897  *     bcmi_gh2_cosq_wred_get
   3898  * Purpose:
   3899  *     Get queue WRED setting
   3900  * Parameters:
   3901  *     unit                - (IN) unit number
   3902  *     port                - (IN) port number or GPORT identifier
   3903  *     cosq                - (IN) COS queue number
   3904  *     flags               - (IN/OUT) BCM_COSQ_DISCARD_XXX
   3905  *     min_thresh          - (OUT)
   3906  *     max_thresh          - (OUT)
   3907  *     drop_probablity     - (OUT)
   3908  *     gain                - (OUT)
   3909  * Returns:
   3910  *     BCM_E_XXX
   3911  * Notes:
   3912  *     If port is any form of local port, cosq is the hardware queue index.
   3913  */
   3914 STATIC int
   3915 bcmi_gh2_cosq_wred_get(int unit, bcm_port_t port, bcm_cos_queue_t cosq,
   3916                        uint32 *flags, uint32 *min_thresh, uint32 *max_thresh,
   3917                        int *drop_probability, int *gain, uint32 lflags)
   3918 {
   3919     int index, profile_index;
   3920     mmu_wred_drop_profile_green_entry_t entry_tcp_green;
   3921     mmu_wred_drop_profile_yellow_entry_t entry_tcp_yellow;
   3922     mmu_wred_drop_profile_red_entry_t entry_tcp_red;
   3923     mmu_wred_mark_profile_green_entry_t entry_mark_green;
   3924     mmu_wred_mark_profile_yellow_entry_t entry_mark_yellow;
   3925     mmu_wred_mark_profile_red_entry_t entry_mark_red;
   3926     void *entries[6];
   3927     void *entry_p = NULL;
   3928     soc_mem_t profile_mem = INVALIDm;
   3929     mmu_wred_config_entry_t qentry;
   3930     int rate = 0;
   3931     int is_64q_port = 0;
   3932     soc_mem_t config_mem = INVALIDm;
   3933     gh2_cosq_node_t *node;
   3934     bcm_port_t local_port;
   3935     int local_cosq = 0;
   3936 
   3937     /*
   3938      * if (port is GPORT scheduler)
   3939      *     cosq is the child index of the GPORT object (QGROUP or QLAYER)
   3940      * otherwise (just resolve the local port id)
   3941      *     cosq is COSQ number, value 0~7 or 0~63
   3942      */
   3943     if (BCM_GPORT_IS_SCHEDULER(port)) {
   3944         BCM_IF_ERROR_RETURN
   3945             (bcmi_gh2_cosq_node_get(unit, port, 0, NULL,
   3946                                     &local_port, NULL, &node));
   3947         if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   3948             if ((cosq < 0) ||
   3949                 (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) {
   3950                 return BCM_E_PARAM;
   3951             }
   3952 
   3953             config_mem = MMU_WRED_CONFIG_QGROUPm;
   3954             /* Get the MMU_WRED_CONFIG_QGROUPm index by (port, cosq) */
   3955             BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qgroup_index
   3956                                 (unit, local_port, cosq, &index));
   3957         } else if (node->node_level == GH2_COSQ_LEVEL_QLAYER) {
   3958             if ((cosq < 0) ||
   3959                 (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) {
   3960                 return BCM_E_PARAM;
   3961             }
   3962 
   3963             config_mem = MMU_WRED_CONFIGm;
   3964             local_cosq = node->qlayer_cosq_min + cosq;
   3965             /* Get the MMU_WRED_CONFIGm index by (port, cosq) */
   3966             BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qlayer_index
   3967                                 (unit, local_port, local_cosq, &index));
   3968         } else {
   3969             return BCM_E_PARAM;
   3970         }
   3971     } else {
   3972         BCM_IF_ERROR_RETURN
   3973             (bcmi_gh2_cosq_localport_resolve(unit, port, &local_port));
   3974 
   3975         if (!SOC_PORT_VALID(unit, local_port) ||
   3976             (CMIC_PORT(unit) == local_port)) {
   3977             return BCM_E_PORT;
   3978         }
   3979 
   3980         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   3981                                                    &is_64q_port));
   3982 
   3983         /* cosq parameter is value */
   3984         if (is_64q_port) {
   3985             if ((cosq < 0) || cosq >= SOC_GH2_2LEVEL_QUEUE_NUM) {
   3986                 return BCM_E_PARAM;
   3987             }
   3988         } else {
   3989             if ((cosq < 0) || cosq >= SOC_GH2_LEGACY_QUEUE_NUM) {
   3990                 return BCM_E_PARAM;
   3991             }
   3992         }
   3993 
   3994         local_cosq = cosq;
   3995         config_mem = MMU_WRED_CONFIGm;
   3996         /* Get the MMU_WRED_CONFIGm index by (port, cosq) */
   3997         BCM_IF_ERROR_RETURN(soc_gh2_mmu_bucket_qlayer_index
   3998                             (unit, local_port, local_cosq, &index));
   3999     }
   4000     if (index < 0) {
   4001         return BCM_E_PARAM;
   4002     }
   4003 
   4004 
   4005     BCM_IF_ERROR_RETURN
   4006         (soc_mem_read(unit, config_mem, MEM_BLOCK_ALL, index, &qentry));
   4007     profile_index = soc_mem_field32_get(unit, config_mem,
   4008                                         &qentry, PROFILE_INDEXf);
   4009 
   4010     if (*flags & BCM_COSQ_DISCARD_MARK_CONGESTION) {
   4011         if (*flags & BCM_COSQ_DISCARD_COLOR_GREEN) {
   4012             profile_mem = MMU_WRED_MARK_PROFILE_GREENm;
   4013             entry_p = &entry_mark_green;
   4014         } else if (*flags & BCM_COSQ_DISCARD_COLOR_YELLOW) {
   4015             profile_mem = MMU_WRED_MARK_PROFILE_YELLOWm;
   4016             entry_p = &entry_mark_yellow;
   4017         } else if (*flags & BCM_COSQ_DISCARD_COLOR_RED) {
   4018             profile_mem = MMU_WRED_MARK_PROFILE_REDm;
   4019             entry_p = &entry_mark_red;
   4020         } else {
   4021             profile_mem = MMU_WRED_MARK_PROFILE_GREENm;
   4022             entry_p = &entry_mark_green;
   4023         }
   4024     } else {
   4025         if (*flags & BCM_COSQ_DISCARD_COLOR_GREEN) {
   4026             profile_mem = MMU_WRED_DROP_PROFILE_GREENm;
   4027             entry_p = &entry_tcp_green;
   4028         } else if (*flags & BCM_COSQ_DISCARD_COLOR_YELLOW) {
   4029             profile_mem = MMU_WRED_DROP_PROFILE_YELLOWm;
   4030             entry_p = &entry_tcp_yellow;
   4031         } else if (*flags & BCM_COSQ_DISCARD_COLOR_RED) {
   4032             profile_mem = MMU_WRED_DROP_PROFILE_REDm;
   4033             entry_p = &entry_tcp_red;
   4034         } else {
   4035             profile_mem = MMU_WRED_DROP_PROFILE_GREENm;
   4036             entry_p = &entry_tcp_green;
   4037         }
   4038     }
   4039 
   4040     entries[0] = &entry_tcp_green;
   4041     entries[1] = &entry_tcp_yellow;
   4042     entries[2] = &entry_tcp_red;
   4043     entries[3] = &entry_mark_green;
   4044     entries[4] = &entry_mark_yellow;
   4045     entries[5] = &entry_mark_red;
   4046     BCM_IF_ERROR_RETURN
   4047         (soc_profile_mem_get(unit, gh2_wred_profile[unit],
   4048                              profile_index, 1, entries));
   4049     if (min_thresh != NULL) {
   4050         *min_thresh = soc_mem_field32_get(unit, profile_mem, entry_p, MIN_THDf);
   4051     }
   4052     if (max_thresh != NULL) {
   4053         *max_thresh = soc_mem_field32_get(unit, profile_mem, entry_p, MAX_THDf);
   4054     }
   4055     if (drop_probability != NULL) {
   4056         if (soc_mem_field_valid(unit, profile_mem, MAX_DROP_RATEf)) {
   4057             rate = soc_mem_field32_get(
   4058                        unit, profile_mem, entry_p, MAX_DROP_RATEf);
   4059         } else if (soc_mem_field_valid(unit, profile_mem, MAX_MARK_RATEf)) {
   4060             rate = soc_mem_field32_get(
   4061                        unit, profile_mem, entry_p, MAX_MARK_RATEf);
   4062         }
   4063         *drop_probability = bcmi_gh2_drop_prob_to_percent(rate);
   4064     }
   4065 
   4066     if (gain) {
   4067         *gain = soc_mem_field32_get(unit, config_mem, &qentry, WEIGHTf);
   4068     }
   4069 
   4070     *flags &= ~(BCM_COSQ_DISCARD_CAP_AVERAGE | BCM_COSQ_DISCARD_ENABLE);
   4071     if (soc_mem_field32_get(unit, config_mem, &qentry, CAP_AVGf)) {
   4072         *flags |= BCM_COSQ_DISCARD_CAP_AVERAGE;
   4073     }
   4074     if (soc_mem_field32_get(unit, config_mem, &qentry, WRED_ENf)) {
   4075         *flags |= BCM_COSQ_DISCARD_ENABLE;
   4076     }
   4077     if (soc_mem_field32_get(unit, config_mem, &qentry, ECN_MARKING_ENf)) {
   4078         *flags |= BCM_COSQ_DISCARD_MARK_CONGESTION;
   4079     }
   4080     return BCM_E_NONE;
   4081 }
   4082 
   4083 int
   4084 bcmi_gh2_cosq_discard_set(int unit, uint32 flags)
   4085 {
   4086     bcm_port_t port;
   4087     int numq, i;
   4088     int is_64q_port = 0;
   4089 
   4090     flags &= ~(BCM_COSQ_DISCARD_NONTCP | BCM_COSQ_DISCARD_COLOR_ALL);
   4091 
   4092     PBMP_PORT_ITER(unit, port) {
   4093         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port,
   4094                                                    &is_64q_port));
   4095         if (is_64q_port) {
   4096             numq = SOC_GH2_2LEVEL_QUEUE_NUM;
   4097         } else {
   4098             numq = SOC_GH2_LEGACY_QUEUE_NUM;
   4099         }
   4100         for (i = 0; i < numq; i++) {
   4101             BCM_IF_ERROR_RETURN
   4102                 (bcmi_gh2_cosq_wred_set(unit, port, i, flags, 0, 0, 0, 0,
   4103                                         FALSE, BCM_COSQ_DISCARD_PORT));
   4104         }
   4105     }
   4106 
   4107     return BCM_E_NONE;
   4108 }
   4109 
   4110 int
   4111 bcmi_gh2_cosq_discard_get(int unit, uint32 *flags)
   4112 {
   4113     bcm_port_t port;
   4114 
   4115     PBMP_PORT_ITER(unit, port) {
   4116         *flags = 0;
   4117         return bcmi_gh2_cosq_wred_get(unit, port, 0, flags, NULL, NULL, NULL,
   4118                                       NULL, BCM_COSQ_DISCARD_PORT);
   4119     }
   4120 
   4121     return BCM_E_NOT_FOUND;
   4122 }
   4123 
   4124 /*
   4125  * Function:
   4126  *     bcmi_gh2_cosq_gport_discard_set
   4127  * Purpose:
   4128  *     Configure port WRED setting
   4129  * Parameters:
   4130  *     unit    - (IN) unit number
   4131  *     port    - (IN) GPORT identifier
   4132  *     cosq    - (IN) COS queue to configure, -1 for all COS queues
   4133  *     discard - (IN) discard settings
   4134  * Returns:
   4135  *     BCM_E_XXX
   4136  */
   4137 
   4138 int
   4139 bcmi_gh2_cosq_gport_discard_set(int unit, bcm_gport_t port,
   4140                                 bcm_cos_queue_t cosq,
   4141                                 bcm_cosq_gport_discard_t *discard)
   4142 {
   4143     int numq, i;
   4144     uint32 min_thresh, max_thresh;
   4145     int cell_size, cell_field_max;
   4146     bcm_port_t local_port;
   4147     bcm_pbmp_t pbmp;
   4148     int cosq_start;
   4149     int is_64q_port = 0;
   4150 
   4151     if (discard == NULL ||
   4152         discard->gain < 0 || discard->gain > 15 ||
   4153         discard->drop_probability < 0 || discard->drop_probability > 100) {
   4154         return BCM_E_PARAM;
   4155     }
   4156 
   4157     if ((discard->min_thresh < 0) || (discard->max_thresh < 0) ||
   4158                         (discard->min_thresh > discard->max_thresh)) {
   4159         return BCM_E_PARAM;
   4160     }
   4161 
   4162     cell_size = GH2_BYTES_PER_CELL;
   4163     cell_field_max = GH2_CELL_FIELD_MAX;
   4164 
   4165     min_thresh = discard->min_thresh;
   4166     max_thresh = discard->max_thresh;
   4167     if (discard->flags & BCM_COSQ_DISCARD_BYTES) {
   4168         /* Convert bytes to cells */
   4169         min_thresh += (cell_size - 1);
   4170         min_thresh /= cell_size;
   4171 
   4172         max_thresh += (cell_size - 1);
   4173         max_thresh /= cell_size;
   4174 
   4175         if ((min_thresh > cell_field_max) ||
   4176             (max_thresh > cell_field_max)) {
   4177             return BCM_E_PARAM;
   4178         }
   4179     } else { /* BCM_COSQ_DISCARD_PACKETS */
   4180         if ((min_thresh > GH2_CELL_FIELD_MAX) ||
   4181             (max_thresh > GH2_CELL_FIELD_MAX)) {
   4182             return BCM_E_PARAM;
   4183         }
   4184     }
   4185 
   4186     if (BCM_GPORT_IS_SET(port)) {
   4187         if (cosq < -1 || cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM) {
   4188             return BCM_E_PARAM;
   4189         }
   4190 
   4191         if (cosq == -1) {
   4192             numq = SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM;
   4193             cosq_start = 0;
   4194         } else {
   4195             numq = 1;
   4196             cosq_start = cosq;
   4197         }
   4198 
   4199         for (i = cosq_start; i < cosq_start+numq; i++) {
   4200             BCM_IF_ERROR_RETURN
   4201                 (bcmi_gh2_cosq_wred_set(unit, port, i,
   4202                                         discard->flags,
   4203                                         min_thresh, max_thresh,
   4204                                         discard->drop_probability,
   4205                                         discard->gain,
   4206                                         FALSE, 0));
   4207         }
   4208     } else {
   4209         if (port == -1) {
   4210             BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit));
   4211         } else if (!SOC_PORT_VALID(unit, port) ||
   4212                    (CMIC_PORT(unit) == port)) {
   4213             return BCM_E_PORT;
   4214         } else {
   4215             BCM_PBMP_PORT_SET(pbmp, port);
   4216         }
   4217 
   4218         BCM_PBMP_ITER(pbmp, local_port) {
   4219             BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   4220                                                        &is_64q_port));
   4221             if (is_64q_port) {
   4222                 if (cosq == -1) {
   4223                     numq = SOC_GH2_QLAYER_COSQ_PER_PORT_NUM;
   4224                     cosq_start = 0;
   4225                 } else {
   4226                     numq = 1;
   4227                     cosq_start = cosq;
   4228                 }
   4229             } else {
   4230                 if (cosq == -1) {
   4231                     numq = SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM;
   4232                     cosq_start = 0;
   4233                 } else {
   4234                     numq = 1;
   4235                     cosq_start = cosq;
   4236                 }
   4237             }
   4238 
   4239             for (i = cosq_start; i < cosq_start + numq; i++) {
   4240                 BCM_IF_ERROR_RETURN
   4241                     (bcmi_gh2_cosq_wred_set(unit, local_port, i,
   4242                                             discard->flags,
   4243                                             min_thresh, max_thresh,
   4244                                             discard->drop_probability,
   4245                                             discard->gain,
   4246                                             FALSE, 0));
   4247             }
   4248         }
   4249     }
   4250 
   4251     return BCM_E_NONE;
   4252 }
   4253 
   4254 int
   4255 bcmi_gh2_cosq_gport_discard_get(int unit, bcm_gport_t port,
   4256                                 bcm_cos_queue_t cosq,
   4257                                 bcm_cosq_gport_discard_t *discard)
   4258 {
   4259     uint32 min_thresh, max_thresh;
   4260     bcm_port_t local_port;
   4261     bcm_pbmp_t pbmp;
   4262 
   4263     if (discard == NULL) {
   4264         return BCM_E_PARAM;
   4265     }
   4266 
   4267     if (BCM_GPORT_IS_SET(port)) {
   4268         local_port = port;
   4269     } else {
   4270         if (port == -1) {
   4271             BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit));
   4272         } else if (!SOC_PORT_VALID(unit, port) ||
   4273                             (CMIC_PORT(unit) == port)) {
   4274             return BCM_E_PORT;
   4275         } else {
   4276             /* coverity[overrun-local] */
   4277             BCM_PBMP_PORT_SET(pbmp, port);
   4278         }
   4279         BCM_PBMP_ITER(pbmp, local_port) {
   4280             break;
   4281         }
   4282     }
   4283 
   4284     if (cosq < -1 || cosq >= gh2_num_cosq[unit]) {
   4285         return BCM_E_PARAM;
   4286     }
   4287     BCM_IF_ERROR_RETURN
   4288         (bcmi_gh2_cosq_wred_get(unit, local_port, cosq == -1 ? 0 : cosq,
   4289                                 &discard->flags, &min_thresh, &max_thresh,
   4290                                 &discard->drop_probability, &discard->gain, 0));
   4291 
   4292     if (discard->flags & BCM_COSQ_DISCARD_BYTES) {
   4293         /* Convert number of cells to number of bytes */
   4294         min_thresh *=  GH2_BYTES_PER_CELL;
   4295         max_thresh *=  GH2_BYTES_PER_CELL;
   4296     }
   4297     discard->min_thresh = min_thresh;
   4298     discard->max_thresh = max_thresh;
   4299 
   4300     return BCM_E_NONE;
   4301 }
   4302 
   4303 int
   4304 bcmi_gh2_cosq_discard_port_set(int unit, bcm_port_t port,
   4305                                bcm_cos_queue_t cosq,
   4306                                uint32 color,
   4307                                int drop_start,
   4308                                int drop_slope,
   4309                                int average_time)
   4310 {
   4311     bcm_port_t local_port;
   4312     bcm_pbmp_t pbmp;
   4313     int gain;
   4314     uint32 min_thresh, max_thresh, n;
   4315     uint32 rval, bits;
   4316     int numq, i, cosq_start;
   4317 
   4318     int is_64q_port = 0;
   4319     int local_cosq;
   4320     gh2_cosq_node_t *node = NULL;
   4321 
   4322     if (drop_start < 0 || drop_start > 100 ||
   4323         drop_slope < 0 || drop_slope > 90) {
   4324         return BCM_E_PARAM;
   4325     }
   4326 
   4327     /*
   4328      * average queue size is reculated every 2us, the formula is
   4329      * avg_qsize(t + 1) =
   4330      *     avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain)
   4331      * gain = log2(average_time / 2)
   4332      */
   4333     bits = (average_time / gh2_wred_update_interval[unit]) & 0xffff;
   4334     if (bits != 0) {
   4335         bits |= bits >> 1;
   4336         bits |= bits >> 2;
   4337         bits |= bits >> 4;
   4338         bits |= bits >> 8;
   4339         gain = _shr_popcount(bits) - 1;
   4340     } else {
   4341         gain = 0;
   4342     }
   4343 
   4344     if (BCM_GPORT_IS_SET(port)) {
   4345         /*
   4346          * Paramteres :
   4347          *     port : gport id, only accept scheduler gport type
   4348          *     cosq : Valid value 0~7, the input/child id of the gport
   4349          *              Checked in bcmi_gh2_cosq_wred_set
   4350          */
   4351         if (cosq == -1) {
   4352             numq = SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM;
   4353             cosq_start = 0;
   4354         } else {
   4355             numq = 1;
   4356             cosq_start = cosq;
   4357         }
   4358 
   4359         BCM_IF_ERROR_RETURN
   4360             (bcmi_gh2_cosq_node_get(unit, port, 0, NULL,
   4361                                     &local_port, NULL, &node));
   4362 
   4363         for (i = cosq_start; i < (cosq_start + numq); i++) {
   4364             /* Get the start point as a function of the HOL limit */
   4365             if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   4366                 if ((i < 0) || (i >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) {
   4367                     return BCM_E_PARAM;
   4368                 }
   4369 
   4370                 SOC_IF_ERROR_RETURN
   4371                     (READ_HOLCOSCELLMAXLIMIT_QGROUPr(unit, local_port,
   4372                                                      i, &rval));
   4373                 n = soc_reg_field_get(unit, HOLCOSCELLMAXLIMIT_QGROUPr, rval,
   4374                                       CELLMAXLIMITf);
   4375             } else if (node->node_level == GH2_COSQ_LEVEL_QLAYER) {
   4376                 if ((i < 0) || (i >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) {
   4377                     return BCM_E_PARAM;
   4378                 }
   4379                 /* transfered to hw queue index (0~63) */
   4380                 local_cosq = node->qlayer_cosq_min + i;
   4381 
   4382                 SOC_IF_ERROR_RETURN
   4383                     (READ_HOLCOSCELLMAXLIMIT_QLAYERr(unit, local_port,
   4384                                                      local_cosq, &rval));
   4385                 n = soc_reg_field_get(unit, HOLCOSCELLMAXLIMIT_QLAYERr, rval,
   4386                                       CELLMAXLIMITf);
   4387             } else {
   4388                 /* only accept scheduler gport type */
   4389                 return BCM_E_PORT;
   4390             }
   4391 
   4392             min_thresh = drop_start * n / 100;
   4393 
   4394             /* Calculate the max threshold. For a given slope (angle in
   4395              * degrees), determine how many packets are in the range from
   4396              * 0% drop probability to 100% drop probability. Add that
   4397              * number to the min_treshold to the the max_threshold.
   4398              */
   4399             max_thresh = min_thresh + bcmi_gh2_angle_to_cells(drop_slope);
   4400             if (max_thresh > GH2_CELL_FIELD_MAX) {
   4401                 max_thresh = GH2_CELL_FIELD_MAX;
   4402             }
   4403             BCM_IF_ERROR_RETURN
   4404                 (bcmi_gh2_cosq_wred_set(unit, port, i,
   4405                                         (color | BCM_COSQ_DISCARD_TCP),
   4406                                         min_thresh, max_thresh, 100,
   4407                                         gain, TRUE, 0));
   4408         }
   4409     } else {
   4410         /*
   4411          * Paramteres :
   4412          *     port : local port id
   4413          *     cosq : Valid value 0~7 or 0~63, depends on MMU port id
   4414          *              Checked in bcmi_gh2_cosq_wred_set
   4415          */
   4416 
   4417         if (port == -1) {
   4418             BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit));
   4419         } else if (!SOC_PORT_VALID(unit, port) || (CMIC_PORT(unit) == port)) {
   4420             return BCM_E_PORT;
   4421         } else {
   4422             BCM_PBMP_PORT_SET(pbmp, port);
   4423         }
   4424 
   4425         BCM_PBMP_ITER(pbmp, local_port) {
   4426             BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   4427                                                        &is_64q_port));
   4428             if (is_64q_port) {
   4429                 if ((cosq < -1) || cosq >= SOC_GH2_2LEVEL_QUEUE_NUM) {
   4430                     return BCM_E_PARAM;
   4431                 }
   4432 
   4433                 if (cosq == -1) {
   4434                     numq = SOC_GH2_QLAYER_COSQ_PER_PORT_NUM;
   4435                     cosq_start = 0;
   4436                 } else {
   4437                     numq = 1;
   4438                     cosq_start = cosq;
   4439                 }
   4440             } else {
   4441                 if ((cosq < -1) || cosq >= SOC_GH2_LEGACY_QUEUE_NUM) {
   4442                     return BCM_E_PARAM;
   4443                 }
   4444 
   4445                 if (cosq == -1) {
   4446                     numq = SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM;
   4447                     cosq_start = 0;
   4448                 } else {
   4449                     numq = 1;
   4450                     cosq_start = cosq;
   4451                 }
   4452             }
   4453 
   4454             for (i = cosq_start; i < (cosq_start + numq); i++) {
   4455                 /* Get the start point as a function of the HOL limit */
   4456                 if (is_64q_port) {
   4457                     SOC_IF_ERROR_RETURN
   4458                         (READ_HOLCOSCELLMAXLIMIT_QLAYERr(unit, local_port,
   4459                                                          i, &rval));
   4460                     n = soc_reg_field_get(unit, HOLCOSCELLMAXLIMIT_QLAYERr,
   4461                                           rval, CELLMAXLIMITf);
   4462                 } else {
   4463                     SOC_IF_ERROR_RETURN
   4464                         (READ_HOLCOSCELLMAXLIMITr(unit, local_port, i, &rval));
   4465                     n = soc_reg_field_get(unit, HOLCOSCELLMAXLIMITr, rval,
   4466                                           CELLMAXLIMITf);
   4467                 }
   4468 
   4469                 min_thresh = drop_start * n / 100;
   4470 
   4471                 /* Calculate the max threshold. For a given slope (angle in
   4472                  * degrees), determine how many packets are in the range from
   4473                  * 0% drop probability to 100% drop probability. Add that
   4474                  * number to the min_treshold to the the max_threshold.
   4475                  */
   4476                 max_thresh = min_thresh + bcmi_gh2_angle_to_cells(drop_slope);
   4477                 if (max_thresh > GH2_CELL_FIELD_MAX) {
   4478                     max_thresh = GH2_CELL_FIELD_MAX;
   4479                 }
   4480                 BCM_IF_ERROR_RETURN
   4481                     (bcmi_gh2_cosq_wred_set(unit, local_port, i,
   4482                                            (color | BCM_COSQ_DISCARD_TCP),
   4483                                            min_thresh, max_thresh, 100,
   4484                                            gain, TRUE, 0));
   4485             }
   4486         }
   4487     }
   4488 
   4489     return BCM_E_NONE;
   4490 }
   4491 
   4492 int
   4493 bcmi_gh2_cosq_discard_port_get(int unit, bcm_port_t port,
   4494                                bcm_cos_queue_t cosq,
   4495                                uint32 color,
   4496                                int *drop_start,
   4497                                int *drop_slope,
   4498                                int *average_time)
   4499 {
   4500     bcm_port_t local_port;
   4501     bcm_pbmp_t pbmp;
   4502     int gain, drop_prob;
   4503     uint32 min_thresh, max_thresh, pkt_limit;
   4504     uint32 rval;
   4505     int is_64q_port = 0;
   4506     int local_cosq;
   4507     gh2_cosq_node_t *node = NULL;
   4508 
   4509     if (drop_start == NULL || drop_slope == NULL || average_time == NULL) {
   4510         return BCM_E_PARAM;
   4511     }
   4512 
   4513     if (BCM_GPORT_IS_SET(port)) {
   4514         local_port = port;
   4515     } else {
   4516         if (port == -1) {
   4517             BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(unit));
   4518         } else if (!SOC_PORT_VALID(unit, port) || (CMIC_PORT(unit) == port)) {
   4519             return BCM_E_PORT;
   4520         } else {
   4521             /* coverity[overrun-local] */
   4522             BCM_PBMP_PORT_SET(pbmp, port);
   4523         }
   4524         BCM_PBMP_ITER(pbmp, local_port) {
   4525             break;
   4526         }
   4527     }
   4528 
   4529     /*
   4530      * Paramteres : checked in bcmi_gh2_cosq_wred_get
   4531      *     port is gport id, only accept scheduler gport type
   4532      *     cosq : Valid value 0~7, the input/child id of the gport
   4533      *
   4534      *     port is local port id
   4535      *     cosq : Valid value 0~7 or 0~63, depends on MMU port id
   4536      */
   4537 
   4538     color |= BCM_COSQ_DISCARD_TCP;
   4539     BCM_IF_ERROR_RETURN
   4540         (bcmi_gh2_cosq_wred_get(unit, local_port, cosq == -1 ? 0 : cosq,
   4541                                 &color, &min_thresh, &max_thresh, &drop_prob,
   4542                                 &gain, 0));
   4543 
   4544     /*
   4545      * average queue size is reculated every 2(or 1)us, the formula is
   4546      * avg_qsize(t + 1) =
   4547      *     avg_qsize(t) + (cur_qsize - avg_qsize(t)) / (2 ** gain)
   4548      */
   4549     *average_time = (1 << gain) * gh2_wred_update_interval[unit];
   4550 
   4551     /* Get the total HOL limit first */
   4552     if (BCM_GPORT_IS_SET(port)) {
   4553         BCM_IF_ERROR_RETURN
   4554             (bcmi_gh2_cosq_node_get(unit, port, 0, NULL,
   4555                                     &local_port, NULL, &node));
   4556         if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   4557             if ((cosq < -1) || (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) {
   4558                 return BCM_E_PARAM;
   4559             }
   4560 
   4561             SOC_IF_ERROR_RETURN
   4562                 (READ_HOLCOSCELLMAXLIMIT_QGROUPr(unit, local_port,
   4563                                                  cosq == -1 ? 0 : cosq, &rval));
   4564 
   4565             pkt_limit = soc_reg_field_get(unit, HOLCOSCELLMAXLIMIT_QGROUPr,
   4566                                           rval, CELLMAXLIMITf);
   4567         } else if (node->node_level == GH2_COSQ_LEVEL_QLAYER) {
   4568             if ((cosq < -1) || (cosq >= SOC_GH2_QLAYER_COSQ_PER_QGROUP_NUM)) {
   4569                 return BCM_E_PARAM;
   4570             }
   4571             /* transfered to hw queue index (0~63) */
   4572             local_cosq = node->qlayer_cosq_min + (cosq == -1 ? 0 : cosq);
   4573 
   4574             SOC_IF_ERROR_RETURN
   4575                 (READ_HOLCOSCELLMAXLIMIT_QLAYERr(unit, local_port,
   4576                                                  local_cosq, &rval));
   4577             pkt_limit = soc_reg_field_get(unit, HOLCOSCELLMAXLIMIT_QLAYERr,
   4578                                           rval, CELLMAXLIMITf);
   4579         } else {
   4580             /* only accept scheduler gport type */
   4581             return BCM_E_PORT;
   4582         }
   4583     } else {
   4584         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   4585                                                    &is_64q_port));
   4586         if (is_64q_port) {
   4587             if ((cosq < -1) || (cosq >= SOC_GH2_2LEVEL_QUEUE_NUM)) {
   4588                 return BCM_E_PARAM;
   4589             }
   4590             BCM_IF_ERROR_RETURN
   4591                 (READ_HOLCOSCELLMAXLIMIT_QLAYERr(unit, local_port,
   4592                                                  cosq == -1 ? 0 : cosq, &rval));
   4593             pkt_limit = soc_reg_field_get(unit, HOLCOSCELLMAXLIMIT_QLAYERr,
   4594                                           rval, CELLMAXLIMITf);
   4595         } else {
   4596             if ((cosq < -1) || (cosq >= SOC_GH2_LEGACY_QUEUE_NUM)) {
   4597                 return BCM_E_PARAM;
   4598             }
   4599             BCM_IF_ERROR_RETURN
   4600                 (READ_HOLCOSCELLMAXLIMITr(unit, local_port,
   4601                                           cosq == -1 ? 0 : cosq, &rval));
   4602             pkt_limit = soc_reg_field_get(unit, HOLCOSCELLMAXLIMITr,
   4603                                           rval, CELLMAXLIMITf);
   4604         }
   4605     }
   4606     if (min_thresh > pkt_limit) {
   4607         min_thresh = pkt_limit;
   4608     }
   4609 
   4610     if (max_thresh > pkt_limit) {
   4611         max_thresh = pkt_limit;
   4612     }
   4613 
   4614     *drop_start = (min_thresh * 100 + pkt_limit - 1) / pkt_limit;
   4615 
   4616     /* Calculate the slope using the min and max threshold.
   4617      * The angle is calculated knowing drop probability at min
   4618      * threshold is 0% and drop probability at max threshold is 100%.
   4619      */
   4620     *drop_slope = bcmi_gh2_cells_to_angle(max_thresh - min_thresh);
   4621     return BCM_E_NONE;
   4622 }
   4623 
   4624 int
   4625 bcmi_gh2_cosq_wred_port_control_set(int unit,
   4626                                     bcm_gport_t gport,
   4627                                     bcm_port_control_t type,
   4628                                     int value)
   4629 {
   4630     bcm_port_t local_port = 0;
   4631     int is_64q_port = 0;
   4632     uint32 val = 0;
   4633     uint32 fld_val = 0;
   4634     int cur_val = 0;
   4635     int shift = 0;
   4636     gh2_cosq_node_t *node = NULL;
   4637 
   4638     switch (type) {
   4639         case bcmPortControlWredDropCountUpdateEnableQueueMask:
   4640             /* parameter checking */
   4641             if (value & 0xffffff00) {
   4642                 /* only 0xff is accepted */
   4643                 return BCM_E_PARAM;
   4644             }
   4645 
   4646             if (BCM_GPORT_IS_SET(gport)) {
   4647                 /* To configure 64Q by QLayer scheduler */
   4648                 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) {
   4649                     return BCM_E_PORT;
   4650                 }
   4651                 if (BCM_GPORT_IS_SCHEDULER(gport)) {
   4652                     BCM_IF_ERROR_RETURN
   4653                         (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL,
   4654                                                 &local_port, NULL, &node));
   4655                     if (node->node_level != GH2_COSQ_LEVEL_QLAYER) {
   4656                         return BCM_E_PORT;
   4657                     }
   4658 
   4659                     if (node->child_idx < 4) {
   4660                         shift = 8 * node->child_idx;
   4661                         BCM_IF_ERROR_RETURN(
   4662                             READ_WRED_DROP_CTR_CONFIG_QLAYER_0r(unit,
   4663                                                                 local_port,
   4664                                                                 &val));
   4665                         fld_val = \
   4666                             soc_reg_field_get(unit,
   4667                                               WRED_DROP_CTR_CONFIG_QLAYER_0r,
   4668                                               val, QUEUE_MASKf);
   4669                         fld_val &= ~(0xff << shift);
   4670                         fld_val |= ((value & 0xff) << shift);
   4671                         soc_reg_field_set(unit, WRED_DROP_CTR_CONFIG_QLAYER_0r,
   4672                                           &val,
   4673                                           QUEUE_MASKf, fld_val);
   4674                         BCM_IF_ERROR_RETURN(
   4675                             WRITE_WRED_DROP_CTR_CONFIG_QLAYER_0r(unit,
   4676                                                                  local_port,
   4677                                                                  val));
   4678                     } else {
   4679                         shift = 8 * (node->child_idx - 4);
   4680                         BCM_IF_ERROR_RETURN(
   4681                             READ_WRED_DROP_CTR_CONFIG_QLAYER_1r(unit,
   4682                                                                 local_port,
   4683                                                                 &val));
   4684                         fld_val = \
   4685                             soc_reg_field_get(unit,
   4686                                               WRED_DROP_CTR_CONFIG_QLAYER_1r,
   4687                                               val, QUEUE_MASKf);
   4688                         fld_val &= ~(0xff << shift);
   4689                         fld_val |= ((value & 0xff) << shift);
   4690                         soc_reg_field_set(unit, WRED_DROP_CTR_CONFIG_QLAYER_1r,
   4691                                           &val,
   4692                                           QUEUE_MASKf, fld_val);
   4693                         BCM_IF_ERROR_RETURN(
   4694                             WRITE_WRED_DROP_CTR_CONFIG_QLAYER_1r(unit,
   4695                                                                  local_port,
   4696                                                                  val));
   4697                     }
   4698                 }
   4699             } else {
   4700                 /* Legacy COSQ mode, 8 queues per port */
   4701                 local_port = gport;
   4702                 if (!SOC_PORT_VALID(unit, gport)) {
   4703                     return BCM_E_PORT;
   4704                 }
   4705 
   4706                 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   4707                                                            &is_64q_port));
   4708                 if (is_64q_port) {
   4709                     BCM_IF_ERROR_RETURN(soc_reg_field32_modify(unit,
   4710                                         WRED_DROP_CTR_CONFIG_QLAYER_0r,
   4711                                         local_port, QUEUE_MASKf, value));
   4712                 } else {
   4713                     BCM_IF_ERROR_RETURN(soc_reg_field32_modify(unit,
   4714                                         WRED_DROP_CTR_CONFIGr,
   4715                                         local_port, QUEUE_MASKf, value));
   4716                 }
   4717             }
   4718             break;
   4719         case bcmPortControlWredDropCountUpdateEnableColorMask:
   4720             if (BCM_GPORT_IS_SET(gport)) {
   4721                     BCM_IF_ERROR_RETURN
   4722                         (bcm_esw_port_local_get(unit, gport, &local_port));
   4723             } else {
   4724                 local_port = gport;
   4725                 if (!SOC_PORT_VALID(unit, local_port)) {
   4726                     return BCM_E_PORT;
   4727                 }
   4728             }
   4729             BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   4730                                                        &is_64q_port));
   4731             /* parameter checking */
   4732             if (value & ~((0x1 << bcmColorGreen) |
   4733                 (0x1 << bcmColorYellow) |
   4734                 (0x1 << bcmColorRed))) {
   4735                 return BCM_E_PARAM;
   4736             }
   4737             cur_val = 0;
   4738             if (value & (0x1 << bcmColorGreen)) {
   4739                 cur_val |= 0x4;
   4740             }
   4741             if (value & (0x1 << bcmColorYellow)) {
   4742                 cur_val |= 0x2;
   4743             }
   4744             if (value & (0x1 << bcmColorRed)) {
   4745                 cur_val |= 0x1;
   4746             }
   4747             if (is_64q_port) {
   4748                 BCM_IF_ERROR_RETURN(soc_reg_field32_modify(unit,
   4749                                     WRED_DROP_CTR_CONFIG_COLOR_MASK_QLAYERr,
   4750                                     local_port, COLOR_MASKf, cur_val));
   4751             } else {
   4752                 BCM_IF_ERROR_RETURN(soc_reg_field32_modify(unit,
   4753                                     WRED_DROP_CTR_CONFIGr,
   4754                                     local_port, COLOR_MASKf, cur_val));
   4755             }
   4756             break;
   4757         default:
   4758             return BCM_E_PARAM;
   4759     }
   4760     return BCM_E_NONE;
   4761 }
   4762 
   4763 int
   4764 bcmi_gh2_cosq_wred_port_control_get(int unit,
   4765                                     bcm_gport_t gport,
   4766                                     bcm_port_control_t type,
   4767                                     int *value)
   4768 {
   4769     bcm_port_t local_port = 0;
   4770     int is_64q_port = 0;
   4771     uint32 val = 0;
   4772     uint32 fld_val = 0;
   4773     int shift = 0;
   4774     gh2_cosq_node_t *node = NULL;
   4775 
   4776     switch (type) {
   4777         case bcmPortControlWredDropCountUpdateEnableQueueMask:
   4778             if (BCM_GPORT_IS_SET(gport)) {
   4779                 /* To configure 64Q by QLayer scheduler */
   4780                 if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) {
   4781                     return BCM_E_PORT;
   4782                 }
   4783                 if (BCM_GPORT_IS_SCHEDULER(gport)) {
   4784                     BCM_IF_ERROR_RETURN
   4785                         (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL,
   4786                                                 &local_port, NULL, &node));
   4787                     if (node->node_level != GH2_COSQ_LEVEL_QLAYER) {
   4788                         return BCM_E_PORT;
   4789                     }
   4790 
   4791                     if (node->child_idx < 4) {
   4792                         shift = 8 * node->child_idx;
   4793                         BCM_IF_ERROR_RETURN(
   4794                             READ_WRED_DROP_CTR_CONFIG_QLAYER_0r(unit,
   4795                                                                 local_port,
   4796                                                                 &val));
   4797                         fld_val = \
   4798                             soc_reg_field_get(unit,
   4799                                               WRED_DROP_CTR_CONFIG_QLAYER_0r,
   4800                                               val, QUEUE_MASKf);
   4801                         *value = (fld_val >> shift) & 0xff;
   4802                     } else {
   4803                         shift = 8 * (node->child_idx - 4);
   4804                         BCM_IF_ERROR_RETURN(
   4805                             READ_WRED_DROP_CTR_CONFIG_QLAYER_1r(unit,
   4806                                                                 local_port,
   4807                                                                 &val));
   4808                         fld_val =
   4809                             soc_reg_field_get(unit,
   4810                                               WRED_DROP_CTR_CONFIG_QLAYER_1r,
   4811                                               val, QUEUE_MASKf);
   4812                         *value = (fld_val >> shift) & 0xff;
   4813                     }
   4814                 }
   4815             } else {
   4816                 /* Legacy COSQ mode, 8 queues per port */
   4817                 local_port = gport;
   4818                 if (!SOC_PORT_VALID(unit, gport)) {
   4819                     return BCM_E_PORT;
   4820                 }
   4821 
   4822                 BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   4823                                                            &is_64q_port));
   4824                 if (is_64q_port) {
   4825                     BCM_IF_ERROR_RETURN(
   4826                         READ_WRED_DROP_CTR_CONFIG_QLAYER_0r(unit,
   4827                                                             local_port,
   4828                                                             &val));
   4829                     fld_val = soc_reg_field_get(unit,
   4830                                                 WRED_DROP_CTR_CONFIG_QLAYER_0r,
   4831                                                 val, QUEUE_MASKf);
   4832                     *value = fld_val & 0xff;
   4833                 } else {
   4834                     BCM_IF_ERROR_RETURN(
   4835                         READ_WRED_DROP_CTR_CONFIGr(unit, local_port, &val));
   4836                     fld_val = soc_reg_field_get(unit, WRED_DROP_CTR_CONFIGr,
   4837                                                 val, QUEUE_MASKf);
   4838                     *value = fld_val & 0xff;
   4839                 }
   4840             }
   4841             break;
   4842         case bcmPortControlWredDropCountUpdateEnableColorMask:
   4843             if (BCM_GPORT_IS_SET(gport)) {
   4844                     BCM_IF_ERROR_RETURN
   4845                         (bcm_esw_port_local_get(unit, gport, &local_port));
   4846             } else {
   4847                 local_port = gport;
   4848                 if (!SOC_PORT_VALID(unit, local_port)) {
   4849                     return BCM_E_PORT;
   4850                 }
   4851             }
   4852             BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   4853                                                        &is_64q_port));
   4854             if (is_64q_port) {
   4855                 BCM_IF_ERROR_RETURN(
   4856                     READ_WRED_DROP_CTR_CONFIG_COLOR_MASK_QLAYERr(unit,
   4857                                                                  local_port,
   4858                                                                  &val));
   4859                 fld_val = \
   4860                     soc_reg_field_get(unit,
   4861                                       WRED_DROP_CTR_CONFIG_COLOR_MASK_QLAYERr,
   4862                                       val, COLOR_MASKf);
   4863             } else {
   4864                 BCM_IF_ERROR_RETURN(
   4865                     READ_WRED_DROP_CTR_CONFIGr(unit, local_port, &val));
   4866                 fld_val = soc_reg_field_get(unit, WRED_DROP_CTR_CONFIGr,
   4867                                             val, COLOR_MASKf);
   4868             }
   4869             *value = 0;
   4870             if (fld_val & 0x4) {
   4871                 *value |= (0x1 << bcmColorGreen);
   4872             }
   4873             if (fld_val & 0x2) {
   4874                 *value |= (0x1 << bcmColorYellow);
   4875             }
   4876             if (fld_val & 0x1) {
   4877                 *value |= (0x1 << bcmColorRed);
   4878             }
   4879             break;
   4880         default:
   4881             return BCM_E_PARAM;
   4882     }
   4883     return BCM_E_NONE;
   4884 }
   4885 
   4886 /*
   4887  * Function:
   4888  *     bcmi_gh2_cosq_gport_add
   4889  * Purpose:
   4890  *     Create a cosq gport structure
   4891  * Parameters:
   4892  *     unit  - (IN) unit number
   4893  *     port  - (IN) port number
   4894  *     numq  - (IN) number of COS queues
   4895  *     flags - (IN) flags (BCM_COSQ_GPORT_XXX)
   4896  *     gport - (OUT) GPORT identifier
   4897  * Returns:
   4898  *     BCM_E_XXX
   4899  */
   4900 int
   4901 bcmi_gh2_cosq_gport_add(int unit, bcm_gport_t port, int numq, uint32 flags,
   4902                         bcm_gport_t *gport)
   4903 {
   4904     bcm_port_t local_port;
   4905     int phy_port, mmu_port;
   4906     uint32 sched_encap;
   4907     gh2_mmu_info_t *mmu_info;
   4908     gh2_cosq_node_t *node = NULL;
   4909     int id;
   4910     int is_64q_port;
   4911 
   4912     LOG_INFO(BSL_LS_BCM_COSQ,
   4913              (BSL_META_U(unit,
   4914                          "bcmi_gh2_cosq_gport_add: unit=%d port=0x%x \
   4915                          numq=%d flags=0x%x\n"),
   4916               unit, port, numq, flags));
   4917 
   4918     if (gport == NULL) {
   4919         return BCM_E_PARAM;
   4920     }
   4921 
   4922     if (gh2_mmu_info[unit] == NULL) {
   4923         return BCM_E_INIT;
   4924     }
   4925 
   4926     BCM_IF_ERROR_RETURN
   4927         (bcmi_gh2_cosq_localport_resolve(unit, port, &local_port));
   4928 
   4929     if (local_port < 0) {
   4930         return BCM_E_PORT;
   4931     }
   4932 
   4933     BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port,
   4934                                                &is_64q_port));
   4935 
   4936     if (!is_64q_port) {
   4937         /* Only MMU port 58-65 support */
   4938         LOG_INFO(BSL_LS_BCM_COSQ,
   4939                  (BSL_META_U(unit,
   4940                   "bcmi_gh2_cosq_gport_add: Only MMU port 58-65 support\n")));
   4941         return BCM_E_PORT;
   4942     }
   4943 
   4944     mmu_info = gh2_mmu_info[unit];
   4945 
   4946     switch (flags) {
   4947         case BCM_COSQ_GPORT_UCAST_QUEUE_GROUP:
   4948             /* to create the gport object of the 64 queues */
   4949             if (numq != 1) {
   4950                 return BCM_E_PARAM;
   4951             }
   4952             for (id = 0;
   4953                  id < GH2_NUM_TOTAL_QUEUES; id++) {
   4954                 if (mmu_info->queue_node[id].in_use == FALSE) {
   4955                     node = &mmu_info->queue_node[id];
   4956                     node->in_use = TRUE;
   4957                     break;
   4958                 }
   4959             }
   4960             if (!node) {
   4961                 return BCM_E_RESOURCE;
   4962             }
   4963 
   4964             node = &mmu_info->queue_node[id];
   4965             node->node_id = id;
   4966             BCM_GPORT_UCAST_QUEUE_GROUP_SYSQID_SET(*gport, local_port, id);
   4967             node->node_gport = *gport;
   4968             node->node_level = GH2_COSQ_LEVEL_QUEUE;
   4969             node->max_num_child = 1;
   4970             break;
   4971     case BCM_COSQ_GPORT_SCHEDULER:
   4972         /* passthru */
   4973     case BCM_COSQ_GPORT_WITH_ID:
   4974     case (BCM_COSQ_GPORT_SCHEDULER | BCM_COSQ_GPORT_WITH_ID):
   4975     case 0:
   4976         if (numq < -1) {
   4977             return BCM_E_PARAM;
   4978         }
   4979 
   4980         /*
   4981             * 80 scheduler nodes,
   4982             * the first 8 are for each MMU port
   4983             * the others are for QGROUP and QLAYER
   4984             */
   4985         if ((flags & BCM_COSQ_GPORT_WITH_ID) || (flags == 0)) {
   4986             /* this is a Port level scheduler */
   4987             if (numq > 1) {
   4988                 LOG_INFO(BSL_LS_BCM_COSQ,
   4989                          (BSL_META_U(unit,
   4990                                      "bcmi_gh2_cosq_gport_add: \
   4991                                      only one QGroup scheduler can be \
   4992                                      attached to egress port\n")));
   4993                 return BCM_E_UNAVAIL;
   4994             }
   4995 
   4996             phy_port = SOC_INFO(unit).port_l2p_mapping[local_port];
   4997             mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port];
   4998             id = (mmu_port - SOC_GH2_64Q_MMU_PORT_IDX_MIN);
   4999 
   5000             if ( id < 0 || id >= GH2_NUM_PORT_SCHEDULERS) {
   5001                 return BCM_E_PARAM;
   5002             }
   5003 
   5004             node = &mmu_info->sched_node[id];
   5005             node->node_id = id;
   5006             sched_encap = (id << 8) | local_port;
   5007             BCM_GPORT_SCHEDULER_SET(*gport, sched_encap);
   5008             node->node_gport = *gport;
   5009             node->node_level = GH2_COSQ_LEVEL_PORT;
   5010             node->max_num_child = 1;
   5011             node->in_use = TRUE;
   5012         } else {
   5013             /* For QGROUP or QLAYER level scheduler */
   5014             if (numq > 8) {
   5015                 LOG_INFO(BSL_LS_BCM_COSQ,
   5016                          (BSL_META_U(unit,
   5017                                      "bcmi_gh2_cosq_gport_add: \
   5018                                      only 8 member scheduler can be \
   5019                                      attached to QGroup scheduler or \
   5020                                      QLayer scheduler\n")));
   5021                 return BCM_E_UNAVAIL;
   5022             }
   5023 
   5024             for (id = GH2_NUM_QGROUP_SCHEDULERS;
   5025                  id < GH2_NUM_TOTAL_SCHEDULERS; id++) {
   5026                 if (mmu_info->sched_node[id].in_use == FALSE) {
   5027                     node = &mmu_info->sched_node[id];
   5028                     node->in_use = TRUE;
   5029                     break;
   5030                 }
   5031             }
   5032             if (!node) {
   5033                 return BCM_E_RESOURCE;
   5034             }
   5035 
   5036             node = &mmu_info->sched_node[id];
   5037             node->node_id = id;
   5038             sched_encap = (id << 8) | local_port;
   5039             BCM_GPORT_SCHEDULER_SET(*gport, sched_encap);
   5040             node->node_gport = *gport;
   5041             node->max_num_child = numq;
   5042        }
   5043        break;
   5044 
   5045     default:
   5046         return BCM_E_PARAM;
   5047     }
   5048 
   5049     LOG_INFO(BSL_LS_BCM_COSQ,
   5050              (BSL_META_U(unit,
   5051                          "                       gport=0x%x\n"),
   5052               *gport));
   5053 
   5054     return BCM_E_NONE;
   5055 }
   5056 
   5057 /*
   5058  * Function:
   5059  *     bcmi_gh2_cosq_gport_delete
   5060  * Purpose:
   5061  *     Destroy a cosq gport structure
   5062  * Parameters:
   5063  *     unit  - (IN) unit number
   5064  *     gport - (IN) GPORT identifier
   5065  * Returns:
   5066  *     BCM_E_XXX
   5067  */
   5068 int
   5069 bcmi_gh2_cosq_gport_delete(int unit, bcm_gport_t gport)
   5070 {
   5071     gh2_cosq_node_t *node;
   5072     gh2_cosq_node_t *node_child;
   5073     int local_port;
   5074     int i;
   5075 
   5076     LOG_INFO(BSL_LS_BCM_COSQ,
   5077              (BSL_META_U(unit,
   5078                          "bcmi_gh2_cosq_gport_delete: unit=%d gport=0x%x\n"),
   5079                          unit, gport));
   5080 
   5081     if (gh2_mmu_info[unit] == NULL) {
   5082         return BCM_E_INIT;
   5083     }
   5084 
   5085     node = NULL;
   5086 
   5087     if (!(BCM_GPORT_IS_SCHEDULER(gport) ||
   5088         BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport))) {
   5089         return BCM_E_PORT;
   5090     }
   5091 
   5092     BCM_IF_ERROR_RETURN
   5093         (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL,
   5094                                 &local_port, NULL, &node));
   5095 
   5096     if (node == NULL) {
   5097         return BCM_E_INTERNAL;
   5098     }
   5099 
   5100     if (node->node_level == GH2_COSQ_LEVEL_PORT) {
   5101         /* detach child (QGroup) if existed */
   5102         if (node->child_gport[0] != -1) {
   5103             BCM_IF_ERROR_RETURN
   5104                 (bcmi_gh2_cosq_node_get(unit, node->child_gport[0],
   5105                                         0, NULL, NULL, NULL, &node_child));
   5106             BCM_IF_ERROR_RETURN
   5107                 (bcmi_gh2_cosq_gport_detach(unit, node_child->node_gport,
   5108                                             node->node_gport, 0));
   5109         }
   5110     } else if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   5111         /* detach all child (QLayer) if existed */
   5112         for (i = 0; i < node->num_child; i++) {
   5113             if (node->child_gport[i] != -1) {
   5114                 BCM_IF_ERROR_RETURN
   5115                     (bcmi_gh2_cosq_node_get(unit, node->child_gport[i],
   5116                                             0, NULL, NULL, NULL,
   5117                                             &node_child));
   5118                 BCM_IF_ERROR_RETURN
   5119                     (bcmi_gh2_cosq_gport_detach(unit, node_child->node_gport,
   5120                                                 node->node_gport,
   5121                                                 node_child->child_idx));
   5122             }
   5123         }
   5124         /* detach from parent */
   5125         if (node->parent_gport != -1) {
   5126             BCM_IF_ERROR_RETURN
   5127                 (bcmi_gh2_cosq_gport_detach(unit, node->node_gport,
   5128                                             node->parent_gport, 0));
   5129         }
   5130     } else if (node->node_level == GH2_COSQ_LEVEL_QLAYER) {
   5131         /* detach all child (QLayer) if existed */
   5132         for (i = 0; i < node->num_child; i++) {
   5133             if (node->child_gport[i] != -1) {
   5134                 BCM_IF_ERROR_RETURN
   5135                     (bcmi_gh2_cosq_node_get(unit, node->child_gport[i],
   5136                                             0, NULL, NULL, NULL,
   5137                                             &node_child));
   5138                 BCM_IF_ERROR_RETURN
   5139                     (bcmi_gh2_cosq_gport_detach(unit, node_child->node_gport,
   5140                                                 node->node_gport,
   5141                                                 node_child->child_idx));
   5142             }
   5143         }
   5144 
   5145         /* detach parent (QGroup) */
   5146         if (node->parent_gport != -1) {
   5147             BCM_IF_ERROR_RETURN
   5148                 (bcmi_gh2_cosq_gport_detach(unit, node->node_gport,
   5149                                             node->parent_gport,
   5150                                             node->child_idx));
   5151         }
   5152     } else { /* GH2_COSQ_LEVEL_QUEUE */
   5153         /* detach parent (QLayer) */
   5154         if (node->parent_gport != -1) {
   5155             BCM_IF_ERROR_RETURN
   5156                 (bcmi_gh2_cosq_gport_detach(unit, node->node_gport,
   5157                                             node->parent_gport,
   5158                                             node->child_idx));
   5159         }
   5160     }
   5161     /*_BCM_GH2_COSQ_NODE_INIT(node); */
   5162     bcmi_gh2_cosq_node_t_init(node);
   5163     return BCM_E_NONE;
   5164 }
   5165 
   5166 /*
   5167  * Function:
   5168  *     bcmi_gh2_cosq_gport_traverse
   5169  * Purpose:
   5170  *     Walks through the valid COSQ GPORTs and calls
   5171  *     the user supplied callback function for each entry.
   5172  * Parameters:
   5173  *     unit       - (IN) unit number
   5174  *     trav_fn    - (IN) Callback function.
   5175  *     user_data  - (IN) User data to be passed to callback function
   5176  * Returns:
   5177  *     BCM_E_NONE - Success.
   5178  *     BCM_E_XXX
   5179  */
   5180 int
   5181 bcmi_gh2_cosq_gport_traverse(int unit, bcm_cosq_gport_traverse_cb cb,
   5182                              void *user_data)
   5183 {
   5184     gh2_mmu_info_t *mmu_info;
   5185     gh2_cosq_node_t *node;
   5186     uint32 flags = BCM_COSQ_GPORT_SCHEDULER;
   5187     int rv = BCM_E_NONE;
   5188     int i;
   5189     int numq;
   5190 
   5191     if (gh2_mmu_info[unit] == NULL) {
   5192         return BCM_E_INIT;
   5193     }
   5194     mmu_info = gh2_mmu_info[unit];
   5195 
   5196     for (i = 0 ; i < GH2_NUM_TOTAL_SCHEDULERS; i++) {
   5197         node = &mmu_info->sched_node[i];
   5198         if (node->in_use) {
   5199             flags = BCM_COSQ_GPORT_SCHEDULER;
   5200             if (node->node_level == GH2_COSQ_LEVEL_PORT) {
   5201                 numq = 1;
   5202             } else if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   5203                 numq = node->num_child;
   5204             } else { /* GH2_COSQ_LEVEL_QLAYER */
   5205                 numq = 8;
   5206             }
   5207             rv = cb(unit, node->node_gport, numq, flags,
   5208                     node->node_gport, user_data);
   5209            if (BCM_FAILURE(rv)) {
   5210 #ifdef BCM_CB_ABORT_ON_ERR
   5211                if (SOC_CB_ABORT_ON_ERR(unit)) {
   5212                    return rv;
   5213                }
   5214 #endif
   5215            }
   5216         }
   5217     }
   5218 
   5219     for (i = 0 ; i < GH2_NUM_TOTAL_QUEUES; i++) {
   5220         node = &mmu_info->queue_node[i];
   5221         if (node->in_use) {
   5222             flags = BCM_COSQ_GPORT_UCAST_QUEUE_GROUP;
   5223             numq = 1;
   5224             rv = cb(unit, node->node_gport, numq, flags,
   5225                       node->node_gport, user_data);
   5226            if (BCM_FAILURE(rv)) {
   5227 #ifdef BCM_CB_ABORT_ON_ERR
   5228                if (SOC_CB_ABORT_ON_ERR(unit)) {
   5229                    return rv;
   5230                }
   5231 #endif
   5232            }
   5233         }
   5234     }
   5235     return BCM_E_NONE;
   5236 }
   5237 
   5238 /*
   5239  * Function:
   5240  *     bcmi_gh2_cosq_gport_get
   5241  * Purpose:
   5242  *     Get a cosq gport structure
   5243  * Parameters:
   5244  *     unit  - (IN) unit number
   5245  *     gport - (IN) GPORT identifier
   5246  *     port  - (OUT) port number
   5247  *     numq  - (OUT) number of COS queues
   5248  *     flags - (OUT) flags (BCM_COSQ_GPORT_XXX)
   5249  * Returns:
   5250  *     BCM_E_XXX
   5251  */
   5252 int
   5253 bcmi_gh2_cosq_gport_get(int unit, bcm_gport_t gport, bcm_gport_t *port,
   5254                         int *numq, uint32 *flags)
   5255 {
   5256     gh2_cosq_node_t *node = NULL;
   5257     bcm_module_t modid;
   5258     bcm_port_t local_port;
   5259     int id;
   5260     _bcm_gport_dest_t dest;
   5261 
   5262     if (gh2_mmu_info[unit] == NULL) {
   5263         return BCM_E_INIT;
   5264     }
   5265 
   5266     if (port == NULL || numq == NULL || flags == NULL) {
   5267         return BCM_E_PARAM;
   5268     }
   5269 
   5270     LOG_INFO(BSL_LS_BCM_COSQ,
   5271              (BSL_META_U(unit,
   5272                          "bcmi_gh2_cosq_gport_get: unit=%d gport=0x%x\n"),
   5273               unit, gport));
   5274 
   5275     if (!(BCM_GPORT_IS_SCHEDULER(gport) ||
   5276         BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport))) {
   5277         return BCM_E_PORT;
   5278     }
   5279 
   5280     BCM_IF_ERROR_RETURN
   5281         (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, &local_port, &id, &node));
   5282 
   5283     if (SOC_USE_GPORT(unit)) {
   5284         BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &modid));
   5285         dest.gport_type = _SHR_GPORT_TYPE_MODPORT;
   5286         dest.modid = modid;
   5287         dest.port = local_port;
   5288         BCM_IF_ERROR_RETURN(_bcm_esw_gport_construct(unit, &dest, port));
   5289     } else {
   5290         *port = local_port;
   5291     }
   5292 
   5293     if (node->node_level == GH2_COSQ_LEVEL_PORT) {
   5294         *flags = 0;
   5295     } else if (node->node_level == GH2_COSQ_LEVEL_QUEUE) {
   5296         *flags = BCM_COSQ_GPORT_UCAST_QUEUE_GROUP;
   5297     } else { /* GH2_COSQ_LEVEL_QGROUP or GH2_COSQ_LEVEL_QLAYER */
   5298         *flags = BCM_COSQ_GPORT_SCHEDULER;
   5299     }
   5300     *numq = node->max_num_child;
   5301 
   5302     LOG_INFO(BSL_LS_BCM_COSQ,
   5303              (BSL_META_U(unit,
   5304                          "                     port=0x%x numq=%d flags=0x%x\n"),
   5305                          *port, *numq, *flags));
   5306 
   5307     return BCM_E_NONE;
   5308 }
   5309 
   5310 /*
   5311  * Function:
   5312  *     bcmi_gh2_cosq_gport_attach
   5313  * Purpose:
   5314  *     Attach sched_port to the specified index (cosq) of input_port
   5315  * Parameters:
   5316  *     unit       - (IN) unit number
   5317  *     sched_port - (IN) scheduler GPORT identifier
   5318  *     input_port - (IN) GPORT to attach to
   5319  *     cosq       - (IN) COS queue to attach to (-1 for first available cosq)
   5320  * Returns:
   5321  *     BCM_E_XXX
   5322  */
   5323 int
   5324 bcmi_gh2_cosq_gport_attach(int unit, bcm_gport_t gport,
   5325                            bcm_gport_t to_gport,
   5326                            bcm_cos_queue_t to_cosq)
   5327 {
   5328     gh2_cosq_node_t *node, *to_node, *temp_node;
   5329     bcm_port_t port, to_port;
   5330     int i;
   5331     int child_index = 0;
   5332     uint32 reg_val = 0;
   5333     int id;
   5334     int phy_port, mmu_port;
   5335     gh2_mmu_info_t *mmu_info;
   5336 
   5337 
   5338     if (gh2_mmu_info[unit] == NULL) {
   5339         return BCM_E_INIT;
   5340     }
   5341 
   5342     /*
   5343      * Three kinds of attach supported
   5344      * 1.QGROUP scheduler(gport) attaches to egress port(to_gport)
   5345      *    egress port(to_gport) here can be local port id or gport id
   5346      * 2.QLAYER scheduler(gport) attaches to QGROUP scheduler(to_gport)
   5347      * 3.Queue node(gport) attaches to QLAYER scheduler(to_gport)
   5348      */
   5349     if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(to_gport)) {
   5350         return BCM_E_PARAM;
   5351     }
   5352 
   5353     if (!(BCM_GPORT_IS_SCHEDULER(to_gport) ||
   5354           BCM_GPORT_IS_LOCAL(to_gport) ||
   5355           BCM_GPORT_IS_MODPORT(to_gport))) {
   5356         return BCM_E_PORT;
   5357     }
   5358 
   5359     if (!(BCM_GPORT_IS_SCHEDULER(gport) ||
   5360         BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport))) {
   5361         return BCM_E_PORT;
   5362     }
   5363 
   5364     if (to_cosq < -1) {
   5365         return BCM_E_PARAM;
   5366     }
   5367 
   5368     to_node = NULL;
   5369     if (BCM_GPORT_IS_SCHEDULER(to_gport)) {
   5370         /*
   5371          * attach cases :
   5372          * 1.QGROUP scheduler(gport) attaches to egress port(to_gport)
   5373          * 2.QLAYER scheduler(gport) attaches to QGROUP scheduler(to_gport)
   5374          * 3.Queue node(gport) attaches to QLAYER scheduler(to_gport)
   5375          */
   5376         BCM_IF_ERROR_RETURN
   5377             (bcmi_gh2_cosq_node_get(unit, to_gport, 0, NULL, &to_port, NULL,
   5378                                     &to_node));
   5379     } else {
   5380         /* to_gport is local port */
   5381 
   5382         /* QGROUP scheduler(gport) attaches to egress port(to_gport) */
   5383         BCM_IF_ERROR_RETURN
   5384             (bcmi_gh2_cosq_localport_resolve(unit, to_gport, &to_port));
   5385 
   5386         /* Does it ever created PORT scheduler?*/
   5387         phy_port = SOC_INFO(unit).port_l2p_mapping[to_port];
   5388         mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port];
   5389         id = (mmu_port - SOC_GH2_64Q_MMU_PORT_IDX_MIN);
   5390 
   5391         if ( id < 0 || id >= GH2_NUM_PORT_SCHEDULERS) {
   5392             return BCM_E_PARAM;
   5393         }
   5394 
   5395         mmu_info = gh2_mmu_info[unit];
   5396         temp_node = &mmu_info->sched_node[id];
   5397         if (temp_node->in_use) {
   5398             to_node = temp_node;
   5399         }
   5400     }
   5401 
   5402     if (to_node != NULL) {
   5403         if (to_node->node_level == GH2_COSQ_LEVEL_PORT) {
   5404             /* only 1 QGROUP scheduler can be attached to egress port(gport) */
   5405             if (to_cosq >= 1) {
   5406                 return BCM_E_PARAM;
   5407             }
   5408         } else {
   5409             /*
   5410              * Only 8 QLAYER scheduler can be attached to QGROUP scheduler
   5411              * Or, only 8 queue can be attached to QLAYER scheduler
   5412              */
   5413             if (to_cosq >= 8) {
   5414                 return BCM_E_PARAM;
   5415             }
   5416         }
   5417     } else {
   5418         /* only 1 QGROUP scheduler can be attached to egress port(gport) */
   5419         if (to_cosq >= 1) {
   5420             return BCM_E_PARAM;
   5421         }
   5422     }
   5423 
   5424     BCM_IF_ERROR_RETURN
   5425         (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, &port, NULL, &node));
   5426 
   5427     if (port != to_port) {
   5428         return BCM_E_PORT;
   5429     }
   5430 
   5431     if (node->parent_gport != -1) {
   5432         /* Has already attached */
   5433         return BCM_E_EXISTS;
   5434     }
   5435 
   5436     if (to_node != NULL) {
   5437         if (to_node->node_level == GH2_COSQ_LEVEL_PORT) {
   5438             /* QGROUP scheduler(gport) attaches to egress port(to_gport) */
   5439             to_node->child_gport[0] = gport;
   5440             to_node->num_child = 1;
   5441 
   5442             node->parent_gport = to_gport;
   5443             node->node_level = GH2_COSQ_LEVEL_QGROUP;
   5444 
   5445             /* enable two layer scheduler mode */
   5446             READ_TWO_LAYER_SCH_MODEr(unit, to_port, &reg_val);
   5447             soc_reg_field_set(unit, TWO_LAYER_SCH_MODEr, &reg_val,
   5448                               SCH_MODEf,  1);
   5449             WRITE_TWO_LAYER_SCH_MODEr(unit, to_port, reg_val);
   5450         } else {
   5451             /* QLAYER scheduler(gport) attaches to QGROUP scheduler(to_gport)
   5452              * or
   5453              * Queue node(gport) attaches to QLAYER scheduler(to_gport)
   5454              */
   5455             if (to_cosq == -1) {
   5456                 /* find the first available index */
   5457                 for (i = 0; i < to_node->max_num_child; i++) {
   5458                     if (to_node->child_gport[i] != BCM_GPORT_INVALID) {
   5459                         child_index = i;
   5460                     }
   5461                 }
   5462             } else {
   5463                 child_index = to_cosq;
   5464             }
   5465 
   5466             to_node->child_gport[child_index] = gport;
   5467             to_node->num_child++;
   5468             node->parent_gport = to_gport;
   5469             node->child_idx = child_index;
   5470             if (to_node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   5471                 node->node_level = GH2_COSQ_LEVEL_QLAYER;
   5472                 node->qlayer_cosq_min = (child_index * 8);
   5473                 node->qlayer_cosq_max = ((child_index + 1) * 8) -1;
   5474             }
   5475         }
   5476     } else {
   5477         /* QGROUP scheduler(gport) attaches to egress port(to_gport) */
   5478         node->parent_gport = to_gport;
   5479         node->node_level = GH2_COSQ_LEVEL_QGROUP;
   5480 
   5481         /* enable two layer scheduler mode */
   5482         READ_TWO_LAYER_SCH_MODEr(unit, to_port, &reg_val);
   5483         soc_reg_field_set(unit, TWO_LAYER_SCH_MODEr, &reg_val,
   5484                   SCH_MODEf,  1);
   5485         WRITE_TWO_LAYER_SCH_MODEr(unit, to_port, reg_val);
   5486     }
   5487 
   5488     return BCM_E_NONE;
   5489 }
   5490 
   5491 /*
   5492  * Function:
   5493  *     bcmi_gh2_cosq_gport_attach_get
   5494  * Purpose:
   5495  *     Get attached status of a scheduler port
   5496  * Parameters:
   5497  *     unit       - (IN) unit number
   5498  *     gport - (IN) scheduler GPORT identifier
   5499  *     input_gport - (OUT) GPORT to attach to
   5500  *     cosq       - (OUT) COS queue to attached to
   5501  * Returns:
   5502  *     BCM_E_XXX
   5503  * Notes:
   5504  */
   5505 int
   5506 bcmi_gh2_cosq_gport_attach_get(int unit, bcm_gport_t gport,
   5507                                bcm_gport_t *input_gport, bcm_cos_queue_t *cosq)
   5508 {
   5509     gh2_cosq_node_t *node;
   5510     bcm_module_t modid;
   5511     bcm_port_t port;
   5512 
   5513     if (gh2_mmu_info[unit] == NULL) {
   5514         return BCM_E_INIT;
   5515     }
   5516 
   5517     if (input_gport == NULL || cosq == NULL) {
   5518         return BCM_E_PARAM;
   5519     }
   5520 
   5521     BCM_IF_ERROR_RETURN
   5522         (bcmi_gh2_cosq_node_get(unit, gport, 0, &modid, &port, NULL,
   5523                                 &node));
   5524 
   5525     if (node->parent_gport == -1) {
   5526         /* Not attached yet */
   5527         return BCM_E_NOT_FOUND;
   5528     }
   5529 
   5530     if (node->node_level == GH2_COSQ_LEVEL_PORT) {
   5531         /* PORT level scheduler has no parent */
   5532         return BCM_E_PORT;
   5533     } else if (node->node_level == GH2_COSQ_LEVEL_QGROUP) {
   5534         *cosq = 0;
   5535     } else {
   5536         /* GH2_COSQ_LEVEL_QLAYER or  GH2_COSQ_LEVEL_QUEUE */
   5537         *cosq = node->child_idx;
   5538     }
   5539     *input_gport = node->parent_gport;
   5540 
   5541     return BCM_E_NONE;
   5542 }
   5543 
   5544 /*
   5545  * Function:
   5546  *      bcmi_gh2_cosq_gport_child_get
   5547  * Purpose:
   5548  *      Get the child node GPORT atatched to N-th index (cosq)
   5549  *      of the scheduler GPORT.
   5550  * Parameters:
   5551  *      unit       - (IN)  Unit number.
   5552  *      in_gport   - (IN)  Scheduler GPORT ID.
   5553  *      cosq       - (IN)  COS queue attached to.
   5554  *      out_gport  - (OUT) child GPORT ID.
   5555  * Returns:
   5556  *      BCM_E_XXX
   5557  * Notes:
   5558  */
   5559 int
   5560 bcmi_gh2_cosq_gport_child_get(int unit, bcm_gport_t in_gport,
   5561                               bcm_cos_queue_t cosq,
   5562                               bcm_gport_t *out_gport)
   5563 {
   5564     gh2_cosq_node_t *in_node = NULL;
   5565     bcm_module_t in_modid = 0;
   5566     bcm_port_t in_port = -1;
   5567     int phy_port, mmu_port;
   5568     int id;
   5569     gh2_mmu_info_t *mmu_info;
   5570 
   5571     if (gh2_mmu_info[unit] == NULL) {
   5572         return BCM_E_INIT;
   5573     }
   5574     mmu_info = gh2_mmu_info[unit];
   5575 
   5576     if (out_gport == NULL) {
   5577         return BCM_E_PARAM;
   5578     }
   5579 
   5580     if (BCM_GPORT_IS_SET(in_gport) && !BCM_GPORT_IS_SCHEDULER(in_gport)) {
   5581         return BCM_E_PORT;
   5582     }
   5583 
   5584     if (cosq < 0) {
   5585         return BCM_E_PARAM;
   5586     }
   5587 
   5588     if (!BCM_GPORT_IS_SET(in_gport)) {
   5589         /* this is a PORT level scheduler */
   5590         /* only 1 QGROUP scheduler can be attached to egress port */
   5591         if (cosq >= 64) {
   5592             return BCM_E_PARAM;
   5593         }
   5594         if (cosq >= 1) {
   5595             return BCM_E_NOT_FOUND;
   5596         }
   5597 
   5598         BCM_IF_ERROR_RETURN
   5599             (bcmi_gh2_cosq_localport_resolve(unit, in_gport, &in_port));
   5600         phy_port = SOC_INFO(unit).port_l2p_mapping[in_port];
   5601         mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port];
   5602         id = (mmu_port - SOC_GH2_64Q_MMU_PORT_IDX_MIN);
   5603 
   5604         if ( id < 0 || id >= GH2_NUM_PORT_SCHEDULERS) {
   5605             return BCM_E_PARAM;
   5606         }
   5607         in_node = &mmu_info->sched_node[id];
   5608         if (in_node->in_use) {
   5609             /* The child gport is not valid (not attached) */
   5610             if (BCM_GPORT_INVALID == in_node->child_gport[0]) {
   5611                 return BCM_E_NOT_FOUND;
   5612             }
   5613             *out_gport =in_node->child_gport[0];
   5614         } else {
   5615             return BCM_E_NOT_FOUND;
   5616         }
   5617     } else {
   5618         BCM_IF_ERROR_RETURN
   5619             (bcmi_gh2_cosq_node_get(unit, in_gport, 0, &in_modid, &in_port,
   5620                                     NULL, &in_node));
   5621         if (in_node->node_level == GH2_COSQ_LEVEL_PORT) {
   5622             /* this is a PORT level scheduler */
   5623             /* only 1 QGROUP scheduler can be attached to egress port */
   5624             if (cosq >= 64) {
   5625                 return BCM_E_PARAM;
   5626             }
   5627             if (cosq >= 1) {
   5628                 return BCM_E_NOT_FOUND;
   5629             }
   5630         } else {
   5631             if (cosq >= 8) {
   5632                 return BCM_E_PARAM;
   5633             }
   5634             }
   5635 
   5636         if (in_node->node_level == GH2_COSQ_LEVEL_QUEUE) {
   5637             /* no child will be attached to the queue node */
   5638             return BCM_E_PARAM;
   5639         }
   5640 
   5641         /* The child gport is not valid (not attached) */
   5642         if (BCM_GPORT_INVALID == in_node->child_gport[cosq]) {
   5643             return BCM_E_NOT_FOUND;
   5644         }
   5645 
   5646         /* Get the child gport */
   5647         *out_gport = in_node->child_gport[cosq];
   5648     }
   5649 
   5650     return BCM_E_NONE;
   5651 }
   5652 
   5653 
   5654 /*
   5655  * Function:
   5656  *     bcmi_gh2_cosq_gport_detach
   5657  * Purpose:
   5658  *     Detach sched_port from the specified index (cosq) of input_port
   5659  * Parameters:
   5660  *     unit       - (IN) unit number
   5661  *     gport - (IN) scheduler GPORT identifier
   5662  *     input_gport - (IN) GPORT to detach from
   5663  *     cosq       - (IN) COS queue to detach from
   5664  * Returns:
   5665  *     BCM_E_XXX
   5666  */
   5667 int
   5668 bcmi_gh2_cosq_gport_detach(int unit, bcm_gport_t gport,
   5669                            bcm_gport_t input_gport, bcm_cos_queue_t cosq)
   5670 {
   5671     gh2_cosq_node_t *node, *input_node = NULL, *temp_node = NULL;
   5672     bcm_port_t port, input_port = -1;
   5673     int child_index;
   5674     uint32 reg_val;
   5675     int id;
   5676     int phy_port, mmu_port;
   5677     gh2_mmu_info_t *mmu_info;
   5678 
   5679     if (gh2_mmu_info[unit] == NULL) {
   5680         return BCM_E_INIT;
   5681     }
   5682 
   5683     /*
   5684      * Three kinds of attach/detach supported
   5685      * 1.QGROUP scheduler(gport) attached to egress port(input_gport)
   5686      * 2.QLAYER scheduler(gport) attached to QGROUP scheduler(input_gport)
   5687      * 3.Queue node(gport) attached to QLAYER scheduler(input_gport)
   5688      */
   5689     if (!(BCM_GPORT_IS_SCHEDULER(input_gport) ||
   5690         BCM_GPORT_IS_MODPORT(input_gport) ||
   5691         BCM_GPORT_IS_LOCAL(input_gport))) {
   5692         return BCM_E_PARAM;
   5693     }
   5694     if (!(BCM_GPORT_IS_SCHEDULER(gport) ||
   5695         BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport))) {
   5696         return BCM_E_PORT;
   5697     }
   5698 
   5699     if (cosq < -1) {
   5700         return BCM_E_PARAM;
   5701     }
   5702 
   5703     input_node = NULL;
   5704     if (BCM_GPORT_IS_SCHEDULER(input_gport)) {
   5705         /*
   5706          * attached cases :
   5707          * 1.QLAYER scheduler(gport) attached to QGROUP scheduler(input_gport)
   5708          * 2.QGROUP scheduler(gport) attached to egress port(input_gport)
   5709          * 3.Queue node(gport) attached to QLAYER scheduler(input_gport)
   5710          */
   5711         BCM_IF_ERROR_RETURN
   5712             (bcmi_gh2_cosq_node_get(unit, input_gport, 0, NULL, &input_port,
   5713                                     NULL, &input_node));
   5714     } else {
   5715         /* input_gport is local port */
   5716 
   5717         /* QGROUP scheduler(gport) attached from egress port(input_gport) */
   5718         BCM_IF_ERROR_RETURN
   5719             (bcmi_gh2_cosq_localport_resolve(unit, input_gport, &input_port));
   5720 
   5721         /* Does it ever created PORT scheduler?*/
   5722         phy_port = SOC_INFO(unit).port_l2p_mapping[input_port];
   5723         mmu_port = SOC_INFO(unit).port_p2m_mapping[phy_port];
   5724         id = (mmu_port - SOC_GH2_64Q_MMU_PORT_IDX_MIN);
   5725 
   5726         if ( id < 0 || id >= GH2_NUM_PORT_SCHEDULERS) {
   5727             return BCM_E_PARAM;
   5728         }
   5729 
   5730         mmu_info = gh2_mmu_info[unit];
   5731         temp_node = &mmu_info->sched_node[id];
   5732         if (temp_node->in_use) {
   5733             input_node = temp_node;
   5734         }
   5735     }
   5736 
   5737     if (input_node != NULL) {
   5738         if (input_node->node_level == GH2_COSQ_LEVEL_PORT) {
   5739             /* only 1 QGROUP scheduler can be attached to egress port(gport) */
   5740             if (cosq >= 1) {
   5741                 return BCM_E_PARAM;
   5742             }
   5743         } else {
   5744             /* only 8 QLAYER scheduler can be attached to QGROUP scheduler */
   5745             /* only 8 QLAYER scheduler can be attached to QGROUP scheduler */
   5746             if (cosq >= 8) {
   5747                 return BCM_E_PARAM;
   5748             }
   5749         }
   5750     } else {
   5751         /* only 1 QGROUP scheduler can be attached to egress port(gport) */
   5752         if (cosq >= 1) {
   5753             return BCM_E_PARAM;
   5754         }
   5755     }
   5756 
   5757     BCM_IF_ERROR_RETURN
   5758         (bcmi_gh2_cosq_node_get(unit, gport, 0, NULL, &port, NULL,
   5759                                 &node));
   5760 
   5761     if (port != input_port) {
   5762         return BCM_E_PORT;
   5763     }
   5764     if (node->parent_gport == -1) {
   5765         /* Not attached yet */
   5766         return BCM_E_NOT_FOUND;
   5767     }
   5768 
   5769     if (input_node != NULL) {
   5770         if (input_node->node_level == GH2_COSQ_LEVEL_PORT) {
   5771             /*
   5772              * QGROUP scheduler(gport) detaches from
   5773              * PORT scheduler(input_gport)
   5774              */
   5775             input_node->child_gport[0] = BCM_GPORT_INVALID;
   5776             input_node->num_child--;
   5777             node->parent_gport = -1;
   5778             node->child_idx = -1;
   5779             node->qlayer_cosq_min = -1;
   5780             node->qlayer_cosq_max = -1;
   5781 
   5782             /* disable two layer scheduler mode */
   5783             READ_TWO_LAYER_SCH_MODEr(unit, input_port, &reg_val);
   5784             soc_reg_field_set(unit, TWO_LAYER_SCH_MODEr, &reg_val,
   5785                               SCH_MODEf,  0);
   5786             WRITE_TWO_LAYER_SCH_MODEr(unit, input_port, reg_val);
   5787         } else {
   5788             /* QLAYER scheduler(gport) detaches from QGROUP scheduler(to_gport)
   5789              * or
   5790              * Queue node(gport) detaches from QLAYER scheduler(to_gport)
   5791              */
   5792             if (cosq == -1) {
   5793                 /* not specified, just get input node */
   5794                 child_index = node->child_idx;
   5795             } else {
   5796                 /* detach cosq is not the same as recorded */
   5797                 if (node->child_idx != cosq) {
   5798                     return BCM_E_PARAM;
   5799                 }
   5800                 child_index = cosq;
   5801             }
   5802 
   5803             input_node->child_gport[child_index] = BCM_GPORT_INVALID;
   5804             input_node->num_child--;
   5805             node->parent_gport = -1;
   5806             node->child_idx = -1;
   5807             node->qlayer_cosq_min = -1;
   5808             node->qlayer_cosq_max = -1;
   5809         }
   5810     } else {
   5811         /* QGROUP scheduler(gport) detaches from egress port(input_gport) */
   5812         node->parent_gport = -1;
   5813 
   5814         /* disable two layer scheduler mode */
   5815         READ_TWO_LAYER_SCH_MODEr(unit, input_port, &reg_val);
   5816         soc_reg_field_set(unit, TWO_LAYER_SCH_MODEr, &reg_val,
   5817                   SCH_MODEf,  0);
   5818         WRITE_TWO_LAYER_SCH_MODEr(unit, input_port, reg_val);
   5819     }
   5820     return BCM_E_NONE;
   5821 }
   5822 #ifndef BCM_SW_STATE_DUMP_DISABLE
   5823 static void
   5824 bcmi_gh2_gport_scheduler_dump(int unit, bcm_gport_t port)
   5825 {
   5826     int rv;
   5827     bcm_gport_t lvl0 = BCM_GPORT_INVALID;
   5828     bcm_gport_t lvl1 = BCM_GPORT_INVALID;
   5829     bcm_gport_t lvl2[8];
   5830     int i, j;
   5831 
   5832     /* Get LVL0 scheduler */
   5833     rv = bcmi_gh2_cosq_gport_child_get(unit, port, 0, &lvl0);
   5834     if (BCM_FAILURE(rv)) {
   5835         return;
   5836     }
   5837 
   5838     LOG_CLI((BSL_META_U(unit,
   5839                         "     Port : %d\n"),
   5840                         port));
   5841     LOG_CLI((BSL_META_U(unit,
   5842                         "       LVL-0 scheduler : 0x%x\n"),
   5843                         lvl0));
   5844     for (i = 0; i < 8; i++) {
   5845         rv = bcmi_gh2_cosq_gport_child_get(unit, lvl0, i, &lvl1);
   5846         if (BCM_FAILURE(rv)) {
   5847             continue;
   5848         }
   5849         LOG_CLI((BSL_META_U(unit,
   5850                             "           LVL-1 scheduler : 0x%x\n"),
   5851                             lvl1));
   5852         LOG_CLI((BSL_META_U(unit,
   5853                             "               LVL-2 queues : ")));
   5854         for (j = 0; j < 8; j++) {
   5855             lvl2[j] = BCM_GPORT_INVALID;
   5856             rv = bcmi_gh2_cosq_gport_child_get(unit, lvl1, j, &lvl2[j]);
   5857             if (BCM_SUCCESS(rv)) {
   5858                 LOG_CLI((BSL_META_U(unit,
   5859                                     "0x%x "),
   5860                                     lvl2[j]));
   5861             }
   5862         }
   5863         LOG_CLI((BSL_META_U(unit,
   5864                             "\n")));
   5865     }
   5866 
   5867     return;
   5868 }
   5869 
   5870 /*
   5871  * Function:
   5872  *     bcmi_gh2_cosq_sw_dump
   5873  * Purpose:
   5874  *     Displays COS Queue information maintained by software.
   5875  * Parameters:
   5876  *     unit - Device unit number
   5877  * Returns:
   5878  *     None
   5879  */
   5880 void
   5881 bcmi_gh2_cosq_sw_dump(int unit)
   5882 {
   5883     int  i;
   5884 
   5885     LOG_CLI((BSL_META_U(unit,
   5886             "\nSW Information COSQ - Unit %d\n"), unit));
   5887 
   5888     /* Number COSQ */
   5889     LOG_CLI((BSL_META_U(unit,
   5890                         "    Number: %d\n"), gh2_num_cosq[unit]));
   5891 
   5892     if (gh2_mmu_info[unit]) {
   5893         bcm_pbmp_t ports;
   5894         bcm_port_t port;
   5895         int is_64q_port = 0;
   5896         int rv = 0;
   5897 
   5898         BCM_PBMP_ASSIGN(ports, PBMP_ALL(unit));
   5899         PBMP_ITER(ports, port) {
   5900             rv = soc_gh2_64q_port_check(unit, port, &is_64q_port);
   5901             if (SOC_SUCCESS(rv) && is_64q_port) {
   5902                 bcmi_gh2_gport_scheduler_dump(unit, port);
   5903             }
   5904         }
   5905     }
   5906 
   5907     /* COSQ Map profile */
   5908     /* Display those entries with reference count > 0 */
   5909     LOG_CLI((BSL_META_U(unit,
   5910             "    COSQ Map Profile:\n")));
   5911     if (gh2_cos_map_profile[unit] != NULL) {
   5912         int     num_entries;
   5913         int     ref_count;
   5914         int     entries_per_set;
   5915         uint32  index;
   5916         port_cos_map_entry_t *entry_p;
   5917         uint32  cosq, hg_cosq;
   5918 
   5919         num_entries = soc_mem_index_count
   5920             (unit, gh2_cos_map_profile[unit]->tables[0].mem);
   5921         LOG_CLI((BSL_META_U(unit,
   5922                             "        Number of entries: %d\n"), num_entries));
   5923         LOG_CLI((BSL_META_U(unit,
   5924                             "        Index RefCount EntriesPerSet - "
   5925                             "COS HG_COS\n")));
   5926 
   5927         for (index = 0; index < num_entries;
   5928             index += GH2_COS_MAP_ENTRIES_PER_SET) {
   5929             if (SOC_FAILURE
   5930                 (soc_profile_mem_ref_count_get(unit,
   5931                                                gh2_cos_map_profile[unit],
   5932                                                index, &ref_count))) {
   5933                 break;
   5934             }
   5935 
   5936             if (ref_count <= 0) {
   5937                 continue;
   5938             }
   5939 
   5940             for (i = 0; i < GH2_COS_MAP_ENTRIES_PER_SET; i++) {
   5941                 entries_per_set =
   5942                     gh2_cos_map_profile[unit]->tables[0].
   5943                         entries[index + i].entries_per_set;
   5944                 LOG_CLI((BSL_META_U(unit,
   5945                         "       %5d %8d %13d    "),
   5946                         index + i, ref_count, entries_per_set));
   5947 
   5948                 entry_p = SOC_PROFILE_MEM_ENTRY(unit,
   5949                                                 gh2_cos_map_profile[unit],
   5950                                                 port_cos_map_entry_t *,
   5951                                                 index + i);
   5952                 cosq = soc_mem_field32_get(unit,
   5953                                            PORT_COS_MAPm,
   5954                                            entry_p,
   5955                                            COSf);
   5956                 LOG_CLI((BSL_META_U(unit,
   5957                                     "%2d "), cosq));
   5958                 if (soc_mem_field_valid(unit, PORT_COS_MAPm, HG_COSf)) {
   5959                     hg_cosq = soc_mem_field32_get(unit, PORT_COS_MAPm,
   5960                                                   entry_p,
   5961                                                   HG_COSf);
   5962                     LOG_CLI((BSL_META_U(unit,
   5963                                         "   %2d"), hg_cosq));
   5964                 }
   5965                 LOG_CLI((BSL_META_U(unit,
   5966                                     "\n")));
   5967             }
   5968         }
   5969     }
   5970 
   5971     return;
   5972 }
   5973 #endif /*BCM_SW_STATE_DUMP_DISABLE */
   5974 
   5975 
   5976 /*
   5977  * Function:
   5978  *      bcmi_gh2_cosq_drop_status_enable_set
   5979  * Purpose:
   5980  *      Program E2ECC mode
   5981  * Parameters:
   5982  *      unit  - (IN) Unit number.
   5983  *      port  - (IN) port ID
   5984  *      enable- (IN) enable or disable.
   5985  * Returns:
   5986  *      BCM_E_xxx
   5987  * Notes:
   5988  */
   5989 int
   5990 bcmi_gh2_cosq_drop_status_enable_set(int unit, bcm_port_t port, int enable)
   5991 {
   5992     uint32 rval;
   5993     bcm_port_t local_port;
   5994     int is_64q;
   5995 
   5996     COMPILER_REFERENCE(port);
   5997     PBMP_E_ITER (unit, local_port) {
   5998         BCM_IF_ERROR_RETURN(READ_E2ECC_PORT_CONFIGr(unit, local_port, &rval));
   5999         soc_reg_field_set(unit, E2ECC_PORT_CONFIGr, &rval,
   6000                           COS_CELL_ENf,  enable ? 0xFF : 0x0);
   6001         soc_reg_field_set(unit, E2ECC_PORT_CONFIGr, &rval,
   6002                           COS_PKT_ENf, enable ? 0xFF : 0x0);
   6003         BCM_IF_ERROR_RETURN(WRITE_E2ECC_PORT_CONFIGr(unit, local_port, rval));
   6004     }
   6005 
   6006     BCM_IF_ERROR_RETURN(READ_E2ECC_MODEr(unit, &rval));
   6007     soc_reg_field_set(unit, E2ECC_MODEr, &rval, ENf,
   6008                       enable ? 1 : 0);
   6009     BCM_IF_ERROR_RETURN(WRITE_E2ECC_MODEr(unit, rval));
   6010 
   6011     is_64q = 0;
   6012     PBMP_E_ITER (unit, local_port) {
   6013         BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, local_port, &is_64q));
   6014         if (is_64q) {
   6015             /* E2ECC does not support 2-level scheduling mode */
   6016             /* Apply the register setting to the first 8 COSQ */
   6017             BCM_IF_ERROR_RETURN(
   6018                 READ_COLOR_DROP_EN_QLAYERr(unit, local_port, 0, &rval));
   6019             soc_reg_field_set(unit, COLOR_DROP_EN_QLAYERr, &rval,
   6020                               COLOR_DROP_ENf,  enable ? 0x0 : 0xff);
   6021             BCM_IF_ERROR_RETURN(
   6022                 WRITE_COLOR_DROP_EN_QLAYERr(unit, local_port, 0, rval));
   6023         } else {
   6024             BCM_IF_ERROR_RETURN(READ_COLOR_DROP_ENr(unit, local_port, &rval));
   6025             soc_reg_field_set(unit, COLOR_DROP_ENr, &rval,
   6026                               COLOR_DROP_ENf,  enable ? 0x0 : 0xff);
   6027             BCM_IF_ERROR_RETURN(WRITE_COLOR_DROP_ENr(unit, local_port, rval));
   6028         }
   6029     }
   6030 
   6031     return BCM_E_NONE;
   6032 }
   6033 
   6034 /*
   6035  * Function:
   6036  *      bcmi_gh2_cosq_pfc_class_resolve
   6037  * Purpose:
   6038  *      Resolve the hw class index from bcmSwitchPFCClassNQueue types
   6039  * Parameters:
   6040  *      sctype- (IN) bcmSwitchPFCClassNQueue type.
   6041  *      class - (OUT) hw class index.
   6042  * Returns:
   6043  *      BCM_E_xxx
   6044  * Notes:
   6045  */
   6046 STATIC int
   6047 bcmi_gh2_cosq_pfc_class_resolve(bcm_switch_control_t sctype, int *class)
   6048 {
   6049     if (class == NULL) {
   6050         return BCM_E_PARAM;
   6051     }
   6052 
   6053     switch (sctype) {
   6054     case bcmSwitchPFCClass7Queue:
   6055         *class = 7;
   6056         break;
   6057     case bcmSwitchPFCClass6Queue:
   6058         *class = 6;
   6059         break;
   6060     case bcmSwitchPFCClass5Queue:
   6061         *class = 5;
   6062         break;
   6063     case bcmSwitchPFCClass4Queue:
   6064         *class = 4;
   6065         break;
   6066     case bcmSwitchPFCClass3Queue:
   6067         *class = 3;
   6068         break;
   6069     case bcmSwitchPFCClass2Queue:
   6070         *class = 2;
   6071         break;
   6072     case bcmSwitchPFCClass1Queue:
   6073         *class = 1;
   6074         break;
   6075     case bcmSwitchPFCClass0Queue:
   6076         *class = 0;
   6077         break;
   6078     default:
   6079         return BCM_E_UNAVAIL;
   6080     }
   6081 
   6082     return BCM_E_NONE;
   6083 }
   6084 
   6085 /*
   6086  * Function:
   6087  *      bcmi_gh2_cosq_port_pfc_op
   6088  * Purpose:
   6089  *      Set or clear the cosq id mapped to the bcmSwitchPFCClassNQueue type
   6090  * Parameters:
   6091  *      unit  - (IN) Unit number.
   6092  *      port  - (IN) port ID
   6093  *      sctype- (IN) bcmSwitchPFCClassNQueue type.
   6094  *      op    - (IN) opcode, add or clear
   6095  *      cosq  - (IN) cosq id.
   6096  * Returns:
   6097  *      BCM_E_xxx
   6098  * Notes:
   6099  */
   6100 int
   6101 bcmi_gh2_cosq_port_pfc_op(
   6102     int unit,
   6103     bcm_port_t port,
   6104     bcm_switch_control_t sctype,
   6105     _bcm_cosq_op_t op,
   6106     int cosq)
   6107 {
   6108     int class;
   6109     uint32 class_bmp;
   6110     int i;
   6111     int is_64q_port = 0;
   6112     gh2_cosq_node_t *node = NULL;
   6113     int index;
   6114     int local_port;
   6115     int regidx_max = SOC_REG_NUMELS(unit, PRI2COS_PFCr);
   6116 
   6117     BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_pfc_class_resolve(sctype, &class));
   6118     BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port));
   6119 
   6120     if (is_64q_port) {
   6121         if (BCM_GPORT_IS_SET(cosq)) {
   6122             /* PFC class mapped to QG0~7(cosq is QLayer scheduler gport id) */
   6123             if (BCM_GPORT_IS_SCHEDULER(cosq)) {
   6124                 BCM_IF_ERROR_RETURN
   6125                     (bcmi_gh2_cosq_node_get(unit, cosq, 0, NULL,
   6126                                             &local_port, NULL, &node));
   6127                 if (local_port != port) {
   6128                     /* The scheduler is not belong to the port */
   6129                     return BCM_E_PARAM;
   6130                 }
   6131                 if (node->node_level != GH2_COSQ_LEVEL_QLAYER) {
   6132                     /* Only available on QLayer scheduler */
   6133                     return BCM_E_PARAM;
   6134                 }
   6135                 /* Get the QGx of the QLayer scheduler*/
   6136                 index = node->child_idx;
   6137             } else {
   6138                 /* Only available on QLayer scheduler */
   6139                 return BCM_E_PARAM;
   6140             }
   6141         } else {
   6142             index = cosq;
   6143         }
   6144     } else {
   6145         index = cosq;
   6146     }
   6147 
   6148     if (op == _BCM_COSQ_OP_CLEAR) {
   6149         for (i = 0; i < regidx_max; i++) {
   6150             BCM_IF_ERROR_RETURN(READ_PRI2COS_PFCr(unit, port,
   6151                                 i, &class_bmp));
   6152             class_bmp &= ~(1 << class);
   6153             BCM_IF_ERROR_RETURN(WRITE_PRI2COS_PFCr(unit, port,
   6154                                 i, class_bmp));
   6155         }
   6156     } else if (op == _BCM_COSQ_OP_ADD) {
   6157         if ((index < 0) || index > NUM_COS(unit)) {
   6158             return BCM_E_PARAM;
   6159         }
   6160 
   6161         BCM_IF_ERROR_RETURN(READ_PRI2COS_PFCr(unit, port, index, &class_bmp));
   6162         class_bmp |= (1 << class);
   6163         BCM_IF_ERROR_RETURN(WRITE_PRI2COS_PFCr(unit, port, index, class_bmp));
   6164     } else {
   6165         return BCM_E_PARAM;
   6166     }
   6167 
   6168     return BCM_E_NONE;
   6169 }
   6170 
   6171 /*
   6172  * Function:
   6173  *      bcmi_gh2_cosq_port_pfc_get
   6174  * Purpose:
   6175  *      Get the cosq id mapped to the bcmSwitchPFCClassNQueue type
   6176  * Parameters:
   6177  *      unit  - (IN) Unit number.
   6178  *      port  - (IN) port ID
   6179  *      sctype- (IN) bcmSwitchPFCClassNQueue type.
   6180  *      cosq  - (OUT) cosq id mapped.
   6181  * Returns:
   6182  *      BCM_E_xxx
   6183  * Notes:
   6184  */
   6185 int
   6186 bcmi_gh2_cosq_port_pfc_get(
   6187     int unit,
   6188     bcm_port_t port,
   6189     bcm_switch_control_t sctype,
   6190     int *cosq)
   6191 {
   6192     int class;
   6193     uint32 class_bmp;
   6194     int i;
   6195     int is_64q_port = 0;
   6196     bcm_gport_t lvl0_node_gport = 0;
   6197     bcm_gport_t lvl1_node_gport = 0;
   6198     int regidx_max = SOC_REG_NUMELS(unit, PRI2COS_PFCr);
   6199     int rv = BCM_E_NONE;
   6200 
   6201     if (cosq == NULL) {
   6202         return BCM_E_PARAM;
   6203     }
   6204 
   6205     BCM_IF_ERROR_RETURN(bcmi_gh2_cosq_pfc_class_resolve(sctype, &class));
   6206 
   6207     for (i = 0; i < regidx_max; i++) {
   6208         BCM_IF_ERROR_RETURN(READ_PRI2COS_PFCr(unit, port, i, &class_bmp));
   6209         if (class_bmp & (1 << class)) {
   6210             break;
   6211         }
   6212     }
   6213 
   6214     if (i >= regidx_max) {
   6215         return BCM_E_NOT_FOUND;
   6216     }
   6217 
   6218     BCM_IF_ERROR_RETURN(soc_gh2_64q_port_check(unit, port, &is_64q_port));
   6219     if (is_64q_port) {
   6220         /* Get the lvl0 scheduler(QGroup scheduler) of the port */
   6221         rv = bcmi_gh2_cosq_gport_child_get(unit, port, 0,
   6222                                            &lvl0_node_gport);
   6223         if (SOC_SUCCESS(rv)) {
   6224         /*
   6225              * Get the i-th lvl1 scheduler(QLayer scheduler) of the
   6226              * lvl0 scheduler
   6227          */
   6228         BCM_IF_ERROR_RETURN(
   6229             bcmi_gh2_cosq_gport_child_get(unit, lvl0_node_gport, i,
   6230                                           &lvl1_node_gport));
   6231         *cosq = lvl1_node_gport;
   6232         } else if (rv == BCM_E_NOT_FOUND) {
   6233             /* cannot find child gport, it is legacy mode */
   6234             *cosq = i;
   6235         } else {
   6236             /* return for other errors */
   6237             return rv;
   6238         }
   6239     } else {
   6240         *cosq = i;
   6241     }
   6242 
   6243     return BCM_E_NONE;
   6244 }
   6245 
   6246 #endif /* BCM_GREYHOUND2_SUPPORT */
   6247