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

switch.c (125602B)


      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  * Module : Switch 
      8  * 
      9  * Purpose: 
     10  * This file has the flexible hashing apis and its accessory functions to configure
     11  * field match data and relative hash offsets for bucket 2 and 3.
     12  * 
     13  * The below shows the configurations of flexible hashing mechanism in UDF and Flex
     14  * tables. Data qualifier apis are used to configure the UDF table with relative
     15  * packet offsets from L4 header. UDF chunk4 - 7 is being used to configure hash
     16  * bucket 2 and 3. Flexible hashing offset mapping is done with functions
     17  * implemented in this file.
     18  * 
     19  * 
     20  * 
     21  * FLEXIBLE HASHING PACKET PARSER (with UDF)
     22  * 
     23  *     Packet            L4
     24  *     +--------+--------+------------+---------+
     25  *     |        |        | L4 header  | Payload |
     26  *     +--------+--------+-+-+--------+---------+
     27  *                 offset  2 2 ....                                      
     28  *                  ||                                            -----+ 
     29  *                  ||                                                 | 
     30  *                           +----Chunk4----+           PKT.field1(16b)| 
     31  *         PKT.offset1  -->  | +--Chunk5-----+                         | 
     32  *                           | | +-Chunk6------+    ==> PKT.field2(16b)|
     33  *     +   PKT.offset2  -->  | | | +-Chunk7------+                    -+ 
     34  *                           +-| | |             |      PKT.field3(16b)| 
     35  *         PKT.offset3  ---->  +-| |UDF_TCAM/OFF |                     | 
     36  *                               +-|  (4 x 16bit)|      PKT.field4(16b)| 
     37  *         PKT.offset4  ------>    +-------------+                     | 
     38  *                                                                -----+ 
     39  *                                                                      
     40  *                                                                                           
     41  * FLEXIBLE HASHING OFFSET MAPPING
     42  *                                                                                               * 
     43  *                        (64bx8)  [UDF_CONDITIONAL_CHECK_TABLE_CAMm]
     44  *                  -----+         +--0-------------+                                    
     45  *        PKT.field1(16b)|          +-|+-2--------------+                                
     46  *                       |           +-|+-3--------------+                               
     47  *        PKT.field2(16b)| 64bit       +| +-4--------------+    ==> offset 2
     48  *                      -+---- Key      +-| +-5--------------+                           
     49  *        PKT.field3(16b)|                +-| +-6--------------+   
     50  *                       |                  +-| +-7--------------+                       
     51  *        PKT.field4(16b)|                    +-|                |                       
     52  *                       |                      +----------------+                       
     53  *                  -----+                 [UDF_CONDITIONAL_CHECK_TABLE_RAMm]
     54  */
     55 
     56 #include <soc/defs.h>
     57 
     58 #if defined(BCM_TRIDENT2_SUPPORT)
     59 #include <soc/mem.h>
     60 #include <soc/mcm/memregs.h>
     61 #include <soc/debug.h>
     62 #include <soc/field.h>
     63 #include <bcm/switch.h>
     64 
     65 #include <bcm_int/esw/xgs4.h>
     66 #include <bcm_int/esw/field.h>
     67 #include <bcm_int/esw/switch.h>
     68 #include <bcm_int/esw/trident2.h>
     69 #include <soc/soc_ser_log.h>
     70 
     71 
     72 
     73 /* Flex enable regmem and fields */
     74 static soc_reg_t _bcm_td2_flex_hash_control = RTAG7_HASH_CONTROL_3r;
     75 static soc_field_t _bcm_td2_flex_hash_enable_fields[] = {
     76     ENABLE_FLEX_FIELD_1_Af,
     77     ENABLE_FLEX_FIELD_1_Bf,
     78     ENABLE_FLEX_FIELD_2_Af,
     79     ENABLE_FLEX_FIELD_2_Bf
     80 };
     81 
     82 #ifdef BCM_TOMAHAWK2_SUPPORT
     83 static soc_reg_t _bcm_th2_flex_hash_control = RTAG7_HASH_CONTROL_3_64r;
     84 static soc_field_t _bcm_th2_flex_hash_enable_fields[] = {
     85     ENABLE_FLEX_FIELD_1_Af,
     86     ENABLE_FLEX_FIELD_1_Bf,
     87     ENABLE_FLEX_FIELD_2_Af,
     88     ENABLE_FLEX_FIELD_2_Bf,
     89     ENABLE_FLEX_FIELD_3_Af,
     90     ENABLE_FLEX_FIELD_3_Bf,
     91     ENABLE_FLEX_FIELD_4_Af,
     92     ENABLE_FLEX_FIELD_4_Bf,
     93     ENABLE_FLEX_FIELD_5_Af,
     94     ENABLE_FLEX_FIELD_5_Bf,
     95     ENABLE_FLEX_FIELD_6_Af,
     96     ENABLE_FLEX_FIELD_6_Bf,
     97     ENABLE_FLEX_FIELD_7_Af,
     98     ENABLE_FLEX_FIELD_7_Bf,
     99     ENABLE_FLEX_FIELD_8_Af,
    100     ENABLE_FLEX_FIELD_8_Bf,
    101     ENABLE_FLEX_FIELD_9_Af,
    102     ENABLE_FLEX_FIELD_9_Bf,
    103     ENABLE_FLEX_FIELD_10_Af,
    104     ENABLE_FLEX_FIELD_10_Bf,
    105     ENABLE_FLEX_FIELD_11_Af,
    106     ENABLE_FLEX_FIELD_11_Bf,
    107     ENABLE_FLEX_FIELD_12_Af,
    108     ENABLE_FLEX_FIELD_12_Bf,
    109     ENABLE_FLEX_FIELD_13_Af,
    110     ENABLE_FLEX_FIELD_13_Bf
    111 };
    112 #endif /*BCM_TOMAHAWK2_SUPPORT*/
    113 
    114 /* register to enable flex hasing scheme */
    115 static soc_reg_t _bcm_td2_ing_hash_config = ING_HASH_CONFIG_0r; 
    116 static soc_field_t _bcm_td2_ing_hash_config_fields[] = {
    117     ENABLE_FLEX_HASHINGf
    118 };
    119 /* 
    120  *   TCAM: FIELD_1_MASK, FIELD_2_MASK
    121  *   FIELD_1_DATA, FIELD_2_DATA
    122 
    123  *   RAM: FIELD_1_MASK, FIELD_2_MASK
    124  *   FIELD_1_OFFSET, FIELD_2_OFFSET
    125  */
    126 
    127 static soc_field_t _bcm_td2_flex_hash_data[] = {
    128     FIELD_2_DATAf,
    129     FIELD_1_DATAf
    130 };
    131 
    132 static soc_field_t _bcm_td2_flex_hash_mask[] = {
    133     FIELD_2_MASKf,
    134     FIELD_1_MASKf,
    135     FIELD_3_MASKf,
    136     FIELD_4_MASKf,
    137     FIELD_5_MASKf,
    138     FIELD_6_MASKf,
    139     FIELD_7_MASKf,
    140     FIELD_8_MASKf,
    141     FIELD_9_MASKf,
    142     FIELD_10_MASKf,
    143     FIELD_11_MASKf,
    144     FIELD_12_MASKf,
    145     FIELD_13_MASKf
    146 };
    147 
    148 static soc_field_t _bcm_td2_flex_hash_offset[] = {
    149     FIELD_2_OFFSETf,
    150     FIELD_1_OFFSETf
    151 };
    152 #if defined(BCM_TOMAHAWK_SUPPORT)
    153 static soc_field_t _bcm_th_flex_hash_offset_udf[] = {
    154     UDF_SEL_2f,
    155     UDF_CHUNK_ID_2f,
    156     UDF_SEL_1f,
    157     UDF_CHUNK_ID_1f,
    158     UDF_SEL_3f,
    159     UDF_CHUNK_ID_3f,
    160     UDF_SEL_4f,
    161     UDF_CHUNK_ID_4f,
    162     UDF_SEL_5f,
    163     UDF_CHUNK_ID_5f,
    164     UDF_SEL_6f,
    165     UDF_CHUNK_ID_6f,
    166     UDF_SEL_7f,
    167     UDF_CHUNK_ID_7f,
    168     UDF_SEL_8f,
    169     UDF_CHUNK_ID_8f,
    170     UDF_SEL_9f,
    171     UDF_CHUNK_ID_9f,
    172     UDF_SEL_10f,
    173     UDF_CHUNK_ID_10f,
    174     UDF_SEL_11f,
    175     UDF_CHUNK_ID_11f,
    176     UDF_SEL_12f,
    177     UDF_CHUNK_ID_12f,
    178     UDF_SEL_13f,
    179     UDF_CHUNK_ID_13f
    180 };
    181 static soc_field_t _bcm_th_flex_hash_offset_type[] = {
    182     FIELD_2_TYPEf,
    183     FIELD_1_TYPEf,
    184     FIELD_3_TYPEf,
    185     FIELD_4_TYPEf,
    186     FIELD_5_TYPEf,
    187     FIELD_6_TYPEf,
    188     FIELD_7_TYPEf,
    189     FIELD_8_TYPEf,
    190     FIELD_9_TYPEf,
    191     FIELD_10_TYPEf,
    192     FIELD_11_TYPEf,
    193     FIELD_12_TYPEf,
    194     FIELD_13_TYPEf
    195 };
    196 #endif /*BCM_TOMAHAWK_SUPPORT*/
    197 static soc_mem_t _bcm_td2_flex_hash_table[] = {
    198     UDF_CONDITIONAL_CHECK_TABLE_CAMm,
    199     UDF_CONDITIONAL_CHECK_TABLE_RAMm
    200 };
    201 
    202 #define FLEX_HASH_TCAM (_bcm_td2_flex_hash_table[0])
    203 #define FLEX_HASH_OFFSET (_bcm_td2_flex_hash_table[1])
    204 #define FLEX_HASH_TCAM_ENTRY_T udf_conditional_check_table_cam_entry_t
    205 #define FLEX_HASH_OFFSET_ENTRY_T udf_conditional_check_table_ram_entry_t
    206 #define FLEX_HASH_OFFSET_MASK(_u_) (((SOC_IS_TOMAHAWK2(_u_)) \
    207                 || (SOC_IS_TOMAHAWK3(_u_))) ? \
    208                 UDF_CONDITIONAL_CHECK_TABLE_RAM_1m : UDF_CONDITIONAL_CHECK_TABLE_RAMm)
    209 #define FLEX_HASH_OFFSET_MASK_ENTRY_T udf_conditional_check_table_ram_1_entry_t
    210 
    211 /*
    212  * Flex Index usage bitmap operations. The 8 indexes of flex tcam table are
    213  * being managed with index bitmap operations.
    214  */
    215 #define _BCM_SWITCH_FLEX_IDX_USED_GET(_u_, _idx_) \
    216         SHR_BITGET(SWITCH_HASH_INFO(_u_)->hash_idx_bitmap, (_idx_))
    217 
    218 #define _BCM_SWITCH_FLEX_IDX_USED_SET(_u_, _idx_) \
    219         SHR_BITSET(SWITCH_HASH_INFO((_u_))->hash_idx_bitmap, (_idx_))
    220 
    221 #define _BCM_SWITCH_FLEX_IDX_USED_CLR(_u_, _idx_) \
    222         SHR_BITCLR(SWITCH_HASH_INFO((_u_))->hash_idx_bitmap, (_idx_))
    223 
    224 
    225 #define FLEX_HASH_MAX_FIELDS 4
    226 #define FLEX_HASH_MAX_OFFSET 13
    227 #define FLEX_QUAL_BIT_PER_SIZE 8
    228 #define FLEX_HASH_OFFSET_NUM(_u_) (((SOC_IS_TOMAHAWK2(_u_)) \
    229                                     || (SOC_IS_TOMAHAWK3(_u_))) ? 13 : 2)
    230 #define FLEX_HASH_CHECK_FIELDS_NUM 2
    231 typedef struct _bcm_flex_hash_match_arr_s {
    232     int             qual_id;    /* Data Qualifier Id */
    233     int             qual_size;  /* Data qualifier size: xbytes, 2byte max */
    234     uint32          qual_match; /* Qualifier match data */
    235     uint32          qual_mask;  /* Qualifier mask */
    236 } _bcm_flex_hash_match_arr_t;
    237 
    238 typedef struct _bcm_flex_hash_entry_s {
    239     int             entry_id;   /* Logical eid for flex hash entry */
    240     int             hw_idx; /* Associated flex table index */
    241     int             entry_count;    /* Reference count of the entry */
    242     int             offset_bitmap;   /* Flex hash offset bitmap */
    243     int             offset_count;   /* Flex hash offset count */
    244     int             hash_offset[FLEX_HASH_MAX_OFFSET]; /* Flex hash offset */
    245     int             hash_mask[FLEX_HASH_MAX_OFFSET]; /* Flex hash mask */
    246     _bcm_flex_hash_match_arr_t match_arr[FLEX_HASH_MAX_FIELDS];
    247     struct _bcm_flex_hash_entry_s *next;    /* Next in flex hash list */
    248     int             type[FLEX_HASH_MAX_OFFSET];   /* field type,
    249                  currently there are two field types in flex hash ram table. 0: offset, 1: udf chunk */
    250     bcm_udf_id_t    udf_id[FLEX_HASH_MAX_OFFSET];  /*udf id when field type is udf*/
    251 } flex_hash_entry_t, *flex_hash_entry_p;
    252 
    253 /* Switch flex hash bookkeeping structure */
    254 typedef struct _bcm_td2_switch_hash_bookeeping_s {
    255     int             init;
    256     int             api_ver;
    257     flex_hash_entry_p hash_entry_list;
    258     SHR_BITDCL     *hash_idx_bitmap;
    259     uint32          last_hash_entry_id;
    260 } _bcm_td2_switch_hash_bookeeping_t;
    261 
    262 STATIC          _bcm_td2_switch_hash_bookeeping_t
    263     _bcm_td2_switch_hash_bk_info[BCM_MAX_NUM_UNITS];
    264 
    265 #define SWITCH_HASH_INFO(_unit_)   (&_bcm_td2_switch_hash_bk_info[_unit_])
    266 #define SWITCH_HASH_INIT(_unit_) \
    267             (_bcm_td2_switch_hash_bk_info[_unit_].init)
    268 #define SWITCH_HASH_ENTRY_LIST(_unit_) \
    269             (_bcm_td2_switch_hash_bk_info[_unit_].hash_entry_list)
    270 #define SWITCH_HASH_IDX_BITMAP(_unit_) \
    271             (_bcm_td2_switch_hash_bk_info[_unit_].hash_idx_bitmap)
    272 #define SWITCH_HASH_LAST_ENTRY_ID(_unit_) \
    273             (_bcm_td2_switch_hash_bk_info[_unit_].last_hash_entry_id)
    274 
    275 #if defined (BCM_WARM_BOOT_SUPPORT)
    276 /* warmboot entry */
    277 typedef struct wb_hash_entry_match_arr_s {
    278     uint32 qual_id;    
    279     uint32 qual_size; 
    280 }  wb_hash_entry_match_arr_t;
    281 
    282 typedef struct bcmi_xgs4_td2_switch_wb_hash_entry_s {
    283     uint32 entry_id;
    284     uint32 hw_idx;
    285     uint32 offset_bitmap;
    286     wb_hash_entry_match_arr_t match_arr[FLEX_HASH_MAX_FIELDS];
    287     bcm_udf_id_t udf_id[FLEX_HASH_MAX_OFFSET];
    288 } bcmi_xgs4_td2_switch_wb_hash_entry_t;
    289 #endif
    290 
    291 
    292 
    293 typedef struct _bcm_td2_gtp_port_match_s {
    294     uint8 match_criteria;
    295     uint16 dst_port;
    296     uint16 src_port;
    297 } _bcm_td2_gtp_port_match_t;
    298 /*
    299  * Software book keeping for Switch Match related information
    300  */
    301 typedef struct _bcm_td2_switch_match_bookkeeping_s {
    302     _bcm_td2_gtp_port_match_t **gtp_ptr_array; /* Array of pointers to gtp port table */
    303     sal_mutex_t match_mutex;
    304 } _bcm_td2_switch_match_bookkeeping_t;
    305 
    306 STATIC _bcm_td2_switch_match_bookkeeping_t
    307     _bcm_td2_switch_match_bk_info[BCM_MAX_NUM_UNITS];
    308 
    309 STATIC int _bcm_td2_match_initialized[BCM_MAX_NUM_UNITS] = { 0 };
    310 
    311 #define TD2_MATCH_INFO(_u_) (&_bcm_td2_switch_match_bk_info[_u_])
    312 
    313 #define TD2_GTP_PORT_MATCH(_u_, id) \
    314     (TD2_MATCH_INFO(_u_)->gtp_ptr_array[id])
    315 
    316 #define TD2_GTP_PORT_MATCH_IS_USED(_u_, id) \
    317     (TD2_MATCH_INFO(_u_)->gtp_ptr_array[id] != NULL)
    318 
    319 
    320 /* Switch Match related definitions */
    321 #define _BCM_TD2_SWITCH_MATCH_ID_MASK               (0xffff)
    322 #define _BCM_TD2_SWITCH_MATCH_TYPE_SHIFT            (28)
    323 
    324 #define TD2_MATCH_TYPE_GET(_id_) \
    325         (_id_ >> _BCM_TD2_SWITCH_MATCH_TYPE_SHIFT)
    326 #define TD2_MATCH_ID_SET(_id_, _service_type_) \
    327         (_id_ | _service_type_ << _BCM_TD2_SWITCH_MATCH_TYPE_SHIFT)
    328 #define TD2_MATCH_HW_ID_GET(_id_) \
    329         (_id_ & _BCM_TD2_SWITCH_MATCH_ID_MASK)
    330 
    331 #define TD2_MATCH_LOCK(_u_) \
    332         sal_mutex_take(TD2_MATCH_INFO(_u_)->match_mutex, sal_mutex_FOREVER);
    333 #define TD2_MATCH_UNLOCK(_u_) \
    334         sal_mutex_give(TD2_MATCH_INFO(_u_)->match_mutex);
    335 
    336 #define TD2_MATCH_INIT(_u_)                               \
    337     do {                                                  \
    338         if ((_u_ < 0) || (_u_ >= BCM_MAX_NUM_UNITS)) {    \
    339             return BCM_E_UNIT;                            \
    340         }                                                 \
    341         if (!_bcm_td2_match_initialized[_u_]) {           \
    342             return BCM_E_INIT;                            \
    343         }                                                 \
    344     } while (0)
    345 
    346 
    347 /* forward declarations */
    348 
    349 STATIC int      _flex_hash_entry_get(int unit, bcm_hash_entry_t hash_entry_id,
    350                      flex_hash_entry_t ** hash_entry);
    351 
    352 STATIC int      _bcm_hash_entry_delete(int unit, bcm_hash_entry_t entry_id);
    353 STATIC int      _bcm_hash_entry_remove(int unit, bcm_hash_entry_t entry_id);
    354 
    355 STATIC int      _flex_hash_entry_destroy(int unit, flex_hash_entry_t * entry);
    356 
    357 
    358 #if defined (BCM_WARM_BOOT_SUPPORT)
    359 STATIC int      _bcm_flex_hash_table_wb_read(int unit,
    360                                      flex_hash_entry_t * hash_entry,
    361                                      bcmi_xgs4_td2_switch_wb_hash_entry_t * wb_hash_entry);
    362 #endif 
    363 
    364 /*
    365  * The below listed flexible hashing support routines are modularized for table
    366  * and list management routines.  
    367  *  1. Flex hash TCAM table read/write routines
    368  *     _bcm_flex_hash_table_write
    369  *     _bcm_flex_hash_table_read
    370  *     _bcm_flex_hash_control_enable
    371  *     _bcm_flex_hash_control_disable
    372  *    
    373  *  2. Flex hash Entry list management routines 
    374  *     _flex_hash_entry_get 
    375  *     _flex_hash_entry_destroy
    376  *     _flex_hash_entry_destroy_all
    377  *     _flex_hash_entry_alloc
    378  *     _flex_hash_entry_add
    379  *     _flex_hash_entry_delete
    380  * 
    381  *  3. Flex hash management routines 
    382  *     _bcm_hash_entry_create
    383  *     _bcm_hash_entry_delete
    384  *     _bcm_hash_entry_qual_set
    385  *     _bcm_hash_entry_qual_get
    386  *     _bcm_hash_entry_qual_data_set
    387  *     _bcm_hash_entry_qual_data_get
    388  * 
    389  * 
    390  *  4. Flexible hash Switch API support routines
    391  *     bcm_td2_switch_hash_entry_init
    392  *     bcm_td2_switch_hash_entry_detach
    393  *     bcm_td2_switch_hash_entry_create
    394  *     bcm_td2_switch_hash_entry_destroy
    395  *     bcm_td2_switch_hash_qualify_data
    396  * 
    397  *     bcm_td2_switch_hash_entry_install
    398  *     bcm_td2_switch_hash_entry_reinstall
    399  *     bcm_td2_switch_hash_entry_remove
    400  */
    401 
    402 /*
    403  * 
    404  *  Flex hash TCAM table read/write routines 
    405  */
    406  #if defined(BCM_TOMAHAWK2_SUPPORT)
    407  STATIC int
    408 _bcm_th2_flex_hash_table_write(int unit, flex_hash_entry_t * hash_entry, uint8 delete)
    409 {
    410         int             fld, rv = BCM_E_NONE;
    411         FLEX_HASH_TCAM_ENTRY_T flex_tcam_entry;
    412         FLEX_HASH_OFFSET_ENTRY_T flex_offset_entry;
    413         FLEX_HASH_OFFSET_MASK_ENTRY_T flex_offset_mask_entry;
    414         uint32          data[2] = { 0, 0 };
    415         uint32          mask[2] = { 0, 0 };
    416 
    417         if (NULL == hash_entry) {
    418             return BCM_E_FAIL;
    419         }
    420 
    421     /*
    422         note :qual_size_range is 0~2. maximum 4 match field data in a flexkey.
    423         it is required to create a flexkey in a such order
    424         field_data2: 1st qual_data, 2nd qual_data
    425         field_data1: 3rd qual_data, 4th qual_data; thus
    426         first and third match field data is shifed to left for 16 bits insdie field data.
    427         in addition, if qual_size is 1, qual_data is shifed to left for 8 bits inside field data
    428         if qual_size is 0 or 2, there won't be any shift inside field data
    429     */
    430         data[0] = (hash_entry->match_arr[0].qual_match <<
    431                       ((hash_entry->match_arr[0].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 16;
    432         data[0] |= (hash_entry->match_arr[1].qual_match <<
    433                       ((hash_entry->match_arr[1].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 0;
    434         data[1] = (hash_entry->match_arr[2].qual_match <<
    435                       ((hash_entry->match_arr[2].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 16;
    436         data[1] |= (hash_entry->match_arr[3].qual_match <<
    437                       ((hash_entry->match_arr[3].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 0;
    438 
    439         mask[0] = (hash_entry->match_arr[0].qual_mask <<
    440                       ((hash_entry->match_arr[0].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 16;
    441         mask[0] |= (hash_entry->match_arr[1].qual_mask <<
    442                       ((hash_entry->match_arr[1].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 0;
    443         mask[1] = (hash_entry->match_arr[2].qual_mask <<
    444                       ((hash_entry->match_arr[2].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 16;
    445         mask[1] |= (hash_entry->match_arr[3].qual_mask <<
    446                       ((hash_entry->match_arr[3].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 0;
    447 
    448         sal_memset(&flex_tcam_entry, 0, sizeof(flex_tcam_entry));
    449         sal_memset(&flex_offset_entry, 0, sizeof(flex_offset_entry));
    450         sal_memset(&flex_offset_mask_entry, 0, sizeof(flex_offset_mask_entry));
    451 
    452         rv = soc_mem_read(unit, FLEX_HASH_TCAM, MEM_BLOCK_ANY,
    453                   hash_entry->hw_idx, &flex_tcam_entry);
    454         if (BCM_FAILURE(rv)) {
    455             return BCM_E_FAIL;
    456         }
    457         rv = soc_mem_read(unit, FLEX_HASH_OFFSET, MEM_BLOCK_ANY,
    458                   hash_entry->hw_idx, &flex_offset_entry);
    459         if (BCM_FAILURE(rv)) {
    460             return BCM_E_FAIL;
    461         }
    462 
    463         rv = soc_mem_read(unit, FLEX_HASH_OFFSET_MASK(unit), MEM_BLOCK_ANY,
    464                   hash_entry->hw_idx, &flex_offset_mask_entry);
    465         if (BCM_FAILURE(rv)) {
    466             return BCM_E_FAIL;
    467         }
    468 
    469         if (soc_mem_field_valid(unit, FLEX_HASH_TCAM, VALIDf)) {
    470             if (delete && !soc_mem_field32_get(unit, FLEX_HASH_TCAM,
    471                                                &flex_tcam_entry, VALIDf)) {
    472                 return BCM_E_NOT_FOUND;
    473             }
    474             soc_mem_field32_set(unit, FLEX_HASH_TCAM, &flex_tcam_entry,
    475                         VALIDf, delete? 0:1);
    476         }
    477 
    478         for (fld = 0; fld < FLEX_HASH_CHECK_FIELDS_NUM; fld++) {
    479             soc_mem_field32_set(unit, FLEX_HASH_TCAM, &flex_tcam_entry,
    480                         _bcm_td2_flex_hash_data[fld], delete ? 0 : data[fld]);
    481             soc_mem_field32_set(unit, FLEX_HASH_TCAM, &flex_tcam_entry,
    482                         _bcm_td2_flex_hash_mask[fld], delete ? 0 : mask[fld]);
    483         }
    484 
    485         for (fld = 0; fld < FLEX_HASH_OFFSET_NUM(unit); fld++) {
    486             if (hash_entry->type[fld] & BCM_SWITCH_HASH_FIELD_TYPE_UDF) {
    487                 if (hash_entry->offset_bitmap & (0x1 << fld)) {
    488                     if (hash_entry->hash_offset[fld] >= MAX_UDF_OFFSET_CHUNKS) {
    489                         return BCM_E_PARAM;
    490                     }
    491                     soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    492                                 &flex_offset_entry,
    493                                 _bcm_th_flex_hash_offset_udf[fld*2],
    494                                 delete ? 0 : hash_entry->hash_offset[fld] / 8);
    495                     soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    496                                 &flex_offset_entry,
    497                                 _bcm_th_flex_hash_offset_udf[fld*2 + 1],
    498                                 delete ? 0 : (7 - hash_entry->hash_offset[fld] % 8));
    499                     soc_mem_field32_set(unit, FLEX_HASH_OFFSET_MASK(unit),
    500                                 &flex_offset_mask_entry,
    501                                 _bcm_td2_flex_hash_mask[fld],
    502                                 delete ? 0 : hash_entry->hash_mask[fld]);
    503                     soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    504                                 &flex_offset_entry,
    505                                 _bcm_th_flex_hash_offset_type[fld],
    506                                 delete ? 0 : 1);
    507                } else {
    508                     soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    509                                 &flex_offset_entry,
    510                                 _bcm_th_flex_hash_offset_udf[fld*2], 0);
    511                     soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    512                                 &flex_offset_entry,
    513                                 _bcm_th_flex_hash_offset_udf[fld*2 + 1], 0);
    514                     soc_mem_field32_set(unit, FLEX_HASH_OFFSET_MASK(unit),
    515                                 &flex_offset_mask_entry,
    516                                 _bcm_td2_flex_hash_mask[fld], 0);
    517                     soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    518                                 &flex_offset_entry,
    519                                 _bcm_th_flex_hash_offset_type[fld], 0);
    520                     break;
    521                 }
    522             } else {
    523                 if (fld > bcmSwitchFlexHashField1) {
    524                         continue;
    525                 }
    526                 if (hash_entry->offset_bitmap & (0x1 << fld)) {
    527                     if (hash_entry->hash_offset[fld] >=
    528                         (FLEX_QUAL_BIT_PER_SIZE *  FLEX_HASH_CHECK_FIELDS_NUM)) {
    529                         return BCM_E_PARAM;
    530                     }
    531                     soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    532                                 &flex_offset_entry,
    533                                 _bcm_td2_flex_hash_offset[fld],
    534                                 delete ? 0 : hash_entry->hash_offset[fld]);
    535                     soc_mem_field32_set(unit, FLEX_HASH_OFFSET_MASK(unit),
    536                                 &flex_offset_mask_entry,
    537                                 _bcm_td2_flex_hash_mask[fld],
    538                                 delete ? 0 : hash_entry->hash_mask[fld]);
    539                 } else {
    540                     soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    541                                 &flex_offset_entry,
    542                                 _bcm_td2_flex_hash_offset[fld], 0);
    543                     soc_mem_field32_set(unit, FLEX_HASH_OFFSET_MASK(unit),
    544                                 &flex_offset_mask_entry,
    545                                 _bcm_td2_flex_hash_mask[fld], 0);
    546                 }
    547                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    548                             &flex_offset_entry,
    549                             _bcm_th_flex_hash_offset_type[fld], 0);
    550             }
    551         }
    552 
    553         rv = soc_mem_write(unit, FLEX_HASH_OFFSET, MEM_BLOCK_ANY,
    554                    hash_entry->hw_idx, &flex_offset_entry);
    555         if (BCM_FAILURE(rv)) {
    556             return BCM_E_FAIL;
    557         }
    558         rv = soc_mem_write(unit, FLEX_HASH_OFFSET_MASK(unit), MEM_BLOCK_ANY,
    559                    hash_entry->hw_idx, &flex_offset_mask_entry);
    560         if (BCM_FAILURE(rv)) {
    561             return BCM_E_FAIL;
    562         }
    563         rv = soc_mem_write(unit, FLEX_HASH_TCAM, MEM_BLOCK_ALL,
    564                    hash_entry->hw_idx, &flex_tcam_entry);
    565 
    566         if (BCM_FAILURE(rv)) {
    567             return BCM_E_FAIL;
    568         }
    569         return BCM_E_NONE;
    570     }
    571 #endif /*BCM_TOMAHAWK2_SUPPORT*/
    572 
    573 STATIC int
    574 _bcm_flex_hash_table_write(int unit, flex_hash_entry_t * hash_entry, uint8 delete)
    575 {
    576     int             fld, rv = BCM_E_NONE;
    577     FLEX_HASH_TCAM_ENTRY_T flex_tcam_entry;
    578     FLEX_HASH_OFFSET_ENTRY_T flex_offset_entry;
    579     uint32          data[2] = { 0, 0 };
    580     uint32          mask[2] = { 0, 0 };
    581 
    582     if (NULL == hash_entry) {
    583         return BCM_E_FAIL;
    584     }
    585 
    586 /*  
    587     note :qual_size_range is 0~2. maximum 4 match field data in a flexkey.
    588     it is required to create a flexkey in a such order
    589     field_data2: 1st qual_data, 2nd qual_data
    590     field_data1: 3rd qual_data, 4th qual_data; thus
    591     first and third match field data is shifed to left for 16 bits insdie field data.
    592     in addition, if qual_size is 1, qual_data is shifed to left for 8 bits inside field data 
    593     if qual_size is 0 or 2, there won't be any shift inside field data
    594 */
    595     data[0] = (hash_entry->match_arr[0].qual_match <<
    596                   ((hash_entry->match_arr[0].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 16;
    597     data[0] |= (hash_entry->match_arr[1].qual_match <<
    598                   ((hash_entry->match_arr[1].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 0;
    599     data[1] = (hash_entry->match_arr[2].qual_match <<
    600                   ((hash_entry->match_arr[2].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 16;
    601     data[1] |= (hash_entry->match_arr[3].qual_match <<
    602                   ((hash_entry->match_arr[3].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 0;
    603 
    604     mask[0] = (hash_entry->match_arr[0].qual_mask <<
    605                   ((hash_entry->match_arr[0].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 16;
    606     mask[0] |= (hash_entry->match_arr[1].qual_mask <<
    607                   ((hash_entry->match_arr[1].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 0;
    608     mask[1] = (hash_entry->match_arr[2].qual_mask <<
    609                   ((hash_entry->match_arr[2].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 16;
    610     mask[1] |= (hash_entry->match_arr[3].qual_mask <<
    611                   ((hash_entry->match_arr[3].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE)) << 0;
    612 
    613     sal_memset(&flex_tcam_entry, 0, sizeof(flex_tcam_entry));
    614     sal_memset(&flex_offset_entry, 0, sizeof(flex_offset_entry));
    615 
    616     rv = soc_mem_read(unit, FLEX_HASH_TCAM, MEM_BLOCK_ANY,
    617               hash_entry->hw_idx, &flex_tcam_entry);
    618     if (BCM_FAILURE(rv)) {
    619         return BCM_E_FAIL;
    620     }
    621     rv = soc_mem_read(unit, FLEX_HASH_OFFSET, MEM_BLOCK_ANY,
    622               hash_entry->hw_idx, &flex_offset_entry);
    623     if (BCM_FAILURE(rv)) {
    624         return BCM_E_FAIL;
    625     }
    626 
    627     if (soc_mem_field_valid(unit, FLEX_HASH_TCAM, VALIDf)) { 
    628         if (delete && !soc_mem_field32_get(unit, FLEX_HASH_TCAM,
    629                                            &flex_tcam_entry, VALIDf)) {
    630             return BCM_E_NOT_FOUND;
    631         }
    632         soc_mem_field32_set(unit, FLEX_HASH_TCAM, &flex_tcam_entry,
    633                     VALIDf, delete? 0:1);
    634     }
    635 
    636     for (fld = 0; fld < FLEX_HASH_CHECK_FIELDS_NUM; fld++) {
    637         soc_mem_field32_set(unit, FLEX_HASH_TCAM, &flex_tcam_entry,
    638                     _bcm_td2_flex_hash_data[fld], delete ? 0 : data[fld]);
    639         soc_mem_field32_set(unit, FLEX_HASH_TCAM, &flex_tcam_entry,
    640                     _bcm_td2_flex_hash_mask[fld], delete ? 0 : mask[fld]);
    641     }
    642 
    643     for (fld = 0; fld < FLEX_HASH_OFFSET_NUM(unit); fld++) {
    644 #if defined(BCM_TOMAHAWK_SUPPORT)
    645         if (hash_entry->type[fld] & BCM_SWITCH_HASH_FIELD_TYPE_UDF) {
    646             if (hash_entry->offset_bitmap & (0x1 << fld)) {
    647                 if (hash_entry->hash_offset[fld] >= MAX_UDF_OFFSET_CHUNKS) {
    648                     return BCM_E_PARAM;
    649                 }
    650                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    651                             &flex_offset_entry,
    652                             _bcm_th_flex_hash_offset_udf[fld*2],
    653                             delete ? 0 : hash_entry->hash_offset[fld] / 8);
    654                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    655                             &flex_offset_entry,
    656                             _bcm_th_flex_hash_offset_udf[fld*2 + 1],
    657                             delete ? 0 : (7 - hash_entry->hash_offset[fld] % 8));
    658                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    659                             &flex_offset_entry,
    660                             _bcm_td2_flex_hash_mask[fld],
    661                             delete ? 0 : hash_entry->hash_mask[fld]);
    662                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    663                             &flex_offset_entry,
    664                             _bcm_th_flex_hash_offset_type[fld],
    665                             delete ? 0 : 1);
    666            } else {
    667                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    668                             &flex_offset_entry,
    669                             _bcm_th_flex_hash_offset_udf[fld*2], 0);
    670                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    671                             &flex_offset_entry,
    672                             _bcm_th_flex_hash_offset_udf[fld*2 + 1], 0);
    673                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    674                             &flex_offset_entry,
    675                             _bcm_td2_flex_hash_mask[fld], 0);
    676                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    677                             &flex_offset_entry,
    678                             _bcm_th_flex_hash_offset_type[fld], 0);
    679                 break;
    680             }
    681         } else
    682 #endif /*BCM_TOMAHAWK_SUPPORT*/
    683         {
    684             if (fld > bcmSwitchFlexHashField1) {
    685                     continue;
    686             }
    687             if (hash_entry->offset_bitmap & (0x1 << fld)) {
    688                 if (hash_entry->hash_offset[fld] >=
    689                     (FLEX_QUAL_BIT_PER_SIZE *  FLEX_HASH_CHECK_FIELDS_NUM)) {
    690                     return BCM_E_PARAM;
    691                 }
    692                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    693                             &flex_offset_entry,
    694                             _bcm_td2_flex_hash_offset[fld],
    695                             delete ? 0 : hash_entry->hash_offset[fld]);
    696                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    697                             &flex_offset_entry,
    698                             _bcm_td2_flex_hash_mask[fld],
    699                             delete ? 0 : hash_entry->hash_mask[fld]);
    700             } else {
    701                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    702                             &flex_offset_entry,
    703                             _bcm_td2_flex_hash_offset[fld], 0);
    704                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    705                             &flex_offset_entry,
    706                             _bcm_td2_flex_hash_mask[fld], 0);
    707             }
    708 #if defined(BCM_TOMAHAWK_SUPPORT)
    709             if (SOC_IS_TOMAHAWK(unit)) {
    710                 soc_mem_field32_set(unit, FLEX_HASH_OFFSET,
    711                             &flex_offset_entry,
    712                             _bcm_th_flex_hash_offset_type[fld], 0);
    713             }
    714 #endif /*BCM_TOMAHAWK_SUPPORT*/
    715         }
    716     }
    717 
    718     rv = soc_mem_write(unit, FLEX_HASH_OFFSET, MEM_BLOCK_ANY,
    719                hash_entry->hw_idx, &flex_offset_entry);
    720     if (BCM_FAILURE(rv)) {
    721         return BCM_E_FAIL;
    722     }
    723     rv = soc_mem_write(unit, FLEX_HASH_TCAM, MEM_BLOCK_ALL,
    724                hash_entry->hw_idx, &flex_tcam_entry);
    725     
    726     if (BCM_FAILURE(rv)) {
    727         return BCM_E_FAIL;
    728     }
    729 
    730     return BCM_E_NONE;
    731 }
    732 
    733 #if defined (BCM_WARM_BOOT_SUPPORT)
    734 STATIC int
    735 _bcm_flex_hash_table_wb_read(int unit,
    736                       flex_hash_entry_t * hash_entry,
    737                       bcmi_xgs4_td2_switch_wb_hash_entry_t * wb_hash_entry)
    738 {
    739     int             fld, rv = BCM_E_NONE;
    740     uint32          data[2], mask[2];
    741     FLEX_HASH_TCAM_ENTRY_T flex_tcam_entry;
    742     FLEX_HASH_OFFSET_ENTRY_T flex_offset_entry;
    743 
    744 #if defined(BCM_TOMAHAWK_SUPPORT)
    745     int udf_chunk_id, udf_sel;
    746 #endif /*BCM_TOMAHAWK_SUPPORT*/
    747 
    748 #ifdef BCM_TOMAHAWK2_SUPPORT
    749     FLEX_HASH_OFFSET_MASK_ENTRY_T flex_offset_mask_entry;
    750 #endif /*BCM_TOMAHAWK2_SUPPORT*/
    751 
    752     sal_memset(&flex_tcam_entry, 0, sizeof(flex_tcam_entry));
    753     sal_memset(&flex_offset_entry, 0, sizeof(flex_offset_entry));
    754     
    755     hash_entry->offset_count = 0;
    756 
    757     rv = soc_mem_read(unit, FLEX_HASH_TCAM, MEM_BLOCK_ANY,
    758               hash_entry->hw_idx, &flex_tcam_entry);
    759     if (BCM_FAILURE(rv)) {
    760         return BCM_E_FAIL;
    761     }
    762 
    763     rv = soc_mem_read(unit, FLEX_HASH_OFFSET, MEM_BLOCK_ANY,
    764               hash_entry->hw_idx, &flex_offset_entry);
    765     if (BCM_FAILURE(rv)) {
    766         return BCM_E_FAIL;
    767     }
    768 #ifdef BCM_TOMAHAWK2_SUPPORT
    769     if ((SOC_IS_TOMAHAWK2(unit)) || (SOC_IS_TOMAHAWK3(unit))) {
    770        sal_memset(&flex_offset_mask_entry, 0, sizeof(flex_offset_mask_entry));
    771        rv = soc_mem_read(unit, FLEX_HASH_OFFSET_MASK(unit), MEM_BLOCK_ANY,
    772                 hash_entry->hw_idx, &flex_offset_mask_entry);
    773         if (BCM_FAILURE(rv)) {
    774             return BCM_E_FAIL;
    775         }
    776     }
    777 #endif
    778 
    779     for (fld = 0; fld < FLEX_HASH_CHECK_FIELDS_NUM; fld++) {
    780         data[fld] =
    781             soc_mem_field32_get(unit, FLEX_HASH_TCAM, &flex_tcam_entry,
    782                     _bcm_td2_flex_hash_data[fld]);
    783         mask[fld] =
    784             soc_mem_field32_get(unit, FLEX_HASH_TCAM, &flex_tcam_entry,
    785                     _bcm_td2_flex_hash_mask[fld]);
    786     }
    787 
    788     for (fld = 0; fld < FLEX_HASH_OFFSET_NUM(unit); fld++) {
    789 #if defined(BCM_TOMAHAWK_SUPPORT)
    790         if (SOC_IS_TOMAHAWKX(unit)) {
    791             hash_entry->type[fld] =
    792                 soc_mem_field32_get(unit, FLEX_HASH_OFFSET,
    793                         &flex_offset_entry,
    794                         _bcm_th_flex_hash_offset_type[fld]);
    795         }
    796         if (hash_entry->type[fld] & BCM_SWITCH_HASH_FIELD_TYPE_UDF) {
    797             udf_sel = soc_mem_field32_get(unit, FLEX_HASH_OFFSET,
    798                         &flex_offset_entry,
    799                         _bcm_th_flex_hash_offset_udf[fld*2]);
    800             udf_chunk_id= soc_mem_field32_get(unit, FLEX_HASH_OFFSET,
    801                         &flex_offset_entry,
    802                         _bcm_th_flex_hash_offset_udf[fld*2 + 1]);
    803             hash_entry->hash_offset[fld] = udf_sel * 8 + (7 - udf_chunk_id);
    804         } else
    805 #endif /*BCM_TOMAHAWK_SUPPORT*/
    806         {
    807             if (fld > bcmSwitchFlexHashField1) {
    808                     continue;
    809             }
    810             hash_entry->hash_offset[fld] =
    811                 soc_mem_field32_get(unit, FLEX_HASH_OFFSET,
    812                         &flex_offset_entry,
    813                         _bcm_td2_flex_hash_offset[fld]);
    814         }
    815 
    816 #ifdef BCM_TOMAHAWK2_SUPPORT
    817         if ((SOC_IS_TOMAHAWK2(unit)) || (SOC_IS_TOMAHAWK3(unit))) {
    818             hash_entry->hash_mask[fld] =
    819                 soc_mem_field32_get(unit, FLEX_HASH_OFFSET_MASK(unit),
    820                         &flex_offset_mask_entry,
    821                         _bcm_td2_flex_hash_mask[fld]);
    822         } else
    823 #endif
    824         {
    825             hash_entry->hash_mask[fld] =
    826                 soc_mem_field32_get(unit, FLEX_HASH_OFFSET,
    827                         &flex_offset_entry,
    828                         _bcm_td2_flex_hash_mask[fld]);
    829         }
    830         
    831         if (hash_entry->hash_offset[fld] > 0) {
    832             hash_entry->offset_count++;
    833         }
    834     }
    835 
    836     for (fld = 0; fld < FLEX_HASH_MAX_FIELDS; fld++) {
    837         hash_entry->match_arr[fld].qual_id= wb_hash_entry->match_arr[fld].qual_id;
    838         if (hash_entry->match_arr[fld].qual_id >= 0)
    839         {
    840             hash_entry->match_arr[fld].qual_size = wb_hash_entry->match_arr[fld].qual_size;
    841 
    842             hash_entry->match_arr[fld].qual_match = (data[fld / 2] >>((fld % 2) ? 0:16)) >>
    843                 ((hash_entry->match_arr[0].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE);
    844             hash_entry->match_arr[fld].qual_mask = (mask[fld / 2] >> ((fld % 2) ? 0:16)) >>
    845                 ((hash_entry->match_arr[0].qual_size & 1) * FLEX_QUAL_BIT_PER_SIZE);
    846 
    847         }
    848     }
    849 #if defined(BCM_TOMAHAWK_SUPPORT)
    850     for (fld = 0; fld < FLEX_HASH_OFFSET_NUM(unit); fld++) {
    851         if (hash_entry->type[fld]) {
    852             hash_entry->udf_id[fld] = wb_hash_entry->udf_id[fld];
    853         }
    854     }
    855 #endif /*BCM_TOMAHAWK_SUPPORT*/
    856 
    857     return BCM_E_NONE;
    858 }
    859 #endif
    860 
    861 /*
    862     enable RTAG7_HASH_CONTROL and ING_HASH_CONFIG_0 registers
    863 */
    864 STATIC int
    865 _bcm_flex_hash_control_enable(int unit)
    866 {
    867 
    868     int             cnt;
    869     soc_reg_t       reg;
    870     uint32          hash_control, hash_config;
    871 #ifdef BCM_TOMAHAWK2_SUPPORT
    872     uint64          hash_control_64;
    873 #endif
    874 
    875     /* 
    876      * Enable Flexible/UDF controls
    877      * Flex hash controls are enabled for Hash A and Hash B, which has 
    878      * high precedence over Flex UDF controls.
    879      */
    880 #ifdef BCM_TOMAHAWK2_SUPPORT
    881     if ((SOC_IS_TOMAHAWK2(unit)) || (SOC_IS_TOMAHAWK3(unit))) {
    882         reg = _bcm_th2_flex_hash_control;
    883         BCM_IF_ERROR_RETURN(soc_reg64_get
    884                     (unit, reg, REG_PORT_ANY, 0, &hash_control_64));
    885         for (cnt = 0;
    886              cnt <
    887              (sizeof(_bcm_th2_flex_hash_enable_fields) /
    888               sizeof(_bcm_th2_flex_hash_enable_fields[0])); cnt++) {
    889             if (SOC_REG_FIELD_VALID
    890                 (unit, reg, _bcm_th2_flex_hash_enable_fields[cnt])) {
    891                 soc_reg64_field32_set(unit, reg, &hash_control_64,
    892                           _bcm_th2_flex_hash_enable_fields[cnt], 1);
    893             }
    894         }
    895         BCM_IF_ERROR_RETURN(soc_reg64_set
    896                     (unit, reg, REG_PORT_ANY, 0, hash_control_64));
    897     } else
    898 #endif
    899     {
    900         reg = _bcm_td2_flex_hash_control;
    901         BCM_IF_ERROR_RETURN(soc_reg32_get
    902                     (unit, reg, REG_PORT_ANY, 0, &hash_control));
    903         for (cnt = 0;
    904              cnt <
    905              (sizeof(_bcm_td2_flex_hash_enable_fields) /
    906               sizeof(_bcm_td2_flex_hash_enable_fields[0])); cnt++) {
    907             if (SOC_REG_FIELD_VALID
    908                 (unit, reg, _bcm_td2_flex_hash_enable_fields[cnt])) {
    909                 soc_reg_field_set(unit, reg, &hash_control,
    910                           _bcm_td2_flex_hash_enable_fields[cnt],
    911                           1);
    912             }
    913         }
    914         BCM_IF_ERROR_RETURN(soc_reg32_set
    915                     (unit, reg, REG_PORT_ANY, 0, hash_control));
    916     }
    917 
    918     /* Enable Actual TCAM lookup using flex key*/
    919     reg = _bcm_td2_ing_hash_config;
    920     BCM_IF_ERROR_RETURN(READ_ING_HASH_CONFIG_0r(unit, &hash_config));
    921 
    922     if (SOC_REG_FIELD_VALID
    923         (unit, reg, _bcm_td2_ing_hash_config_fields[0])) {
    924         soc_reg_field_set(unit, reg, &hash_config,
    925             _bcm_td2_ing_hash_config_fields[0], 1);
    926     } 
    927 
    928     BCM_IF_ERROR_RETURN(WRITE_ING_HASH_CONFIG_0r(unit, hash_config));
    929 
    930     return BCM_E_NONE;
    931 }
    932 
    933 STATIC int
    934 _bcm_flex_hash_control_disable(int unit)
    935 {
    936 
    937     int             cnt;
    938     soc_reg_t       reg;
    939     uint32          hash_control, hash_config;
    940 #ifdef BCM_TOMAHAWK2_SUPPORT
    941     uint64          hash_control_64;
    942 #endif
    943 
    944     /* 
    945      * Disable Flexible/UDF controls
    946      * Flex hash controls are enabled for Hash A and Hash B, which has 
    947      * high precedence over Flex UDF controls.
    948      */
    949 #ifdef BCM_TOMAHAWK2_SUPPORT
    950     if ((SOC_IS_TOMAHAWK2(unit)) || (SOC_IS_TOMAHAWK3(unit))) {
    951         reg = _bcm_th2_flex_hash_control;
    952         BCM_IF_ERROR_RETURN(soc_reg64_get
    953                     (unit, reg, REG_PORT_ANY, 0, &hash_control_64));
    954         for (cnt = 0;
    955              cnt <
    956              (sizeof(_bcm_th2_flex_hash_enable_fields) /
    957               _bcm_th2_flex_hash_enable_fields[0]); cnt++) {
    958             if (SOC_REG_FIELD_VALID
    959                 (unit, reg, _bcm_th2_flex_hash_enable_fields[cnt])) {
    960                 soc_reg64_field32_set(unit, reg, &hash_control_64,
    961                           _bcm_th2_flex_hash_enable_fields[cnt], 0);
    962             }
    963         }
    964         BCM_IF_ERROR_RETURN(soc_reg64_set
    965                     (unit, reg, REG_PORT_ANY, 0, hash_control_64));
    966     } else
    967 #endif
    968     {
    969         reg = _bcm_td2_flex_hash_control;
    970         BCM_IF_ERROR_RETURN(soc_reg32_get
    971                     (unit, reg, REG_PORT_ANY, 0, &hash_control));
    972         for (cnt = 0;
    973              cnt <
    974              (sizeof(_bcm_td2_flex_hash_enable_fields) /
    975               _bcm_td2_flex_hash_enable_fields[0]); cnt++) {
    976             if (SOC_REG_FIELD_VALID
    977                 (unit, reg, _bcm_td2_flex_hash_enable_fields[cnt])) {
    978                 soc_reg_field_set(unit, reg, &hash_control,
    979                           _bcm_td2_flex_hash_enable_fields[cnt],
    980                           0);
    981             }
    982         }
    983         BCM_IF_ERROR_RETURN(soc_reg32_set
    984                     (unit, reg, REG_PORT_ANY, 0, hash_control));
    985     }
    986 
    987     /* Disable TCAM lookup using flex key*/
    988     reg = _bcm_td2_ing_hash_config;
    989     BCM_IF_ERROR_RETURN(READ_ING_HASH_CONFIG_0r(unit, &hash_config));
    990 
    991     if (SOC_REG_FIELD_VALID
    992         (unit, reg, _bcm_td2_ing_hash_config_fields[0])) {
    993 
    994         soc_reg_field_set(unit, reg, &hash_config,
    995             _bcm_td2_ing_hash_config_fields[0], 0);
    996     } 
    997 
    998     BCM_IF_ERROR_RETURN(WRITE_ING_HASH_CONFIG_0r(unit, hash_config));
    999     return BCM_E_NONE;
   1000 }
   1001 
   1002 /*
   1003  * 
   1004  *  Flex hash Entry list management routines 
   1005  */
   1006 
   1007 STATIC int
   1008 _flex_hash_entry_get(int unit, bcm_hash_entry_t hash_entry_id,
   1009              flex_hash_entry_t ** hash_entry)
   1010 {
   1011     *hash_entry = SWITCH_HASH_ENTRY_LIST(unit);
   1012     while (*hash_entry != NULL) {
   1013         if ((*hash_entry)->entry_id == hash_entry_id) {
   1014             return BCM_E_NONE;
   1015         }
   1016         *hash_entry = (*hash_entry)->next;
   1017     }
   1018     return BCM_E_NOT_FOUND;
   1019 }
   1020 
   1021 STATIC int
   1022 _flex_hash_entry_destroy(int unit, flex_hash_entry_t * entry)
   1023 {
   1024 
   1025     if (NULL == entry) {
   1026         return BCM_E_NOT_FOUND;
   1027     }
   1028 
   1029     if (entry->entry_count == 0) {
   1030         sal_free(entry);
   1031     }
   1032     return BCM_E_NONE;
   1033 }
   1034 
   1035 STATIC int
   1036 _flex_hash_entry_destroy_all(int unit)
   1037 {
   1038 
   1039     flex_hash_entry_t *hash_entry = NULL;
   1040     flex_hash_entry_t *hash_curr = NULL;
   1041 
   1042     hash_entry = SWITCH_HASH_ENTRY_LIST(unit);
   1043 
   1044     SWITCH_HASH_ENTRY_LIST(unit) = NULL;
   1045     if (NULL != hash_entry) {
   1046         while (hash_entry != NULL) {
   1047             hash_curr = hash_entry;
   1048             hash_entry = hash_curr->next;
   1049             _BCM_SWITCH_FLEX_IDX_USED_CLR(unit, hash_curr->hw_idx);
   1050             sal_free(hash_curr);
   1051         }
   1052     }
   1053     BCM_IF_ERROR_RETURN(_bcm_flex_hash_control_disable(unit));
   1054     return BCM_E_NONE;
   1055 }
   1056 
   1057 STATIC int
   1058 _flex_hash_entry_alloc(int unit, flex_hash_entry_t ** entry)
   1059 {
   1060     int             entry_size;
   1061     int             entry_wrap = 0;
   1062     flex_hash_entry_p hash_entry = NULL;
   1063 
   1064     if (NULL == entry) {
   1065         return BCM_E_FAIL;
   1066     }
   1067 
   1068     entry_size = sizeof(flex_hash_entry_t);
   1069     *entry = sal_alloc(entry_size, "flex hash entry");
   1070     if (*entry == NULL) {
   1071         return BCM_E_MEMORY;
   1072     }
   1073     sal_memset(*entry, 0, entry_size);
   1074 
   1075     while (BCM_SUCCESS
   1076            (_flex_hash_entry_get(unit, SWITCH_HASH_LAST_ENTRY_ID(unit),
   1077                &hash_entry))) {
   1078         if (SWITCH_HASH_LAST_ENTRY_ID(unit)++ == 0) {
   1079             if (entry_wrap++ >= 2) {
   1080                 sal_free(*entry);
   1081                 return BCM_E_RESOURCE;
   1082             }
   1083         }
   1084     }
   1085     (*entry)->entry_id = SWITCH_HASH_LAST_ENTRY_ID(unit);
   1086     (*entry)->next = NULL;   
   1087 
   1088     return BCM_E_NONE;
   1089 }
   1090 
   1091 
   1092 STATIC int
   1093 _flex_hash_entry_add(int unit, flex_hash_entry_t * entry, int hw_index)
   1094 {
   1095     flex_hash_entry_t *hash_entry = NULL;
   1096     flex_hash_entry_t *hash_prev = NULL;
   1097 
   1098     if (NULL == entry) {
   1099         return BCM_E_FAIL;
   1100     }
   1101 
   1102     hash_entry = SWITCH_HASH_ENTRY_LIST(unit);
   1103     if (NULL == hash_entry) {
   1104         entry->hw_idx = hw_index;
   1105         SWITCH_HASH_ENTRY_LIST(unit) = entry;
   1106         if (!SOC_WARM_BOOT(unit)) {
   1107             BCM_IF_ERROR_RETURN(_bcm_flex_hash_control_enable(unit));
   1108         }
   1109     } else {
   1110         while (hash_entry != NULL) {
   1111             if (hash_entry->entry_id == entry->entry_id) {
   1112                 entry->hw_idx = hw_index;
   1113                 /* Increment entry count */
   1114                 entry->entry_count++;
   1115             } else if (hash_entry->entry_id < entry->entry_id) {
   1116                 if (NULL == hash_prev) {
   1117                     SWITCH_HASH_ENTRY_LIST(unit) = entry;
   1118                 } else {
   1119                     hash_prev->next = entry;
   1120                 }
   1121                 entry->next = hash_entry;
   1122                 entry->hw_idx = hw_index;
   1123                 /* Increment entry count */
   1124                 entry->entry_count++;
   1125                 break;
   1126             } 
   1127             hash_prev = hash_entry;
   1128             hash_entry = hash_entry->next;
   1129         }
   1130         if (hash_entry == NULL) {
   1131             hash_prev->next = entry;
   1132             entry->next = hash_entry;
   1133             entry->hw_idx = hw_index;
   1134             /* Increment entry count */
   1135             entry->entry_count++;
   1136         }
   1137     }
   1138     return BCM_E_NONE;
   1139 }
   1140 
   1141 STATIC int
   1142 _flex_hash_entry_delete(int unit, flex_hash_entry_t * entry)
   1143 {
   1144     flex_hash_entry_t *hash_entry = NULL;
   1145     flex_hash_entry_t *hash_prev = NULL;
   1146 
   1147     if (NULL == entry) {
   1148         return BCM_E_FAIL;
   1149     }
   1150 
   1151     hash_entry = SWITCH_HASH_ENTRY_LIST(unit);
   1152     if (NULL != hash_entry) {
   1153     
   1154             while (hash_entry != NULL) {
   1155             if (hash_entry->entry_id == entry->entry_id) {
   1156                 if (NULL == hash_prev) {
   1157                     SWITCH_HASH_ENTRY_LIST(unit) = hash_entry->next;
   1158                 } else {
   1159                     hash_prev->next = hash_entry->next;
   1160                 }
   1161                 if (SWITCH_HASH_ENTRY_LIST(unit) == NULL) {
   1162                     BCM_IF_ERROR_RETURN
   1163                         (_bcm_flex_hash_control_disable(unit));
   1164 
   1165                 }
   1166                 break;  
   1167         }
   1168             hash_prev = hash_entry;
   1169             hash_entry = hash_entry->next;
   1170         }
   1171     }
   1172     return BCM_E_NONE;
   1173 }
   1174 
   1175 /*
   1176  * 
   1177  *  Flexible Hashing management routines 
   1178  */
   1179 
   1180 STATIC int
   1181 _bcm_hash_entry_create(int unit, bcm_hash_entry_t * entry)
   1182 {
   1183     int             num_indexes, idx_cnt;
   1184     int             hw_index = -1;
   1185     flex_hash_entry_p hash_entry = NULL;
   1186     int             rv = BCM_E_NONE;
   1187 
   1188     /* Allocate hardware index into flex tcam table. */
   1189     num_indexes = soc_mem_index_count(unit, FLEX_HASH_TCAM);
   1190     for (idx_cnt = 0; idx_cnt < num_indexes; idx_cnt++) {
   1191         if (!_BCM_SWITCH_FLEX_IDX_USED_GET(unit, idx_cnt)) {
   1192             hw_index = idx_cnt; /* free index */
   1193             break;
   1194         }
   1195     }
   1196     if (hw_index == -1) {
   1197         return BCM_E_FULL;
   1198     }
   1199     _BCM_SWITCH_FLEX_IDX_USED_SET(unit, hw_index);
   1200 
   1201     /* Allocate entry id and associate with hardware index. */
   1202     rv = _flex_hash_entry_alloc(unit, &hash_entry);
   1203     if (BCM_FAILURE(rv)) {
   1204         return rv;
   1205     }
   1206 
   1207     /* Add in hash entry list. 
   1208        If RTAG7_HASH_CONTROL and ING_HASH_CONFIG_0 are not set,
   1209        the registers will be programemed in this routine */
   1210     rv = _flex_hash_entry_add(unit, hash_entry, hw_index);
   1211     if (BCM_FAILURE(rv)) {
   1212         _flex_hash_entry_destroy(unit, hash_entry);
   1213         return rv;
   1214     }
   1215 
   1216     /* return entry id */
   1217     *entry = hash_entry->entry_id;
   1218     return rv;
   1219 }
   1220 
   1221 STATIC int
   1222 _bcm_hash_entry_delete(int unit, bcm_hash_entry_t entry_id)
   1223 {
   1224     int             rv = BCM_E_NONE;
   1225     flex_hash_entry_t *hash_entry;
   1226 
   1227     rv = _flex_hash_entry_get(unit, entry_id, &hash_entry);
   1228     if (BCM_FAILURE(rv)) {
   1229         return rv;
   1230     }
   1231 
   1232     _BCM_SWITCH_FLEX_IDX_USED_CLR(unit, hash_entry->hw_idx);
   1233 
   1234     rv = _flex_hash_entry_delete(unit, hash_entry);
   1235     if (BCM_FAILURE(rv)) {
   1236         return rv;
   1237     }
   1238 #ifdef BCM_TOMAHAWK2_SUPPORT
   1239     if ((SOC_IS_TOMAHAWK2(unit)) || (SOC_IS_TOMAHAWK3(unit))) {
   1240         rv = _bcm_th2_flex_hash_table_write(unit, hash_entry, TRUE);
   1241     } else
   1242 #endif
   1243     {
   1244         rv = _bcm_flex_hash_table_write(unit, hash_entry, TRUE);
   1245     }
   1246     if (BCM_FAILURE(rv) && (rv != BCM_E_NOT_FOUND)) {
   1247         return rv;
   1248     }
   1249 
   1250     rv = _flex_hash_entry_destroy(unit, hash_entry);
   1251     if (BCM_FAILURE(rv)) {
   1252         return rv;
   1253     }
   1254 
   1255    
   1256     return rv;
   1257 }
   1258 
   1259 STATIC int
   1260 _bcm_hash_entry_remove(int unit, bcm_hash_entry_t entry_id)
   1261 {
   1262     int             rv = BCM_E_NONE;
   1263     flex_hash_entry_t *hash_entry;
   1264 
   1265     rv = _flex_hash_entry_get(unit, entry_id, &hash_entry);
   1266     if (BCM_FAILURE(rv)) {
   1267         return rv;
   1268     }
   1269 #ifdef BCM_TOMAHAWK2_SUPPORT
   1270     if ((SOC_IS_TOMAHAWK2(unit)) || (SOC_IS_TOMAHAWK3(unit))) {
   1271         return _bcm_th2_flex_hash_table_write(unit, hash_entry, TRUE);
   1272     } else
   1273 #endif
   1274     {
   1275         return _bcm_flex_hash_table_write(unit, hash_entry, TRUE);
   1276     }
   1277 }
   1278 
   1279 STATIC int
   1280 _bcm_hash_entry_udf_set(int unit, bcm_hash_entry_t entry_id,
   1281              int qual_count, int *qual_array)
   1282 {
   1283     int             id = 0;
   1284     int             rv = BCM_E_NONE;
   1285     int             idx, chunk_id, chunk_base, chunk_max;
   1286     flex_hash_entry_t *hash_entry;
   1287     bcmi_xgs4_udf_offset_info_t *offset_info;
   1288 
   1289     rv = _flex_hash_entry_get(unit, entry_id, &hash_entry);
   1290     if (BCM_FAILURE(rv)) {
   1291         return rv;
   1292     }
   1293 
   1294     if (qual_count > FLEX_HASH_MAX_FIELDS) {
   1295         /* reset outbound size */
   1296         qual_count = FLEX_HASH_MAX_FIELDS;
   1297     }
   1298 
   1299     chunk_base = 12; /* UDF2.4 */
   1300     chunk_max  = chunk_base + FLEX_HASH_MAX_FIELDS - 1;
   1301 
   1302     for (id = 0; id < qual_count; id++) {
   1303         /* Get data qualifier info. */
   1304         rv = bcmi_xgs4_udf_offset_node_get(unit, qual_array[id],
   1305                                            &offset_info);
   1306         BCM_IF_ERROR_RETURN(rv);
   1307 
   1308         if (!(BCMI_XGS4_UDF_OFFSET_FLEXHASH & offset_info->flags) ||
   1309             !(offset_info->hw_bmap & (0xf << chunk_base))) {
   1310             return BCM_E_PARAM;
   1311         }
   1312 
   1313         for (chunk_id = chunk_base; chunk_id <= chunk_max; chunk_id++) {
   1314             if (offset_info->hw_bmap & (0x1 << chunk_id)) {
   1315                 idx = chunk_id - chunk_base;
   1316                 hash_entry->match_arr[idx].qual_id = qual_array[id];
   1317                 hash_entry->match_arr[idx].qual_size = offset_info->width;
   1318                 break;
   1319             }
   1320         }
   1321     }
   1322     
   1323     return BCM_E_NONE;
   1324 }
   1325 
   1326 STATIC int
   1327 _bcm_hash_entry_qual_set(int unit, bcm_hash_entry_t entry_id,
   1328              int qual_count, int *qual_array)
   1329 {
   1330     int             id = 0;
   1331     int             rv = BCM_E_NONE;
   1332     int             idx, chunk_id, chunk_base, chunk_max;
   1333     flex_hash_entry_t *hash_entry;
   1334     _field_data_qualifier_t data_qual;
   1335 
   1336     rv = _flex_hash_entry_get(unit, entry_id, &hash_entry);
   1337     if (BCM_FAILURE(rv)) {
   1338         return rv;
   1339     }
   1340 
   1341     if (qual_count > FLEX_HASH_MAX_FIELDS) {
   1342         /* reset outbound size */
   1343         qual_count = FLEX_HASH_MAX_FIELDS;
   1344     }
   1345 
   1346     chunk_base = 12; /* UDF2.4 */
   1347     chunk_max  = chunk_base + FLEX_HASH_MAX_FIELDS - 1;
   1348 
   1349     for (id = 0; id < qual_count; id++) {
   1350         /* Get data qualifier info. */
   1351         rv = _field_data_qualifier_get(unit, qual_array[id],
   1352                               &data_qual);
   1353         if (BCM_FAILURE(rv)) {
   1354             return (rv);
   1355         }
   1356         if (!
   1357             (BCM_FIELD_DATA_QUALIFIER_OFFSET_FLEX_HASH ==
   1358              data_qual.flags) ||
   1359             !(data_qual.hw_bmap & (0xf << chunk_base))) {
   1360             return BCM_E_FAIL;
   1361         }
   1362 
   1363         for (chunk_id = chunk_base; chunk_id <= chunk_max; chunk_id++) {
   1364             if (data_qual.hw_bmap & (0x1 << chunk_id)) {
   1365                 idx = chunk_id - chunk_base;
   1366                 hash_entry->match_arr[idx].qual_id = qual_array[id];
   1367                 hash_entry->match_arr[idx].qual_size = data_qual.length;
   1368                 break;
   1369             }
   1370         }
   1371     }
   1372 
   1373     return BCM_E_NONE;
   1374 }
   1375 
   1376 #if 0 /* Code required for warmboot when implemented */
   1377 STATIC int
   1378 _bcm_hash_entry_qual_get(int unit, bcm_hash_entry_t entry_id,
   1379              int *qual_array, int *qual_count)
   1380 {
   1381     int             id = 0;
   1382     int             rv = BCM_E_NONE;
   1383     flex_hash_entry_t *hash_entry;
   1384     bcm_field_data_qualifier_t data_qual;
   1385 
   1386     *qual_count = 0;
   1387     rv = _flex_hash_entry_get(unit, entry_id, &hash_entry);
   1388     if (BCM_FAILURE(rv)) {
   1389         return rv;
   1390     }
   1391 
   1392     for (id = 0; id < FLEX_HASH_MAX_FIELDS; id++) {
   1393         if (bcm_esw_field_data_qualifier_get(unit,
   1394                          hash_entry->match_arr[id].
   1395                          qual_id, &data_qual)) {
   1396             qual_array[id] = hash_entry->match_arr[id].qual_id;
   1397             *qual_count += 1;
   1398             return BCM_E_NONE;
   1399         }
   1400     }
   1401     return BCM_E_NOT_FOUND;
   1402 }
   1403 #endif
   1404 
   1405 STATIC int
   1406 _bcm_hash_entry_qual_data_set(int unit, bcm_hash_entry_t entry_id, int qual_id,
   1407                   uint32 data, uint32 mask)
   1408 {
   1409     int             id = 0;
   1410     int             rv = BCM_E_NONE;
   1411     flex_hash_entry_t *hash_entry;
   1412 
   1413     rv = _flex_hash_entry_get(unit, entry_id, &hash_entry);
   1414     if (BCM_FAILURE(rv)) {
   1415         return rv;
   1416     }
   1417 
   1418     for (id = 0; id < FLEX_HASH_MAX_FIELDS; id++) {
   1419         if (hash_entry->match_arr[id].qual_id == qual_id) {
   1420             hash_entry->match_arr[id].qual_match = data;
   1421             hash_entry->match_arr[id].qual_mask = mask;
   1422 
   1423             return BCM_E_NONE;
   1424         }
   1425     }
   1426     return BCM_E_NOT_FOUND;
   1427 }
   1428 
   1429 #if 0 /* Code required for warmboot when implemented */
   1430 STATIC int
   1431 _bcm_hash_entry_qual_data_get(int unit, bcm_hash_entry_t entry_id, int qual_id,
   1432                   uint32 * data, uint32 * mask)
   1433 {
   1434     int             id = 0;
   1435     int             rv = BCM_E_NONE;
   1436     flex_hash_entry_t *hash_entry;
   1437 
   1438     rv = _flex_hash_entry_get(unit, entry_id, &hash_entry);
   1439     if (BCM_FAILURE(rv)) {
   1440         return rv;
   1441     }
   1442 
   1443     for (id = 0; id < FLEX_HASH_MAX_FIELDS; id++) {
   1444         if (hash_entry->match_arr[id].qual_id == qual_id) {
   1445             *data = hash_entry->match_arr[id].qual_match;
   1446             *mask = hash_entry->match_arr[id].qual_mask;
   1447         }
   1448     }
   1449 
   1450     if (FLEX_HASH_MAX_FIELDS == id) {
   1451         return BCM_E_NOT_FOUND;
   1452     }
   1453 
   1454     return BCM_E_NONE;
   1455 }
   1456 #endif
   1457 
   1458 #if defined (BCM_WARM_BOOT_SUPPORT)
   1459 int 
   1460 bcmi_td2_switch_wb_hash_entry_reinit(int unit, uint8 **scache_ptr)
   1461 {
   1462     int rv;
   1463     int i;
   1464     int num_hash_entry;
   1465     int hw_index;
   1466     int wb_last_hash_entry_id;
   1467     bcmi_xgs4_td2_switch_wb_hash_entry_t *hash_entry_scache_p;
   1468     uint32 *u32_scache_p;
   1469     flex_hash_entry_p hash_entry = NULL;
   1470     BCM_IF_ERROR_RETURN(bcm_td2_switch_hash_entry_init(unit));
   1471 
   1472     u32_scache_p = (uint32 *)(*scache_ptr);
   1473 
   1474     /* Number of UDFs created */
   1475     num_hash_entry = *u32_scache_p;
   1476     u32_scache_p++;
   1477 
   1478     _bcm_td2_switch_hash_bk_info[unit].api_ver = *u32_scache_p;
   1479     u32_scache_p++;
   1480 
   1481     wb_last_hash_entry_id = *u32_scache_p;
   1482     u32_scache_p++;
   1483 
   1484     hash_entry_scache_p =
   1485         (bcmi_xgs4_td2_switch_wb_hash_entry_t *)u32_scache_p;
   1486 
   1487     for (i = 0; i < num_hash_entry; i++) {
   1488         hw_index = hash_entry_scache_p->hw_idx;
   1489         
   1490         rv = _flex_hash_entry_alloc(unit, &hash_entry);
   1491         if (BCM_FAILURE(rv)) {
   1492             return rv;
   1493         }
   1494         hash_entry->entry_id = hash_entry_scache_p->entry_id;
   1495         hash_entry->hw_idx = hash_entry_scache_p->hw_idx;
   1496         hash_entry->offset_bitmap = hash_entry_scache_p->offset_bitmap;        
   1497         _bcm_flex_hash_table_wb_read(unit, hash_entry, hash_entry_scache_p);
   1498             
   1499         _BCM_SWITCH_FLEX_IDX_USED_SET(unit, hw_index);
   1500 
   1501         rv = _flex_hash_entry_add(unit, hash_entry, hw_index);
   1502         if (BCM_FAILURE(rv)) {
   1503             _flex_hash_entry_destroy(unit, hash_entry);
   1504             return rv;
   1505         }
   1506 
   1507         hash_entry_scache_p++;
   1508     }
   1509     SWITCH_HASH_LAST_ENTRY_ID(unit) = wb_last_hash_entry_id;
   1510     *scache_ptr = (uint8 *)hash_entry_scache_p;
   1511 
   1512     return BCM_E_NONE; 
   1513 }
   1514 #if defined(BCM_TOMAHAWK_SUPPORT)
   1515 int
   1516 bcmi_th_switch_wb_hash_entry_reinit(int unit, uint8 **scache_ptr)
   1517 {
   1518     flex_hash_entry_t *hash_entry = NULL;
   1519     int fld;
   1520     bcm_udf_id_t *udf_id_p = NULL;
   1521 
   1522     hash_entry = SWITCH_HASH_ENTRY_LIST(unit);
   1523     udf_id_p = (bcm_udf_id_t *)(*scache_ptr);
   1524 
   1525     while (hash_entry != NULL) {
   1526         for (fld = 0; fld < FLEX_HASH_MAX_OFFSET; fld++) {
   1527             hash_entry->udf_id[fld] = *udf_id_p;
   1528             udf_id_p++;
   1529         }
   1530         hash_entry = hash_entry->next;
   1531     }
   1532 
   1533     return BCM_E_NONE;
   1534 }
   1535 #endif /*BCM_TOMAHAWK_SUPPORT*/
   1536 
   1537 
   1538 STATIC int
   1539 _flex_hash_entry_num(int unit)
   1540 {
   1541     int num_hash_entry = 0;
   1542    
   1543     flex_hash_entry_t *hash_entry = SWITCH_HASH_ENTRY_LIST(unit);
   1544 
   1545     while (hash_entry != NULL) {
   1546         hash_entry = hash_entry->next;
   1547         num_hash_entry++;
   1548     }
   1549     return num_hash_entry;
   1550 }
   1551 
   1552 
   1553 int
   1554 bcmi_td2_switch_wb_hash_entry_sync(int unit, uint8 **scache_ptr)
   1555 {
   1556     int fld;
   1557     bcmi_xgs4_td2_switch_wb_hash_entry_t *hash_entry_scache_p;
   1558     uint32 *u32_scache_p;
   1559     flex_hash_entry_p hash_entry = NULL;
   1560     int num_hash_entry = 0;
   1561 #if defined(BCM_TOMAHAWK_SUPPORT)
   1562         bcm_udf_id_t *udf_id_p = NULL;
   1563 #endif
   1564 
   1565     num_hash_entry = _flex_hash_entry_num(unit);    
   1566     hash_entry = SWITCH_HASH_ENTRY_LIST(unit);
   1567 
   1568     u32_scache_p = (uint32 *)(*scache_ptr);
   1569 
   1570     /* Number of hash entry created */
   1571     *u32_scache_p = num_hash_entry;
   1572     u32_scache_p++;
   1573 
   1574     *u32_scache_p = _bcm_td2_switch_hash_bk_info[unit].api_ver;
   1575     u32_scache_p++;
   1576 
   1577     *u32_scache_p = SWITCH_HASH_LAST_ENTRY_ID(unit);
   1578     u32_scache_p++;
   1579 
   1580     hash_entry_scache_p =
   1581         (bcmi_xgs4_td2_switch_wb_hash_entry_t *)u32_scache_p;
   1582 
   1583     while (hash_entry != NULL) {
   1584         hash_entry_scache_p->entry_id = hash_entry->entry_id;
   1585         hash_entry_scache_p->hw_idx = hash_entry->hw_idx;
   1586         hash_entry_scache_p->offset_bitmap = hash_entry->offset_bitmap;
   1587         for (fld = 0; fld < FLEX_HASH_MAX_FIELDS; fld++) {
   1588             hash_entry_scache_p->match_arr[fld].qual_id= hash_entry->match_arr[fld].qual_id;
   1589             hash_entry_scache_p->match_arr[fld].qual_size= hash_entry->match_arr[fld].qual_size;
   1590         }
   1591         hash_entry_scache_p++;
   1592         
   1593         hash_entry = hash_entry->next;
   1594     }
   1595     *scache_ptr = (uint8 *)u32_scache_p;
   1596 
   1597 #if defined(BCM_TOMAHAWK_SUPPORT)
   1598     if (SOC_IS_TOMAHAWKX(unit)) {
   1599         udf_id_p = (bcm_udf_id_t *)hash_entry_scache_p;
   1600         hash_entry = SWITCH_HASH_ENTRY_LIST(unit);
   1601         while (hash_entry != NULL) {
   1602             for (fld = 0; fld < FLEX_HASH_MAX_OFFSET; fld++) {
   1603                 *udf_id_p = hash_entry->udf_id[fld];
   1604                 udf_id_p++;
   1605             }
   1606             hash_entry = hash_entry->next;
   1607         }
   1608         /* overwrite scache_ptr*/
   1609         *scache_ptr = (uint8 *)udf_id_p;
   1610     }
   1611 #endif /*BCM_TOMAHAWK_SUPPORT*/
   1612 
   1613     return BCM_E_NONE;
   1614 }
   1615 
   1616 /* If this size be changed, please don't forget to change udf wb version simultaneously */
   1617 int
   1618 bcmi_td2_switch_wb_hash_entry_scache_size_get(int unit, int *req_scache_size)
   1619 {
   1620     int alloc_size = 0;
   1621     int hash_entries = 0;
   1622 
   1623     alloc_size += sizeof(hash_entries);
   1624     alloc_size += sizeof(_bcm_td2_switch_hash_bk_info[unit].api_ver);
   1625     alloc_size += sizeof(SWITCH_HASH_LAST_ENTRY_ID(unit));
   1626     /* Number of  hash entries*/
   1627     if (SOC_IS_TRIDENT3X(unit)) {
   1628         /* TD3TBD */
   1629         hash_entries = 128;
   1630     } else {
   1631         hash_entries = soc_mem_index_count(unit, FLEX_HASH_TCAM);
   1632     }
   1633 
   1634     alloc_size += (hash_entries *
   1635                    sizeof(bcmi_xgs4_td2_switch_wb_hash_entry_t));
   1636 
   1637 #if defined(BCM_TOMAHAWK_SUPPORT)
   1638     if (SOC_IS_TOMAHAWKX(unit)) {
   1639         alloc_size += sizeof(bcm_udf_id_t) * hash_entries * FLEX_HASH_MAX_OFFSET;
   1640     }
   1641 #endif /*BCM_TOMAHAWK_SUPPORT*/
   1642 
   1643     *req_scache_size += alloc_size;
   1644 
   1645     return BCM_E_NONE;
   1646 }
   1647 #endif 
   1648 
   1649 /*
   1650  * 
   1651  *  Flexible hash Switch API support routines 
   1652  */
   1653 int
   1654 bcm_td2_switch_hash_entry_detach(int unit)
   1655 {
   1656 
   1657     if (SWITCH_HASH_ENTRY_LIST(unit)) {
   1658         _flex_hash_entry_destroy_all(unit);
   1659     }
   1660 
   1661     if (SWITCH_HASH_IDX_BITMAP(unit)) {
   1662         sal_free(SWITCH_HASH_IDX_BITMAP(unit));
   1663         SWITCH_HASH_IDX_BITMAP(unit) = NULL;
   1664     }
   1665 
   1666     SWITCH_HASH_INIT(unit) = FALSE;
   1667 
   1668     return BCM_E_NONE;
   1669 }
   1670 
   1671 int
   1672 bcm_td2_switch_hash_entry_init(int unit)
   1673 {
   1674     int             hash_entries;
   1675 
   1676     if (SWITCH_HASH_INIT(unit) == TRUE ) {
   1677         bcm_td2_switch_hash_entry_detach(unit);
   1678     }
   1679 
   1680     if (SWITCH_HASH_IDX_BITMAP(unit)) {
   1681 
   1682     }
   1683     /* Initialize bookeeping */
   1684     sal_memset(SWITCH_HASH_INFO(unit), 0, sizeof(*SWITCH_HASH_INFO(unit)));
   1685 
   1686     /* Initialize the hash entry list */
   1687     SWITCH_HASH_ENTRY_LIST(unit) = NULL;
   1688 
   1689     if (SOC_IS_TRIDENT3X(unit)) {
   1690         /* Flex Hashing is not supported for TD3X */
   1691         hash_entries = 0;
   1692     } else {
   1693         hash_entries = soc_mem_index_count(unit, FLEX_HASH_TCAM);
   1694     }
   1695 
   1696     SWITCH_HASH_IDX_BITMAP(unit) = sal_alloc(SHR_BITALLOCSIZE(hash_entries),
   1697                          "hash index bitmap");
   1698     if (NULL == SWITCH_HASH_IDX_BITMAP(unit)) {
   1699         bcm_td2_switch_hash_entry_detach(unit);
   1700         return BCM_E_FAIL;
   1701     }
   1702     sal_memset(SWITCH_HASH_IDX_BITMAP(unit), 0, SHR_BITALLOCSIZE(hash_entries));
   1703 
   1704     SWITCH_HASH_INIT(unit) = TRUE;
   1705 
   1706     return BCM_E_NONE;
   1707 }
   1708 
   1709 
   1710 /*
   1711  * Function: 
   1712  *      bcm_td2_switch_hash_entry_create
   1713  * Purpose: 
   1714  *      Create a blank flex hash entry.
   1715  * Parameters: 
   1716  *      unit       - (IN) bcm device
   1717  *      group      - (IN)  BCM field group
   1718  *      *entry     - (OUT) BCM hash entry
   1719  *
   1720  * Returns:
   1721  *      BCM_E_NONE - Success
   1722  *      BCM_E_XXX
   1723  * Notes:
   1724  */
   1725 int
   1726 bcm_td2_switch_hash_entry_create(int unit,
   1727                  bcm_field_group_t group,
   1728                  bcm_hash_entry_t * entry_id)
   1729 {
   1730     int             rv = BCM_E_NONE;
   1731     bcm_field_qset_t qset;
   1732     int             qual_array[FLEX_HASH_MAX_FIELDS];
   1733     int             qual_count;
   1734 
   1735 
   1736     /* Validate unit, group of qualifier Ids */
   1737     if (!SOC_UNIT_VALID(unit)) {
   1738         return BCM_E_UNIT;
   1739     }
   1740 
   1741     rv = bcm_esw_field_group_get(unit, group, &qset);
   1742     if (BCM_FAILURE(rv)) {
   1743         return BCM_E_BADID;
   1744     }
   1745 
   1746     /* Either this API or the create_qset should be used
   1747      * Users should not intermix the APIs.
   1748      */
   1749     if (SWITCH_HASH_INFO(unit)->api_ver == 0) {
   1750         SWITCH_HASH_INFO(unit)->api_ver = 1;
   1751     } else if (SWITCH_HASH_INFO(unit)->api_ver == 2) {
   1752         return BCM_E_CONFIG;
   1753     }
   1754 
   1755     /* 
   1756      * Check for the required qualifier fields, the assumption is qual_array
   1757      * has the same sequence of offsets from UDF2.4 .. UDF2.7 for flex hash
   1758      */
   1759     rv = bcm_esw_field_qset_data_qualifier_get(unit, qset,
   1760                            FLEX_HASH_MAX_FIELDS,
   1761                            qual_array, &qual_count);
   1762     if (BCM_FAILURE(rv)) {
   1763         return BCM_E_FAIL;
   1764     }
   1765 
   1766     if (0 == qual_count) {
   1767         return BCM_E_FAIL;
   1768     }
   1769 
   1770     /* Create flexible hash entry */
   1771     /* Get free index from the flex hash tcam */
   1772     BCM_IF_ERROR_RETURN(_bcm_hash_entry_create(unit, entry_id));
   1773 
   1774     /* Add qualifier ids in the hash entry */
   1775     BCM_IF_ERROR_RETURN(_bcm_hash_entry_qual_set
   1776                 (unit, *entry_id, qual_count, qual_array));
   1777     return rv;
   1778 }
   1779 
   1780 /*
   1781  * Function: 
   1782  *      bcm_td2_switch_hash_entry_create_qset
   1783  * Purpose: 
   1784  *      Create a blank flex hash entry.
   1785  * Parameters: 
   1786  *      unit       - (IN)  bcm device
   1787  *      qset       - (IN)  Qset
   1788  *      *entry     - (OUT) BCM hash entry
   1789  *
   1790  * Returns:
   1791  *      BCM_E_NONE - Success
   1792  *      BCM_E_XXX
   1793  * Notes:
   1794  */
   1795 int
   1796 bcm_td2_switch_hash_entry_create_qset(int unit,
   1797                                       bcm_field_qset_t qset,
   1798                                       bcm_hash_entry_t * entry_id)
   1799 {
   1800     int             rv = BCM_E_NONE;
   1801     int             qual_array[FLEX_HASH_MAX_FIELDS];
   1802     int             qual_count;
   1803 
   1804     /* Either this API or the create_qset should be used
   1805      * Users should not intermix the APIs.
   1806      */
   1807     if (SWITCH_HASH_INFO(unit)->api_ver == 0) {
   1808         SWITCH_HASH_INFO(unit)->api_ver = 2;
   1809     } else if (SWITCH_HASH_INFO(unit)->api_ver == 1) {
   1810         return BCM_E_CONFIG;
   1811     }
   1812 
   1813     /*
   1814      * Check for the required qualifier fields, the assumption is qual_array
   1815      * has the same sequence of offsets from UDF2.4 .. UDF2.7 for flex hash
   1816      */
   1817     rv = bcm_esw_field_qset_id_multi_get(unit, qset, bcmFieldQualifyUdf,
   1818                                     FLEX_HASH_MAX_FIELDS,
   1819                                     qual_array, &qual_count);
   1820     BCM_IF_ERROR_RETURN(rv);
   1821 
   1822     if (0 == qual_count) {
   1823         return BCM_E_PARAM;
   1824     }
   1825 
   1826     /* Create flexible hash entry */
   1827     /* Get free index from the flex hash tcam */
   1828     BCM_IF_ERROR_RETURN(_bcm_hash_entry_create(unit, entry_id));
   1829 
   1830     /* Add qualifier ids in the hash entry */
   1831     BCM_IF_ERROR_RETURN(_bcm_hash_entry_udf_set
   1832                         (unit, *entry_id, qual_count, qual_array));
   1833 
   1834     return rv;
   1835 }
   1836 
   1837 
   1838 /*
   1839  * Function: 
   1840  *      bcm_td2_switch_hash_entry_destroy
   1841  * Purpose: 
   1842  *      Destroy a flex hash entry.
   1843  * Parameters: 
   1844  *      unit       - (IN) bcm device
   1845  *      entry_id   - (IN) BCM hash entry
   1846  *
   1847  * Returns:
   1848  *      BCM_E_NONE - Success
   1849  *      BCM_E_XXX
   1850  * Notes:
   1851  */
   1852 int
   1853 bcm_td2_switch_hash_entry_destroy(int unit, bcm_hash_entry_t entry_id)
   1854 {
   1855 
   1856     return _bcm_hash_entry_delete(unit, entry_id);
   1857 }
   1858 
   1859 /*
   1860  * Function:
   1861  *      bcm_td2_switch_hash_entry_set
   1862  * Purpose:
   1863  *      Set a flex hash entry configuration information.
   1864  * Parameters:
   1865  *      unit       - (IN) BCM device
   1866  *      entry      - (IN) BCM hash entry
   1867  *      config     - (IN) BCM hash configure information
   1868  *
   1869  * Returns:
   1870  *      BCM_E_NONE - Success
   1871  *      BCM_E_XXX
   1872  * Notes:
   1873  */
   1874 int 
   1875 bcm_td2_switch_hash_entry_set(int unit,
   1876                               bcm_hash_entry_t entry, 
   1877                               bcm_switch_hash_entry_config_t *config)
   1878 {
   1879     int mask_bit_max;
   1880     uint32 mask;
   1881 #ifdef LE_HOST
   1882     uint32 mask_swap;
   1883 #endif /* LE_HOST */
   1884     flex_hash_entry_t *hash_entry;
   1885     uint8 *p;
   1886 #if defined(BCM_TOMAHAWK_SUPPORT)
   1887     bcmi_xgs4_udf_offset_info_t *offset_info = NULL;
   1888     int i, gran, pos, chunk_pos = 0;
   1889 #endif
   1890 
   1891     if (config == NULL) {
   1892         return BCM_E_PARAM;
   1893     }
   1894 
   1895     BCM_IF_ERROR_RETURN(
   1896         _flex_hash_entry_get(unit, entry, &hash_entry));
   1897 
   1898 #ifdef BCM_TOMAHAWK2_SUPPORT
   1899     if ((SOC_IS_TOMAHAWK2(unit)) || (SOC_IS_TOMAHAWK3(unit))) {
   1900         /* In TH2 bcmSwitchFlexHashField2~12 only support udf type. */
   1901         if ((config->field >= bcmSwitchFlexHashFieldCount) ||
   1902             ((config->field > bcmSwitchFlexHashField1) &&
   1903              !(config->flags & BCM_SWITCH_HASH_FIELD_TYPE_UDF))) {
   1904             return BCM_E_PARAM;
   1905         }
   1906     } else
   1907 #endif /*BCM_TOMAHAWK2_SUPPORT*/
   1908     {
   1909         /* In TH and TD2 only first two fields are supported. */
   1910         if (config->field > bcmSwitchFlexHashField1) {
   1911             return BCM_E_PARAM;
   1912         }
   1913     }
   1914 
   1915     /*Only TH series support UDF type flex Hash*/
   1916     if (!SOC_IS_TOMAHAWKX(unit) &&
   1917         config->flags & BCM_SWITCH_HASH_FIELD_TYPE_UDF) {
   1918         return BCM_E_UNAVAIL;
   1919     }
   1920     mask_bit_max = soc_mem_field_length(unit, FLEX_HASH_OFFSET_MASK(unit),
   1921                              _bcm_td2_flex_hash_mask[config->field]);
   1922 
   1923     if (config->mask_length > BITS2BYTES(mask_bit_max)
   1924         || config->mask_length > sizeof(mask)) {
   1925         return BCM_E_PARAM;
   1926     }
   1927 
   1928     mask = 0;
   1929     if (config->mask_length) {
   1930         p = (uint8 *)&mask;
   1931         p += sizeof(mask) - config->mask_length;
   1932         sal_memcpy(p, config->mask, config->mask_length);
   1933     }
   1934 
   1935 #ifdef LE_HOST
   1936     mask_swap = _shr_swap32(mask);
   1937     mask = mask_swap;
   1938 #endif /* LE_HOST */
   1939 
   1940 #if defined(BCM_TOMAHAWK_SUPPORT)
   1941     /*Extract udf chunk id from udf_id*/
   1942     if (config->flags & BCM_SWITCH_HASH_FIELD_TYPE_UDF) {
   1943         if ((config->udf_id < BCMI_XGS4_UDF_ID_MIN) ||
   1944             (config->udf_id > BCMI_XGS4_UDF_ID_MAX)) {
   1945             return BCM_E_PARAM;
   1946         }
   1947         hash_entry->type[config->field] |= BCM_SWITCH_HASH_FIELD_TYPE_UDF;
   1948         hash_entry->udf_id[config->field] = config->udf_id;
   1949         gran = BCMI_XGS4_UDF_CTRL_OFFSET_GRAN(unit);
   1950         BCM_IF_ERROR_RETURN
   1951             (bcmi_xgs4_udf_offset_node_get(unit, config->udf_id, &offset_info));
   1952         /*Sanity check, the offset should start at even boundary of a packet */
   1953         if ((offset_info->width < config->offset / 8 + gran) ||
   1954             (offset_info->start + config->offset / 8) % gran) {
   1955             return BCM_E_PARAM;
   1956         }
   1957         /*get the chunk id which the offset points to*/
   1958         chunk_pos = 0;
   1959         pos = offset_info->start % gran + (config->offset / 8) / gran;
   1960         for (i = 0, chunk_pos = 0; i < MAX_UDF_OFFSET_CHUNKS; i++) {
   1961             if (offset_info->hw_bmap & (1 << i)) {
   1962                 if (chunk_pos == pos) {
   1963                 break;
   1964             }
   1965             chunk_pos++;
   1966           }
   1967         }
   1968         hash_entry->hash_offset[config->field] = i;
   1969     } else
   1970 #endif
   1971     {
   1972         hash_entry->hash_offset[config->field] = config->offset & 0xf;
   1973     }
   1974     hash_entry->hash_mask[config->field] = (int)mask;
   1975     if (mask) {
   1976         hash_entry->offset_bitmap |=  (0x1 << config->field);
   1977     } else {
   1978         hash_entry->offset_bitmap &= ~(0x1 << config->field);
   1979     }
   1980     hash_entry->offset_count = _shr_popcount(hash_entry->offset_bitmap);
   1981 
   1982     return BCM_E_NONE;
   1983 }
   1984 
   1985 /*
   1986  * Function:
   1987  *      bcm_td2_switch_hash_entry_get
   1988  * Purpose:
   1989  *      Get a flex hash entry configure information.
   1990  * Parameters:
   1991  *      unit       - (IN) BCM device
   1992  *      entry      - (IN) BCM hash entry
   1993  *      config     - (IN/OUT) BCM hash configure information
   1994  *
   1995  * Returns:
   1996  *      BCM_E_NONE - Success
   1997  *      BCM_E_XXX
   1998  * Notes:
   1999  */
   2000 int
   2001 bcm_td2_switch_hash_entry_get(int unit,
   2002                               bcm_hash_entry_t entry, 
   2003                               bcm_switch_hash_entry_config_t *config)
   2004 {
   2005     int i, mask_len;
   2006     uint32 mask;
   2007 #ifdef LE_HOST
   2008     uint32 mask_swap;
   2009 #endif /* LE_HOST */
   2010     flex_hash_entry_t *hash_entry;
   2011 #if defined(BCM_TOMAHAWK_SUPPORT)
   2012     int gran, position = 0;
   2013     bcmi_xgs4_udf_offset_info_t *offset_info = NULL;
   2014 #endif /*BCM_TOMAHAWK_SUPPORT*/
   2015 
   2016     if (config == NULL) {
   2017         return BCM_E_PARAM;
   2018     }
   2019 
   2020     BCM_IF_ERROR_RETURN(
   2021         _flex_hash_entry_get(unit, entry, &hash_entry));
   2022 
   2023 #if defined(BCM_TOMAHAWK2_SUPPORT)
   2024     if ((SOC_IS_TOMAHAWK2(unit)) || (SOC_IS_TOMAHAWK3(unit))) {
   2025         if (config->field >= bcmSwitchFlexHashFieldCount) {
   2026             return BCM_E_PARAM;
   2027         }
   2028     } else
   2029 #endif
   2030     {
   2031         if (config->field > bcmSwitchFlexHashField1) {
   2032             return BCM_E_PARAM;
   2033         }
   2034     }
   2035 
   2036     mask_len = 0;
   2037     mask = (uint32)hash_entry->hash_mask[config->field];
   2038     for (i = 0; i < sizeof(mask); i++) {
   2039         if (mask & 0xff000000) {
   2040             mask_len = sizeof(mask) - i;
   2041             break;
   2042         }
   2043         mask <<= 8;
   2044     }
   2045 
   2046     if (mask_len == 0) {
   2047         return BCM_E_NOT_FOUND;
   2048     }
   2049 
   2050 #ifdef LE_HOST
   2051     mask_swap = _shr_swap32(mask);
   2052     mask = mask_swap;
   2053 #endif /* LE_HOST */
   2054 
   2055 #if defined(BCM_TOMAHAWK_SUPPORT)
   2056     /*Extract udf chunk id from udf_id*/
   2057     if (hash_entry->type[config->field] & BCM_SWITCH_HASH_FIELD_TYPE_UDF) {
   2058         config->udf_id = hash_entry->udf_id[config->field];
   2059         gran = BCMI_XGS4_UDF_CTRL_OFFSET_GRAN(unit);
   2060         BCM_IF_ERROR_RETURN
   2061             (bcmi_xgs4_udf_offset_node_get(unit, config->udf_id, &offset_info));
   2062         position = 0;
   2063         for (i = 0; i < hash_entry->hash_offset[config->field]; i++) {
   2064             if (SHR_BITGET(&(offset_info->hw_bmap), i)) {
   2065                 position++;
   2066             }
   2067         }
   2068         /* offset gran is in bit, not byte. */
   2069         config->offset = (position * gran - offset_info->start % gran) * 8;
   2070     } else
   2071 
   2072 #endif
   2073     {
   2074         config->offset = hash_entry->hash_offset[config->field];
   2075     }
   2076     config->flags = hash_entry->type[config->field];
   2077     config->mask_length = mask_len;
   2078     if (config->mask_length > 0) {
   2079         sal_memcpy(config->mask, &mask, mask_len);
   2080     }
   2081 
   2082     return BCM_E_NONE;
   2083 }
   2084 
   2085 /*
   2086  * Function:
   2087  *      bcm_td2_switch_hash_entry_traverse
   2088  * Purpose:
   2089  *      Traverse flex hash entry tables.
   2090  * Parameters: 
   2091  *      unit       - (IN) BCM device
   2092  *      cb_fn      - (IN) BCM traverse call back function
   2093  *      user_data  - (IN) BCM user data
   2094  *
   2095  * Returns:
   2096  *      BCM_E_NONE - Success
   2097  *      BCM_E_XXX
   2098  * Notes:
   2099  */
   2100 int
   2101 bcm_td2_switch_hash_entry_traverse(int unit, int flags, 
   2102                                    bcm_switch_hash_entry_traverse_cb cb_fn,
   2103                                    void *user_data)
   2104 {
   2105     int rv;
   2106     flex_hash_entry_t *hash_entry = SWITCH_HASH_ENTRY_LIST(unit);
   2107 
   2108     if (cb_fn == NULL) {
   2109         return BCM_E_PARAM;
   2110     }
   2111 
   2112     while (hash_entry != NULL) {
   2113         rv = cb_fn(unit, flags, hash_entry->entry_id, user_data);
   2114         if (BCM_FAILURE(rv)) {
   2115             return rv;
   2116         }
   2117         hash_entry = hash_entry->next;
   2118     }
   2119 
   2120     return BCM_E_NONE;
   2121 }
   2122 
   2123 /*
   2124  * Function: 
   2125  *      bcm_td2_switch_hash_entry_install
   2126  * Purpose: 
   2127  *      Install a flex hash entry into hardware tables.
   2128  * Parameters: 
   2129  *      unit       - (IN) bcm device
   2130  *      entry      - (IN) BCM hash entry
   2131  *
   2132  * Returns:
   2133  *      BCM_E_NONE - Success
   2134  *      BCM_E_XXX
   2135  * Notes:
   2136  */
   2137 int
   2138 bcm_td2_switch_hash_entry_install(int unit, bcm_hash_entry_t entry_id,
   2139                                   uint32 offset, uint32 mask)
   2140 {
   2141     int             rv = BCM_E_NONE;
   2142     flex_hash_entry_t *hash_entry;
   2143 
   2144     rv = _flex_hash_entry_get(unit, entry_id, &hash_entry);
   2145     if (BCM_FAILURE(rv)) {
   2146         return rv;
   2147     }
   2148 
   2149     if (offset != BCM_SWITCH_HASH_USE_CONFIG) {
   2150         if (++hash_entry->offset_count > FLEX_HASH_OFFSET_NUM(unit)) {
   2151             return BCM_E_RESOURCE;
   2152         }
   2153         hash_entry->hash_offset[hash_entry->offset_count - 1] = offset & 0xf;
   2154         hash_entry->hash_mask[hash_entry->offset_count - 1] = mask & 0xffff;
   2155         hash_entry->offset_bitmap |= 0x1 << (hash_entry->offset_count - 1);
   2156     }
   2157 
   2158 #ifdef BCM_TOMAHAWK2_SUPPORT
   2159     if ((SOC_IS_TOMAHAWK2(unit)) || (SOC_IS_TOMAHAWK3(unit))) {
   2160         rv = _bcm_th2_flex_hash_table_write(unit, hash_entry, FALSE);
   2161     } else
   2162 #endif
   2163     {
   2164         rv = _bcm_flex_hash_table_write(unit, hash_entry, FALSE);
   2165     }
   2166 
   2167     if (BCM_FAILURE(rv)) {
   2168         return rv;
   2169     }
   2170 
   2171     return rv;
   2172 }
   2173 
   2174 /*
   2175  * Function: 
   2176  *      bcm_td2_switch_hash_entry_reinstall
   2177  * Purpose: 
   2178  *      Re-install a flex hash entry into hardware tables.
   2179  * Parameters: 
   2180  *      unit       - (IN) bcm device
   2181  *      entry      - (IN) BCM hash entry
   2182  *      offset     - (IN) BCM hash offset
   2183  *
   2184  * Returns:
   2185  *      BCM_E_NONE - Success
   2186  *      BCM_E_XXX
   2187  * Notes:
   2188  */
   2189 int
   2190 bcm_td2_switch_hash_entry_reinstall(int unit,
   2191                     bcm_hash_entry_t entry_id, uint32 offset, uint32 mask)
   2192 {
   2193     int             cnt, rv = BCM_E_NONE, reinstall;
   2194     flex_hash_entry_t *hash_entry;
   2195 
   2196     if (offset != BCM_SWITCH_HASH_USE_CONFIG) {
   2197         rv = _flex_hash_entry_get(unit, entry_id, &hash_entry);
   2198         if (BCM_FAILURE(rv)) {
   2199             return rv;
   2200         }
   2201 
   2202         reinstall = 1;
   2203         for (cnt = 0; cnt < FLEX_HASH_OFFSET_NUM(unit); cnt++) {
   2204             if (hash_entry->hash_offset[cnt] == -1) {
   2205                 reinstall = 0;
   2206             }
   2207         }
   2208         if ((reinstall == 1) && (cnt == FLEX_HASH_OFFSET_NUM(unit))) {
   2209             for (cnt = 0; cnt < FLEX_HASH_OFFSET_NUM(unit); cnt++) {
   2210                 hash_entry->hash_offset[cnt] = -1;
   2211                 hash_entry->offset_count = 0;
   2212                 hash_entry->offset_bitmap = 0;
   2213             }
   2214         }
   2215     }
   2216 
   2217     return bcm_td2_switch_hash_entry_install(unit, entry_id, offset, mask);
   2218 }
   2219 
   2220 /*
   2221  * Function: 
   2222  *      bcm_td2_switch_hash_entry_remove
   2223  * Purpose: 
   2224  *      Remove a flex hash entry from hardware tables.
   2225  * Parameters: 
   2226  *      unit       - (IN) bcm device
   2227  *      entry      - (IN) BCM hash entry
   2228  *
   2229  * Returns:
   2230  *      BCM_E_NONE - Success
   2231  *      BCM_E_XXX
   2232  * Notes:
   2233  */
   2234 int
   2235 bcm_td2_switch_hash_entry_remove(int unit, bcm_hash_entry_t entry_id)
   2236 {
   2237     return _bcm_hash_entry_remove(unit, entry_id);;
   2238 }
   2239 
   2240 /*
   2241  * Function:
   2242  *      bcm_td2_switch_hash_qualify_data
   2243  * Purpose:
   2244  *      Add flex hash field qualifiers into hardware tables.
   2245  * Parameters:
   2246  *      unit       - (IN) bcm device
   2247  *      entry      - (IN) BCM hash entry
   2248  *      qual_id    - (IN) BCM qualifier id
   2249  *      data       - (IN) BCM hash field qualifier
   2250  *      mask       - (IN) BCM hash field mask
   2251  * Returns:
   2252  *      BCM_E_NONE - Success
   2253  *      BCM_E_XXX
   2254  * Notes:
   2255  */
   2256 
   2257 int
   2258 bcm_td2_switch_hash_qualify_data(int unit, bcm_hash_entry_t entry_id,
   2259                  int qual_id, uint32 data, uint32 mask)
   2260 {
   2261     int             rv = BCM_E_NONE;
   2262 
   2263     rv = _bcm_hash_entry_qual_data_set(unit, entry_id, qual_id, data, mask);
   2264     if (BCM_FAILURE(rv)) {
   2265         return rv;
   2266     }
   2267 
   2268     return rv;
   2269 }
   2270 
   2271 /*
   2272  * Function:
   2273  *      bcm_td2_switch_hash_qualify_udf
   2274  * Purpose:
   2275  *      Add flex hash udf qualifiers into hardware tables.
   2276  * Parameters: 
   2277  *      unit       - (IN) bcm device
   2278  *      entry      - (IN) BCM hash entry
   2279  *      udf_id     - (IN) BCM qualifier id
   2280  *      length     - (IN) BCM qualifier id
   2281  *      data       - (IN) BCM hash field qualifier
   2282  *      mask       - (IN) BCM hash field mask
   2283  * Returns:
   2284  *      BCM_E_NONE - Success
   2285  *      BCM_E_XXX
   2286  * Notes:
   2287  */
   2288 int 
   2289 bcm_td2_switch_hash_qualify_udf(int unit,
   2290                                 bcm_hash_entry_t entry, 
   2291                                 bcm_udf_id_t udf_id,
   2292                                 int length, 
   2293                                 uint8 *data, uint8 *mask)
   2294 {
   2295     int i, idx, len;
   2296     int id, chunk_base, chunk_size, chunk_cnt;
   2297     flex_hash_entry_t *hash_entry;
   2298     bcmi_xgs4_udf_offset_info_t *offset_info;
   2299     uint8 *p;
   2300     uint32 qual_match, qual_mask; 
   2301 #ifdef LE_HOST
   2302     uint32 qual_match_swap, qual_mask_swap; 
   2303 #endif /* LE_HOST */
   2304 
   2305     if (data == NULL || mask == NULL) {
   2306         return BCM_E_PARAM;
   2307     }
   2308     BCM_IF_ERROR_RETURN(
   2309         _flex_hash_entry_get(unit, entry, &hash_entry));
   2310     chunk_base = 12; /* UDF2.4 */
   2311     chunk_size = 2;
   2312     /* Get data qualifier info. */
   2313     BCM_IF_ERROR_RETURN(
   2314         bcmi_xgs4_udf_offset_node_get(unit, udf_id, &offset_info));
   2315 
   2316     if (!(offset_info->flags & BCMI_XGS4_UDF_OFFSET_FLEXHASH) ||
   2317         !(offset_info->hw_bmap & (0xf << chunk_base)) ||
   2318         !(offset_info->width > 0)) {
   2319         return BCM_E_PARAM;
   2320     }
   2321     if (length > offset_info->width) {
   2322         return BCM_E_PARAM;
   2323     }
   2324     for (id = 0; id < FLEX_HASH_MAX_FIELDS; id++) {
   2325         if (hash_entry->match_arr[id].qual_id == udf_id) {
   2326             hash_entry->match_arr[id].qual_size = 0;
   2327             break;
   2328         }
   2329     }
   2330     if (id == FLEX_HASH_MAX_FIELDS) {
   2331         return BCM_E_PARAM;
   2332     }
   2333     chunk_cnt  = (offset_info->width + chunk_size - 1) / chunk_size;
   2334     if ((id + chunk_cnt) > FLEX_HASH_MAX_FIELDS) {
   2335         return BCM_E_PARAM;
   2336     }
   2337 
   2338     for (i = 0; i < length; i += chunk_size) {
   2339         idx = id + i / chunk_size;
   2340         len = ((length - i) >= chunk_size) ? chunk_size : (length - i);
   2341         qual_match = qual_mask = 0;
   2342 
   2343         p = (uint8 *)&qual_match;
   2344         p += sizeof(uint32) - len;
   2345         sal_memcpy(p, &data[i], len);
   2346         p = (uint8 *)&qual_mask;
   2347         p += sizeof(uint32) - len;
   2348         sal_memcpy(p, &mask[i], len);
   2349 
   2350 #ifdef LE_HOST
   2351         qual_match_swap = _shr_swap32(qual_match);
   2352         qual_match      = qual_match_swap;
   2353         qual_mask_swap  = _shr_swap32(qual_mask);
   2354         qual_mask       = qual_mask_swap;
   2355 #endif /* LE_HOST */
   2356 
   2357         hash_entry->match_arr[idx].qual_match = qual_match;
   2358         hash_entry->match_arr[idx].qual_mask  = qual_mask;
   2359         hash_entry->match_arr[idx].qual_size  = len;
   2360     }
   2361 
   2362     return BCM_E_NONE;
   2363 }
   2364 
   2365 /*
   2366  * Function:
   2367  *      bcm_td2_switch_hash_qualify_udf_get
   2368  * Purpose:
   2369  *      Get flex hash udf qualifiers' length, data and mask.
   2370  * Parameters:
   2371  *      unit       - (IN) bcm device
   2372  *      entry      - (IN) BCM hash entry
   2373  *      udf_id     - (IN) BCM qualifier id
   2374  *      length     - (OUT) BCM qualifier id
   2375  *      data       - (OUT) BCM hash field qualifier
   2376  *      mask       - (OUT) BCM hash field mask
   2377  * Returns:
   2378  *      BCM_E_NONE - Success
   2379  *      BCM_E_XXX
   2380  * Notes:
   2381  */
   2382 int 
   2383 bcm_td2_switch_hash_qualify_udf_get(int unit, 
   2384                                     bcm_hash_entry_t entry, 
   2385                                     bcm_udf_id_t udf_id,
   2386                                     int max_length, 
   2387                                     uint8 *data, uint8 *mask,
   2388                                     int *actual_length)
   2389 {
   2390     int i, idx, len, len_tmp = 0;
   2391     int id, chunk_base, chunk_size, chunk_cnt;
   2392     flex_hash_entry_t *hash_entry;
   2393     bcmi_xgs4_udf_offset_info_t *offset_info;
   2394     uint8 *p;
   2395     uint32 qual_match, qual_mask; 
   2396 #ifdef LE_HOST
   2397     uint32 qual_match_swap, qual_mask_swap; 
   2398 #endif /* LE_HOST */
   2399 
   2400     if (data == NULL || mask == NULL || actual_length == NULL) {
   2401         return BCM_E_PARAM;
   2402     }
   2403 
   2404     BCM_IF_ERROR_RETURN(
   2405         _flex_hash_entry_get(unit, entry, &hash_entry));
   2406 
   2407     chunk_base = 12; /* UDF2.4 */
   2408     chunk_size = 2;
   2409     /* Get data qualifier info. */
   2410     BCM_IF_ERROR_RETURN(
   2411         bcmi_xgs4_udf_offset_node_get(unit, udf_id, &offset_info));
   2412     if (!(offset_info->flags & BCMI_XGS4_UDF_OFFSET_FLEXHASH) ||
   2413         !(offset_info->hw_bmap & (0xf << chunk_base))) {
   2414         return BCM_E_PARAM;
   2415     }
   2416 
   2417     if (max_length < offset_info->width) {
   2418         return BCM_E_PARAM;
   2419     }
   2420 
   2421     for (id = 0; id < FLEX_HASH_MAX_FIELDS; id++) {
   2422         if (hash_entry->match_arr[id].qual_id == udf_id) {
   2423             break;
   2424         }
   2425     }
   2426     if (id >= FLEX_HASH_MAX_FIELDS) {
   2427         return BCM_E_NOT_FOUND;
   2428     }
   2429 
   2430     chunk_cnt  = (offset_info->width + chunk_size - 1) / chunk_size;
   2431     if ((id + chunk_cnt) > FLEX_HASH_MAX_FIELDS) {
   2432         return BCM_E_INTERNAL;
   2433     }
   2434 
   2435     for (i = 0; i < offset_info->width; i += chunk_size) {
   2436         idx = id + i / chunk_size;
   2437         len = hash_entry->match_arr[idx].qual_size;
   2438         if (len) {
   2439             qual_match = hash_entry->match_arr[idx].qual_match;
   2440             qual_mask  = hash_entry->match_arr[idx].qual_mask;
   2441 
   2442 #ifdef LE_HOST
   2443             qual_match_swap = _shr_swap32(qual_match);
   2444             qual_match      = qual_match_swap;
   2445             qual_mask_swap  = _shr_swap32(qual_mask);
   2446             qual_mask       = qual_mask_swap;
   2447 #endif /* LE_HOST */
   2448 
   2449             p = (uint8 *)&qual_match;
   2450             p += sizeof(uint32) - len;
   2451             sal_memcpy(&data[i], p, len);
   2452             p = (uint8 *)&qual_mask;
   2453             p += sizeof(uint32) - len;
   2454             sal_memcpy(&mask[i], p, len);
   2455             len_tmp += len;
   2456         }
   2457     }
   2458     
   2459     *actual_length = len_tmp;
   2460 
   2461     return BCM_E_NONE;
   2462 }
   2463 
   2464 /*
   2465  * Function:
   2466  *   _bcm_td2_switch_match_free_resources
   2467  * Purpose:
   2468  *   Free match bookkeeping resources associated with a given unit.  This
   2469  *   happens either during an error initializing or during a detach operation.
   2470  * Parameters:
   2471  *   unit - (IN) Unit number
   2472  * Returns:
   2473  *   BCM_E_XXX
   2474  */
   2475 STATIC void
   2476 _bcm_td2_switch_match_free_resources(int unit)
   2477 {
   2478     _bcm_td2_switch_match_bookkeeping_t *match_info = TD2_MATCH_INFO(unit);
   2479     int i;
   2480 
   2481     if (match_info->gtp_ptr_array) {
   2482         for (i = 0; i < soc_mem_index_count(unit, GTP_PORT_TABLEm); i++) {
   2483             if (match_info->gtp_ptr_array[i]) {
   2484                 sal_free(match_info->gtp_ptr_array[i]);
   2485             }
   2486         }
   2487         sal_free(match_info->gtp_ptr_array);
   2488         match_info->gtp_ptr_array = NULL;
   2489     }
   2490 
   2491     if (match_info->match_mutex) {
   2492         sal_mutex_destroy(match_info->match_mutex);
   2493         match_info->match_mutex = NULL;
   2494     }
   2495 }
   2496 
   2497 /*
   2498  * Function:
   2499  *   bcm_td2_switch_match_detach
   2500  * Purpose:
   2501  *   Detach the TD2 match resource. Called when the module should de-initialize.
   2502  * Parameters:
   2503  *   unit - (IN) Unit being detached.
   2504  * Returns:
   2505  *   BCM_E_XXX
   2506  */
   2507 int
   2508 bcm_td2_switch_match_detach(int unit)
   2509 {
   2510     if (_bcm_td2_match_initialized[unit]) {
   2511         _bcm_td2_switch_match_free_resources(unit);
   2512         _bcm_td2_match_initialized[unit] = 0;
   2513     }
   2514 
   2515     return BCM_E_NONE;
   2516 }
   2517 
   2518 #ifdef BCM_WARM_BOOT_SUPPORT
   2519 
   2520 /*
   2521  * Function:
   2522  *   _bcmi_td2_gtp_match_reinit
   2523  * Purpose:
   2524  *   Restore GTP match entries
   2525  * Parameters:
   2526  *   unit - (IN) Unit being initialized
   2527  * Returns:
   2528  *   BCM_E_XXX
   2529  */
   2530 STATIC int
   2531 _bcm_td2_gtp_port_match_reinit(int unit)
   2532 {
   2533     int hw_id, table_size;
   2534     gtp_port_table_entry_t gtp_port_table_entry;
   2535     int match_type;
   2536     _bcm_td2_gtp_port_match_t *gtp_port_match;
   2537 
   2538     table_size = soc_mem_index_count(unit, GTP_PORT_TABLEm);
   2539 
   2540     for (hw_id = 0; hw_id < table_size; hw_id++) {
   2541         sal_memset(&gtp_port_table_entry, 0, sizeof(gtp_port_table_entry_t));
   2542         BCM_IF_ERROR_RETURN(
   2543             soc_mem_read(unit, GTP_PORT_TABLEm, MEM_BLOCK_ANY,
   2544                          hw_id, &gtp_port_table_entry));
   2545 
   2546         match_type = soc_mem_field32_get(unit, GTP_PORT_TABLEm,
   2547                                          &gtp_port_table_entry, MATCH_ENABLEf);
   2548         if (match_type == 0) {
   2549             continue;
   2550         }
   2551 
   2552         gtp_port_match = sal_alloc(sizeof(_bcm_td2_gtp_port_match_t),
   2553                                    "gtp_port_match");
   2554         if (gtp_port_match == NULL) {
   2555             return BCM_E_MEMORY;
   2556         }
   2557 
   2558         gtp_port_match->match_criteria = match_type;
   2559         gtp_port_match->src_port = soc_mem_field32_get(unit, GTP_PORT_TABLEm,
   2560                                                        &gtp_port_table_entry,
   2561                                                        SRC_PORTf);
   2562         gtp_port_match->dst_port = soc_mem_field32_get(unit, GTP_PORT_TABLEm,
   2563                                                        &gtp_port_table_entry,
   2564                                                        DST_PORTf);
   2565 
   2566         TD2_GTP_PORT_MATCH(unit, hw_id) = gtp_port_match;
   2567     }
   2568 
   2569     return BCM_E_NONE;
   2570 }
   2571 
   2572 /*
   2573  * Function:
   2574  *   bcm_td2_switch_match_reinit
   2575  * Purpose:
   2576  *   Re-initialize the TD2 match resourse. Restore bookkeeping information.
   2577  * Parameters:
   2578  *   unit - (IN) Unit being initialized
   2579  * Returns:
   2580  *   BCM_E_XXX
   2581  */
   2582 STATIC int
   2583 _bcm_td2_switch_match_reinit(int unit)
   2584 {
   2585     BCM_IF_ERROR_RETURN(_bcm_td2_gtp_port_match_reinit(unit));
   2586 
   2587     return BCM_E_NONE;
   2588 }
   2589 #endif /* BCM_WARM_BOOT_SUPPORT */
   2590 
   2591 /*
   2592  * Function:
   2593  *   bcmi_td2_switch_match_init
   2594  * Purpose:
   2595  *   Initialize the TD2 match resourse.  Allocate bookkeeping information.
   2596  * Parameters:
   2597  *   unit - (IN) Unit being initialized
   2598  * Returns:
   2599  *   BCM_E_XXX
   2600  */
   2601 int
   2602 bcm_td2_switch_match_init(int unit)
   2603 {
   2604     _bcm_td2_switch_match_bookkeeping_t *match_info = TD2_MATCH_INFO(unit);
   2605     int gtp_port_table_size;
   2606 #ifdef BCM_WARM_BOOT_SUPPORT
   2607     int rv;
   2608 #endif /* BCM_WARM_BOOT_SUPPORT */
   2609 
   2610     if (_bcm_td2_match_initialized[unit]) {
   2611         BCM_IF_ERROR_RETURN(bcm_td2_switch_match_detach(unit));
   2612     }
   2613 
   2614     sal_memset(match_info, 0, sizeof(_bcm_td2_switch_match_bookkeeping_t));
   2615     gtp_port_table_size = soc_mem_index_count(unit, GTP_PORT_TABLEm);
   2616 
   2617     match_info->gtp_ptr_array =
   2618         sal_alloc(sizeof(_bcm_td2_gtp_port_match_t *) * gtp_port_table_size,
   2619                   "gtp_ptr_array");
   2620     if (match_info->gtp_ptr_array == NULL) {
   2621         _bcm_td2_switch_match_free_resources(unit);
   2622         return BCM_E_MEMORY;
   2623     }
   2624     sal_memset(match_info->gtp_ptr_array, 0,
   2625                sizeof(_bcm_td2_gtp_port_match_t *) * gtp_port_table_size);
   2626 
   2627     /* Create mutex */
   2628     match_info->match_mutex = sal_mutex_create("match_mutex");
   2629     if (match_info->match_mutex == NULL) {
   2630         _bcm_td2_switch_match_free_resources(unit);
   2631         return BCM_E_MEMORY;
   2632     }
   2633 
   2634 #ifdef BCM_WARM_BOOT_SUPPORT
   2635     if (SOC_WARM_BOOT(unit)) {
   2636         /* Warm Boot recovery */
   2637         rv = _bcm_td2_switch_match_reinit(unit);
   2638         if (BCM_FAILURE(rv)) {
   2639             _bcm_td2_switch_match_free_resources(unit);
   2640             return rv;
   2641         }
   2642     }
   2643 #endif /* BCM_WARM_BOOT_SUPPORT */
   2644 
   2645     _bcm_td2_match_initialized[unit] = 1;
   2646 
   2647     return BCM_E_NONE;
   2648 }
   2649 
   2650 /*
   2651  * Function:
   2652  *      _bcm_td2_switch_match_id_check
   2653  * Purpose:
   2654  *      Check match_id is valid
   2655  * Parameters:
   2656  *      unit          - (IN) Unit number
   2657  *      match_service - (IN) Match service type
   2658  *      match_id      - (IN) Match ID
   2659  * Returns:
   2660  *      BCM_E_xxx
   2661  */
   2662 STATIC int
   2663 _bcm_td2_switch_match_id_check(
   2664     int unit,
   2665     bcm_switch_match_service_t match_service,
   2666     int match_id)
   2667 {
   2668     int match_type, table_size;
   2669     uint32 hw_id = TD2_MATCH_HW_ID_GET(match_id);
   2670 
   2671     if (match_service != bcmSwitchMatchServiceGtp) {
   2672         return BCM_E_PARAM;
   2673     }
   2674     table_size = soc_mem_index_count(unit, GTP_PORT_TABLEm);
   2675     match_type = TD2_MATCH_TYPE_GET(match_id);
   2676 
   2677     if ((match_type <= BCM_SWITCH_GTP_MATCH_DST_PORT) ||
   2678         (match_type > BCM_SWITCH_GTP_MATCH_SRC_AND_DST_PORT)) {
   2679         return BCM_E_PARAM;
   2680     }
   2681 
   2682     if (hw_id >= table_size) {
   2683         return BCM_E_PARAM;
   2684     }
   2685 
   2686     return BCM_E_NONE;
   2687 }
   2688 
   2689 STATIC int
   2690 _bcm_td2_gtp_port_match_config_find(
   2691     int unit,
   2692     bcm_switch_match_service_t match_service,
   2693     bcm_switch_match_config_info_t config_info,
   2694     int *match_id)
   2695 {
   2696     int rv = BCM_E_NOT_FOUND;
   2697     int i, table_size;
   2698 
   2699    table_size = soc_mem_index_count(unit, GTP_PORT_TABLEm);
   2700 
   2701     for (i = 0; i < table_size; i++) {
   2702         if (!TD2_GTP_PORT_MATCH_IS_USED(unit, i)) {
   2703             continue;
   2704         }
   2705         if (config_info.match_criteria !=
   2706             TD2_GTP_PORT_MATCH(unit, i)->match_criteria) {
   2707             continue;
   2708         }
   2709         switch (config_info.match_criteria) {
   2710         case BCM_SWITCH_GTP_MATCH_DST_PORT:
   2711             if (config_info.dst_port ==
   2712                 TD2_GTP_PORT_MATCH(unit, i)->dst_port) {
   2713                 *match_id = TD2_MATCH_ID_SET(i, bcmSwitchMatchServiceGtp);
   2714                 return BCM_E_NONE;
   2715             }
   2716             break;
   2717         case BCM_SWITCH_GTP_MATCH_SRC_PORT:
   2718             if (config_info.src_port ==
   2719                 TD2_GTP_PORT_MATCH(unit, i)->src_port) {
   2720                 *match_id = TD2_MATCH_ID_SET(i, bcmSwitchMatchServiceGtp);
   2721                 return BCM_E_NONE;
   2722             }
   2723             break;
   2724         case BCM_SWITCH_GTP_MATCH_SRC_AND_DST_PORT:
   2725         case BCM_SWITCH_GTP_MATCH_SRC_OR_DST_PORT:
   2726             if ((config_info.dst_port ==
   2727                  TD2_GTP_PORT_MATCH(unit, i)->dst_port) &&
   2728                 (config_info.src_port ==
   2729                  TD2_GTP_PORT_MATCH(unit, i)->src_port)) {
   2730                  *match_id = TD2_MATCH_ID_SET(i, bcmSwitchMatchServiceGtp);
   2731                  return BCM_E_NONE;
   2732             }
   2733             break;
   2734         default:
   2735             return BCM_E_PARAM;
   2736             break;
   2737         }
   2738     }
   2739 
   2740     return rv;
   2741 }
   2742 
   2743 
   2744 /*
   2745  * Function:
   2746  *      _bcm_td2_custom_hdr_match_config_add
   2747  * Purpose:
   2748  *      Add a match config, match_id will be returned after match
   2749  *      config created.
   2750  * Parameters:
   2751  *      unit          - (IN) Unit number
   2752  *      match_service - (IN) Match service type
   2753  *      config_info   - (IN) Match configuration
   2754  *      match_id      - (OUT) Match ID
   2755  * Returns:
   2756  *      BCM_E_xxx
   2757  */
   2758 STATIC int
   2759 _bcm_td2_gtp_port_match_config_add(
   2760     int unit,
   2761     bcm_switch_match_service_t match_service,
   2762     bcm_switch_match_config_info_t *config_info,
   2763     int *match_id)
   2764 {
   2765     int rv = BCM_E_NONE;
   2766     int i, table_size;
   2767     int exist_match_id;
   2768     int src_port = 0, dst_port = 0;
   2769     gtp_port_table_entry_t gtp_port_entry;
   2770 
   2771     if ((config_info->match_criteria < BCM_SWITCH_GTP_MATCH_DST_PORT) ||
   2772         (config_info->match_criteria > BCM_SWITCH_GTP_MATCH_SRC_AND_DST_PORT)) {
   2773         return BCM_E_PARAM;
   2774     }
   2775 
   2776     rv = _bcm_td2_gtp_port_match_config_find(unit, bcmSwitchMatchServiceGtp,
   2777                                              *config_info, &exist_match_id);
   2778     if (rv == BCM_E_NONE) {
   2779         return BCM_E_EXISTS;
   2780     }
   2781 
   2782     table_size = soc_mem_index_count(unit, GTP_PORT_TABLEm);
   2783     for (i = 0; i < table_size; i++) {
   2784         if (!TD2_GTP_PORT_MATCH_IS_USED(unit, i)) {
   2785             break;
   2786         }
   2787     }
   2788 
   2789     if (i == table_size) {
   2790         return BCM_E_FULL;
   2791     }
   2792 
   2793     switch (config_info->match_criteria) {
   2794     case BCM_SWITCH_GTP_MATCH_DST_PORT:
   2795         dst_port = config_info->dst_port;
   2796         src_port = 0;
   2797         break;
   2798     case BCM_SWITCH_GTP_MATCH_SRC_PORT:
   2799         src_port = config_info->src_port;
   2800         dst_port = 0;
   2801         break;
   2802     case BCM_SWITCH_GTP_MATCH_SRC_AND_DST_PORT:
   2803     case BCM_SWITCH_GTP_MATCH_SRC_OR_DST_PORT:
   2804         src_port = config_info->src_port;
   2805         dst_port = config_info->dst_port;
   2806         break;
   2807     default:
   2808         return BCM_E_PARAM;
   2809         break;
   2810     }
   2811 
   2812     sal_memset(&gtp_port_entry, 0, sizeof(gtp_port_table_entry_t));
   2813     soc_mem_field32_set(unit, GTP_PORT_TABLEm, &gtp_port_entry,
   2814                         MATCH_ENABLEf, config_info->match_criteria);
   2815     soc_mem_field32_set(unit, GTP_PORT_TABLEm, &gtp_port_entry,
   2816                         SRC_PORTf, src_port);
   2817     soc_mem_field32_set(unit, GTP_PORT_TABLEm, &gtp_port_entry,
   2818                         DST_PORTf, dst_port);
   2819     SOC_IF_ERROR_RETURN(
   2820         soc_mem_write(unit, GTP_PORT_TABLEm, MEM_BLOCK_ALL, i, &gtp_port_entry));
   2821 
   2822     TD2_GTP_PORT_MATCH(unit, i) =
   2823         sal_alloc(sizeof(_bcm_td2_gtp_port_match_t), "gtp_port_match");
   2824     if (TD2_GTP_PORT_MATCH(unit, i) == NULL) {
   2825         return BCM_E_MEMORY;
   2826     }
   2827     TD2_GTP_PORT_MATCH(unit, i)->match_criteria = config_info->match_criteria;
   2828     TD2_GTP_PORT_MATCH(unit, i)->dst_port = dst_port;
   2829     TD2_GTP_PORT_MATCH(unit, i)->src_port = src_port;
   2830     *match_id = TD2_MATCH_ID_SET(i, bcmSwitchMatchServiceGtp);
   2831     return BCM_E_NONE;
   2832 }
   2833 
   2834 /*
   2835  * Function:
   2836  *      bcm_td2_switch_match_config_add
   2837  * Purpose:
   2838  *      Add a match config to hardware.
   2839  * Parameters:
   2840  *      unit          - (IN) Unit number
   2841  *      match_service - (IN) Match service type
   2842  *      config_info   - (IN) Match configuration
   2843  *      match_id      - (OUT) Match ID
   2844  * Returns:
   2845  *      BCM_E_xxx
   2846  */
   2847 int
   2848 bcm_td2_switch_match_config_add(
   2849     int unit,
   2850     bcm_switch_match_service_t match_service,
   2851     bcm_switch_match_config_info_t *config_info,
   2852     int *match_id)
   2853 {
   2854     int rv = BCM_E_NONE;
   2855 
   2856     TD2_MATCH_INIT(unit);
   2857     TD2_MATCH_LOCK(unit);
   2858 
   2859     if (match_service == bcmSwitchMatchServiceGtp) {
   2860         rv = _bcm_td2_gtp_port_match_config_add(unit, match_service,
   2861                                                 config_info, match_id);
   2862     }
   2863 
   2864     TD2_MATCH_UNLOCK(unit);
   2865 
   2866     return rv;
   2867 }
   2868 
   2869 /*
   2870  * Function:
   2871  *     _bcm_td2_custom_hdr_match_config_delete
   2872  * Purpose:
   2873  *     Destroy a match ID by removing it from hardware.
   2874  * Parameters:
   2875  *      unit          - (IN) Unit number
   2876  *      match_service - (IN) Match service type
   2877  *      match_id      - (IN) Match ID
   2878  * Returns:
   2879  *     BCM_E_XXX
   2880  */
   2881 STATIC int
   2882 _bcm_td2_gtp_port_match_config_delete(
   2883     int unit,
   2884     bcm_switch_match_service_t match_service,
   2885     int match_id)
   2886 {
   2887     int hw_id;
   2888     gtp_port_table_entry_t gtp_port_entry;
   2889 
   2890     BCM_IF_ERROR_RETURN(
   2891         _bcm_td2_switch_match_id_check(unit, match_service, match_id));
   2892 
   2893     hw_id = TD2_MATCH_HW_ID_GET(match_id);
   2894     if (!TD2_GTP_PORT_MATCH_IS_USED(unit, hw_id)) {
   2895         return BCM_E_NOT_FOUND;
   2896     }
   2897 
   2898     sal_memset(&gtp_port_entry, 0, sizeof(gtp_port_table_entry_t));
   2899     soc_mem_field32_set(unit, GTP_PORT_TABLEm, &gtp_port_entry,
   2900                         MATCH_ENABLEf, 0);
   2901     soc_mem_field32_set(unit, GTP_PORT_TABLEm, &gtp_port_entry,
   2902                         SRC_PORTf, 0);
   2903     soc_mem_field32_set(unit, GTP_PORT_TABLEm, &gtp_port_entry,
   2904                         DST_PORTf, 0);
   2905     SOC_IF_ERROR_RETURN(
   2906         soc_mem_write(unit, GTP_PORT_TABLEm, MEM_BLOCK_ALL, hw_id,
   2907                       &gtp_port_entry));
   2908 
   2909     sal_free(TD2_GTP_PORT_MATCH(unit, hw_id));
   2910     TD2_GTP_PORT_MATCH(unit, hw_id) = NULL;
   2911 
   2912     return BCM_E_NONE;
   2913 }
   2914 
   2915 /*
   2916  * Function:
   2917  *      bcm_td2_switch_match_config_delete
   2918  * Purpose:
   2919  *      Delete a match config with the given match_id by removing it from
   2920  *      hardware and deleting the associated software state info.
   2921  * Parameters:
   2922  *      unit          - (IN) Unit number
   2923  *      match_service - (IN) Match service type
   2924  *      match_id      - (IN) Match ID
   2925  * Returns:
   2926  *      BCM_E_xxx
   2927  */
   2928 int
   2929 bcm_td2_switch_match_config_delete(
   2930     int unit,
   2931     bcm_switch_match_service_t match_service,
   2932     int match_id)
   2933 {
   2934     int rv = BCM_E_NONE;
   2935 
   2936     BCM_IF_ERROR_RETURN(
   2937         _bcm_td2_switch_match_id_check(unit, match_service, match_id));
   2938 
   2939     TD2_MATCH_INIT(unit);
   2940     TD2_MATCH_LOCK(unit);
   2941 
   2942     if (match_service == bcmSwitchMatchServiceGtp) {
   2943         rv = _bcm_td2_gtp_port_match_config_delete(
   2944                 unit, match_service, match_id);
   2945     }
   2946 
   2947     TD2_MATCH_UNLOCK(unit);
   2948 
   2949     return rv;
   2950 }
   2951 
   2952 /*
   2953  * Function:
   2954  *      bcm_td2_switch_match_config_delete_all
   2955  * Purpose:
   2956  *      Delete all match config with the given match_service.
   2957  * Parameters:
   2958  *      unit          - (IN) Unit number
   2959  *      match_service - (IN) Match service type
   2960  * Returns:
   2961  *      BCM_E_xxx
   2962  */
   2963 int
   2964 bcm_td2_switch_match_config_delete_all(
   2965     int unit,
   2966     bcm_switch_match_service_t match_service)
   2967 {
   2968     int rv = BCM_E_NONE;
   2969     int i, table_size;
   2970 
   2971     TD2_MATCH_INIT(unit);
   2972     TD2_MATCH_LOCK(unit);
   2973 
   2974     if (match_service == bcmSwitchMatchServiceGtp) {
   2975         table_size = soc_mem_index_count(unit, GTP_PORT_TABLEm);
   2976         rv = soc_mem_clear(unit, GTP_PORT_TABLEm, MEM_BLOCK_ANY, TRUE);
   2977         if (SOC_FAILURE(rv)) {
   2978             TD2_MATCH_UNLOCK(unit);
   2979             return rv;
   2980         }
   2981         for (i = 0; i < table_size; i++) {
   2982             if (TD2_GTP_PORT_MATCH_IS_USED(unit,i)) {
   2983                 sal_free(TD2_GTP_PORT_MATCH(unit,i));
   2984                 TD2_GTP_PORT_MATCH(unit,i) = NULL;
   2985             }
   2986         }
   2987     }
   2988 
   2989     TD2_MATCH_UNLOCK(unit);
   2990     return rv;
   2991 }
   2992 
   2993 /*
   2994  * Function:
   2995  *      _bcm_td2_gtp_port_match_config_get
   2996  * Purpose:
   2997  *      Get the match configuration from hardware
   2998  * Parameters:
   2999  *      unit          - (IN) Unit number
   3000  *      match_service - (IN) Match service type
   3001  *      match_id      - (IN) Match ID
   3002  *      config_info   - (OUT) Match configuration
   3003  * Returns:
   3004  *      BCM_E_xxx
   3005  */
   3006 STATIC int
   3007 _bcm_td2_gtp_port_match_config_get(
   3008     int unit,
   3009     bcm_switch_match_service_t match_service,
   3010     int match_id,
   3011     bcm_switch_match_config_info_t *config_info)
   3012 {
   3013     uint32 hw_id;
   3014 
   3015     hw_id = TD2_MATCH_HW_ID_GET(match_id);
   3016 
   3017     if (!TD2_GTP_PORT_MATCH_IS_USED(unit, hw_id)) {
   3018         return BCM_E_NOT_FOUND;
   3019     }
   3020 
   3021     bcm_switch_match_config_info_t_init(config_info);
   3022     config_info->match_criteria = TD2_GTP_PORT_MATCH(unit, hw_id)->match_criteria;
   3023     config_info->dst_port = TD2_GTP_PORT_MATCH(unit, hw_id)->dst_port;
   3024     config_info->src_port = TD2_GTP_PORT_MATCH(unit, hw_id)->src_port;
   3025 
   3026     return BCM_E_NONE;
   3027 }
   3028 
   3029 
   3030 /*
   3031  * Function:
   3032  *      bcm_td2_switch_match_config_get
   3033  * Purpose:
   3034  *      Get the configuration of the match with the given match_id.
   3035  * Parameters:
   3036  *      unit          - (IN) Unit number
   3037  *      match_service - (IN) Match service type
   3038  *      match_id      - (IN) Match ID
   3039  *      config_info   - (OUT) Match configuration
   3040  * Returns:
   3041  *      BCM_E_xxx
   3042  */
   3043 int
   3044 bcm_td2_switch_match_config_get(
   3045     int unit,
   3046     bcm_switch_match_service_t match_service,
   3047     int match_id,
   3048     bcm_switch_match_config_info_t *config_info)
   3049 {
   3050     int rv = BCM_E_NONE;
   3051 
   3052     BCM_IF_ERROR_RETURN(
   3053         _bcm_td2_switch_match_id_check(unit, match_service, match_id));
   3054 
   3055     TD2_MATCH_INIT(unit);
   3056     TD2_MATCH_LOCK(unit);
   3057 
   3058     if (match_service == bcmSwitchMatchServiceGtp) {
   3059         rv = _bcm_td2_gtp_port_match_config_get(
   3060                 unit, match_service, match_id, config_info);
   3061     }
   3062 
   3063     TD2_MATCH_UNLOCK(unit);
   3064 
   3065     return rv;
   3066 }
   3067 
   3068 /*
   3069  * Function:
   3070  *      _bcm_td2_gtp_port_match_config_set
   3071  * Purpose:
   3072  *      Set the match configuration from hardware
   3073  * Parameters:
   3074  *      unit          - (IN) Unit number
   3075  *      match_service - (IN) Match service type
   3076  *      match_id      - (IN) Match ID
   3077  *      config_info   - (IN) Match configuration
   3078  * Returns:
   3079  *      BCM_E_xxx
   3080  */
   3081 STATIC int
   3082 _bcm_td2_gtp_port_match_config_set(
   3083     int unit,
   3084     bcm_switch_match_service_t match_service,
   3085     int match_id,
   3086     bcm_switch_match_config_info_t *config_info)
   3087 {
   3088     int rv;
   3089     uint32 hw_id;
   3090     int exist_match_id;
   3091     int src_port = 0, dst_port = 0;
   3092     gtp_port_table_entry_t gtp_port_entry;
   3093 
   3094     hw_id = TD2_MATCH_HW_ID_GET(match_id);
   3095 
   3096     rv = _bcm_td2_gtp_port_match_config_find(unit, bcmSwitchMatchServiceGtp,
   3097                                              *config_info, &exist_match_id);
   3098     if (rv != BCM_E_NOT_FOUND) {
   3099         if (rv == BCM_E_NONE) {
   3100             if (exist_match_id != match_id) {
   3101                 return BCM_E_EXISTS;
   3102             } else {
   3103                 return BCM_E_NONE;
   3104             }
   3105         } else {
   3106             return rv;
   3107         }
   3108     }
   3109 
   3110     switch (config_info->match_criteria) {
   3111     case BCM_SWITCH_GTP_MATCH_DST_PORT:
   3112         dst_port = config_info->dst_port;
   3113         src_port = 0;
   3114         break;
   3115     case BCM_SWITCH_GTP_MATCH_SRC_PORT:
   3116         src_port = config_info->src_port;
   3117         dst_port = 0;
   3118         break;
   3119     case BCM_SWITCH_GTP_MATCH_SRC_AND_DST_PORT:
   3120     case BCM_SWITCH_GTP_MATCH_SRC_OR_DST_PORT:
   3121         src_port = config_info->src_port;
   3122         dst_port = config_info->dst_port;
   3123         break;
   3124     default:
   3125         return BCM_E_PARAM;
   3126         break;
   3127     }
   3128 
   3129     sal_memset(&gtp_port_entry, 0, sizeof(gtp_port_table_entry_t));
   3130     soc_mem_field32_set(unit, GTP_PORT_TABLEm, &gtp_port_entry,
   3131                         MATCH_ENABLEf, config_info->match_criteria);
   3132     soc_mem_field32_set(unit, GTP_PORT_TABLEm, &gtp_port_entry,
   3133                         SRC_PORTf, src_port);
   3134     soc_mem_field32_set(unit, GTP_PORT_TABLEm, &gtp_port_entry,
   3135                         DST_PORTf, dst_port);
   3136     SOC_IF_ERROR_RETURN(
   3137         soc_mem_write(unit, GTP_PORT_TABLEm, MEM_BLOCK_ALL,
   3138                       hw_id, &gtp_port_entry));
   3139 
   3140     if (!TD2_GTP_PORT_MATCH_IS_USED(unit, hw_id)) {
   3141         TD2_GTP_PORT_MATCH(unit, hw_id) =
   3142             sal_alloc(sizeof(_bcm_td2_gtp_port_match_t), "gtp_port_match");
   3143         if (TD2_GTP_PORT_MATCH(unit, hw_id) == NULL) {
   3144             return BCM_E_MEMORY;
   3145         }
   3146     }
   3147 
   3148     TD2_GTP_PORT_MATCH(unit, hw_id)->match_criteria = config_info->match_criteria;
   3149     TD2_GTP_PORT_MATCH(unit, hw_id)->dst_port = dst_port;
   3150     TD2_GTP_PORT_MATCH(unit, hw_id)->src_port = src_port;
   3151 
   3152     return BCM_E_NONE;
   3153 }
   3154 
   3155 /*
   3156  * Function:
   3157  *      bcm_td2_switch_match_config_set
   3158  * Purpose:
   3159  *      Set the configuration of the match with the given match_id.
   3160  * Parameters:
   3161  *      unit          - (IN) Unit number
   3162  *      match_service - (IN) Match service type
   3163  *      match_id      - (IN) Match ID
   3164  *      config_info   - (IN) Match configuration
   3165  * Returns:
   3166  *      BCM_E_xxx
   3167  */
   3168 int
   3169 bcm_td2_switch_match_config_set(
   3170     int unit,
   3171     bcm_switch_match_service_t match_service,
   3172     int match_id,
   3173     bcm_switch_match_config_info_t *config_info)
   3174 {
   3175     int rv = BCM_E_NONE;
   3176 
   3177     if ((config_info->match_criteria < BCM_SWITCH_GTP_MATCH_DST_PORT) ||
   3178         (config_info->match_criteria > BCM_SWITCH_GTP_MATCH_SRC_AND_DST_PORT)) {
   3179         return BCM_E_PARAM;
   3180     }
   3181     BCM_IF_ERROR_RETURN(
   3182         _bcm_td2_switch_match_id_check(unit, match_service, match_id));
   3183 
   3184     TD2_MATCH_INIT(unit);
   3185     TD2_MATCH_LOCK(unit);
   3186 
   3187     if (match_service == bcmSwitchMatchServiceGtp) {
   3188         rv = _bcm_td2_gtp_port_match_config_set(
   3189                 unit, match_service, match_id, config_info);
   3190     }
   3191 
   3192     TD2_MATCH_UNLOCK(unit);
   3193 
   3194     return rv;
   3195 }
   3196 
   3197 /*
   3198  * Function:
   3199  *      bcm_td2_switch_match_config_traverse
   3200  * Purpose:
   3201  *      Traverse the created match config.
   3202  * Parameters:
   3203  *      unit          - (IN) Unit number
   3204  *      match_service - (IN) Match service type
   3205  *      cb_fn         - (IN) Traverse call back function
   3206  *      user_data     - (IN) User data
   3207  * Returns:
   3208  *      BCM_E_xxx
   3209  */
   3210 int
   3211 bcm_td2_switch_match_config_traverse(
   3212     int unit,
   3213     bcm_switch_match_service_t match_service,
   3214     bcm_switch_match_config_traverse_cb cb_fn,
   3215     void *user_data)
   3216 {
   3217     uint32 match_id;
   3218     int table_size = 0, i = 0;
   3219     bcm_switch_match_config_info_t match_config;
   3220     int rv = BCM_E_NONE;
   3221 
   3222     if (cb_fn == NULL) {
   3223         return BCM_E_PARAM;
   3224     }
   3225 
   3226     TD2_MATCH_INIT(unit);
   3227     TD2_MATCH_LOCK(unit);
   3228 
   3229     table_size = soc_mem_index_count(unit, GTP_PORT_TABLEm);
   3230 
   3231     for (i = 0; i < table_size; i++) {
   3232         if (TD2_GTP_PORT_MATCH_IS_USED(unit, i)) {
   3233             match_id = TD2_MATCH_ID_SET(i, bcmSwitchMatchServiceGtp);
   3234             rv = bcm_td2_switch_match_config_get(
   3235                      unit, match_service, match_id, &match_config);
   3236             if (BCM_FAILURE(rv)) {
   3237                 TD2_MATCH_UNLOCK(unit);
   3238                 return rv;
   3239             }
   3240 
   3241             rv = cb_fn(unit, match_id, &match_config, user_data);
   3242             if (BCM_FAILURE(rv)) {
   3243                 TD2_MATCH_UNLOCK(unit);
   3244                 return rv;
   3245             }
   3246         }
   3247     }
   3248 
   3249     TD2_MATCH_UNLOCK(unit);
   3250     return BCM_E_NONE;
   3251 }
   3252 
   3253 /*
   3254  * Function:
   3255  *      bcmi_td2_l2x_freeze_mode_map_bcm2soc
   3256  * Description:
   3257  *      Conver freeze mode from BCM layer value to SOC layer value.
   3258  * Parameters:
   3259  *      bcm_mode  - (IN)  BCM layer value
   3260  *      soc_mode  - (OUT) SOC layer value
   3261  * Return Value:
   3262  *      BCM_E_XXX
   3263  */
   3264 STATIC int
   3265 bcmi_td2_l2x_freeze_mode_map_bcm2soc(int bcm_mode, int *soc_mode)
   3266 {
   3267     if (soc_mode == NULL) {
   3268         return BCM_E_PARAM;
   3269     }
   3270     switch(bcm_mode) {
   3271         case BCM_SWITCH_L2_FREEZE_MODE_PORT:
   3272             *soc_mode = SOC_L2X_FREEZE_MODE_PORT_RECONFIGURE;
   3273             break;
   3274         case BCM_SWITCH_L2_FREEZE_MODE_GLOBAL:
   3275             *soc_mode = SOC_L2X_FREEZE_MODE_GLOBAL_OVERRIDE;
   3276             break;
   3277         default:
   3278             LOG_ERROR(BSL_LS_BCM_COMMON,
   3279                       (BSL_META("Unknown freeze mode: %d\n"), bcm_mode));
   3280             return BCM_E_PARAM;
   3281     }
   3282     return BCM_E_NONE;
   3283 }
   3284 
   3285 /*
   3286  * Function:
   3287  *      bcmi_td2_l2x_freeze_mode_map_soc2bcm
   3288  * Description:
   3289  *      Conver freeze mode from SOC layer value to BCM layer value.
   3290  * Parameters:
   3291  *      soc_mode  - (IN)  SOC layer value
   3292  *      bcm_mode  - (OUT) BCM layer value
   3293  * Return Value:
   3294  *      BCM_E_XXX
   3295  */
   3296 STATIC int
   3297 bcmi_td2_l2x_freeze_mode_map_soc2bcm(int soc_mode, int *bcm_mode)
   3298 {
   3299     if (bcm_mode == NULL) {
   3300         return BCM_E_PARAM;
   3301     }
   3302     switch(soc_mode) {
   3303         case SOC_L2X_FREEZE_MODE_PORT_RECONFIGURE:
   3304             *bcm_mode = BCM_SWITCH_L2_FREEZE_MODE_PORT;
   3305             break;
   3306         case SOC_L2X_FREEZE_MODE_GLOBAL_OVERRIDE:
   3307             *bcm_mode = BCM_SWITCH_L2_FREEZE_MODE_GLOBAL;
   3308             break;
   3309         default:
   3310             LOG_ERROR(BSL_LS_BCM_COMMON,
   3311                       (BSL_META("Unknown soc freeze mode: %d\n"), soc_mode));
   3312             return BCM_E_INTERNAL;
   3313     }
   3314     return BCM_E_NONE;
   3315 }
   3316 
   3317 int
   3318 bcm_td2_l2x_freeze_mode_set(int unit, int arg)
   3319 {
   3320     int mode = 0;
   3321 
   3322     BCM_IF_ERROR_RETURN(bcmi_td2_l2x_freeze_mode_map_bcm2soc(arg, &mode));
   3323     SOC_IF_ERROR_RETURN(soc_l2x_freeze_mode_set(unit, mode));
   3324 
   3325     return BCM_E_NONE;
   3326 }
   3327 
   3328 int
   3329 bcm_td2_l2x_freeze_mode_get(int unit, int *arg)
   3330 {
   3331     int mode = 0;
   3332 
   3333     if (arg == NULL) {
   3334         return BCM_E_PARAM;
   3335     }
   3336     SOC_IF_ERROR_RETURN(soc_l2x_freeze_mode_get(unit, &mode));
   3337     BCM_IF_ERROR_RETURN(bcmi_td2_l2x_freeze_mode_map_soc2bcm(mode, arg));
   3338 
   3339     return BCM_E_NONE;
   3340 }
   3341 
   3342 /*
   3343  * Function:
   3344  *      bcm_td2_switch_l2_freeze_mode_init
   3345  * Description:
   3346  *      Set default L2 freeze mode to global override mode.
   3347  *      Global override mode is less time consuming.
   3348  * Parameters:
   3349  *      unit      - (IN) Device number
   3350  * Return Value:
   3351  *      BCM_E_XXX
   3352  */
   3353 int
   3354 bcm_td2_switch_l2_freeze_mode_init(int unit)
   3355 {
   3356     BCM_IF_ERROR_RETURN(
   3357         bcm_td2_l2x_freeze_mode_set(unit,
   3358                                     BCM_SWITCH_L2_FREEZE_MODE_GLOBAL));
   3359     return BCM_E_NONE;
   3360 }
   3361 
   3362 STATIC void
   3363 bcm_td2_ser_log_tlv2info(int unit,
   3364     void *buffer, bcm_switch_ser_log_info_t *info)
   3365 {
   3366     soc_ser_log_tlv_hdr_t *tlv_hdr = buffer;
   3367     char *data = (char*)buffer + sizeof(soc_ser_log_tlv_hdr_t);
   3368     soc_ser_log_tlv_memory_t *tlv_mem;
   3369     soc_ser_log_tlv_register_t *tlv_reg;
   3370     soc_ser_log_tlv_generic_t *tlv_generic;
   3371     soc_ser_log_flag_t flags;
   3372     soc_mem_t mem = INVALIDm;
   3373     int entry_dw = 0;
   3374 
   3375     LOG_VERBOSE(BSL_LS_BCM_COMMON,
   3376                 (BSL_META("type: %d\n"), tlv_hdr->type));
   3377 
   3378     switch (tlv_hdr->type) {
   3379     case SOC_SER_LOG_TLV_MEMORY:
   3380         tlv_mem = (soc_ser_log_tlv_memory_t*)data;
   3381         info->flags |= BCM_SWITCH_SER_LOG_MEM;
   3382         info->mem_reg = tlv_mem->memory;
   3383         info->index = tlv_mem->index;
   3384         if (SOC_MEM_IS_VALID(unit, info->mem_reg)) {
   3385             sal_memcpy(info->name, SOC_MEM_NAME(unit, info->mem_reg),
   3386                        strlen(SOC_MEM_NAME(unit, info->mem_reg)) + 1);
   3387         }
   3388         break;
   3389     case SOC_SER_LOG_TLV_REGISTER:
   3390         tlv_reg = (soc_ser_log_tlv_register_t*)data;
   3391         info->flags |= BCM_SWITCH_SER_LOG_REG;
   3392         info->mem_reg = tlv_reg->reg;
   3393         info->index = tlv_reg->index;
   3394         info->port = tlv_reg->port;
   3395         if (SOC_REG_IS_VALID(unit, info->mem_reg)) {
   3396             sal_memcpy(info->name, SOC_REG_NAME(unit, info->mem_reg),
   3397                        strlen(SOC_REG_NAME(unit, info->mem_reg)) + 1);
   3398         }
   3399         break;
   3400     case SOC_SER_LOG_TLV_CONTENTS:
   3401         mem = info->mem_reg;
   3402         if (SOC_MEM_IS_VALID(unit, mem)) {
   3403             entry_dw = soc_mem_entry_words(unit, mem);
   3404         }
   3405         if (entry_dw != 0) {
   3406             info->flags |= BCM_SWITCH_SER_LOG_ENTRY;
   3407             sal_memcpy(info->entry_data, data, entry_dw * 4);
   3408         }
   3409         break;
   3410     case SOC_SER_LOG_TLV_CACHE:
   3411         mem = info->mem_reg;
   3412         if (SOC_MEM_IS_VALID(unit, mem)) {
   3413             entry_dw = soc_mem_entry_words(unit, mem);
   3414         }
   3415         if (entry_dw != 0) {
   3416             info->flags |= BCM_SWITCH_SER_LOG_CACHE;
   3417             sal_memcpy(info->cache_data, data, entry_dw * 4);
   3418         }
   3419         break;
   3420     case SOC_SER_LOG_TLV_GENERIC:
   3421         tlv_generic = (soc_ser_log_tlv_generic_t*)data;
   3422         flags = tlv_generic->flags;
   3423 
   3424         info->flags |= (flags & SOC_SER_LOG_FLAG_MULTIBIT) ?
   3425                         BCM_SWITCH_SER_LOG_MULTI:0;
   3426         info->time = tlv_generic->time;
   3427         info->addr = tlv_generic->address;
   3428         info->instance = tlv_generic->inst;
   3429         info->pipe = tlv_generic->pipe_num;
   3430         switch(tlv_generic->block_type) {
   3431             case SOC_BLK_MMU:
   3432                 info->block_type = bcmSwitchBlockTypeMmu;
   3433                 break;
   3434             case SOC_BLK_MMU_GLB:
   3435                 info->block_type = bcmSwitchBlockTypeMmuGlb;
   3436                 break;
   3437             case SOC_BLK_MMU_XPE:
   3438                 info->block_type = bcmSwitchBlockTypeMmuXpe;
   3439                 break;
   3440             case SOC_BLK_MMU_SC:
   3441                 info->block_type = bcmSwitchBlockTypeMmuSc;
   3442                 break;
   3443             case SOC_BLK_MMU_SED:
   3444                 info->block_type = bcmSwitchBlockTypeMmuSed;
   3445                 break;
   3446             case SOC_BLK_IPIPE:
   3447                 info->block_type = bcmSwitchBlockTypeIpipe;
   3448                 break;
   3449             case SOC_BLK_EPIPE:
   3450                 info->block_type = bcmSwitchBlockTypeEpipe;
   3451                 break;
   3452             case SOC_BLK_PGW_CL:
   3453                 info->block_type = bcmSwitchBlockTypePgw;
   3454                 break;
   3455             case SOC_BLK_CLPORT:
   3456                 info->block_type = bcmSwitchBlockTypeClport;
   3457                 break;
   3458             case SOC_BLK_XLPORT:
   3459                 info->block_type = bcmSwitchBlockTypeXlport;
   3460                 break;
   3461             case SOC_BLK_MACSEC:
   3462                 info->block_type = bcmSwitchBlockTypeMacsec;
   3463                 break;
   3464             default:
   3465                 LOG_CLI((BSL_META_U(unit, "\tUnknown block type\n")));
   3466                 break;
   3467         }
   3468 
   3469         switch (tlv_generic->parity_type) {
   3470             case SOC_PARITY_TYPE_PARITY:
   3471                 info->error_type = bcmSwitchErrorTypeParity;
   3472                 break;
   3473             case SOC_PARITY_TYPE_ECC:
   3474                 if (flags & SOC_SER_LOG_FLAG_DOUBLEBIT) {
   3475                     info->error_type = bcmSwitchErrorTypeEccDoubleBit;
   3476                 } else {
   3477                     info->error_type = bcmSwitchErrorTypeEccSingleBit;
   3478                 }
   3479                 break;
   3480             default:
   3481                 info->error_type = bcmSwitchErrorTypeUnknown;
   3482                 break;
   3483         }
   3484 
   3485         info->flags |= tlv_generic->corrected ? BCM_SWITCH_SER_LOG_CORRECTED:0;
   3486 
   3487         switch (tlv_generic->ser_response_flag) {
   3488             case SOC_MEM_FLAG_SER_ENTRY_CLEAR:
   3489                 info->correction_type = bcmSwitchCorrectTypeEntryClear;
   3490                 break;
   3491             case SOC_MEM_FLAG_SER_ECC_CORRECTABLE:
   3492             case SOC_MEM_FLAG_SER_CACHE_RESTORE:
   3493             case SOC_MEM_FLAG_SER_WRITE_CACHE_RESTORE:
   3494                 info->correction_type = bcmSwitchCorrectTypeCacheRestore;
   3495                 break;
   3496             case SOC_MEM_FLAG_SER_SPECIAL:
   3497                 info->correction_type = bcmSwitchCorrectTypeSpecial;
   3498                 break;
   3499             default:
   3500                 info->correction_type = bcmSwitchCorrectTypeNoAction;
   3501                 break;
   3502         }
   3503         if (TRUE == tlv_generic->hw_cache) {
   3504             info->correction_type = bcmSwitchCorrectTypeHwCacheRestore;
   3505         }
   3506         break;
   3507     default:
   3508         LOG_CLI((BSL_META_U(unit, "\tUnknown type\n")));
   3509         break;
   3510     }
   3511 
   3512     return;
   3513 }
   3514 
   3515 
   3516 STATIC int
   3517 bcm_td2_ser_log_entry2info(int unit,
   3518     void *buffer, bcm_switch_ser_log_info_t *info)
   3519 {
   3520     soc_ser_log_tlv_hdr_t *tlv_hdr = buffer;
   3521 
   3522     while (tlv_hdr->type != 0) {
   3523         bcm_td2_ser_log_tlv2info(unit, (char*)tlv_hdr, info);
   3524         tlv_hdr = (soc_ser_log_tlv_hdr_t*)((char*)tlv_hdr +
   3525             tlv_hdr->length + sizeof(soc_ser_log_tlv_hdr_t));
   3526     }
   3527 
   3528     return BCM_E_NONE;
   3529 }
   3530 
   3531 /*
   3532  * Function:
   3533  *      bcm_td2_switch_ser_log_info_get
   3534  * Purpose:
   3535  *     To get ser log info.
   3536  * Parameters:
   3537  *      unit - (IN) Unit number.
   3538  *      id - (IN) log id.
   3539  *      info - (OUT) ser log info.
   3540  * Returns:
   3541  *      BCM_E_xxx
   3542  * Notes:
   3543  */
   3544 int
   3545 bcm_td2_switch_ser_log_info_get(int unit,
   3546     int id, bcm_switch_ser_log_info_t *info)
   3547 {
   3548     int rv = BCM_E_NONE;
   3549     int size;
   3550     char *buffer;
   3551 
   3552     if (NULL == info) {
   3553         return (BCM_E_PARAM);
   3554     }
   3555 
   3556     buffer = sal_alloc(_SOC_SER_LOG_BUFFER_SIZE, "ser log info");
   3557     if (NULL == buffer) {
   3558         return (BCM_E_MEMORY);
   3559     }
   3560 
   3561     rv = soc_ser_log_get_entry_size(unit, id, &size);
   3562     if ((size <= 0) || (size > _SOC_SER_LOG_BUFFER_SIZE)
   3563         || (BCM_E_NONE != rv)) {
   3564         LOG_ERROR(BSL_LS_BCM_COMMON,
   3565                   (BSL_META("Log %d not found!\n"), id));
   3566         rv = BCM_E_NOT_FOUND;
   3567         goto error;
   3568     }
   3569 
   3570     rv = soc_ser_log_get_entry(unit, id, size, buffer);
   3571     if (BCM_FAILURE(rv)) {
   3572         goto error;
   3573     }
   3574 
   3575     rv = bcm_td2_ser_log_entry2info(unit, buffer, info);
   3576 error:
   3577     if (NULL != buffer) {
   3578         sal_free(buffer);
   3579     }
   3580     return rv;
   3581 }
   3582 
   3583 /*
   3584  * Map BCM layer block type, SER error type, SER error correction type to SOC layer ones
   3585  */
   3586 STATIC int
   3587 bcm_td2_ser_error_stat_type_mapping(int unit,
   3588     bcm_switch_ser_error_stat_type_t stat_type,
   3589     soc_ser_block_type_t *btype,
   3590     soc_ser_error_type_t *etype,
   3591     soc_ser_correction_type_t *ctype)
   3592 {
   3593     soc_ser_block_type_t btype_tmp;
   3594     soc_ser_error_type_t etype_tmp;
   3595     soc_ser_correction_type_t ctype_tmp;
   3596 
   3597     switch (stat_type.block_type) {
   3598         case bcmSwitchBlockTypeAll:
   3599             btype_tmp = SocSerBlockTypeAll;
   3600             break;
   3601         case bcmSwitchBlockTypeMmu:
   3602             btype_tmp = SocSerBlockTypeMMU;
   3603             break;
   3604         case bcmSwitchBlockTypeMmuGlb:
   3605             btype_tmp = SocSerBlockTypeMMU_GLB;
   3606             break;
   3607         case bcmSwitchBlockTypeMmuXpe:
   3608             btype_tmp = SocSerBlockTypeMMU_XPE;
   3609             break;
   3610         case bcmSwitchBlockTypeMmuSc:
   3611             btype_tmp = SocSerBlockTypeMMU_SC;
   3612             break;
   3613         case bcmSwitchBlockTypeMmuSed:
   3614             btype_tmp = SocSerBlockTypeMMU_SED;
   3615             break;
   3616         case bcmSwitchBlockTypeIpipe:
   3617             btype_tmp = SocSerBlockTypeIPIPE;
   3618             break;
   3619         case bcmSwitchBlockTypeEpipe:
   3620             btype_tmp = SocSerBlockTypeEPIPE;
   3621             break;
   3622         case bcmSwitchBlockTypePgw:
   3623             btype_tmp = SocSerBlockTypePGW;
   3624             break;
   3625         case bcmSwitchBlockTypeClport:
   3626             btype_tmp = SocSerBlockTypeCLPORT;
   3627             break;
   3628         case bcmSwitchBlockTypeXlport:
   3629             btype_tmp = SocSerBlockTypeXLPORT;
   3630             break;
   3631         case bcmSwitchBlockTypeMacsec:
   3632             btype_tmp = SocSerBlockTypeMACSEC;
   3633             break;
   3634         case bcmSwitchBlockTypeCount:
   3635             btype_tmp = SocSerBlockTypeCount;
   3636             break;
   3637         default:
   3638             return (BCM_E_PARAM);
   3639     }
   3640 
   3641     switch (stat_type.error_type) {
   3642         case bcmSwitchErrorTypeAll:
   3643             etype_tmp = SocSerErrorTypeAll;
   3644             break;
   3645         case bcmSwitchErrorTypeUnknown:
   3646             etype_tmp = SocSerErrorTypeUnknown;
   3647             break;
   3648         case bcmSwitchErrorTypeParity:
   3649             etype_tmp = SocSerErrorTypeParity;
   3650             break;
   3651         case bcmSwitchErrorTypeEccSingleBit:
   3652             etype_tmp = SocSerErrorTypeEccSingleBit;
   3653             break;
   3654         case bcmSwitchErrorTypeEccDoubleBit:
   3655             etype_tmp = SocSerErrorTypeEccDoubleBit;
   3656             break;
   3657         case bcmSwitchErrorTypeCount:
   3658             etype_tmp = SocSerErrorTypeCount;
   3659             break;
   3660         default:
   3661             return (BCM_E_PARAM);
   3662     }
   3663 
   3664     switch (stat_type.correction_type) {
   3665         case bcmSwitchCorrectTypeAll:
   3666             ctype_tmp = SocSerCorrectTypeAll;
   3667             break;
   3668         case bcmSwitchCorrectTypeNoAction:
   3669             ctype_tmp = SocSerCorrectTypeNoAction;
   3670             break;
   3671         case bcmSwitchCorrectTypeFailToCorrect:
   3672             ctype_tmp = SocSerCorrectTypeFailedToCorrect;
   3673             break;
   3674         case bcmSwitchCorrectTypeEntryClear:
   3675             ctype_tmp = SocSerCorrectTypeEntryClear;
   3676             break;
   3677         case bcmSwitchCorrectTypeCacheRestore:
   3678             ctype_tmp = SocSerCorrectTypeCacheRestore;
   3679             break;
   3680         case bcmSwitchCorrectTypeHwCacheRestore:
   3681             ctype_tmp = socSerCorrectTypeHwCacheRestore;
   3682             break;
   3683         case bcmSwitchCorrectTypeSpecial:
   3684             ctype_tmp = SocSerCorrectTypeSpecial;
   3685             break;
   3686         case bcmSwitchCorrectTypeCount:
   3687             ctype_tmp = SocSerCorrectTypeCount;
   3688             break;
   3689         default:
   3690             return (BCM_E_PARAM);
   3691     }
   3692 
   3693     *btype = btype_tmp;
   3694     *etype = etype_tmp;
   3695     *ctype = ctype_tmp;
   3696     return (BCM_E_NONE);
   3697 }
   3698 
   3699 STATIC int
   3700 bcm_td2_ser_error_count_sum(int unit,
   3701     uint32 flags,
   3702     soc_ser_block_type_t btype,
   3703     soc_ser_error_type_t etype,
   3704     soc_ser_correction_type_t ctype,
   3705     uint32 *value)
   3706 {
   3707     int rv = BCM_E_NONE;
   3708     uint32 value_tmp = 0;
   3709 
   3710     /* All block types */
   3711     if (btype == SocSerBlockTypeAll &&
   3712         etype != SocSerErrorTypeAll &&
   3713         ctype != SocSerCorrectTypeAll) {
   3714         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3715             SOC_SER_TCAM_ERROR_STAT_ALL_BTYPE_SUM(unit, etype, ctype, value_tmp);
   3716         } else {
   3717             SOC_SER_ERROR_STAT_ALL_BTYPE_SUM(unit, etype, ctype, value_tmp);
   3718         }
   3719     } /* All error types */
   3720     else if (btype != SocSerBlockTypeAll &&
   3721              etype == SocSerErrorTypeAll &&
   3722              ctype != SocSerCorrectTypeAll) {
   3723         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3724             SOC_SER_TCAM_ERROR_STAT_ALL_ETYPE_SUM(unit, btype, ctype, value_tmp);
   3725         } else {
   3726             SOC_SER_ERROR_STAT_ALL_ETYPE_SUM(unit, btype, ctype, value_tmp);
   3727         }
   3728     } /* All correction types */
   3729     else if (btype != SocSerBlockTypeAll &&
   3730              etype != SocSerErrorTypeAll &&
   3731              ctype == SocSerCorrectTypeAll) {
   3732         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3733             SOC_SER_TCAM_ERROR_STAT_ALL_CTYPE_SUM(unit, btype, etype, value_tmp);
   3734         } else {
   3735             SOC_SER_ERROR_STAT_ALL_CTYPE_SUM(unit, btype, etype, value_tmp);
   3736         }
   3737     } /* All block and error types*/
   3738     else if (btype == SocSerBlockTypeAll &&
   3739              etype == SocSerErrorTypeAll &&
   3740              ctype != SocSerCorrectTypeAll) {
   3741         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3742             SOC_SER_TCAM_ERROR_STAT_ALL_BTYPE_ETYPE_SUM(unit, ctype, value_tmp);
   3743         } else {
   3744             SOC_SER_ERROR_STAT_ALL_BTYPE_ETYPE_SUM(unit, ctype, value_tmp);
   3745         }
   3746     } /* All block and correction types */
   3747     else if (btype == SocSerBlockTypeAll &&
   3748              etype != SocSerErrorTypeAll &&
   3749              ctype == SocSerCorrectTypeAll) {
   3750         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3751             SOC_SER_TCAM_ERROR_STAT_ALL_BTYPE_CTYPE_SUM(unit, etype, value_tmp);
   3752         } else {
   3753             SOC_SER_ERROR_STAT_ALL_BTYPE_CTYPE_SUM(unit, etype, value_tmp);
   3754         }
   3755     } /* All error and correction types */
   3756     else if (btype != SocSerBlockTypeAll &&
   3757              etype == SocSerErrorTypeAll &&
   3758              ctype == SocSerCorrectTypeAll) {
   3759         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3760             SOC_SER_TCAM_ERROR_STAT_ALL_ETYPE_CTYPE_SUM(unit, btype, value_tmp);
   3761         } else {
   3762             SOC_SER_ERROR_STAT_ALL_ETYPE_CTYPE_SUM(unit, btype, value_tmp);
   3763         }
   3764     } /* All block, error and correction types */
   3765     else if (btype == SocSerBlockTypeAll &&
   3766              etype == SocSerErrorTypeAll &&
   3767              ctype == SocSerCorrectTypeAll) {
   3768         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3769             SOC_SER_TCAM_ERROR_STAT_ALL_BTYPE_ETYPE_CTYPE_SUM(unit, value_tmp);
   3770         } else {
   3771             SOC_SER_ERROR_STAT_ALL_BTYPE_ETYPE_CTYPE_SUM(unit, value_tmp);
   3772         }
   3773     } else {
   3774         return (BCM_E_PARAM);
   3775     }
   3776 
   3777     *value = value_tmp;
   3778     return rv;
   3779 }
   3780 
   3781 /*
   3782  * Function:
   3783  *      bcm_td2_switch_ser_error_stat_get
   3784  * Purpose:
   3785  *     Get SER error statistics for specified statistics type.
   3786  * Parameters:
   3787  *      unit - (IN) Unit number.
   3788  *      type - (IN) SER error statistics type.
   3789  *      value - (OUT) Number of errors
   3790  * Returns:
   3791  *      BCM_E_xxx
   3792  * Notes:
   3793  */
   3794 int
   3795 bcm_td2_switch_ser_error_stat_get(int unit,
   3796     bcm_switch_ser_error_stat_type_t stat_type,
   3797     uint32 *value)
   3798 {
   3799     int rv = BCM_E_NONE;
   3800     soc_ser_block_type_t btype;
   3801     soc_ser_error_type_t etype;
   3802     soc_ser_correction_type_t ctype;
   3803 
   3804     /* Parameter boundary check */
   3805     if (stat_type.block_type >= bcmSwitchBlockTypeCount ||
   3806         stat_type.error_type >= bcmSwitchErrorTypeCount ||
   3807         stat_type.correction_type >= bcmSwitchCorrectTypeCount ||
   3808         stat_type.block_type < bcmSwitchBlockTypeAll ||
   3809         stat_type.error_type < bcmSwitchErrorTypeAll ||
   3810         stat_type.correction_type < bcmSwitchCorrectTypeAll) {
   3811         return (BCM_E_PARAM);
   3812     }
   3813 
   3814     BCM_IF_ERROR_RETURN
   3815         (bcm_td2_ser_error_stat_type_mapping(unit, stat_type, &btype,
   3816                                              &etype, &ctype));
   3817     if (btype == SocSerBlockTypeAll ||
   3818         etype == SocSerErrorTypeAll ||
   3819         ctype == SocSerCorrectTypeAll) {
   3820         /* Sum error count based on type */
   3821         rv = bcm_td2_ser_error_count_sum(unit, stat_type.flags,
   3822                                          btype, etype, ctype, value);
   3823         return rv;
   3824     }
   3825 
   3826     if (BCM_SWITCH_SER_STAT_TCAM & stat_type.flags) {
   3827         *value = SOC_SER_TCAM_ERROR_STAT(unit, btype, etype, ctype);
   3828     } else {
   3829         *value = SOC_SER_ERROR_STAT(unit, btype, etype, ctype);
   3830     }
   3831 
   3832     return rv;
   3833 }
   3834 
   3835 STATIC int
   3836 bcm_td2_ser_error_clear_by_type(int unit,
   3837     uint32 flags,
   3838     soc_ser_block_type_t btype,
   3839     soc_ser_error_type_t etype,
   3840     soc_ser_correction_type_t ctype)
   3841 {
   3842     int rv = BCM_E_NONE;
   3843 
   3844     /* All block types */
   3845     if (btype == SocSerBlockTypeAll &&
   3846         etype != SocSerErrorTypeAll &&
   3847         ctype != SocSerCorrectTypeAll) {
   3848         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3849             SOC_SER_TCAM_ERROR_STAT_ALL_BTYPE_CLEAR(unit, etype, ctype);
   3850         } else {
   3851             SOC_SER_ERROR_STAT_ALL_BTYPE_CLEAR(unit, etype, ctype);
   3852         }
   3853     } /* All error types */
   3854     else if (btype != SocSerBlockTypeAll &&
   3855              etype == SocSerErrorTypeAll &&
   3856              ctype != SocSerCorrectTypeAll) {
   3857         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3858             SOC_SER_TCAM_ERROR_STAT_ALL_ETYPE_CLEAR(unit, btype, ctype);
   3859         } else {
   3860             SOC_SER_ERROR_STAT_ALL_ETYPE_CLEAR(unit, btype, ctype);
   3861         }
   3862     } /* All correction types */
   3863     else if (btype != SocSerBlockTypeAll &&
   3864              etype != SocSerErrorTypeAll &&
   3865              ctype == SocSerCorrectTypeAll) {
   3866         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3867             SOC_SER_TCAM_ERROR_STAT_ALL_CTYPE_CLEAR(unit, btype, etype);
   3868         } else {
   3869             SOC_SER_ERROR_STAT_ALL_CTYPE_CLEAR(unit, btype, etype);
   3870         }
   3871     } /* All block and error types*/
   3872     else if (btype == SocSerBlockTypeAll &&
   3873              etype == SocSerErrorTypeAll &&
   3874              ctype != SocSerCorrectTypeAll) {
   3875         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3876             SOC_SER_TCAM_ERROR_STAT_ALL_BTYPE_ETYPE_CLEAR(unit, ctype);
   3877         } else {
   3878             SOC_SER_ERROR_STAT_ALL_BTYPE_ETYPE_CLEAR(unit, ctype);
   3879         }
   3880     } /* All block and correction types */
   3881     else if (btype == SocSerBlockTypeAll &&
   3882              etype != SocSerErrorTypeAll &&
   3883              ctype == SocSerCorrectTypeAll) {
   3884         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3885             SOC_SER_TCAM_ERROR_STAT_ALL_BTYPE_CTYPE_CLEAR(unit, etype);
   3886         } else {
   3887             SOC_SER_ERROR_STAT_ALL_BTYPE_CTYPE_CLEAR(unit, etype);
   3888         }
   3889     } /* All error and correction types */
   3890     else if (btype != SocSerBlockTypeAll &&
   3891              etype == SocSerErrorTypeAll &&
   3892              ctype == SocSerCorrectTypeAll) {
   3893         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3894             SOC_SER_TCAM_ERROR_STAT_ALL_ETYPE_CTYPE_CLEAR(unit, btype);
   3895         } else {
   3896             SOC_SER_ERROR_STAT_ALL_ETYPE_CTYPE_CLEAR(unit, btype);
   3897         }
   3898     } /* All block, error and correction types */
   3899     else if (btype == SocSerBlockTypeAll &&
   3900              etype == SocSerErrorTypeAll &&
   3901              ctype == SocSerCorrectTypeAll) {
   3902         if (BCM_SWITCH_SER_STAT_TCAM & flags) {
   3903             SOC_SER_TCAM_ERROR_STAT_ALL_BTYPE_ETYPE_CTYPE_CLEAR(unit);
   3904         } else {
   3905             SOC_SER_ERROR_STAT_ALL_BTYPE_ETYPE_CTYPE_CLEAR(unit);
   3906         }
   3907     } else {
   3908         return (BCM_E_PARAM);
   3909     }
   3910     return rv;
   3911 }
   3912 
   3913 /*
   3914  * Function:
   3915  *      bcm_td2_switch_ser_error_stat_clear
   3916  * Purpose:
   3917  *     Clear SER error statistics for specified statistics type.
   3918  * Parameters:
   3919  *      unit - (IN) Unit number.
   3920  *      type - (IN) SER error statistics type.
   3921  * Returns:
   3922  *      BCM_E_xxx
   3923  * Notes:
   3924  */
   3925 int
   3926 bcm_td2_switch_ser_error_stat_clear(int unit,
   3927     bcm_switch_ser_error_stat_type_t stat_type)
   3928 {
   3929     int rv = BCM_E_NONE;
   3930     soc_ser_block_type_t btype;
   3931     soc_ser_error_type_t etype;
   3932     soc_ser_correction_type_t ctype;
   3933 
   3934     /* Parameter boundary check */
   3935     if (stat_type.block_type >= bcmSwitchBlockTypeCount ||
   3936         stat_type.error_type >= bcmSwitchErrorTypeCount ||
   3937         stat_type.correction_type >= bcmSwitchCorrectTypeCount ||
   3938         stat_type.block_type < bcmSwitchBlockTypeAll ||
   3939         stat_type.error_type < bcmSwitchErrorTypeAll ||
   3940         stat_type.correction_type < bcmSwitchCorrectTypeAll) {
   3941         return (BCM_E_PARAM);
   3942     }
   3943 
   3944     BCM_IF_ERROR_RETURN
   3945         (bcm_td2_ser_error_stat_type_mapping(unit, stat_type, &btype,
   3946                                              &etype, &ctype));
   3947 
   3948     if (btype == SocSerBlockTypeAll ||
   3949         etype == SocSerErrorTypeAll ||
   3950         ctype == SocSerCorrectTypeAll) {
   3951         /* Clear error count based on type */
   3952         SOC_SER_ERR_STAT_LOCK(unit);
   3953         rv = bcm_td2_ser_error_clear_by_type(unit, stat_type.flags, btype,
   3954                                              etype, ctype);
   3955         SOC_SER_ERR_STAT_UNLOCK(unit);
   3956         return rv;
   3957     }
   3958 
   3959     SOC_SER_ERR_STAT_LOCK(unit);
   3960     if (BCM_SWITCH_SER_STAT_TCAM & stat_type.flags) {
   3961         SOC_SER_TCAM_ERROR_STAT_CLEAR(unit, btype, etype, ctype);
   3962     } else {
   3963         SOC_SER_ERROR_STAT_CLEAR(unit, btype, etype, ctype);
   3964     }
   3965     SOC_SER_ERR_STAT_UNLOCK(unit);
   3966 
   3967     return rv;
   3968 }
   3969 
   3970 #endif              /* defined(BCM_TRIDENT2_SUPPORT) */