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

qos.c (58441B)


      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  * File:        qos.c
      8  * Purpose:     Tomahawk QoS functions
      9  */
     10 #include <soc/mem.h>
     11 #include <soc/debug.h>
     12 #include <soc/cm.h>
     13 #include <soc/drv.h>
     14 #include <soc/register.h>
     15 #include <soc/memory.h>
     16 #include <soc/hash.h>
     17 #include <soc/l2x.h>
     18 #include <bcm/l2.h>
     19 #include <bcm/error.h>
     20 #include <bcm_int/esw/trx.h>
     21 #include <bcm_int/esw/l2.h>
     22 #include <bcm_int/esw/qos.h>
     23 #include <bcm_int/esw/triumph2.h>
     24 #include <bcm_int/esw/tomahawk.h>
     25 #include <bcm_int/esw/xgs3.h>
     26 #include <bcm_int/esw_dispatch.h>
     27 #include <bcm/qos.h>
     28 
     29 #ifdef BCM_TOMAHAWK_SUPPORT
     30 
     31 #define _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP     16
     32 #define _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP 64
     33 
     34 #define _BCM_QOS_MAX_PKT_PRIORITIES             8
     35 #define _BCM_QOS_MAX_INT_PRIORITIES             16
     36 #define _BCM_QOS_MAX_PKT_DES             2
     37 
     38 #define _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS                   \
     39             (soc_mem_index_count(unit, ING_ETAG_PCP_MAPPINGm)/ \
     40              _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP)
     41 #define _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS                   \
     42             (soc_mem_index_count(unit, EGR_ETAG_PCP_MAPPINGm)/ \
     43              _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP)
     44 
     45 #define _BCM_QOS_MAX_L2_VLAN_ETAG_MAP_IDS    ((_BCM_QOS_MAX_L2_VLAN_ETAG_MAPS)\
     46                                           * _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP)
     47 #define _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAP_IDS    ((_BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS)\
     48 											  * _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP)
     49 
     50 #define _BCM_QOS_MAP_TYPE_MASK           0x7ff
     51 #define _BCM_QOS_MAP_SHIFT                  11
     52 
     53 #define _BCM_QOS_NO_MAP                     -1
     54 
     55 typedef struct _bcm_th_qos_bookkeeping_s {
     56     SHR_BITDCL *ing_l2_vlan_etag_map;
     57     uint32     *ing_l2_vlan_etag_map_hwidx;   
     58     SHR_BITDCL *egr_l2_vlan_etag_map;
     59     uint32     *egr_l2_vlan_etag_map_hwidx;
     60     sal_mutex_t qos_mutex;
     61 } _bcm_th_qos_bookkeeping_t;
     62 
     63 static _bcm_th_qos_bookkeeping_t _bcm_th_qos_bk_info[BCM_MAX_NUM_UNITS];
     64 static int _bcm_th_qos_initialized[BCM_MAX_NUM_UNITS] = { 0 };
     65 
     66 #define TH_QOS_INFO(_unit_) (&_bcm_th_qos_bk_info[_unit_])
     67 
     68 #define _BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_GET(_u_, _identifier_) \
     69         SHR_BITGET(TH_QOS_INFO(_u_)->ing_l2_vlan_etag_map, (_identifier_))
     70 #define _BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_SET(_u_, _identifier_) \
     71         SHR_BITSET(TH_QOS_INFO((_u_))->ing_l2_vlan_etag_map, (_identifier_))
     72 #define _BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_CLR(_u_, _identifier_) \
     73         SHR_BITCLR(TH_QOS_INFO((_u_))->ing_l2_vlan_etag_map, (_identifier_))
     74 
     75 #define _BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_GET(_u_, _identifier_) \
     76         SHR_BITGET(TH_QOS_INFO(_u_)->egr_l2_vlan_etag_map, (_identifier_))
     77 #define _BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_SET(_u_, _identifier_) \
     78         SHR_BITSET(TH_QOS_INFO((_u_))->egr_l2_vlan_etag_map, (_identifier_))
     79 #define _BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_CLR(_u_, _identifier_) \
     80         SHR_BITCLR(TH_QOS_INFO((_u_))->egr_l2_vlan_etag_map, (_identifier_))
     81 
     82 #define QOS_LOCK(unit) \
     83         sal_mutex_take(TH_QOS_INFO(unit)->qos_mutex, sal_mutex_FOREVER);
     84 #define QOS_UNLOCK(unit) \
     85         sal_mutex_give(TH_QOS_INFO(unit)->qos_mutex);
     86 
     87 #define QOS_INIT(unit)                                    \
     88     do {                                                  \
     89         if ((unit < 0) || (unit >= BCM_MAX_NUM_UNITS)) {  \
     90             return BCM_E_UNIT;                            \
     91         }                                                 \
     92         if (!_bcm_th_qos_initialized[unit]) {            \
     93             return BCM_E_INIT;                            \
     94         }                                                 \
     95     } while (0)
     96 
     97 /*
     98  * Function: 
     99  *     _bcm_th_qos_map_id_alloc
    100  * Purpose:
    101  *     Allocate a new QOS map ID.  The bitmap given contains bits set for 
    102  *     existing IDs, so find the first empty one, set it, and return it.
    103  * Parameters:
    104  *     unit   - (IN) Unit to be operated on
    105  *     bitmap - (IN/OUT)
    106  *     id     - (OUT)
    107  * Returns:
    108  *     BCM_E_XXX
    109  */
    110 STATIC int
    111 _bcm_th_qos_map_id_alloc(int unit, SHR_BITDCL *bitmap, int *id, 
    112                          int map_size)
    113 {
    114     int i;
    115 
    116     for (i = 0; i < map_size; i++) {
    117         if (!SHR_BITGET(bitmap, i)) {
    118             SHR_BITSET(bitmap, i);
    119             *id = i;
    120             return BCM_E_NONE;
    121         }
    122     }
    123 
    124     return BCM_E_RESOURCE;
    125 }
    126 
    127 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP
    128 /* 
    129  * Function:
    130  *      _bcm_th_qos_sw_dump
    131  * Purpose:
    132  *      Displays QOS software state info
    133  * Parameters:
    134  *      unit        : (IN) Device Unit Number
    135  * Returns:
    136  *      NONE
    137  */
    138 void
    139 _bcm_th_qos_sw_dump(int unit)
    140 {
    141     int i;
    142     if (!_bcm_th_qos_initialized[unit]) {
    143         LOG_CLI((BSL_META_U(unit,
    144                      "ERROR: QOS module not initialized on Unit:%d \n"), unit));
    145         return;
    146     }
    147 
    148     LOG_CLI((BSL_META_U(unit,
    149                         "QOS: ING_L2_VLAN_ETAG_MAP info \n")));
    150     for (i = 0; i < _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS; i++) {
    151         if (_BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, i)) {
    152             LOG_CLI((BSL_META_U(unit,
    153                          "    map id:%4d    HW index:%4d\n"), i, 
    154                          TH_QOS_INFO(unit)->ing_l2_vlan_etag_map_hwidx[i]));                         
    155         }
    156     }
    157 
    158     LOG_CLI((BSL_META_U(unit,
    159                         "QOS: EGR_L2_VLAN_ETAG_MAP info \n")));
    160     for (i = 0; i < _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS; i++) {
    161         if (_BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, i)) {
    162             LOG_CLI((BSL_META_U(unit,
    163                          "    map id:%4d    HW index:%4d\n"), i, 
    164                          TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx[i]));                         
    165         }
    166     }    
    167 }
    168 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */
    169 
    170 #ifdef BCM_WARM_BOOT_SUPPORT
    171 #define _BCM_TH_REINIT_INVALID_HW_IDX  0xff    /* used as an invalid hw idx */
    172 
    173 /* 
    174  * Function:
    175  *      _bcm_th_qos_reinit_scache_len_get
    176  * Purpose:
    177  *      Helper utility to determine scache details.
    178  * Parameters:
    179  *      unit        : (IN) Device Unit Number
    180  *      scache_len  : (OUT) Total required scache length
    181  * Returns:
    182  *      BCM_E_XXX
    183  */
    184 int
    185 _bcm_th_qos_reinit_scache_len_get(int unit, uint32 *scache_len)
    186 {
    187     if (scache_len == NULL) {
    188         return BCM_E_PARAM;
    189     }
    190 
    191     *scache_len += _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS * sizeof(uint32);
    192     *scache_len += _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS * sizeof(uint32);
    193 
    194     return BCM_E_NONE;
    195 }
    196 
    197 int
    198 _bcm_th_qos_reinit_from_hw_state(int unit, soc_mem_t mem, 
    199                                  soc_field_t field, uint8 map_type, 
    200                                  SHR_BITDCL *hw_idx_bmp, 
    201                                  int hw_idx_bmp_len)
    202 {
    203     int         rv = BCM_E_NONE;
    204     int         idx, min_idx, max_idx, map_size, map_id, hw_prof_idx;
    205     uint32      buf[SOC_MAX_MEM_FIELD_WORDS];
    206     uint32      *hw_idx_table;
    207     SHR_BITDCL  *map_bmp;
    208 
    209     switch (map_type) {
    210     case _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP:
    211         map_bmp = TH_QOS_INFO(unit)->ing_l2_vlan_etag_map;
    212         hw_idx_table = TH_QOS_INFO(unit)->ing_l2_vlan_etag_map_hwidx;
    213         map_size = _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS;
    214         break;
    215     case _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP:
    216         map_bmp = TH_QOS_INFO(unit)->egr_l2_vlan_etag_map;
    217         hw_idx_table = TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx;
    218         map_size = _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS;
    219         break;
    220     default:
    221         return BCM_E_PARAM;
    222     }
    223 
    224     min_idx = soc_mem_index_min(unit, mem);
    225     max_idx = soc_mem_index_max(unit, mem);
    226 
    227     for (idx = min_idx; idx <= max_idx; idx++) {
    228         rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx, &buf);
    229         if (SOC_FAILURE(rv)) {
    230             LOG_ERROR(BSL_LS_BCM_QOS,
    231                       (BSL_META_U(unit,
    232                                   "Error(%s) reading mem(%d) at "
    233                                   "index:%d \n"), soc_errmsg(rv), mem, idx));
    234             return rv;
    235         }
    236 
    237         hw_prof_idx = soc_mem_field32_get(unit, mem, &buf, field);
    238 
    239         if (hw_prof_idx > (hw_idx_bmp_len - 1)) {
    240             LOG_ERROR(BSL_LS_BCM_QOS,
    241                       (BSL_META_U(unit,
    242                                   "Invalid profile(%d) in mem(%d) "
    243                                   "at index:%d\n"), hw_prof_idx, mem, idx));
    244             return BCM_E_INTERNAL;
    245         }
    246         if (hw_prof_idx && (!SHR_BITGET(hw_idx_bmp, hw_prof_idx))) {
    247             /* non-zero profile id and not stored previously */
    248             BCM_IF_ERROR_RETURN(_bcm_th_qos_map_id_alloc(unit, map_bmp, &map_id,
    249                                      map_size));
    250             if (map_id < 0) {
    251                 LOG_ERROR(BSL_LS_BCM_QOS,
    252                           (BSL_META_U(unit,
    253                                       "Invalid profile(%d) in mem"
    254                                       "(%d) at index:%d\n"), hw_prof_idx, mem, idx));
    255                 return BCM_E_RESOURCE;
    256             }
    257             hw_idx_table[map_id] = hw_prof_idx;
    258             SHR_BITSET(hw_idx_bmp, hw_prof_idx);
    259             SHR_BITSET(map_bmp, map_id);
    260         }
    261     }
    262     
    263     return rv;
    264 }
    265 
    266 /* 
    267  * Function:
    268  *      _bcm_th_qos_unsynchronized_reinit
    269  * Purpose:
    270  *      This routine handles Level 1 Warmboot init. In this style of reinit, the 
    271  *      map-ids allocated previously are not guaranteed to be the same.
    272  *      Cold-boot: Does nothing
    273  *      Warm-boot: The data-structures are populated by reading the HW tables. 
    274  * Parameters:
    275  *      unit    : (IN) Device Unit Number
    276  * Returns:
    277  *      BCM_E_XXX
    278  */
    279 int
    280 _bcm_th_qos_unsynchronized_reinit(int unit)
    281 {
    282     int                 rv = BCM_E_NONE;
    283     int                 bmp_len;
    284     SHR_BITDCL          *temp_bmp;
    285 
    286     /* read hw tables and populate the state */
    287     bmp_len = _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS;
    288     temp_bmp = NULL;
    289     temp_bmp = sal_alloc(SHR_BITALLOCSIZE(bmp_len), "temp_bmp");
    290     if (temp_bmp == NULL) {
    291         return BCM_E_MEMORY;
    292     }
    293     sal_memset(temp_bmp, 0x0, SHR_BITALLOCSIZE(bmp_len));
    294     
    295     if (soc_mem_is_valid(unit, PORT_TABm)) {
    296         rv = _bcm_th_qos_reinit_from_hw_state(unit, PORT_TABm, 
    297                      ETAG_PCP_DE_MAPPING_PTRf, 
    298                      _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP,
    299                      temp_bmp, bmp_len);
    300     }
    301     sal_free(temp_bmp);
    302 
    303     /* now extract EGR_MPLS_PRI_MAPPING state */
    304     if (BCM_SUCCESS(rv)) {
    305         bmp_len = _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS;
    306         temp_bmp = NULL;
    307         temp_bmp = sal_alloc(SHR_BITALLOCSIZE(bmp_len), "temp_bmp");
    308         if (temp_bmp == NULL) {
    309             return BCM_E_MEMORY;
    310         }
    311         sal_memset(temp_bmp, 0x0, SHR_BITALLOCSIZE(bmp_len));
    312         if (soc_mem_field_valid(unit, PORT_TABm, 
    313                                 ETAG_DOT1P_MAPPING_PTRf)) {
    314             rv = _bcm_th_qos_reinit_from_hw_state(unit, PORT_TABm,                      
    315                      ETAG_DOT1P_MAPPING_PTRf, 
    316                      _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP,
    317                      temp_bmp, bmp_len);
    318         }
    319         sal_free(temp_bmp);
    320     }
    321 
    322     return rv;
    323 }
    324 
    325 /* 
    326  * Function:
    327  *      _bcm_th_qos_extended_reinit
    328  * Purpose:
    329  *      This routine handles Level 2 Warmboot init. 
    330  *      Cold-boot: scache location is allocated.
    331  *      Warm-boot: The data-structs are populated from recovered scache state
    332  * Parameters:
    333  *      unit    : (IN) Device Unit Number
    334  * Returns:
    335  *      BCM_E_XXX
    336  */
    337 int
    338 _bcm_th_qos_extended_reinit(int unit, uint8 **scache_ptr)
    339 {
    340     uint32              hw_idx;
    341     int                 idx;
    342 
    343     for (idx = 0; idx < _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS; idx++) {
    344         sal_memcpy(&hw_idx, (*scache_ptr), sizeof(uint32));
    345         (*scache_ptr) += sizeof(hw_idx);
    346         if (hw_idx != _BCM_TH_REINIT_INVALID_HW_IDX) {
    347             _BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_SET(unit, idx);
    348             TH_QOS_INFO(unit)->ing_l2_vlan_etag_map_hwidx[idx] = hw_idx;
    349         }
    350     }
    351     for (idx = 0; idx < _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS; idx++) {
    352         sal_memcpy(&hw_idx, (*scache_ptr), sizeof(uint32));
    353         (*scache_ptr) += sizeof(hw_idx);
    354         if (hw_idx != _BCM_TH_REINIT_INVALID_HW_IDX) {
    355             _BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_SET(unit, idx);
    356             TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx[idx] = hw_idx;
    357         }
    358     }
    359 
    360     return BCM_E_NONE;
    361 }
    362 
    363 /* 
    364  * Function:
    365  *      _bcm_th_qos_reinit_hw_profiles_update
    366  * Purpose:
    367  *      Updates the shared memory profile tables reference counts
    368  * Parameters:
    369  *      unit    : (IN) Device Unit Number
    370  * Returns:
    371  *      BCM_E_XXX
    372  */
    373 int
    374 _bcm_th_qos_reinit_hw_profiles_update(int unit)
    375 {
    376     int     i;
    377 
    378     for (i = 0; i < _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS; i++) {
    379         if (_BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, i)) {
    380             BCM_IF_ERROR_RETURN(_bcm_ing_l2_vlan_etag_map_entry_reference(unit, 
    381                                ((TH_QOS_INFO(unit)->ing_l2_vlan_etag_map_hwidx[i]) * 
    382                                _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP), 
    383                                _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP));
    384         }
    385     }
    386     for (i = 0; i < _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS; i++) {
    387         if (_BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, i)) {
    388             BCM_IF_ERROR_RETURN(_bcm_egr_l2_vlan_etag_map_entry_reference(unit, 
    389                                ((TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx[i]) * 
    390                                _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP), 
    391                                _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP));
    392         }
    393     }    
    394  
    395     return BCM_E_NONE;
    396 }
    397 
    398 /* 
    399  * Function:
    400  *      _bcm_th_qos_sync
    401  * Purpose:
    402  *      This routine extracts the state that needs to be stored from the 
    403  *      book-keeping structs and stores it in the allocated scache location 
    404  * Compression format:  0   - A     l2_vlan_etag table
    405  *                      A+1 - B     egr_l2_vlan_etag table
    406  * Parameters:
    407  *      unit    : (IN) Device Unit Number
    408  * Returns:
    409  *      BCM_E_XXX
    410  */
    411 int
    412 _bcm_th_qos_sync(int unit, uint8 **scache_ptr)
    413 {
    414     uint32              hw_idx;
    415     int                 idx;    
    416 
    417     /* now store the state into the compressed format */
    418     for (idx = 0; idx < _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS; idx++) {
    419         if (_BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, idx)) {
    420             hw_idx = TH_QOS_INFO(unit)->ing_l2_vlan_etag_map_hwidx[idx];
    421         } else {
    422             hw_idx = _BCM_TH_REINIT_INVALID_HW_IDX;
    423         }
    424         sal_memcpy((*scache_ptr), &hw_idx, sizeof(uint32));
    425         (*scache_ptr) += sizeof(hw_idx);
    426     }
    427     for (idx = 0; idx < _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS; idx++) {
    428         if (_BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, idx)) {
    429             hw_idx = TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx[idx];
    430         } else {
    431             hw_idx = _BCM_TH_REINIT_INVALID_HW_IDX;
    432         }
    433         sal_memcpy((*scache_ptr), &hw_idx, sizeof(uint32));
    434         (*scache_ptr) += sizeof(hw_idx);
    435     }
    436 
    437     return BCM_E_NONE;
    438 }
    439 #endif /* BCM_WARM_BOOT_SUPPORT */
    440 
    441 /*
    442  * Function: 
    443  *   _bcm_th_qos_free_resources
    444  * Purpose:
    445  *   Free QOS bookkeeping resources associated with a given unit.  This
    446  *   happens either during an error initializing or during a detach operation.
    447  * Parameters:
    448  *   unit - (IN) Unit to free resources of
    449  * Returns:
    450  *   BCM_E_XXX
    451  */
    452 STATIC void
    453 _bcm_th_qos_free_resources(int unit)
    454 {
    455     _bcm_th_qos_bookkeeping_t *qos_info = TH_QOS_INFO(unit);
    456 
    457     if (!qos_info) {
    458         /*
    459          * Coverity
    460          * This is defencive statement.
    461          */
    462         /* coverity[dead_error_line] */
    463         return;
    464     }	
    465     if (qos_info->ing_l2_vlan_etag_map) {
    466         sal_free(qos_info->ing_l2_vlan_etag_map);
    467         qos_info->ing_l2_vlan_etag_map = NULL;
    468     }
    469 
    470     if (qos_info->ing_l2_vlan_etag_map_hwidx) {
    471         sal_free(qos_info->ing_l2_vlan_etag_map_hwidx);
    472         qos_info->ing_l2_vlan_etag_map_hwidx = NULL;
    473     }
    474 
    475     if (qos_info->egr_l2_vlan_etag_map) {
    476         sal_free(qos_info->egr_l2_vlan_etag_map);
    477         qos_info->egr_l2_vlan_etag_map = NULL;
    478     }
    479 
    480     if (qos_info->egr_l2_vlan_etag_map_hwidx) {
    481         sal_free(qos_info->egr_l2_vlan_etag_map_hwidx);
    482         qos_info->egr_l2_vlan_etag_map_hwidx = NULL;
    483     }
    484 
    485     if (qos_info->qos_mutex) {
    486         sal_mutex_destroy(qos_info->qos_mutex);
    487         qos_info->qos_mutex = NULL;
    488     }
    489 }
    490 
    491 /*
    492  * Function: 
    493  *   bcm_th_qos_detach
    494  * Purpose:
    495  *   Detach the QOS module.  Called when the module should de-initialize.
    496  * Parameters:
    497  *   unit - (IN) Unit being detached.
    498  * Returns:
    499  *   BCM_E_XXX
    500  */
    501 int 
    502 bcm_th_qos_detach(int unit)
    503 {
    504     if (_bcm_th_qos_initialized[unit]) {
    505         _bcm_th_qos_initialized[unit] = 0;
    506         _bcm_th_qos_free_resources(unit);
    507     }
    508 
    509     return BCM_E_NONE;
    510 }
    511 		
    512 /*
    513  * Function: 
    514  *   bcm_th_qos_init
    515  * Purpose:
    516  *   Initialize the TH QOS module.  Allocate bookkeeping information.
    517  * Parameters:
    518  *   unit - (IN) Unit being initialized
    519  * Returns:
    520  *   BCM_E_XXX
    521  */
    522 int
    523 bcm_th_qos_init(int unit)
    524 {
    525     _bcm_th_qos_bookkeeping_t *qos_info = TH_QOS_INFO(unit);
    526     int l2_vlan_tag_map_size  = _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS;
    527     int egr_l2_vlan_tag_map_size  = _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS;
    528     bcm_pbmp_t all_pbmp;
    529     uint32 entry[SOC_MAX_MEM_WORDS];
    530     bcm_port_t port;
    531     int index;
    532 
    533     if (_bcm_th_qos_initialized[unit]) {
    534         BCM_IF_ERROR_RETURN(bcm_th_qos_detach(unit));
    535     }
    536 
    537     memset(qos_info, 0, sizeof *qos_info);
    538 
    539     /* ingress l2 vlan etag map bitmap */
    540     qos_info->ing_l2_vlan_etag_map = 
    541                     sal_alloc(SHR_BITALLOCSIZE(l2_vlan_tag_map_size), 
    542                     "ing_l2_vlan_etag_map");
    543     if (qos_info->ing_l2_vlan_etag_map == NULL) {
    544         _bcm_th_qos_free_resources(unit);
    545         return BCM_E_MEMORY;
    546     }
    547     sal_memset(qos_info->ing_l2_vlan_etag_map, 0, 
    548                 SHR_BITALLOCSIZE(l2_vlan_tag_map_size));
    549 
    550     /* ingress l2 vlan etag map hardware indexes */
    551     qos_info->ing_l2_vlan_etag_map_hwidx = 
    552                 sal_alloc(sizeof(uint32) * l2_vlan_tag_map_size, 
    553                 "ing_l2_vlan_etag_map_hwidx");
    554     if (qos_info->ing_l2_vlan_etag_map_hwidx == NULL) {
    555         _bcm_th_qos_free_resources(unit);
    556         return BCM_E_MEMORY;
    557     }
    558     sal_memset(qos_info->ing_l2_vlan_etag_map_hwidx, 0, 
    559                 sizeof(uint32) * l2_vlan_tag_map_size);
    560 
    561     /* egress l2 vlan etag priority map bitmap */
    562     qos_info->egr_l2_vlan_etag_map = sal_alloc(SHR_BITALLOCSIZE(egr_l2_vlan_tag_map_size), 
    563                                 "egr_l2_vlan_etag_map");
    564     if (qos_info->egr_l2_vlan_etag_map == NULL) {
    565         _bcm_th_qos_free_resources(unit);
    566         return BCM_E_MEMORY;
    567     }
    568     sal_memset(qos_info->egr_l2_vlan_etag_map, 0, 
    569                 SHR_BITALLOCSIZE(egr_l2_vlan_tag_map_size));
    570 
    571     /* egress l2 vlan etag map hardware indexes */
    572     qos_info->egr_l2_vlan_etag_map_hwidx = 
    573                 sal_alloc(sizeof(uint32) * egr_l2_vlan_tag_map_size, 
    574                 "egr_l2_vlan_etag_map_hwidx");
    575     if (qos_info->egr_l2_vlan_etag_map_hwidx == NULL) {
    576         _bcm_th_qos_free_resources(unit);
    577         return BCM_E_MEMORY;
    578     }
    579     sal_memset(qos_info->egr_l2_vlan_etag_map_hwidx, 0, 
    580                 sizeof(uint32) * egr_l2_vlan_tag_map_size);
    581 
    582     /* accessor mutex */
    583     qos_info->qos_mutex = sal_mutex_create("vft qos_mutex");
    584     if (qos_info->qos_mutex == NULL) {
    585         _bcm_th_qos_free_resources(unit);
    586         return BCM_E_MEMORY;
    587     }
    588 
    589     if (SOC_WARM_BOOT(unit)) {
    590         /* Update reference counts for DSCP_TABLE profile*/
    591         BCM_PBMP_CLEAR(all_pbmp);
    592         BCM_PBMP_ASSIGN(all_pbmp, PBMP_ALL(unit));
    593 
    594         PBMP_ITER(all_pbmp, port) {
    595             if (IS_LB_PORT(unit, port)) {
    596                 /* Loopback port base starts from 64 */
    597                 continue;
    598             }
    599             SOC_IF_ERROR_RETURN(soc_mem_read(unit, PORT_TABm, MEM_BLOCK_ALL,
    600                                           port, &entry));
    601             index = soc_mem_field32_get(unit, PORT_TABm, &entry, TRUST_DSCP_PTRf);
    602             SOC_IF_ERROR_RETURN(_bcm_dscp_table_entry_reference(unit, index * 64, 64));
    603         }
    604     }
    605 
    606     _bcm_th_qos_initialized[unit] = 1;
    607     return BCM_E_NONE;
    608 }
    609 
    610 /*
    611  * Function: 
    612  *   _bcm_th_qos_flags_sanity_check
    613  * Purpose:
    614  *   Check that the combination of flags specified is valid.
    615  * Parameters:
    616  *   flags  - (IN) BCM_QOS_MAP_* flags (eg. ingress/egress/with_id/replace)
    617   * Returns:
    618  *   BCM_E_XXX
    619  */
    620 STATIC int
    621 _bcm_th_qos_flags_sanity_check(uint32 flags)
    622 {
    623     int rv = BCM_E_NONE;
    624 
    625     /* must be ingress or egress, not both */
    626     if ((flags & BCM_QOS_MAP_INGRESS) && (flags & BCM_QOS_MAP_EGRESS)) {
    627         rv = BCM_E_PARAM;
    628     }
    629 
    630     /* must be ingress or egress, not neither */
    631     if (!(flags & BCM_QOS_MAP_INGRESS) && !(flags & BCM_QOS_MAP_EGRESS)) {
    632         rv = BCM_E_PARAM;
    633     }
    634 
    635     /* support BCM_QOS_MAP_L2_VLAN_ETAG */
    636     if (!(flags & BCM_QOS_MAP_L2_VLAN_ETAG)) {
    637         rv = BCM_E_PARAM;
    638     }
    639 
    640     return rv;
    641 }
    642 
    643 /*
    644  * Function: 
    645  *     _bcm_th_qos_assign_creation_table_vars
    646  * Purpose:
    647  *     Assign the various pointers to tables and table sizes and bitmaps used
    648  *     for the bcm_th_qos_map_create so that it can create the different types
    649  *     of maps with common logic.  
    650  * 
    651  *     Assumes "flags" has already been validated.
    652  * Parameters:
    653  *     unit       - (IN)  Unit to be operated on
    654  *     flags      - (IN)  BCM_QOS_MAP_* flags (eg. ingress/egress/with_id/etc)
    655  *     is_ingress - (OUT) 1 for ingress, 0 for egress map
    656  *     bitmap     - (OUT) pointer to priority map's bitmap
    657  *     hwmap      - (OUT) pointer to priority map's hwidx mapping
    658  *     map_type   - (OUT) _BCM_QOS_MAP_TYPE_*
    659  *     map_size   - (OUT) size of the selected map
    660  *     max_maps   - (OUT) maximum number of maps available for the selected type
    661  * Returns:
    662  *     None
    663  */
    664 STATIC void
    665 _bcm_th_qos_assign_creation_table_vars(int unit, int flags, int *is_ingress, 
    666                                         SHR_BITDCL **bitmap,
    667                                         uint32 **hwmap, int *map_type, 
    668                                         int *map_size, int *max_maps)
    669 {
    670     if (flags & BCM_QOS_MAP_INGRESS) {
    671         *is_ingress = 1;
    672         if (flags & BCM_QOS_MAP_L2_VLAN_ETAG) {
    673             *bitmap     = TH_QOS_INFO(unit)->ing_l2_vlan_etag_map;
    674             *hwmap      = TH_QOS_INFO(unit)->ing_l2_vlan_etag_map_hwidx;
    675             *map_type   = _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP;
    676             *map_size   = _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS;
    677             *max_maps   = _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS;
    678         }        
    679     } else if (flags & BCM_QOS_MAP_EGRESS) {
    680         *is_ingress = 0;
    681 
    682         if (flags & BCM_QOS_MAP_L2_VLAN_ETAG) {
    683             *bitmap     = TH_QOS_INFO(unit)->egr_l2_vlan_etag_map;
    684             *hwmap      = TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx;
    685             *map_type   = _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP;
    686             *map_size   = _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS;
    687             *max_maps   = _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS;
    688         }
    689     } 
    690 }
    691 
    692 /*
    693  * Function: 
    694  *     _bcm_th_qos_count_used_maps
    695  * Purpose:
    696  *     Count the number maps currently used in hardware.  Since IDs in app-space
    697  *     can point to the same hardware index, count how many hardware indexes are
    698  *     used, ignoring duplicates.
    699  * Parameters:
    700  *     unit   - (IN) Unit to be operated on
    701  *     bitmap - (IN) Bitmap of used map IDs
    702  *     hwmap  - (IN) Array that maps userspace IDs to hardware IDs
    703  * Returns:
    704  *     integer containing the number of used hardware indexes
    705  */
    706 STATIC int
    707 _bcm_th_qos_count_used_maps(int unit, SHR_BITDCL *bitmap, uint32 *hwmap, 
    708                              int map_size, int max_maps) 
    709 {
    710     uint8 *hw_used = sal_alloc(map_size, "TH_qos_used_maps");
    711     int total_used = 0;
    712     int i = 0;
    713     
    714     if (hw_used == NULL) {
    715         return max_maps;
    716     }
    717 
    718     memset(hw_used, 0, map_size);
    719 
    720     for (i = 0; i < map_size; i++) {
    721         if (SHR_BITGET(bitmap, i) && hw_used[hwmap[i]] == 0) {
    722             hw_used[hwmap[i]] = 1;
    723             total_used++;
    724         }
    725     }
    726 
    727     sal_free(hw_used);
    728     return total_used;
    729 }
    730 
    731 /*
    732  * Function: 
    733  *     _bcm_th_qos_map_create_with_id
    734  * Purpose:
    735  *     Allocate a new QOS map ID where the app has specified the ID.  So just
    736  *     check that the requested ID is available, and mark it as used.
    737  * Parameters:
    738  *     unit       - (IN) Unit to be operated on
    739  *     flags      - (IN) Used only to test if BCM_QOS_MAP_REPLACE is set
    740  *     bitmap     - (IN/OUT) Bitmap containing the set of used IDs
    741  *     map_id     - (IN) The ID requested by the application
    742  *     is_ingress - (IN) 1=ingress map, 0=egress map
    743  * Returns:
    744  *     BCM_E_XXX
    745  */
    746 STATIC int
    747 _bcm_th_qos_map_create_with_id(int unit, int flags, SHR_BITDCL *bitmap, 
    748                                     int *map_id, int is_ingress, int max_ids)
    749 {
    750     int id = 0, map_type = 0, rv = BCM_E_NONE;
    751 
    752     id = *map_id & _BCM_QOS_MAP_TYPE_MASK;
    753     map_type = *map_id >> _BCM_QOS_MAP_SHIFT;
    754 
    755     if (id < 0 || id >= max_ids) {
    756         return BCM_E_BADID;
    757     }
    758 
    759     if ((map_type == _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP && is_ingress)) {
    760 
    761         if (SHR_BITGET(bitmap, id) == 1) {
    762             if (!(flags & BCM_QOS_MAP_REPLACE)) {
    763                 rv = BCM_E_EXISTS;
    764             }
    765         }
    766 
    767         if (BCM_SUCCESS(rv)) {
    768             SHR_BITSET(bitmap, id);
    769         }
    770     } else {
    771         rv = BCM_E_PARAM;
    772     }
    773 
    774     return rv;
    775 }
    776 
    777 /*
    778  * Function: 
    779  *     bcm_th_qos_map_create
    780  * Purpose:
    781  *     Create a new QOS map.
    782  * Parameters:
    783  *     unit   - (IN) Unit to be operated on
    784  *     flags  - (IN) BCM_QOS_MAP_* flags (eg. ingress/egress/with_id/replace)
    785  *     map_id - (IN/OUT) If BCM_QOS_MAP_WITH_ID is set, then this is the ID
    786  *                       being requested.  Otherwise, it's assigned as the ID
    787  *                       allocated.
    788  * Returns:
    789  *     BCM_E_XXX
    790  */
    791 int
    792 bcm_th_qos_map_create(int unit, uint32 flags, int *map_id)
    793 {
    794     int        is_ingress = 0;
    795     int        map_type = 0;
    796     SHR_BITDCL *bitmap = NULL;
    797     uint32     index = 0;
    798     int        rv    = BCM_E_NONE;
    799     int        id    = 0;
    800     void       *entries[1];
    801     uint32     *hwmap = NULL;
    802     int        map_size = 0;
    803     int        max_maps = 0;
    804 
    805     QOS_INIT(unit);
    806     QOS_LOCK(unit);
    807 
    808     rv = _bcm_th_qos_flags_sanity_check(flags);
    809 
    810     if (BCM_SUCCESS(rv)) {
    811         _bcm_th_qos_assign_creation_table_vars(unit, flags, &is_ingress, 
    812                                                 &bitmap, &hwmap, &map_type, 
    813                                                 &map_size, &max_maps);
    814     }
    815 
    816     if (BCM_SUCCESS(rv)) {
    817         if (_bcm_th_qos_count_used_maps(unit, bitmap, hwmap, map_size, 
    818                                          max_maps) >= max_maps) {
    819             rv = BCM_E_MEMORY;
    820         }
    821     }
    822 
    823     if (BCM_SUCCESS(rv)) {
    824         if (flags & BCM_QOS_MAP_WITH_ID) {
    825             rv = _bcm_th_qos_map_create_with_id(unit, flags, bitmap, map_id, 
    826                                                  is_ingress, map_size);
    827             id = *map_id & _BCM_QOS_MAP_TYPE_MASK;
    828         } else {
    829             rv = _bcm_th_qos_map_id_alloc(unit, bitmap, &id, map_size);
    830             if (BCM_SUCCESS(rv)) {
    831                 /*_BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_SET(unit, id);*/
    832                 *map_id = id | (map_type << _BCM_QOS_MAP_SHIFT);
    833             }
    834         }
    835     }
    836 
    837     if (BCM_SUCCESS(rv)) {
    838         if ((flags & BCM_QOS_MAP_INGRESS) &&
    839             (flags & BCM_QOS_MAP_L2_VLAN_ETAG)) {
    840             ing_etag_pcp_mapping_entry_t 
    841                                 table[_BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP];
    842             memset(&table, 0, sizeof table);
    843             entries[0] = &table;
    844 
    845             rv = _bcm_ing_l2_vlan_etag_map_entry_add(unit, entries, 
    846                                            _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP, 
    847                                            &index);
    848 
    849             if (BCM_SUCCESS(rv)) {
    850                 TH_QOS_INFO(unit)->ing_l2_vlan_etag_map_hwidx[id] = index /
    851                                            _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP;
    852             }
    853         } else if ((flags & BCM_QOS_MAP_EGRESS) &&
    854                    (flags & BCM_QOS_MAP_L2_VLAN_ETAG)) {
    855             egr_etag_pcp_mapping_entry_t 
    856                                 table[_BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP];
    857             memset(&table, 0, sizeof table);
    858             entries[0] = &table;
    859 
    860             rv = _bcm_egr_l2_vlan_etag_map_entry_add(unit, entries, 
    861                                 _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP, 
    862                                 &index);
    863 
    864             if (BCM_SUCCESS(rv)) {
    865                 TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx[id] = index /
    866                                         _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP;
    867             }
    868         } 
    869     }
    870 
    871     QOS_UNLOCK(unit);
    872 
    873     return rv;
    874 }
    875 
    876 /*
    877  * Function: 
    878  *     _bcm_th_qos_map_destroy
    879  * Purpose:
    880  *     Destroy a map ID by removing it from hardware.
    881  * Parameters:
    882  *     unit  - (IN) The unit being operated on
    883  *     table - (IN) Indicates either ingress or egress
    884  *     id    - (IN) The map ID being destroyed
    885  * Returns:
    886  *     BCM_E_XXX
    887  */
    888 STATIC int
    889 _bcm_th_qos_map_destroy(int unit, int table, int id)
    890 {
    891     int rv = BCM_E_NONE;
    892     _bcm_th_qos_bookkeeping_t *qos_info = TH_QOS_INFO(unit);
    893 
    894     if (table == _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP) {
    895         rv = _bcm_ing_l2_vlan_etag_map_entry_del(unit, 
    896                                     qos_info->ing_l2_vlan_etag_map_hwidx[id] *
    897                                     _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP);
    898     } else if (table == _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP) {
    899         rv = _bcm_egr_l2_vlan_etag_map_entry_del(unit, 
    900                                     qos_info->egr_l2_vlan_etag_map_hwidx[id] *
    901                                     _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP);
    902     }
    903 
    904     return rv;
    905 }
    906 
    907 /*
    908  * Function: 
    909  *     bcm_th_qos_map_destroy
    910  * Purpose:
    911  *     Destroy a QOS map ID by removing it from hardware and deleting the
    912  *     associated software state info.
    913  * Parameters:
    914  *     unit   - (IN) Unit being operated on
    915  *     map_id - (IN) QOS map ID to be destroyed
    916  * Returns:
    917  *     BCM_E_XXX
    918  */
    919 int
    920 bcm_th_qos_map_destroy(int unit, int map_id)
    921 {
    922     int id = map_id & _BCM_QOS_MAP_TYPE_MASK;
    923     int rv = BCM_E_UNAVAIL;
    924 
    925     QOS_INIT(unit);
    926     QOS_LOCK(unit);
    927 
    928     switch (map_id >> _BCM_QOS_MAP_SHIFT) {
    929         case _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP:
    930             if (!_BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, id)) {
    931                 rv = BCM_E_NOT_FOUND;
    932             } else {
    933                 rv = _bcm_th_qos_map_destroy(unit, 
    934                         _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP, id);
    935         
    936                 if (BCM_SUCCESS(rv)) {
    937                     _BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_CLR(unit, id);
    938                 }
    939             }
    940             break;
    941         case _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP:
    942             if (!_BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, id)) {
    943                 rv = BCM_E_NOT_FOUND;
    944             } else {
    945                 rv = _bcm_th_qos_map_destroy(unit, 
    946                     _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP, id);
    947 		
    948                 if (BCM_SUCCESS(rv)) {
    949                     _BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_CLR(unit, id);
    950                 }
    951             }
    952             break;
    953         default:
    954             rv = BCM_E_PARAM;
    955     }
    956 
    957     QOS_UNLOCK(unit);
    958 
    959     return rv;
    960 }
    961 
    962 /*
    963  * Function: 
    964  *     _bcm_th_qos_map_add_sanity_check
    965  * Purpose:
    966  *     Check that all the paramters given to the bcm_qos_map_add() function make
    967  *     sense and are internally consistent.
    968  * Parameters:
    969  *     unit   - (IN) The unit being operated on
    970  *     flags  - (IN) BCM_QOS_MAP_* flags sent in by the app
    971  *     map    - (IN) The map structure sent in by the app
    972  *     map_id - (IN) The map ID sent in by the app
    973  * Returns:
    974  *     BCM_E_XXX
    975  */
    976 STATIC int
    977 _bcm_th_qos_map_add_sanity_check(int unit, uint32 flags, bcm_qos_map_t *map, 
    978                                  int map_id)
    979 {
    980     int map_type = map_id >> _BCM_QOS_MAP_SHIFT;
    981     int id = map_id & _BCM_QOS_MAP_TYPE_MASK;
    982     int rv;
    983 
    984     rv = _bcm_th_qos_flags_sanity_check(flags);
    985     if (BCM_FAILURE(rv)) {
    986         return rv;
    987     }
    988 
    989     if ((flags & BCM_QOS_MAP_INGRESS) &&
    990         (map_type != _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP)) {
    991         return BCM_E_PARAM;
    992     }
    993 
    994     if ((flags & BCM_QOS_MAP_EGRESS) &&
    995         (map_type != _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP)) {
    996         return BCM_E_PARAM;
    997     }
    998 
    999     if ((flags & BCM_QOS_MAP_INGRESS) &&
   1000         (map_type == _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP) &&
   1001         (_BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, id) == 0)) {
   1002         return BCM_E_BADID;
   1003     }
   1004 
   1005     if ((flags & BCM_QOS_MAP_EGRESS) &&
   1006         (map_type == _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP) &&
   1007         (_BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, id) == 0)) {
   1008         return BCM_E_BADID;
   1009     }
   1010 
   1011     if (!(flags & BCM_QOS_MAP_L2_VLAN_ETAG)) {
   1012         if (map->int_pri < 0) {
   1013             return BCM_E_PARAM;
   1014         }
   1015     }
   1016 
   1017     if (map->pkt_pri >= _BCM_QOS_MAX_PKT_PRIORITIES) {
   1018         return BCM_E_PARAM;
   1019     }
   1020 
   1021     if (flags & BCM_QOS_MAP_L2_VLAN_ETAG) {
   1022         if ((map->etag_pcp >= _BCM_QOS_MAX_PKT_PRIORITIES)
   1023             || (map->etag_de >= _BCM_QOS_MAX_PKT_DES)
   1024             || (map->pkt_cfi >= _BCM_QOS_MAX_PKT_DES)) {
   1025             return BCM_E_PARAM;
   1026         }
   1027     } 
   1028 
   1029     if ((flags & BCM_QOS_MAP_L2_VLAN_ETAG) &&
   1030         (flags & BCM_QOS_MAP_EGRESS)) {
   1031         if (map->color != bcmColorGreen && map->color != bcmColorYellow
   1032             && map->color != bcmColorRed) {
   1033             return BCM_E_PARAM;
   1034         }
   1035         if (map->int_pri >= _BCM_QOS_MAX_INT_PRIORITIES) {
   1036             return BCM_E_PARAM;
   1037         }
   1038     } 
   1039 
   1040     return BCM_E_NONE;
   1041 }
   1042 
   1043 /*
   1044  * Function: 
   1045  *     _bcm_th_ing_qos_map_update_index
   1046  * Purpose:
   1047  *     Update an existing profile (or a newly created one) in the hardware's
   1048  *     table with a new mapping.  
   1049  *   
   1050  *     The structure is: (1) get existing profile for this map from hardware, 
   1051  *     (2) update the profile in RAM, (3) delete the old profile from hardware, 
   1052  *     and (4) push the updated profile in RAM to hardware.
   1053  * Parameters:
   1054  *     unit   - (IN) The unit being operated on
   1055  *     map    - (IN) Map structure sent in by app to be applied to hardware
   1056  *     map_id - (IN) Map ID sent in by app to be applied to hardware
   1057  * Returns:
   1058  *     BCM_E_XXX
   1059  */
   1060 STATIC int
   1061 _bcm_th_ing_qos_map_update_index(int unit, bcm_qos_map_t *map, int map_id)
   1062 {
   1063     void    *entries[1];
   1064     int     rv = BCM_E_NONE;
   1065     uint32  index;
   1066     int     id = map_id & _BCM_QOS_MAP_TYPE_MASK;
   1067 
   1068     if (QOS_MAP_IS_L2_VLAN_ETAG(map_id)) {
   1069         ing_etag_pcp_mapping_entry_t table[_BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP];        
   1070         index = TH_QOS_INFO(unit)->ing_l2_vlan_etag_map_hwidx[id] *
   1071                                             _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP;
   1072 
   1073         entries[0] = &table;
   1074         rv = _bcm_ing_l2_vlan_etag_map_entry_get(unit, index, 
   1075                                             _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP, 
   1076                                             entries);
   1077 
   1078         if (BCM_SUCCESS(rv)) {
   1079             ing_etag_pcp_mapping_entry_t *entry = 
   1080                                     &table[(map->pkt_pri << 1) | map->pkt_cfi];
   1081 
   1082             soc_mem_field32_set(unit, ING_ETAG_PCP_MAPPINGm, 
   1083                                 entry, PCPf, map->etag_pcp);
   1084             soc_mem_field32_set(unit, ING_ETAG_PCP_MAPPINGm, 
   1085                                 entry, DEf, map->etag_de);
   1086             
   1087             rv = _bcm_ing_l2_vlan_etag_map_entry_del(unit, (int)index);
   1088         }
   1089 
   1090         if (BCM_SUCCESS(rv)) {
   1091             rv = _bcm_ing_l2_vlan_etag_map_entry_add(unit, entries, 
   1092                                             _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP,
   1093                                             &index);
   1094             TH_QOS_INFO(unit)->ing_l2_vlan_etag_map_hwidx[id] = index /
   1095                                             _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP;  
   1096         }
   1097     }
   1098     return rv;
   1099 }
   1100 
   1101 /*
   1102  * Function: 
   1103  *     _bcm_th_egr_qos_map_update_index
   1104  * Purpose:
   1105  *     Update an existing profile (or a newly created one) in the hardware's
   1106  *     table with a new mapping.  
   1107  *   
   1108  *     The structure is: (1) get existing profile for this map from hardware, 
   1109  *     (2) update the profile in RAM, (3) delete the old profile from hardware, 
   1110  *     and (4) push the updated profile in RAM to hardware.
   1111  * Parameters:
   1112  *     unit   - (IN) The unit being operated on
   1113  *     map    - (IN) Map structure sent in by app to be applied to hardware
   1114  *     map_id - (IN) Map ID sent in by app to be applied to hardware
   1115  * Returns:
   1116  *     BCM_E_XXX
   1117  */
   1118 STATIC int
   1119 _bcm_th_egr_qos_map_update_index(int unit, bcm_qos_map_t *map, int map_id)
   1120 {
   1121     void    *entries[1];
   1122     int     rv = BCM_E_NONE;
   1123     int     cng;
   1124     uint32  index;
   1125     int     id = map_id & _BCM_QOS_MAP_TYPE_MASK;
   1126 
   1127     if (QOS_MAP_IS_L2_VLAN_ETAG(map_id)) {
   1128         egr_etag_pcp_mapping_entry_t table[_BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP];
   1129         index = TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx[id] * 
   1130                                             _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP;
   1131 
   1132         entries[0] = &table;
   1133         rv = _bcm_egr_l2_vlan_etag_map_entry_get(unit, index, 
   1134                                             _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP,
   1135                                             entries);
   1136         if (BCM_SUCCESS(rv)) {
   1137             egr_etag_pcp_mapping_entry_t *entry; 
   1138             cng = _BCM_COLOR_ENCODING(unit, map->color);
   1139             entry = &table[(map->int_pri << 2) | cng];
   1140 
   1141             soc_mem_field32_set(unit, EGR_ETAG_PCP_MAPPINGm, 
   1142                                 entry, PCPf, map->etag_pcp);
   1143             soc_mem_field32_set(unit, EGR_ETAG_PCP_MAPPINGm, 
   1144                                 entry, DEf, map->etag_de);
   1145 
   1146             rv = _bcm_egr_l2_vlan_etag_map_entry_del(unit, (int)index);
   1147         }
   1148 
   1149         if (BCM_SUCCESS(rv)) {
   1150             rv = _bcm_egr_l2_vlan_etag_map_entry_add(unit, entries, 
   1151                                             _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP,
   1152                                             &index);
   1153             TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx[id] = index /
   1154                                             _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP;  
   1155         }
   1156     }
   1157 
   1158     return rv;
   1159 }
   1160 
   1161 /*
   1162  * Function: 
   1163  *     bcm_th_qos_map_add
   1164  * Purpose:
   1165  *     Add a new QOS mapping to hardware.
   1166  * Parameters:
   1167  *     unit   - (IN) The unit being operated on
   1168  *     flags  - (IN) BCM_QOS_MAP_* flags
   1169  *     map    - (IN) Structure containing the priorities to be mapped
   1170  *     map_id - (IN) The ID of the map to add the new information to
   1171  * Returns:
   1172  *     BCM_E_XXX
   1173  */
   1174 int
   1175 bcm_th_qos_map_add(int unit, uint32 flags, bcm_qos_map_t *map, int map_id)
   1176 {
   1177     int rv = BCM_E_NONE;
   1178 
   1179     QOS_INIT(unit);
   1180     QOS_LOCK(unit);
   1181 
   1182     rv = _bcm_th_qos_map_add_sanity_check(unit, flags, map, map_id);
   1183     if (BCM_SUCCESS(rv)) {
   1184         if ((flags & BCM_QOS_MAP_INGRESS) &&
   1185             (flags & BCM_QOS_MAP_L2_VLAN_ETAG)) {
   1186             rv = _bcm_th_ing_qos_map_update_index(unit, map, map_id);
   1187         } else {
   1188             rv = _bcm_th_egr_qos_map_update_index(unit, map, map_id);
   1189         }
   1190     }
   1191 
   1192     QOS_UNLOCK(unit);
   1193 
   1194     return rv;
   1195 }
   1196 
   1197 /* bcm_th_qos_map_multi_get */
   1198 int
   1199 bcm_th_qos_map_multi_get(int unit, uint32 flags,
   1200                          int map_id, int array_size, 
   1201                          bcm_qos_map_t *array, int *array_count)
   1202 {
   1203     int             rv = BCM_E_NONE;
   1204     int             num_entries, idx, id, hw_id, alloc_size, entry_size, count;
   1205     uint8           *dma_buf;
   1206     void            *entry;
   1207     soc_mem_t       mem;
   1208     bcm_qos_map_t   *map;
   1209     int cng = 0;
   1210 
   1211     /* ignore with_id & replace flags */
   1212     flags &= (~(BCM_QOS_MAP_WITH_ID | BCM_QOS_MAP_REPLACE));
   1213     id = map_id & _BCM_QOS_MAP_TYPE_MASK;
   1214     mem = INVALIDm;
   1215     hw_id = 0;
   1216     num_entries = 0;
   1217     entry_size = 0;
   1218     QOS_LOCK(unit);
   1219     switch (map_id >> _BCM_QOS_MAP_SHIFT) {
   1220     case _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP:
   1221         if ((flags != (BCM_QOS_MAP_L2_VLAN_ETAG | BCM_QOS_MAP_INGRESS)) ||
   1222             (!_BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, id))) {
   1223             rv = BCM_E_PARAM;
   1224         }
   1225         num_entries = _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP;
   1226         entry_size = sizeof(ing_etag_pcp_mapping_entry_t);
   1227         hw_id = TH_QOS_INFO(unit)->ing_l2_vlan_etag_map_hwidx[id] *
   1228                                             _BCM_QOS_MAP_CHUNK_L2_VLAN_ETAG_MAP;
   1229         mem = ING_ETAG_PCP_MAPPINGm;
   1230         break;
   1231     case _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP:
   1232         if ((flags != (BCM_QOS_MAP_L2_VLAN_ETAG | BCM_QOS_MAP_EGRESS)) ||
   1233             (!_BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, id))) {
   1234             rv = BCM_E_PARAM;
   1235         }
   1236         num_entries = _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP;
   1237         entry_size = sizeof(egr_etag_pcp_mapping_entry_t);
   1238         hw_id = TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx[id] *
   1239                                         _BCM_QOS_MAP_CHUNK_EGR_L2_VLAN_ETAG_MAP;
   1240         mem = EGR_ETAG_PCP_MAPPINGm;
   1241         break;
   1242     default:
   1243         rv = BCM_E_PARAM;
   1244     }
   1245     QOS_UNLOCK(unit);
   1246     BCM_IF_ERROR_RETURN(rv);
   1247 
   1248     if (array_size == 0) { /* querying the size of map-chunk */
   1249         *array_count = num_entries;
   1250         return BCM_E_NONE;
   1251     }
   1252     if (!array || !array_count) {
   1253         return BCM_E_PARAM;
   1254     }
   1255 
   1256     /* Allocate memory for DMA & regular */
   1257     alloc_size = num_entries * entry_size;
   1258     dma_buf = soc_cm_salloc(unit, alloc_size, "TH qos multi get DMA buf");
   1259     if (!dma_buf) {
   1260         return BCM_E_MEMORY;
   1261     }
   1262     sal_memset(dma_buf, 0, alloc_size);
   1263 
   1264     /* Read the profile chunk */
   1265     rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, hw_id, 
   1266                             (hw_id + num_entries - 1), dma_buf);
   1267     if (BCM_FAILURE(rv)) {
   1268         soc_cm_sfree(unit, dma_buf);
   1269         return rv;
   1270     }
   1271 
   1272     count = 0;
   1273     QOS_LOCK(unit);
   1274     switch (map_id >> _BCM_QOS_MAP_SHIFT) {
   1275     case _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP:
   1276         for (idx=0; ((idx<num_entries) && (count < array_size)); idx++) {
   1277             map = &array[idx];
   1278             sal_memset(map, 0x0, sizeof(bcm_qos_map_t));
   1279             map->pkt_pri = ((idx & 0xe) >> 1);
   1280             map->pkt_cfi = (idx & 0x1);
   1281             entry = soc_mem_table_idx_to_pointer(unit, mem, void *, 
   1282                                                  dma_buf, idx);
   1283             map->etag_pcp = soc_mem_field32_get(unit, mem, entry, PCPf);
   1284             map->etag_de = soc_mem_field32_get(unit, mem, entry, DEf);
   1285             count++;
   1286         }
   1287         break;
   1288     case _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP:
   1289         for (idx=0; ((idx<num_entries) && (count < array_size)); idx++) {
   1290             map = &array[idx];
   1291             sal_memset(map, 0x0, sizeof(bcm_qos_map_t));
   1292             map->int_pri = ((idx & 0x3c) >> 2);
   1293             cng = (idx & 0x3);
   1294             map->color = _BCM_COLOR_DECODING(unit, cng);
   1295             entry = soc_mem_table_idx_to_pointer(unit, mem, void *, 
   1296                                             dma_buf, idx);
   1297             map->etag_pcp = soc_mem_field32_get(unit, mem, entry, PCPf);
   1298             map->etag_de = soc_mem_field32_get(unit, mem, entry, DEf);
   1299             count++;
   1300         }
   1301         break;
   1302     default:
   1303         rv = BCM_E_INTERNAL; /* should not hit this */
   1304     }
   1305     QOS_UNLOCK(unit);
   1306     soc_cm_sfree(unit, dma_buf);
   1307 
   1308     BCM_IF_ERROR_RETURN(rv);
   1309 
   1310     *array_count = count;
   1311     return BCM_E_NONE;
   1312 }
   1313 
   1314 /*
   1315  * Function: 
   1316  *     bcm_th_qos_map_delete
   1317  * Purpose:
   1318  *     Delete a mapping (for example, the map from 7 to 3).  This is equivalent
   1319  *     to changing it to a map from 7 to 0, so this function maps the call into
   1320  *     bcm_td2_qos_map_add().
   1321  * Parameters:
   1322  *     unit   - (IN) The unit being operated on
   1323  *     flags  - (IN) BCM_QOS_MAP_* flags
   1324  *     map    - (IN) Structure containing the priorities to be mapped
   1325  *     map_id - (IN) The ID of the map to add the new information to
   1326  * Returns:
   1327  *     BCM_E_XXX
   1328  */
   1329 int
   1330 bcm_th_qos_map_delete(int unit, uint32 flags, bcm_qos_map_t *map, int map_id)
   1331 {
   1332     int rv = BCM_E_NONE;
   1333     bcm_qos_map_t clr_map;
   1334     
   1335     QOS_INIT(unit);
   1336 
   1337     sal_memcpy(&clr_map, map, sizeof clr_map);
   1338 
   1339     rv = _bcm_th_qos_flags_sanity_check(flags);
   1340     if (BCM_SUCCESS(rv)) {
   1341         if (flags & BCM_QOS_MAP_INGRESS) {
   1342             if (flags & BCM_QOS_MAP_L2_VLAN_ETAG) {
   1343                 clr_map.etag_pcp = 0;
   1344                 clr_map.etag_de = 0;
   1345             }
   1346         } else {
   1347             if(flags & BCM_QOS_MAP_L2_VLAN_ETAG) {
   1348                 clr_map.etag_pcp = 0;
   1349                 clr_map.etag_de = 0;
   1350             } else {
   1351             clr_map.pkt_pri = 0;
   1352             }
   1353         }
   1354     }
   1355 
   1356     if (BCM_SUCCESS(rv)) {
   1357         rv = bcm_th_qos_map_add(unit, flags, &clr_map, map_id);
   1358     }
   1359 
   1360     return rv;
   1361 }
   1362 
   1363 /*
   1364  * Function: 
   1365  *     _bcm_th_qos_apply_ing_map_to_port
   1366  * Purpose:
   1367  *     Apply a fully created ingress map to a hardware port.  This is the final
   1368  *     step in the process, where the mapping becomes operational.
   1369  * Parameters:
   1370  *     unit       - (IN) Unit being operated on
   1371  *     ing_map    - (IN) ID of the map to be applied
   1372  *     local_port - (IN) Local port number to apply map to
   1373  * Returns:
   1374  *     BCM_E_XXX
   1375  */
   1376 STATIC int
   1377 _bcm_th_qos_apply_ing_map_to_port(int unit, int ing_map, bcm_port_t local_port)
   1378 {
   1379     int rv = BCM_E_PARAM;
   1380     int id = ing_map & _BCM_QOS_MAP_TYPE_MASK;
   1381     int profile_idx = TH_QOS_INFO(unit)->ing_l2_vlan_etag_map_hwidx[id]; 
   1382     
   1383     soc_mem_lock(unit, PORT_TABm);
   1384     
   1385     if ((ing_map >> _BCM_QOS_MAP_SHIFT) == _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP) {
   1386         rv = _bcm_tr2_port_tab_set(unit, local_port, ETAG_PCP_DE_MAPPING_PTRf,
   1387                                  profile_idx);
   1388     }
   1389 
   1390     soc_mem_unlock(unit, PORT_TABm);
   1391 
   1392     return rv;
   1393 }
   1394 
   1395 /*
   1396  * Function: 
   1397  *     _bcm_th_qos_apply_egr_map_to_port
   1398  * Purpose:
   1399  *     Apply a fully created ingress map to a hardware port.  This is the final
   1400  *     step in the process, where the mapping becomes operational.
   1401  * Parameters:
   1402  *     unit       - (IN) Unit being operated on
   1403  *     ing_map    - (IN) ID of the map to be applied
   1404  *     local_port - (IN) Local port number to apply map to
   1405  * Returns:
   1406  *     BCM_E_XXX
   1407  */
   1408 STATIC int
   1409 _bcm_th_qos_apply_egr_map_to_port(int unit, int egr_map, bcm_port_t local_port)
   1410 {
   1411     int rv = BCM_E_PARAM;
   1412     int id = egr_map & _BCM_QOS_MAP_TYPE_MASK;
   1413     int profile_idx = TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx[id];  
   1414     soc_mem_lock(unit, PORT_TABm);
   1415     
   1416     if ((egr_map >> _BCM_QOS_MAP_SHIFT) == _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP) {
   1417         rv = _bcm_tr2_port_tab_set(unit, local_port, ETAG_DOT1P_MAPPING_PTRf,
   1418                                  profile_idx);
   1419     }
   1420 
   1421     soc_mem_unlock(unit, PORT_TABm);
   1422 
   1423     return rv;
   1424 }
   1425 
   1426 /*
   1427  * Function: 
   1428  *     bcm_th_qos_port_map_set
   1429  * Purpose:
   1430  *     Apply a fully created ingress and/or egress map to a given port.  If
   1431  *     either map is given as -1 (_BCM_QOS_NO_MAP), then the parameter should be
   1432  *     ignored.
   1433  * Parameters:
   1434  *     unit    - (IN) The unit to be operated on
   1435  *     port    - (IN) The port number for the map to be applied to
   1436  *     ing_map - (IN) The ID of an ingress map to be applied
   1437  *     egr_map - (IN) The ID of an egress map to be applied
   1438  * Returns:
   1439  *     BCM_E_XXX
   1440  */
   1441 int
   1442 bcm_th_qos_port_map_set(int unit, bcm_gport_t port, int ing_map, int egr_map)
   1443 {
   1444     int rv = BCM_E_NONE;
   1445     bcm_port_t local_port;
   1446     
   1447     QOS_INIT(unit);
   1448     QOS_LOCK(unit);
   1449 
   1450     if (!BCM_GPORT_IS_SET(port)) {
   1451         rv = BCM_E_PARAM;
   1452     }
   1453 
   1454     if (BCM_SUCCESS(rv)) {
   1455         rv = bcm_esw_port_local_get(unit, port, &local_port);
   1456     }
   1457 
   1458     if (BCM_SUCCESS(rv) && !SOC_PORT_VALID(unit, local_port)) {
   1459         rv = BCM_E_PARAM;
   1460     }
   1461 
   1462     if (BCM_SUCCESS(rv) && ing_map != _BCM_QOS_NO_MAP) {
   1463         int id = ing_map & _BCM_QOS_MAP_TYPE_MASK;
   1464 
   1465         if ((ing_map >> _BCM_QOS_MAP_SHIFT) != 
   1466             _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP){
   1467             rv = BCM_E_PARAM;
   1468         }
   1469 
   1470         if (BCM_SUCCESS(rv) 
   1471             && (((ing_map >> _BCM_QOS_MAP_SHIFT) == 
   1472             _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP) 
   1473             && (!_BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, id)))) {
   1474             rv = BCM_E_PARAM;
   1475         }
   1476 
   1477         if (BCM_SUCCESS(rv)) {
   1478             rv = _bcm_th_qos_apply_ing_map_to_port(unit, ing_map, local_port);
   1479         }
   1480     }
   1481 
   1482     if (BCM_SUCCESS(rv) && egr_map != _BCM_QOS_NO_MAP) {
   1483         int id = egr_map & _BCM_QOS_MAP_TYPE_MASK;
   1484 
   1485         if ((egr_map >> _BCM_QOS_MAP_SHIFT) != 
   1486             _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP){
   1487             rv = BCM_E_PARAM;
   1488         }
   1489 
   1490         if (BCM_SUCCESS(rv) 
   1491             && (((egr_map >> _BCM_QOS_MAP_SHIFT) == 
   1492             _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP) 
   1493             && (!_BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, id)))) {
   1494             rv = BCM_E_PARAM;
   1495         }
   1496 
   1497         if (BCM_SUCCESS(rv)) {
   1498             rv = _bcm_th_qos_apply_egr_map_to_port(unit, egr_map, local_port);
   1499         }
   1500     }
   1501 
   1502     QOS_UNLOCK(unit);
   1503 
   1504     return rv;
   1505 }
   1506 
   1507 /*
   1508  * Function:
   1509  *     _bcm_th_qos_port_ing_profile_get
   1510  * Purpose:
   1511  *     Retrieve a specific ingress QoS map index from given port.
   1512  * Parameters:
   1513  *     unit               - (IN) Unit being operated on
   1514  *     local_port         - (IN) Local port number to apply map to
   1515  *     ing_map_type       - (IN) type of the map to be retrieved
   1516  *     profile_idx        - (OUT) Hardware index
   1517  * Returns:
   1518  *     BCM_E_XXX
   1519  */
   1520 STATIC int
   1521 _bcm_th_qos_port_ing_profile_get(int unit, bcm_port_t local_port,
   1522                                  int ing_map_type, int *profile_idx)
   1523 {
   1524     int rv = BCM_E_PARAM;
   1525 
   1526     if (profile_idx == NULL) {
   1527         return BCM_E_PARAM;
   1528     }
   1529 
   1530     if (ing_map_type == _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP) {
   1531         rv = _bcm_esw_port_tab_get(unit, local_port, ETAG_PCP_DE_MAPPING_PTRf,
   1532                                    profile_idx);
   1533     }
   1534 
   1535     return rv;
   1536 }
   1537 
   1538 /*
   1539  * Function:
   1540  *     _bcm_th_qos_port_egr_profile_get
   1541  * Purpose:
   1542  *     Retrieve a specific egress QoS map index from given port.
   1543  * Parameters:
   1544  *     unit                 - (IN) Unit being operated on
   1545  *     local_port           - (IN) Local port number to apply map to
   1546  *     egr_map_type         - (IN) type of the map to be retrieved
   1547  *     profile_idx          - (OUT) Hardware index
   1548  * Returns:
   1549  *     BCM_E_XXX
   1550  */
   1551 STATIC int
   1552 _bcm_th_qos_port_egr_profile_get(int unit, bcm_port_t local_port,
   1553                                  int egr_map_type, int *profile_idx)
   1554 {
   1555     int rv = BCM_E_PARAM;
   1556 
   1557     if (profile_idx == NULL) {
   1558         return BCM_E_PARAM;
   1559     }
   1560 
   1561     if (egr_map_type == _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP) {
   1562         rv = BCM_E_UNAVAIL;
   1563     }
   1564 
   1565     return rv;
   1566 }
   1567 
   1568 
   1569 /* Function:
   1570 *     _bcm_th_qos_id2idx
   1571 * Purpose:
   1572 *    Translate hardware table index into map ID used by API
   1573 * Parameters:
   1574 * Returns:
   1575 *    BCM_E_XXX
   1576 */
   1577 int
   1578 _bcm_th_qos_idx2id(int unit, int hw_idx, int type, int *map_id)
   1579 {
   1580     int idx;
   1581     int rv = BCM_E_NOT_FOUND;
   1582 
   1583     if (map_id == NULL) {
   1584         return BCM_E_PARAM;
   1585     }
   1586 
   1587     QOS_INIT(unit);
   1588 
   1589     switch (type) {
   1590     case _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP:
   1591         for (idx = 0; idx < _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS; idx++) {
   1592             if (_BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, idx)) {
   1593                 if (TH_QOS_INFO(unit)->ing_l2_vlan_etag_map_hwidx[idx]
   1594                         == hw_idx) {
   1595                     *map_id = idx | (_BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP
   1596                                          << _BCM_QOS_MAP_SHIFT);
   1597                     rv = BCM_E_NONE;
   1598                     break;
   1599                 }
   1600             }
   1601         }
   1602 
   1603         break;
   1604 
   1605     case _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP:
   1606         for (idx = 0; idx < _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS; idx++) {
   1607             if (_BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, idx)) {
   1608                 if (TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx[idx]
   1609                         == hw_idx) {
   1610                     *map_id = idx | (_BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP
   1611                                          << _BCM_QOS_MAP_SHIFT);
   1612                     rv = BCM_E_NONE;
   1613                     break;
   1614                 }
   1615             }
   1616         }
   1617 
   1618         break;
   1619 
   1620     default:
   1621         rv = BCM_E_NOT_FOUND;
   1622     }
   1623 
   1624     return rv;
   1625 }
   1626 
   1627 /*
   1628  * Function:
   1629  *     bcm_th_qos_port_map_type_get
   1630  * Purpose:
   1631  *     Retrieve ingress or egress map from a given port.
   1632  * Parameters:
   1633  *     unit         - (IN) The unit to be operated on
   1634  *     port         - (IN) The port number for the map to be retrieved from
   1635  *     flags        - (IN) type of the map which is of interest
   1636  *     map_id       - (OUT) The ID of map returned
   1637  * Returns:
   1638  *     BCM_E_XXX
   1639  */
   1640 int
   1641 bcm_th_qos_port_map_type_get(int unit, bcm_gport_t port, uint32 flags,
   1642                              int *map_id)
   1643 {
   1644     int rv = BCM_E_NONE;
   1645     bcm_port_t local_port;
   1646     int map_type;
   1647     int profile_idx;
   1648 
   1649     QOS_INIT(unit);
   1650 
   1651     if (map_id == NULL) {
   1652         rv = BCM_E_PARAM;
   1653     }
   1654     if (!BCM_GPORT_IS_SET(port)) {
   1655         rv = BCM_E_PARAM;
   1656     }
   1657 
   1658     if (BCM_SUCCESS(rv)) {
   1659         rv = bcm_esw_port_local_get(unit, port, &local_port);
   1660     }
   1661 
   1662     if (BCM_SUCCESS(rv) && !SOC_PORT_VALID(unit, local_port)) {
   1663         rv = BCM_E_PARAM;
   1664     }
   1665 
   1666     BCM_IF_ERROR_RETURN(rv);
   1667 
   1668     if (flags & BCM_QOS_MAP_INGRESS) {
   1669         if (flags & BCM_QOS_MAP_L2_VLAN_ETAG) {
   1670             map_type = _BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP;
   1671         } else {
   1672            rv = BCM_E_PARAM;
   1673            return rv;
   1674         }
   1675         rv = _bcm_th_qos_port_ing_profile_get(unit, local_port, map_type,
   1676                                               &profile_idx);
   1677     } else if (flags & BCM_QOS_MAP_EGRESS) {
   1678         if (flags & BCM_QOS_MAP_L2_VLAN_ETAG) {
   1679             map_type = _BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP;
   1680         } else {
   1681             rv = BCM_E_PARAM;
   1682             return rv;
   1683         }
   1684         rv = _bcm_th_qos_port_egr_profile_get(unit, local_port, map_type,
   1685                                               &profile_idx);
   1686     } else {
   1687         rv = BCM_E_PARAM;
   1688         return rv;
   1689     }
   1690 
   1691     if(BCM_SUCCESS(rv)) {
   1692         /* map H/W profile ID to API QoS map ID */
   1693         rv = _bcm_th_qos_idx2id(unit, profile_idx, map_type, map_id);
   1694     }
   1695 
   1696     return rv;
   1697 }
   1698 
   1699 /* Function:
   1700  *      bcm_th_qos_egr_etag_id2profile
   1701  *  Purpose:
   1702  *      Given a QOS map ID for a egress etag mapping profile, return the profile number
   1703  *     into the EGR_ETAG_PCP_MAPPING table.
   1704  *  Parameters:
   1705  *      unit - (IN) Unit being operated on
   1706  *      map_id - (IN) ID of the map to be retrieved
   1707  *      profile_num - (OUT) Hardware profile number that map_id maps to
   1708  *  Returns:
   1709  *      BCM_E_XXX
   1710  */
   1711 int
   1712 bcm_th_qos_egr_etag_id2profile(int unit, int map_id, int *profile_num)
   1713 {
   1714     int id;
   1715 
   1716     QOS_INIT(unit);
   1717     id = map_id & _BCM_QOS_MAP_TYPE_MASK;
   1718 
   1719     QOS_LOCK(unit);
   1720     if (!_BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, id)) {
   1721         QOS_UNLOCK(unit);
   1722         return BCM_E_NOT_FOUND;
   1723     } else {
   1724         *profile_num = TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx[id];
   1725     }
   1726 
   1727     QOS_UNLOCK(unit);
   1728     return BCM_E_NONE;
   1729 }
   1730 
   1731 /* Function:
   1732 *      bcm_th_qos_egr_etag_profile2id
   1733 * Purpose:
   1734 *      Given a EGR_ETAG_PCP_MAPPING table profile number, find the QOS map ID which maps to it.
   1735 * Parameters:
   1736 *      unit - (IN) Unit being operated on
   1737 *      profile_num - (IN) profile number of the map to be retrieved
   1738  *     map_id       - (OUT) Map ID that points to profile_num
   1739 * Returns:
   1740 *      BCM_E_XXX
   1741 */
   1742 int
   1743 bcm_th_qos_egr_etag_profile2id(int unit, int profile_num, int *map_id)
   1744 {
   1745     int i;
   1746 
   1747     QOS_INIT(unit);
   1748 
   1749     QOS_LOCK(unit);
   1750     for (i = 0; i < _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAP_IDS; i++) {
   1751         if (TH_QOS_INFO(unit)->egr_l2_vlan_etag_map_hwidx[i] == profile_num) {
   1752                 *map_id = (_BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP << _BCM_QOS_MAP_SHIFT) | i;
   1753                  QOS_UNLOCK(unit);
   1754                  return BCM_E_NONE;
   1755         }
   1756     }
   1757 
   1758     QOS_UNLOCK(unit);
   1759     return BCM_E_BADID;
   1760 }
   1761 
   1762 int
   1763 _bcm_th_qos_multi_get(int unit, int array_size, int *map_ids_array,
   1764                       int *flags_array, int *array_count)
   1765 {
   1766     /* Assume that QoS lock has been taken */
   1767 
   1768     int idx, count;
   1769     int rv = BCM_E_NONE;
   1770 
   1771     if (array_size == 0) {
   1772         if (array_count == NULL) {
   1773             rv = BCM_E_PARAM;
   1774         }
   1775 
   1776         if (BCM_SUCCESS(rv)) {
   1777             *array_count = 0;
   1778             count = 0;
   1779             SHR_BITCOUNT_RANGE(TH_QOS_INFO(unit)->ing_l2_vlan_etag_map, count,
   1780                                0, _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS);
   1781             *array_count += count;
   1782             count = 0;
   1783             SHR_BITCOUNT_RANGE(TH_QOS_INFO(unit)->egr_l2_vlan_etag_map, count,
   1784                                0, _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS);
   1785             *array_count += count;
   1786         }
   1787     } else {
   1788         if ((map_ids_array == NULL) || (flags_array == NULL) ||
   1789             (array_count == NULL)) {
   1790             rv = BCM_E_PARAM;
   1791         }
   1792 
   1793         if (BCM_SUCCESS(rv)) {
   1794             count = 0;
   1795             for (idx = 0; ((idx < _BCM_QOS_MAX_L2_VLAN_ETAG_MAPS) &&
   1796                  (count < array_size)); idx++) {
   1797                 if (_BCM_QOS_ING_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, idx)) {
   1798                     *(map_ids_array + count) =
   1799                         idx | (_BCM_QOS_MAP_TYPE_ING_L2_VLAN_ETAG_MAP <<
   1800                                _BCM_QOS_MAP_SHIFT);
   1801                     *(flags_array + count) = BCM_QOS_MAP_L2_VLAN_ETAG | BCM_QOS_MAP_INGRESS;
   1802                     count++;
   1803                 }
   1804             }
   1805             for (idx = 0; ((idx < _BCM_QOS_MAX_EGR_L2_VLAN_ETAG_MAPS) &&
   1806                  (count < array_size)); idx++) {
   1807                 if (_BCM_QOS_EGR_L2_VLAN_ETAG_MAP_TABLE_USED_GET(unit, idx)) {
   1808                     *(map_ids_array + count) =
   1809                         idx | (_BCM_QOS_MAP_TYPE_EGR_L2_VLAN_ETAG_MAP <<
   1810                                _BCM_QOS_MAP_SHIFT);
   1811                     *(flags_array + count) = BCM_QOS_MAP_L2_VLAN_ETAG | BCM_QOS_MAP_EGRESS;
   1812                     count++;
   1813                 }
   1814             }
   1815 
   1816             *array_count = count;
   1817         }
   1818 
   1819     }
   1820 
   1821     return rv;
   1822 }
   1823 
   1824 #endif /* BCM_TOMAHAWK_SUPPORT */
   1825