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

cancun.c (105767B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        cancun.c
      8  * Purpose:     CANCUN API and routines
      9  *              This module provides API's for all CANCUN related operations
     10  */
     11 #include <sal/core/libc.h>
     12 #include <shared/bsl.h>
     13 
     14 #include <bcm/types.h>
     15 #include <soc/drv.h>
     16 #include <soc/error.h>
     17 #include <soc/cmic.h>
     18 #include <soc/util.h>
     19 #include <soc/debug.h>
     20 #ifdef BCM_CMICM_SUPPORT
     21 #include <soc/cmicm.h>
     22 #endif
     23 #include <soc/esw/cancun.h>
     24 
     25 #ifdef BCM_WARM_BOOT_SUPPORT
     26 #include <soc/scache.h>
     27 #endif
     28 
     29 #include <soc/devids.h>
     30 
     31 /* Environment switch */
     32 #define _PCID_TEST 0
     33 
     34 /* Local defines */
     35 #define BYTES_PER_UINT32    (sizeof(uint32))
     36 
     37 /*
     38  * Variable:
     39  *      soc_cancun_info
     40  * Purpose:
     41  *      One entry for each SOC device containing port information
     42  *      for that device. 
     43  */
     44 static soc_cancun_t *soc_cancun_info[BCM_MAX_NUM_UNITS];
     45 
     46 /* Local functions */
     47 static int _soc_cancun_alloc(soc_cancun_t** cancun);
     48 static int _soc_cancun_file_pio_load(int unit, uint8* buf, int buf_words);
     49 static int _soc_cancun_file_cmh_load(int unit, uint8* buf, int buf_words);
     50 static int _soc_cancun_file_cch_load(int unit, uint8* buf, int buf_words);
     51 static int _soc_cancun_file_ceh_load(int unit, uint8* buf, int buf_words);
     52 static int _soc_cancun_cih_load(int unit, uint8* buf, int num_data_blobs);
     53 static int _soc_cancun_cih_pio_load(int unit, uint8* buf, int length,
     54                                     uint32 flags);
     55 static int _soc_cancun_cih_tcam_write(int unit, uint8 *buf);
     56 static int _soc_cancun_hash(soc_cancun_hash_table_t* t, uint32 mem,
     57                             soc_field_t field, uint32* key);
     58 static uint32* _soc_cancun_hash_find_entry(uint32 *hash_entry, uint32 src_mem,
     59                                            uint32 src_field, int src_app);
     60 static int _soc_cancun_cmh_list_update(soc_cancun_cmh_t *cmh);
     61 static int _soc_cancun_memcpy_letohl(uint32 *des, uint32 *src, uint32 word_len);
     62 static int _soc_cancun_enum_check(int unit, int regmem, int enum_val, int enum_type);
     63 static int _soc_cancun_cih_mem_load(int unit, uint8 *buf);
     64 static int _soc_cancun_cch_dest_set (int unit,
     65                soc_cancun_cch_map_t *cch_map, uint64 data);
     66 static int _soc_cancun_cch_dest_set_with_idx (int unit,
     67                soc_cancun_cch_map_t *cch_map, uint64 data, uint32 val_idx);
     68 
     69 
     70 /* ZLIB CRC-32 table*/
     71 static uint32 soc_crc32_tab[] = {
     72     0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
     73     0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
     74     0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
     75     0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
     76     0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
     77     0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
     78     0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
     79     0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
     80     0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
     81     0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
     82     0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
     83     0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
     84     0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
     85     0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
     86     0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
     87     0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
     88     0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
     89     0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
     90     0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
     91     0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
     92     0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
     93     0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
     94     0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
     95     0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
     96     0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
     97     0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
     98     0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
     99     0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
    100     0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
    101     0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
    102     0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
    103     0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
    104     0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
    105     0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
    106     0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
    107     0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
    108     0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
    109     0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
    110     0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
    111     0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
    112     0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
    113     0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
    114     0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
    115     0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
    116     0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
    117     0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
    118     0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
    119     0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
    120     0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
    121     0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
    122     0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
    123     0x2d02ef8dL
    124 };
    125 
    126 /*
    127  * Function:
    128  *      soc_cancun_init
    129  * Purpose:
    130  *      Initialization sequence for loading all applied CANCUN loadable files
    131  * Parameters:
    132  *      unit  - (IN) Unit ID
    133  * Returns:
    134  *      SOC_E_NONE
    135  *      SOC_E_FAIL
    136 */
    137 int soc_cancun_init (uint32 unit) {
    138     soc_cancun_t* cc = soc_cancun_info[unit];
    139     char *cancun_path;
    140     uint32 val, cancun_path_len = 0;
    141 
    142     if(cc == NULL) {
    143 
    144         if(_soc_cancun_alloc(&cc)) {
    145             return SOC_E_MEMORY;
    146         }
    147 
    148         cc->unit = unit;
    149         cc->flags = SOC_CANCUN_FLAG_LOAD_DEFAULT_ALL;
    150 
    151         cancun_path = soc_property_get_str(unit, "cancun_dir");
    152         if(cancun_path != NULL) {
    153             cancun_path_len = sal_strlen(cancun_path);
    154             if(cancun_path_len < CANCUN_FILENAME_SIZE) {
    155                 sal_memcpy(cc->default_path, cancun_path, cancun_path_len);
    156             }
    157         } else {
    158             sal_memset(cc->default_path, 0, CANCUN_FILENAME_SIZE);
    159         }
    160 
    161         val = soc_property_get(unit, "cancun_load_skip", 0);
    162         cc->flags &= (val & SOC_PROPERTY_CANCUN_LOAD_SKIP_CIH)?
    163                      (~SOC_CANCUN_FLAG_LOAD_DEFAULT_CIH) : (~0);
    164         cc->flags &= (val & SOC_PROPERTY_CANCUN_LOAD_SKIP_CMH)?
    165                      (~SOC_CANCUN_FLAG_LOAD_DEFAULT_CMH) : (~0);
    166         cc->flags &= (val & SOC_PROPERTY_CANCUN_LOAD_SKIP_CCH)?
    167                      (~SOC_CANCUN_FLAG_LOAD_DEFAULT_CCH) : (~0);
    168         cc->flags &= (val & SOC_PROPERTY_CANCUN_LOAD_SKIP_CFH)?
    169                      (~SOC_CANCUN_FLAG_LOAD_DEFAULT_CFH) : (~0);
    170         cc->flags &= (val & SOC_PROPERTY_CANCUN_LOAD_SKIP_CEH)?
    171                      (~SOC_CANCUN_FLAG_LOAD_DEFAULT_CEH) : (~0);
    172         val = soc_property_get(unit, "cancun_debug_mode", 0);
    173         cc->flags |= (val & SOC_PROPERTY_CANCUN_DEBUG_MODE)?
    174                      SOC_CANCUN_FLAG_DEBUG_MODE: 0;
    175         cc->flags |= (val & SOC_PROPERTY_CANCUN_FILE_VALIDITY)?
    176                      SOC_CANCUN_FLAG_SKIP_VALIDITY: 0;
    177         cc->flags |= SOC_CANCUN_FLAG_INITIALIZED;
    178         soc_cancun_info[unit] = cc;
    179     }
    180 
    181     if((cc->flags & SOC_CANCUN_FLAG_INITIALIZED) == 0) {
    182         return SOC_E_INIT;
    183     }
    184 
    185 #ifdef BCM_WARM_BOOT_SUPPORT
    186         if (!SOC_WARM_BOOT(unit)) {
    187             (void)soc_cancun_scache_alloc(unit);
    188         }
    189 #endif /* BCM_WARM_BOOT_SUPPORT */
    190 
    191     return SOC_E_NONE;
    192 }
    193 
    194 /*
    195  * Function:
    196  *      soc_cancun_deinit
    197  * Purpose:
    198  *      De-initialization CANCUN control structures
    199  * Parameters:
    200  *      unit  - (IN) Unit ID
    201  * Returns:
    202  *      SOC_E_NONE
    203  *      SOC_E_FAIL
    204 */
    205 void soc_cancun_deinit(uint32 unit) {
    206     soc_cancun_t* cc = soc_cancun_info[unit];
    207 
    208     LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
    209         "De-initialize CANCUN for UNIT %d\n"), unit));
    210 
    211     if(cc != NULL) {
    212         if(cc->cih != NULL) {
    213             sal_free(cc->cih);
    214         }
    215 
    216         if(cc->cmh != NULL) {
    217             if(cc->cmh->cmh_table != NULL) {
    218                 sal_free(cc->cmh->cmh_table);
    219             }
    220             if(cc->cmh->cmh_list != NULL) {
    221                 sal_free(cc->cmh->cmh_list);
    222             }
    223             sal_free(cc->cmh);
    224         }
    225 
    226         if(cc->cch != NULL) {
    227             if(cc->cch->cch_table != NULL) {
    228                 sal_free(cc->cch->cch_table);
    229             }
    230             if(cc->cch->pseudo_regs != NULL) {
    231                 sal_free(cc->cch->pseudo_regs);
    232             }
    233             sal_free(cc->cch);
    234         }
    235 
    236         if(cc->ceh != NULL) {
    237             if(cc->ceh->ceh_table != NULL) {
    238                 sal_free(cc->ceh->ceh_table);
    239             }
    240             sal_free(cc->ceh);
    241         }
    242 
    243         if(cc->flow_db != NULL) {
    244             if(cc->flow_db->flow_map != NULL) {
    245                 sal_free(cc->flow_db->flow_map);
    246             }
    247             sal_free(cc->flow_db);
    248         }
    249 
    250         sal_free(cc);
    251 
    252         soc_cancun_info[unit] = (soc_cancun_t*) NULL;
    253     }
    254 }
    255 
    256 /*
    257  * Function:
    258  *      soc_cancun_info_get
    259  * Purpose:
    260  *      Get cancun info
    261  * Parameters:
    262  *      unit  - (IN)     Unit ID
    263  *      cc    - (IN/OUT) cancun info
    264  * Returns:
    265  *      SOC_E_NONE
    266  *      SOC_E_FAIL
    267 */
    268 int soc_cancun_info_get(uint32 unit, soc_cancun_t** cc) {
    269 
    270     soc_cancun_t* pcc = soc_cancun_info[unit];
    271 
    272     if(pcc == NULL) {
    273         return SOC_E_INTERNAL;
    274     }
    275 
    276     *cc = soc_cancun_info[unit];
    277 
    278     return SOC_E_NONE;
    279 }
    280 
    281 /*
    282  * Function:
    283  *      soc_cancun_status_get
    284  * Purpose:
    285  *      Initialization sequence for loading all applied CANCUN loadable files
    286  * Parameters:
    287  *      unit  - (IN) Unit ID
    288  * Returns:
    289  *      SOC_E_NONE
    290  *      SOC_E_FAIL
    291 */
    292 int soc_cancun_status_get(uint32 unit, soc_cancun_t** cc) {
    293 
    294     soc_cancun_t* pcc = soc_cancun_info[unit];
    295 
    296     if(pcc == NULL) {
    297         return SOC_E_UNIT;
    298     } else if (!(pcc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
    299         return SOC_E_INIT;
    300     }
    301 
    302     *cc = soc_cancun_info[unit];
    303 
    304     return SOC_E_NONE;
    305 }
    306 
    307 void soc_cancun_buf_swap32(uint8 *buf, long buf_size)
    308 {
    309     long i;
    310     uint32 *fword = (uint32 *)buf;
    311     for (i = 0; i < ((buf_size + 3) / 4); i++) {
    312         *fword = soc_letohl(*fword);
    313         fword ++;
    314     }
    315     return ;
    316 }
    317 
    318 int soc_cancun_chip_rev_validate(const uint32 chip_rev_id,
    319     const uint16 dev_id, const uint8 rev_id) {
    320     uint16 cancun_dev_id = chip_rev_id >> 16;
    321     uint8 cancun_rev_id = chip_rev_id & 0xff;
    322 
    323     if(chip_rev_id == ((dev_id << 16) | rev_id)) {
    324         return TRUE;
    325     }
    326 
    327 
    328     if ((cancun_dev_id == BCM56870_DEVICE_ID) &&
    329             (cancun_rev_id == BCM56870_A0_REV_ID)) {
    330         if ((dev_id == BCM56873_DEVICE_ID) && (rev_id == BCM56873_A0_REV_ID)) {
    331             return TRUE;
    332         }
    333     }
    334     if ((cancun_dev_id == BCM56770_DEVICE_ID) &&
    335             (cancun_rev_id == BCM56770_A0_REV_ID)) {
    336         if ((dev_id == BCM56771_DEVICE_ID) && (rev_id == BCM56771_A0_REV_ID)) {
    337             return TRUE;
    338         }
    339     }
    340 
    341     if ((cancun_dev_id == BCM56370_DEVICE_ID) &&
    342             (cancun_rev_id == BCM56370_A0_REV_ID)) {
    343         if (((dev_id == BCM56371_DEVICE_ID) && (rev_id == BCM56371_A0_REV_ID)) ||
    344             ((dev_id == BCM56372_DEVICE_ID) && (rev_id == BCM56372_A0_REV_ID)) ||
    345             ((dev_id == BCM56374_DEVICE_ID) && (rev_id == BCM56374_A0_REV_ID)) ||
    346             ((dev_id == BCM56375_DEVICE_ID) && (rev_id == BCM56375_A0_REV_ID)) ||
    347             ((dev_id == BCM56376_DEVICE_ID) && (rev_id == BCM56376_A0_REV_ID)) ||
    348             ((dev_id == BCM56377_DEVICE_ID) && (rev_id == BCM56377_A0_REV_ID)) ||
    349             ((dev_id == BCM56577_DEVICE_ID) && (rev_id == BCM56577_A0_REV_ID)) ||
    350             ((dev_id == BCM56578_DEVICE_ID) && (rev_id == BCM56578_A0_REV_ID)) ||
    351             ((dev_id == BCM56579_DEVICE_ID) && (rev_id == BCM56579_A0_REV_ID)) ||
    352             ((dev_id == BCM56370_DEVICE_ID) && (rev_id == BCM56370_A1_REV_ID)) ||
    353             ((dev_id == BCM56371_DEVICE_ID) && (rev_id == BCM56371_A1_REV_ID)) ||
    354             ((dev_id == BCM56372_DEVICE_ID) && (rev_id == BCM56372_A1_REV_ID)) ||
    355             ((dev_id == BCM56374_DEVICE_ID) && (rev_id == BCM56374_A1_REV_ID)) ||
    356             ((dev_id == BCM56375_DEVICE_ID) && (rev_id == BCM56375_A1_REV_ID)) ||
    357             ((dev_id == BCM56376_DEVICE_ID) && (rev_id == BCM56376_A1_REV_ID)) ||
    358             ((dev_id == BCM56377_DEVICE_ID) && (rev_id == BCM56377_A1_REV_ID)) ||
    359             ((dev_id == BCM56577_DEVICE_ID) && (rev_id == BCM56577_A1_REV_ID)) ||
    360             ((dev_id == BCM56578_DEVICE_ID) && (rev_id == BCM56578_A1_REV_ID)) ||
    361             ((dev_id == BCM56579_DEVICE_ID) && (rev_id == BCM56579_A1_REV_ID))) {
    362             return TRUE;
    363         }
    364     }
    365 
    366     return FALSE;
    367 }
    368 
    369 
    370 /*
    371  * Function:
    372  *      soc_cancun_file_info_get
    373  * Purpose:
    374  *      Decode a packaged format CANCUN files and save it into file structure
    375  * Parameters:
    376  *      unit        - (IN) Unit ID
    377  *      ccf         - (OUT) Pointer to CANCUN file structure
    378  *      filename    - (IN) Filename string if available
    379  *      buf         - (IN) Pointer to buffer of a CANCUN loadable file
    380  *      buf_bytes   - (IN) Length of buffer in bytes
    381  * Returns:
    382  *      SOC_E_NONE
    383  *      SOC_E_INTERNAL - NULL file structure pointer
    384  *      SOC_E_BADID    - File validity check fails
    385  */
    386 int soc_cancun_file_info_get(int unit, soc_cancun_file_t* ccf, char *filename,
    387         uint8 *buf, long buf_bytes) {
    388 
    389     soc_cancun_t *cc = soc_cancun_info[unit];
    390     soc_cancun_file_header_t *ccfh = (soc_cancun_file_header_t *) buf;
    391     uint16 dev_id;
    392     uint8 rev_id;
    393     uint32 crc, *file_crc;
    394     uint8 *cur_buf;
    395     long cur_buf_size;
    396 
    397     if (ccf == NULL) {
    398         return SOC_E_INTERNAL;
    399     }
    400 
    401     crc = soc_cancun_crc32(0, buf, buf_bytes - 4);
    402 
    403     /* convert file header into correct endianness */
    404     cur_buf = buf;
    405     cur_buf_size = SOC_CANCUN_FILE_HEADER_OFFSET;
    406     soc_cancun_buf_swap32(cur_buf, cur_buf_size);
    407     sal_memcpy(&ccf->header, ccfh, sizeof(soc_cancun_file_header_t));
    408 
    409     cur_buf += cur_buf_size;
    410     cur_buf_size = buf_bytes - cur_buf_size;
    411     /* check if CEH or CFH, don't swap rest of file */
    412     if ((ccfh->file_type != SOC_CANCUN_FILE_ID_CEH) &&
    413         (ccfh->file_type != SOC_CANCUN_FILE_ID_CFH)) { 
    414         soc_cancun_buf_swap32(cur_buf, cur_buf_size);
    415     } else {
    416         /* swap the checksum */
    417         soc_cancun_buf_swap32(buf + buf_bytes - 4, 4);
    418     }
    419 
    420     if (filename) {
    421         sal_strncpy(ccf->filename, filename, sal_strlen(filename)+1);
    422     }
    423 
    424     ccf->valid = 0;
    425     /* 1. File identifier */
    426     if(ccfh->file_identifier != SOC_CANCUN_FILE_ID) {
    427         if (filename) {
    428             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
    429                 "ERROR: %s is not a CANCUN file\n"), filename));
    430         } else {
    431             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
    432                 "ERROR: Not a CANCUN file: 0x%08x. Abort\n"), ccfh->file_identifier));
    433         }
    434         return SOC_E_INTERNAL;
    435     }
    436     /* 2. File type */
    437     switch(ccfh->file_type) {
    438         case SOC_CANCUN_FILE_ID_CIH:
    439             ccf->type = CANCUN_SOC_FILE_TYPE_CIH;
    440             break;
    441         case SOC_CANCUN_FILE_ID_CMH:
    442             ccf->type = CANCUN_SOC_FILE_TYPE_CMH;
    443             break;
    444         case SOC_CANCUN_FILE_ID_CCH:
    445             ccf->type = CANCUN_SOC_FILE_TYPE_CCH;
    446             break;
    447         case SOC_CANCUN_FILE_ID_CFH:
    448             ccf->type = CANCUN_SOC_FILE_TYPE_CFH;
    449             break;
    450         case SOC_CANCUN_FILE_ID_CEH:
    451             ccf->type = CANCUN_SOC_FILE_TYPE_CEH;
    452             break;
    453 
    454         default:
    455             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
    456                 "ERROR: Invalid file type. Abort\n")));
    457             return SOC_E_INTERNAL;
    458     }
    459 
    460     /* CANCUN file validation */
    461     if((cc->flags & SOC_CANCUN_FLAG_SKIP_VALIDITY) == 0) {
    462         /* 3. File length */
    463         if(ccfh->file_length != BYTES2WORDS(buf_bytes)) {
    464             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
    465                 "ERROR: File length mismatch. Abort\n")));
    466             return SOC_E_INTERNAL;
    467         }
    468         /* 4. HW version */
    469         soc_cm_get_id(unit, &dev_id, &rev_id);
    470         if(!soc_cancun_chip_rev_validate(ccfh->chip_rev_id, dev_id, rev_id)) {
    471             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
    472                 "ERROR: HW version mismatch. Abort\n")));
    473             return SOC_E_INTERNAL;
    474         }
    475         /* 5. CRC */
    476         file_crc = (uint32 *) (buf + buf_bytes - 4);
    477         if (crc != *file_crc) {
    478             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
    479                 "ERROR: CRC check fails (crc 0x%08x, file_crc 0x%08x. Abort\n"), crc, *file_crc));
    480             return SOC_E_INTERNAL;
    481         }
    482     }
    483 
    484     ccf->valid = 1;
    485     ccf->format = CANCUN_SOC_FILE_FORMAT_PACK;
    486     ccf->status = CANCUN_SOC_FILE_LOAD_NONE;
    487 
    488     return SOC_E_NONE;
    489 }
    490 
    491 /*
    492  * Function:
    493  *      soc_cancun_file_load
    494  * Purpose:
    495  *      Loading a CANCUN loadable file into device or internal structures. This
    496  *      function also reports file type and format if input content is in
    497  *      packaged format, or it keep them unchanged
    498  * Parameters:
    499  *      unit        - (IN) Unit ID
    500  *      buf         - (IN) Pointer to buffer of a CANCUN loadable file
    501  *      buf_bytes   - (IN) Length of buffer in bytes
    502  *      type        - (INOUT) File type
    503  *      format      - (INOUT) File format
    504  * Returns:
    505  *      SOC_E_NONE
    506  *      SOC_E_UNIT  - Invalid unit ID
    507  *      SOC_E_PARAM - Invalid input buffer
    508  *      SOC_E_BADID - File validity check fails
    509  *      SOC_E_FAIL  - Loading fails
    510  */
    511 
    512 int soc_cancun_file_load(int unit, uint8* buf, long buf_bytes, uint32* type,
    513                           uint32* format) {
    514     soc_cancun_t *cc;
    515     soc_cancun_file_t ccf_file, *ccf;
    516     uint32 status = SOC_CANCUN_LOAD_STATUS_NOT_LOADED;
    517     int rv = SOC_E_NONE;
    518 
    519     cc = soc_cancun_info[unit];
    520     if(cc == NULL) {
    521         return SOC_E_UNIT;
    522     } else if (!(cc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
    523         return SOC_E_INIT;
    524     } else if (buf == NULL) {
    525         return SOC_E_PARAM;
    526     }
    527 
    528     /* Get file information if input PACK or UNKNOWN format */
    529     sal_memset(&ccf_file, 0, sizeof(soc_cancun_file_t));
    530     if (*format == CANCUN_SOC_FILE_FORMAT_PACK ||
    531         *format == CANCUN_SOC_FILE_FORMAT_UNKNOWN) {
    532         rv = soc_cancun_file_info_get(unit, &ccf_file, NULL, buf, buf_bytes);
    533         if(rv == SOC_E_NONE) {
    534             *type = ccf_file.type;
    535             *format = ccf_file.format;
    536 
    537             if(*format == CANCUN_SOC_FILE_FORMAT_PACK) {
    538                 buf += SOC_CANCUN_FILE_HEADER_OFFSET;
    539                 buf_bytes -= (SOC_CANCUN_FILE_HEADER_OFFSET + 1);
    540             } else {
    541                 return SOC_E_BADID;
    542             }
    543         } else {
    544             return rv;
    545         }
    546     }
    547 
    548     if(*type == CANCUN_SOC_FILE_TYPE_CIH) {
    549         soc_cancun_file_branch_id_e branch_id = 0;
    550         ccf = &cc->cih->file;
    551         status = SOC_CANCUN_LOAD_STATUS_IN_PROGRESS;
    552         if(*format == CANCUN_SOC_FILE_FORMAT_PIO) {
    553             cc->cih->status = status;
    554             rv = _soc_cancun_file_pio_load(unit, buf,
    555                                            (buf_bytes/BYTES_PER_UINT32));
    556 
    557         } else if(*format == CANCUN_SOC_FILE_FORMAT_PACK) {
    558 	        if(SOC_WARM_BOOT(unit)) {
    559                 rv = SOC_E_NONE;
    560             } else {
    561                 cc->cih->status = status;
    562                 rv = _soc_cancun_cih_load(unit, buf,
    563                                       ccf_file.header.num_data_blobs);
    564             }
    565 
    566         } else {
    567             return SOC_E_PARAM;
    568         }
    569 
    570         if(rv == SOC_E_NONE) {
    571             status = SOC_CANCUN_LOAD_STATUS_LOADED;
    572             cc->cih->version = ccf_file.header.version;
    573             cc->flags |= SOC_CANCUN_FLAG_CIH_LOADED;
    574 
    575         } else {
    576             status = SOC_CANCUN_LOAD_STATUS_FAILED;
    577             cc->flags &= ~SOC_CANCUN_FLAG_CIH_LOADED;
    578         }
    579         cc->cih->status = status;
    580         rv = soc_cancun_branch_id_get(unit,
    581                        CANCUN_SOC_FILE_TYPE_CIH, &branch_id);
    582         if (branch_id == CANCUN_FILE_BRANCH_ID_HGoE) {
    583             SOC_FEATURE_SET(unit, soc_feature_higig_over_ethernet);
    584         }
    585 
    586 
    587     } else if (*type == CANCUN_SOC_FILE_TYPE_CMH) {
    588         ccf = &cc->cmh->file;
    589         status = SOC_CANCUN_LOAD_STATUS_IN_PROGRESS;
    590         cc->cmh->status = status;
    591         rv = _soc_cancun_file_cmh_load(unit, buf, (buf_bytes/BYTES_PER_UINT32));
    592 
    593         if(rv == SOC_E_NONE) {
    594             status = SOC_CANCUN_LOAD_STATUS_LOADED;
    595             cc->cmh->version = ccf_file.header.version;
    596             cc->cmh->sdk_version = ccf_file.header.sdk_version;
    597             cc->flags |= SOC_CANCUN_FLAG_CMH_LOADED;
    598         } else {
    599             status = SOC_CANCUN_LOAD_STATUS_FAILED;
    600             cc->flags &= ~SOC_CANCUN_FLAG_CMH_LOADED;
    601         }
    602         cc->cmh->status = status;
    603 
    604     } else if (*type == CANCUN_SOC_FILE_TYPE_CCH) {
    605         ccf = &cc->cch->file;
    606         status = SOC_CANCUN_LOAD_STATUS_IN_PROGRESS;
    607         cc->cch->status = status;
    608         rv = _soc_cancun_file_cch_load(unit, buf, (buf_bytes/BYTES_PER_UINT32));
    609 
    610         if(rv == SOC_E_NONE) {
    611             status = SOC_CANCUN_LOAD_STATUS_LOADED;
    612             cc->cch->version = ccf_file.header.version;
    613             cc->cch->sdk_version = ccf_file.header.sdk_version;
    614             cc->flags |= SOC_CANCUN_FLAG_CCH_LOADED;
    615         } else {
    616             status = SOC_CANCUN_LOAD_STATUS_FAILED;
    617             cc->flags &= ~SOC_CANCUN_FLAG_CCH_LOADED;
    618         }
    619         cc->cch->status = status;
    620 
    621     } else if (*type == CANCUN_SOC_FILE_TYPE_CEH) {
    622         ccf = &cc->ceh->file;
    623         status = SOC_CANCUN_LOAD_STATUS_IN_PROGRESS;
    624         cc->ceh->status = status;
    625         rv = _soc_cancun_file_ceh_load(unit, buf, (buf_bytes/BYTES_PER_UINT32));
    626 
    627         if(rv == SOC_E_NONE) {
    628             status = SOC_CANCUN_LOAD_STATUS_LOADED;
    629             cc->ceh->version = ccf_file.header.version;
    630             cc->ceh->sdk_version = ccf_file.header.sdk_version;
    631             cc->flags |= SOC_CANCUN_FLAG_CEH_LOADED;
    632         } else {
    633             status = SOC_CANCUN_LOAD_STATUS_FAILED;
    634             cc->flags &= ~SOC_CANCUN_FLAG_CEH_LOADED;
    635         }
    636         cc->ceh->status = status;
    637 
    638     } else if (*type == CANCUN_SOC_FILE_TYPE_CFH)  {
    639         ccf =  &cc->flow_db->file;
    640         status = SOC_CANCUN_LOAD_STATUS_IN_PROGRESS;
    641         cc->flow_db->status = status;
    642         rv = _soc_flow_db_load(unit, buf, (buf_bytes/BYTES_PER_UINT32));
    643 
    644         if(rv == SOC_E_NONE) {
    645             status = SOC_CANCUN_LOAD_STATUS_LOADED;
    646             cc->flow_db->version = ccf_file.header.version;
    647             cc->flags |= SOC_CANCUN_FLAG_CFH_LOADED;
    648         } else {
    649             status = SOC_CANCUN_LOAD_STATUS_FAILED;
    650             cc->flags &= ~SOC_CANCUN_FLAG_CFH_LOADED;
    651         }
    652         cc->flow_db->status = status;
    653     } else {
    654         LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
    655             "ERROR: can't recognize file type enum %d\n"), *type));
    656         return SOC_E_PARAM;
    657     }
    658 
    659     /* File successfully loaded here. Update ccf */
    660     if(ccf) {
    661         sal_memcpy(ccf, &ccf_file, sizeof(soc_cancun_file_t));
    662         ccf->status = status;
    663     }
    664 
    665     return rv;
    666 }
    667 
    668 
    669 /*
    670  * Function:
    671  *      soc_cancun_cmh_list
    672  * Purpose:
    673  *      Return the array that contain memory and field pairs covered in CMH
    674  * Parameters:
    675  *      unit        - (IN) Unit ID
    676  *      cmh_list    - (INOUT) pointer to a buffer to hold CMH list.
    677  * Returns:
    678  *      SOC_E_NONE
    679  *      SOC_E_FAIL
    680  *
    681  * Note: Output format of CANCUN coverage list
    682  *      +-------------------+-----------------+--------------+--------------+
    683  *      | mem_num           | mem_1           | field_num    | field_1      |
    684  *      +-------------------+-----------------+--------------+--------------+
    685  *      | field_2           | ...             | mem_n        | field_num_n  |
    686  *      +-------------------+-----------------+--------------+--------------+
    687  *      | field_n1          | field_n2        | ...          |              |
    688  *      +-------------------+-----------------+--------------+--------------+
    689 */
    690 int soc_cancun_cmh_list (int unit, uint32** cmh_list) {
    691     soc_cancun_t *pcc = soc_cancun_info[unit];
    692     soc_cancun_cmh_t *cmh;
    693 
    694     if(pcc == NULL) {
    695         return SOC_E_UNIT;
    696     } else if (!(pcc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
    697         return SOC_E_INIT;
    698     }
    699 
    700     cmh = pcc->cmh;
    701     if(cmh != NULL) {
    702         if(cmh->cmh_list != NULL) {
    703             *cmh_list = cmh->cmh_list;
    704             return SOC_E_NONE;
    705         }
    706     }
    707     return SOC_E_INIT;
    708 }
    709 
    710 /*
    711  * Function:
    712  *      soc_cancun_cmh_check
    713  * Purpose:
    714  *      Check if a mem/field is covered by CMH mapping
    715  * Parameters:
    716  *      unit  - (IN) Unit ID
    717  *      mem   - (IN) Memory ID
    718  *      field - (IN) Field ID
    719  * Returns:
    720  *      SOC_E_NONE - input mem/field is covered by CMH
    721  *      SOC_E_FAIL - input mem/field is NOT covered by CMH
    722  *
    723  * Note: For cmh_list, the first word is the number of the entries, and each two
    724  *       words after it is the pair of memory and field pair in enumeration
    725  *      +-------------------+-----------------+--------------+--------------+
    726  *      | entry_num         | mem_1           | field_1      | app_1        |
    727  *      +-------------------+-----------------+--------------+--------------+
    728  *      | ...               | mem_n           | field_n      | app_n        |
    729  *      +-------------------+-----------------+--------------+--------------+
    730 */
    731 int soc_cancun_cmh_check (int unit, soc_mem_t mem, soc_field_t field) {
    732     soc_cancun_t *pcc = soc_cancun_info[unit];
    733     soc_cancun_cmh_t *cmh;
    734     uint32 entry_num = 0, i;
    735     uint32 *entry = NULL;
    736 
    737     if(pcc == NULL) {
    738         return SOC_E_UNIT;
    739     } else if (!(pcc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
    740         return SOC_E_INIT;
    741     }
    742 
    743     cmh = pcc->cmh;
    744     if(cmh != NULL) {
    745         if(cmh->cmh_list != NULL) {
    746             entry = cmh->cmh_list;
    747             entry_num = *entry++;
    748             for(i = 0; i < entry_num; i++, entry += SOC_CANCUN_CMH_LIST_ENTRY_SIZE) {
    749                 if(mem == *(entry + SOC_CANCUN_CMH_LIST_ENTRY_OFFSET_MEM) &&
    750                    field == *(entry + SOC_CANCUN_CMH_LIST_ENTRY_OFFSET_FIELD)) {
    751                     LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
    752                         "%s.%s is covered by CMH\n"),
    753                             SOC_MEM_NAME(unit, mem),
    754                             SOC_FIELD_NAME(unit, field)));
    755                     return SOC_E_NONE;
    756                 }
    757             }
    758             return SOC_E_FAIL;
    759         }
    760     }
    761     return SOC_E_INIT;
    762 }
    763 
    764 /*
    765  * Function:
    766  *      soc_cancun_cmh_mem_set
    767  * Purpose:
    768  *      Configure memory field values according to internal CMH tables
    769  * Parameters:
    770  *      unit  - (IN) Unit ID
    771  *      mem   - (IN) Memory ID. Input INVALIDm if not applied
    772  *      index - (IN) Memory entry index
    773  *      field - (IN) Field ID. Input INVALIDf if not applied
    774  *      input - (IN) This parameter can be field value or application
    775  *
    776  * Returns:
    777  *      SOC_E_NONE
    778  *      SOC_E_FAIL
    779  *      SOC_E_INTERNAL  - CMH tables are not loaded
    780  *      SOC_E_PARAM     - Input parameters are invalid
    781  *      SOC_E_NOT_FOUND - Input mem/reg/field are not found in CMH
    782  *
    783  * Note:
    784  *      CMH entry format is shown as following. For more details, please refer
    785  *      to section 4.1.1 in document "Trident3 SOC Layer Support for CANCUN".
    786  *
    787  *      +-------------------+-----------------+--------------+--------------+
    788  *      | entry flags/size  | src_mem         | src_field    | src_value_num|
    789  *      +-------------------+-----------------+--------------+--------------+
    790  *      | /removed/         | dest_mem_num    | src_val_0    | ...          |
    791  *      +-------------------+-----------------+--------------+--------------+
    792  *      | src_val_n         | des_mem_0       | field_num_0  | field_0      |
    793  *      +-------------------+-----------------+--------------+--------------+
    794  *      | ...               | field_m         | dest_val_00  | ...          |
    795  *      +-------------------+-----------------+--------------+--------------+
    796  *      | dest_val_0m       | dest_val_10     | ...          | dest_val_1m  |
    797  *      +-------------------+-----------------+--------------+--------------+
    798  *      | dest_mem_1        | ...                                           |
    799  *      +-------------------+-----------------------------------------------+
    800  */
    801 int soc_cancun_cmh_mem_set (int unit, soc_mem_t mem, int index,
    802                             soc_field_t field, uint32 input) {
    803     soc_cancun_t* cc;
    804     soc_cancun_cmh_t* cmh;
    805     soc_cancun_cmh_map_t* cmh_map;
    806     soc_cancun_hash_table_t* hash_table_header;
    807     uint32 *hash_table_entry, *p;
    808     uint32 entry_num, value_ind, mem_num, field_num, value_num;
    809     uint32 i, j, k, offset, key, app;
    810     soc_mem_t d_mem;
    811     soc_field_t fields[SOC_MAX_MEM_FIELD_WORDS];
    812     uint32 values[SOC_MAX_MEM_FIELD_WORDS];
    813     int rv, dest_index = index;
    814 
    815     cc = soc_cancun_info[unit];
    816     if(cc == NULL) {
    817         return SOC_E_UNIT;
    818     } else if (!(cc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
    819         return SOC_E_INIT;
    820     }
    821 
    822     /* deal with EGR_PORT.PORT_TYPE covered by CMH format 2 */
    823     if(mem == EGR_PORTm && field == PORT_TYPEf) {
    824         switch(input) {
    825         case 0: /* Ethernet */
    826             if(IS_CPU_PORT(unit, index)) {
    827                 app = CANCUN_APP__EGR_PORT__CPU_ETHERNET_PORT;
    828             } else {
    829                 app = CANCUN_APP__EGR_PORT__ETHERNET;
    830             }
    831             break;
    832         case 1: /* HG2 */
    833             if(IS_CPU_PORT(unit, index)) {
    834                 app = CANCUN_APP__EGR_PORT__CPU_HG2_PORT;
    835             } else {
    836                 app = CANCUN_APP__EGR_PORT__HG2_PORT;
    837             }
    838             break;
    839         case 2: /* Loopback */
    840             app = CANCUN_APP__EGR_PORT__LOOPBACK;
    841             break;
    842         case 4: /* Cascade */
    843             app = CANCUN_APP__EGR_PORT__CASCADED_PORT;
    844             break;
    845         default:
    846             return SOC_E_PARAM;
    847             break;
    848         };
    849         rv = soc_cancun_app_dest_entry_set (unit, mem, index, field, app, input);
    850         
    851         
    852         (void)soc_cancun_app_dest_entry_set (unit, EGR_PORTm, index, INVALIDf, CANCUN_APP__EGR_PORT__QOS_LAYERED_RESOLUTION, 0);
    853         
    854         return rv;
    855     }
    856 
    857     cmh = cc->cmh;
    858     hash_table_header = (soc_cancun_hash_table_t*) cmh->cmh_table;
    859     hash_table_entry = &hash_table_header->table_entry;
    860 
    861     rv = _soc_cancun_hash(hash_table_header, mem, field, &key);
    862     if(rv != SOC_E_NONE) {
    863         return rv;
    864     }
    865     offset = *(hash_table_entry + key);
    866     if(offset == 0) {
    867         return SOC_E_NOT_FOUND;
    868     }
    869 
    870     p = hash_table_entry + offset;
    871     entry_num = *p++;
    872     cmh_map = (soc_cancun_cmh_map_t*) p;
    873     if (entry_num != 0) {
    874         for(i = 0; i < entry_num; i++) {
    875             if(cmh_map->src_mem == mem && cmh_map->src_field == field &&
    876                (cmh_map->format == 1 || cmh_map->format == 5)) {
    877 
    878                 /* check if value is in value list */
    879                 value_num = cmh_map->src_value_num;
    880                 p = &(cmh_map->dest_map_entry);
    881                 for(j = 0; j < value_num; j++) {
    882                     if(input == *(p+j)) {
    883                         break;
    884                     }
    885                 }
    886 
    887                 if(j >= value_num) {
    888                     return SOC_E_PARAM;
    889                 } else {
    890                     value_ind = j;
    891                 }
    892 
    893                 /* writing mapped mem/field */
    894                 mem_num = cmh_map->dest_mem_num;
    895                 p = &(cmh_map->dest_map_entry) + value_num;
    896                 for(j = 0; j < mem_num; j++) {
    897                     d_mem = *p++;
    898                     if(cmh_map->format == 5) {
    899                         dest_index = *p++;
    900                     } else {
    901                         dest_index = index;
    902                     }
    903                     field_num = *p++;
    904                     for(k = 0; k < field_num; k++) {
    905                         fields[k] = *p++;
    906                     }
    907                     p += value_ind * field_num;
    908                     for(k = 0; k < field_num; k++) {
    909                         values[k] = *p++;
    910                     }
    911 
    912                     rv = soc_mem_fields32_modify(unit, d_mem, dest_index, field_num,
    913                                                  fields, values);
    914 
    915                     /* Debug log */
    916                     if(cc->flags & SOC_CANCUN_FLAG_DEBUG_MODE) {
    917                         LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
    918                             "For index %d, mem %s, field %s, value %d\nCMH writes:\n\tmem:   %s[%d]\n"),
    919                              index,
    920                              SOC_MEM_NAME(unit, mem),
    921                              SOC_FIELD_NAME(unit, field), input,
    922                              SOC_MEM_NAME(unit, d_mem),
    923                              dest_index));
    924 
    925                         for(k = 0; k < field_num; k++) {
    926                             LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
    927                                 "\tfield: %s, value: %d\n"),
    928                                  SOC_FIELD_NAME(unit, fields[k]), values[k]));
    929                         }
    930                     }
    931                 }
    932                 return SOC_E_NONE;
    933             }
    934             cmh_map = (soc_cancun_cmh_map_t *) \
    935                       ((uint32 *)cmh_map + cmh_map->entry_size);
    936         }
    937         return SOC_E_NOT_FOUND;
    938     }
    939     return SOC_E_NOT_FOUND;
    940 }
    941 
    942 int soc_cancun_cmh_mem_get (int unit, soc_mem_t mem, int index,
    943                             soc_field_t field, uint32* value) {
    944 
    945     /* No deprecated fields for now. No need to be implement */
    946 
    947     return SOC_E_NONE;
    948 }
    949 
    950 STATIC
    951 int _soc_cancun_ceh_hash_key_get(int unit, soc_cancun_hash_table_t *hash_tbl,
    952                                       char *obj_name,
    953                                       uint32 *key)
    954 {
    955     char *cp;
    956     uint32 len;
    957     uint32 hash = 0;
    958 
    959     if ((hash_tbl == NULL) ||
    960         (key == NULL)) {
    961         return SOC_E_PARAM;
    962     }
    963     /* hash function */
    964     cp = obj_name;
    965     len = sal_strlen(obj_name);
    966     if (len == 0) {
    967         return SOC_E_PARAM;
    968     }
    969     while (*cp != '\0') {
    970         hash += *cp++;
    971     }
    972 
    973     *key = (hash_tbl->pb * hash) % hash_tbl->pd;
    974 
    975     return SOC_E_NONE;
    976 }
    977 
    978 /*
    979  * Function:
    980  *      soc_cancun_ceh_obj_field_get
    981  * Purpose:
    982  *      Get the Cancun encoded object field definition
    983  * Parameters:
    984  *      unit        - (IN) Unit ID
    985  *      obj_name    - (IN) object name
    986  *      field_name  - (IN) object field name
    987  *      field_info  - (OUT) Retrieved field information
    988  * Returns:
    989  *      SOC_E_XXX
    990  */
    991 int soc_cancun_ceh_obj_field_get (int unit, char *obj_name,
    992                                       char *field_name,
    993                                       soc_cancun_ceh_field_info_t *info)
    994 {
    995 
    996     soc_cancun_t* cc;
    997     soc_cancun_ceh_t* ceh;
    998     soc_cancun_hash_table_t* hash_table_header;
    999     uint32 *entry_location_tbl;
   1000     uint32 entry_num;
   1001     uint32 i, j, offset, key;
   1002     uint32 *curr_p;
   1003     soc_cancun_ceh_object_t *obj_p;
   1004     soc_cancun_ceh_field_t  *fld_p;
   1005     char *str_mem_offset;
   1006 
   1007     cc = soc_cancun_info[unit];
   1008     if(cc == NULL) {
   1009         return SOC_E_UNIT;
   1010     } else if (!(cc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
   1011         return SOC_E_INIT;
   1012     }
   1013 
   1014     ceh = cc->ceh;
   1015     hash_table_header = SOC_CANCUN_CEH_HASH_HDR_TBL(ceh->ceh_table);
   1016     entry_location_tbl = SOC_CANCUN_CEH_OBJ_ENTRY_LOC_TBL(ceh->ceh_table);
   1017 
   1018     /* hash key generation. The hash function must be same as in CEH */
   1019     SOC_IF_ERROR_RETURN(_soc_cancun_ceh_hash_key_get(unit,hash_table_header,
   1020                                       obj_name, &key));
   1021 
   1022     /* the hash key is the index to the entry location table where each location
   1023      * could have one or more entries with the same hash key value. The location
   1024      * is represented by an offset value from the start of entry_location_tbl
   1025      * to the start of the entry.
   1026      */
   1027     offset = *(entry_location_tbl + key);
   1028     if(offset == 0) {
   1029         return SOC_E_NOT_FOUND;
   1030     }
   1031 
   1032     /* point to the location where the first entry starts */
   1033     curr_p = entry_location_tbl + offset;
   1034     entry_num = *curr_p++;
   1035     if (!entry_num) {
   1036         return SOC_E_NOT_FOUND;
   1037     }
   1038     /* start of string offset location */
   1039     str_mem_offset = (char *)SOC_CANCUN_CEH_STR_NAME_TBL(ceh->ceh_table);
   1040 
   1041     for (i = 0; i < entry_num; i++) {
   1042         obj_p = (soc_cancun_ceh_object_t *)curr_p;
   1043         fld_p = (soc_cancun_ceh_field_t *)(obj_p + 1);
   1044         if (sal_strcmp(obj_name, str_mem_offset + obj_p->name_addr) == 0) {
   1045             /* found object */
   1046             for (j = 0; j < obj_p->num_fields; j++) {
   1047                 if (sal_strcmp(field_name,
   1048                     str_mem_offset + (fld_p + j)->name_addr) == 0) {
   1049                     info->offset = (fld_p + j)->offset;
   1050                     info->width  = (fld_p + j)->width;
   1051                     info->value  = (fld_p + j)->value;
   1052                     info->flags  = 0;
   1053                     return SOC_E_NONE;
   1054                 }
   1055             }
   1056         }
   1057         /* next entry with the same hash key */
   1058         curr_p = (uint32 *)(fld_p + obj_p->num_fields);
   1059     }
   1060     return SOC_E_NOT_FOUND;
   1061 }
   1062 
   1063 /*
   1064  * Function:
   1065  *      soc_cancun_ceh_obj_field_id_list_get
   1066  * Purpose:
   1067  *      Get a list of field IDs for the given object 
   1068  * Parameters:
   1069  *      unit         - (IN) Unit ID
   1070  *      obj_name     - (IN) object name
   1071  *      size         - (IN/OUT) size of field_id array buffer 
   1072  *      field_id_arr - (OUT) field_id array buffer 
   1073  * Returns:
   1074  *      SOC_E_XXX
   1075  */
   1076 int soc_cancun_ceh_obj_field_id_list_get (int unit, char *obj_name,
   1077                                       int *size,
   1078                                       uint32 *field_id_arr)
   1079 {
   1080 
   1081     soc_cancun_t* cc;
   1082     soc_cancun_ceh_t* ceh;
   1083     soc_cancun_hash_table_t* hash_table_header;
   1084     uint32 *entry_location_tbl;
   1085     uint32 entry_num;
   1086     uint32 i, j, offset, key;
   1087     uint32 *curr_p;
   1088     soc_cancun_ceh_object_t *obj_p;
   1089     soc_cancun_ceh_field_t  *fld_p;
   1090     char *str_mem_offset;
   1091 
   1092     cc = soc_cancun_info[unit];
   1093     if(cc == NULL) {
   1094         return SOC_E_UNIT;
   1095     } else if (!(cc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
   1096         return SOC_E_INIT;
   1097     }
   1098 
   1099     ceh = cc->ceh;
   1100     hash_table_header = SOC_CANCUN_CEH_HASH_HDR_TBL(ceh->ceh_table);
   1101     entry_location_tbl = SOC_CANCUN_CEH_OBJ_ENTRY_LOC_TBL(ceh->ceh_table);
   1102 
   1103     /* hash key generation. The hash function must be same as in CEH */
   1104     SOC_IF_ERROR_RETURN(_soc_cancun_ceh_hash_key_get(unit,hash_table_header,
   1105                                       obj_name, &key));
   1106 
   1107     /* the hash key is the index to the entry location table where each location
   1108      * could have one or more entries with the same hash key value. The location
   1109      * is represented by an offset value from the start of entry_location_tbl
   1110      * to the start of the entry.
   1111      */
   1112     offset = *(entry_location_tbl + key);
   1113     if(offset == 0) {
   1114         return SOC_E_NOT_FOUND;
   1115     }
   1116 
   1117     /* point to the location where the first entry starts */
   1118     curr_p = entry_location_tbl + offset;
   1119     entry_num = *curr_p++;
   1120     if (!entry_num) {
   1121         return SOC_E_NOT_FOUND;
   1122     }
   1123     /* start of string offset location */
   1124     str_mem_offset = (char *)SOC_CANCUN_CEH_STR_NAME_TBL(ceh->ceh_table);
   1125 
   1126     for (i = 0; i < entry_num; i++) {
   1127         obj_p = (soc_cancun_ceh_object_t *)curr_p;
   1128         fld_p = (soc_cancun_ceh_field_t *)(obj_p + 1);
   1129         if (sal_strcmp(obj_name, str_mem_offset + obj_p->name_addr) == 0) {
   1130             /* found object */
   1131             if (field_id_arr == NULL) {
   1132                 /* return size only */
   1133                 *size = obj_p->num_fields;
   1134                 return SOC_E_NONE;
   1135             } 
   1136             for (j = 0; (j < obj_p->num_fields) && (j < *size); j++) {
   1137                 field_id_arr[j] = (fld_p + j)->name_addr;
   1138             }
   1139             return SOC_E_NONE;
   1140         }
   1141         /* next entry with the same hash key */
   1142         curr_p = (uint32 *)(fld_p + obj_p->num_fields);
   1143     }
   1144     return SOC_E_NOT_FOUND;
   1145 }
   1146 
   1147 /*
   1148  * Function:
   1149  *      soc_cancun_ceh_obj_field_id_get
   1150  * Purpose:
   1151  *      Get the field ID for the given field name 
   1152  * Parameters:
   1153  *      unit        - (IN) Unit ID
   1154  *      field_name  - (IN) object field name
   1155  *      field_id  - (OUT) Retrieved field id
   1156  * Returns:
   1157  *      SOC_E_XXX
   1158  */
   1159 int soc_cancun_ceh_obj_field_id_get (int unit,
   1160                                       char *field_name,
   1161                                       uint32 *field_id)
   1162 {
   1163 
   1164     soc_cancun_t* cc;
   1165     soc_cancun_ceh_t* ceh;
   1166     uint32 offset;
   1167     char *str_tbl;
   1168     uint32 str_tbl_size;
   1169 
   1170     cc = soc_cancun_info[unit];
   1171     if(cc == NULL) {
   1172         return SOC_E_UNIT;
   1173     } else if (!(cc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
   1174         return SOC_E_INIT;
   1175     }
   1176 
   1177     ceh = cc->ceh;
   1178 
   1179     str_tbl_size = *SOC_CANCUN_CEH_STR_NAME_TBL(ceh->ceh_table);
   1180 
   1181     /* start of string offset location */
   1182     str_tbl = (char *)SOC_CANCUN_CEH_STR_NAME_TBL(ceh->ceh_table);
   1183     offset  = 4;
   1184     while ((offset < str_tbl_size) && (*(str_tbl + offset) != 0)) {
   1185         if (sal_strcmp(field_name, str_tbl + offset) == 0) {
   1186             *field_id = offset;
   1187             return SOC_E_NONE;
   1188         }
   1189         offset += sal_strlen(str_tbl + offset) + 1;
   1190     }
   1191     return SOC_E_NOT_FOUND;
   1192 }
   1193 
   1194 /*
   1195  * Function:
   1196  *      soc_cancun_ceh_obj_field_name_get
   1197  * Purpose:
   1198  *      Get the object field name for the given field_id
   1199  * Parameters:
   1200  *      unit        - (IN) Unit ID
   1201  *      field_id    - (IN) field id
   1202  *      size        - (IN) size of the field name buffer
   1203  *      field_name  - (OUT) field name buffer
   1204  * Returns:
   1205  *      SOC_E_XXX
   1206  */
   1207 int soc_cancun_ceh_obj_field_name_get (int unit,
   1208                                       uint32 field_id,
   1209                                       int *size,
   1210                                       char *field_name)
   1211 {
   1212 
   1213     soc_cancun_t* cc;
   1214     soc_cancun_ceh_t* ceh;
   1215     char *str_tbl;
   1216     uint32 str_tbl_size;
   1217 
   1218     cc = soc_cancun_info[unit];
   1219     if(cc == NULL) {
   1220         return SOC_E_UNIT;
   1221     } else if (!(cc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
   1222         return SOC_E_INIT;
   1223     }
   1224 
   1225     ceh = cc->ceh;
   1226 
   1227     str_tbl_size = *SOC_CANCUN_CEH_STR_NAME_TBL(ceh->ceh_table);
   1228 
   1229     /* start of string offset location */
   1230     str_tbl = (char *)SOC_CANCUN_CEH_STR_NAME_TBL(ceh->ceh_table);
   1231 
   1232     /* validate field_id */
   1233     if ((field_id < 4) || (field_id >= str_tbl_size) ) {
   1234         return SOC_E_NOT_FOUND;
   1235     }
   1236     /* return size */
   1237     if (field_name == NULL) {
   1238         *size = sal_strlen(str_tbl + field_id) + 1;
   1239         return SOC_E_NONE;
   1240     }
   1241 
   1242     if (sal_strlen(str_tbl + field_id) < *size) {
   1243        sal_strcpy(field_name, str_tbl + field_id);
   1244     } else {
   1245        sal_strncpy(field_name, str_tbl + field_id, *size - 1);
   1246        field_name[*size - 1] = 0;
   1247     }
   1248     return SOC_E_NONE;
   1249 }
   1250 
   1251 /*
   1252  * Function:
   1253  *      soc_cancun_app_dest_entry_set
   1254  * Purpose:
   1255  *      Write to destination fields according to source table and application
   1256  * Parameters:
   1257  *      unit        - (IN) Unit ID
   1258  *      mem         - (IN) Memory ID or Register ID
   1259  *      app         - (IN) CANCUN application ID
   1260  * Returns:
   1261  *      SOC_E_NONE
   1262  *      SOC_E_FAIL - input mem/app is NOT covered by CANCUN
   1263 */
   1264 int soc_cancun_app_dest_entry_set (int unit, soc_mem_t mem, int index, soc_field_t field, int app, uint32 input) {
   1265     soc_cancun_t *cc;
   1266     soc_cancun_cmh_t *cmh;
   1267     soc_cancun_cmh_map_t *cmh_map = NULL;
   1268     soc_cancun_hash_table_t *hash_table_header;
   1269     uint32 *hash_table_entry, *hash_entry, *p;
   1270     uint32 d_mem, d_field_num, key, offset, value_ind=0, value_num = 0;
   1271     int i, j, rv, cmh_d_mem_is_reg = 0;
   1272     soc_field_t fields[SOC_MAX_MEM_FIELD_WORDS];
   1273     uint32 values[SOC_MAX_MEM_FIELD_WORDS];
   1274 
   1275     cc = soc_cancun_info[unit];
   1276     if(cc == NULL) {
   1277         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1278             "CANCUN is not initialized\n")));
   1279         return SOC_E_INIT;
   1280     } else if (!(cc->flags & SOC_CANCUN_FLAG_CMH_LOADED)) {
   1281         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1282             "CMH file is not loaded\n")));
   1283         return SOC_E_INIT;
   1284     }
   1285 
   1286     cmh = cc->cmh;
   1287     hash_table_header = (soc_cancun_hash_table_t*) cmh->cmh_table;
   1288     hash_table_entry = &hash_table_header->table_entry;
   1289     rv = _soc_cancun_hash(hash_table_header, mem, app, &key);
   1290     if(rv != SOC_E_NONE) {
   1291         return rv;
   1292     }
   1293     offset = *(hash_table_entry + key);
   1294     if(offset == 0) {
   1295         return SOC_E_NOT_FOUND;
   1296     }
   1297     hash_table_entry = &hash_table_header->table_entry + offset;
   1298     hash_entry = _soc_cancun_hash_find_entry(hash_table_entry, mem, field, app);
   1299     if(hash_entry == NULL) {
   1300         return SOC_E_NOT_FOUND;
   1301     }
   1302     cmh_map = (soc_cancun_cmh_map_t *) hash_entry;
   1303 
   1304     p = &cmh_map->dest_map_entry;
   1305     if(cmh_map->format == 3 || cmh_map->format == 2) {
   1306         if(cmh_map->format == 2) {
   1307             value_num = cmh_map->src_value_num;
   1308             for(i = 0; i < value_num; i++) {
   1309                 if(input == *(p+i)) {
   1310                     break;
   1311                 }
   1312             }
   1313 
   1314             if(i >= value_num) {
   1315                 return SOC_E_PARAM;
   1316             } else {
   1317                 value_ind = i;
   1318             }
   1319             p += value_num;
   1320         }
   1321         
   1322         for(i = 0; i < cmh_map->dest_mem_num; i++) {
   1323             d_mem = *p++;
   1324             d_field_num = *p++;
   1325             for(j = 0; j < d_field_num; j++) {
   1326                 fields[j] = *p++;
   1327             }
   1328             if(cmh_map->format == 2) {
   1329                 p += value_ind * d_field_num;
   1330             }
   1331             for(j = 0; j < d_field_num; j++) {
   1332                 values[j] = *p++;
   1333             }
   1334             if(cmh_map->format == 2) {
   1335                 p += (value_num - value_ind - 1) * d_field_num;
   1336             }
   1337 
   1338             cmh_d_mem_is_reg = (d_mem & SOC_CANCUN_FLAG_REG_ENUM)? 1: 0;
   1339             
   1340             if(cmh_d_mem_is_reg) {
   1341                 d_mem &= ~(SOC_CANCUN_FLAG_REG_ENUM);
   1342                 rv = soc_reg_fields32_modify(unit, d_mem, REG_PORT_ANY, 
   1343                                     d_field_num, fields, values);
   1344             } else {
   1345                 rv = soc_mem_fields32_modify(unit, d_mem, index, d_field_num,
   1346                                          fields, values);
   1347             }
   1348 
   1349             if(rv != SOC_E_NONE) {
   1350                 return rv;
   1351             }
   1352 
   1353             /* Debug log */
   1354             if(cc->flags & SOC_CANCUN_FLAG_DEBUG_MODE) {
   1355                 LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1356                     "For index %d, mem %s, app %d\nCMH writes:\n\t%s:   %s\n"),
   1357                      index,
   1358                      SOC_MEM_IS_VALID(unit, mem)? SOC_MEM_NAME(unit, mem):
   1359                                                   SOC_REG_NAME(unit,mem),
   1360                      app,
   1361                      cmh_d_mem_is_reg? "reg": "mem",
   1362                      cmh_d_mem_is_reg? SOC_REG_NAME(unit, d_mem): 
   1363                                        SOC_MEM_NAME(unit, d_mem)));
   1364 
   1365                 for(j = 0; j < d_field_num; j++) {
   1366                     LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1367                         "\tfield: %s, value: %d\n"),
   1368                          SOC_FIELD_NAME(unit, fields[j]), values[j]));
   1369                 }
   1370             }
   1371         }
   1372     } else {
   1373         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1374             "CMH format %d is not supported for soc_cancun_app_dest_entry_set() yet\n"),
   1375             cmh_map->format));
   1376         return SOC_E_INTERNAL;
   1377     }
   1378 
   1379     return SOC_E_NONE;
   1380 }
   1381 
   1382 /*
   1383  * Function:
   1384  *      soc_cancun_app_dest_entry_get
   1385  * Purpose:
   1386  *      Return CANCUN destination entry by input source table and application
   1387  * Parameters:
   1388  *      unit        - (IN) Unit ID
   1389  *      mem         - (IN) Memory ID or Register ID
   1390  *      app         - (IN) CANCUN application ID
   1391  *      dest_entry  - (OUT) CANCUN destination information entry
   1392  * Returns:
   1393  *      SOC_E_NONE
   1394  *      SOC_E_FAIL - input mem/app is NOT covered by CMH
   1395 */
   1396 int soc_cancun_app_dest_entry_get (int unit, soc_mem_t mem, int index, soc_field_t field, int app,
   1397                                    soc_cancun_dest_entry_t *dest_entry) {
   1398 
   1399     soc_cancun_t *cc;
   1400     soc_cancun_cmh_t *cmh;
   1401     soc_cancun_cmh_map_t *cmh_map = NULL;
   1402     soc_cancun_hash_table_t *hash_table_header;
   1403     uint32 *hash_table_entry, *hash_entry, *p;
   1404     uint32 key, offset;
   1405     int i, rv;
   1406 
   1407     cc = soc_cancun_info[unit];
   1408     if(cc == NULL) {
   1409         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1410             "CANCUN is not initialized\n")));
   1411         return SOC_E_INIT;
   1412     } else if (!(cc->flags & SOC_CANCUN_FLAG_CMH_LOADED)) {
   1413         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1414             "CMH file is not loaded\n")));
   1415         return SOC_E_INIT;
   1416     }
   1417 
   1418     cmh = cc->cmh;
   1419     hash_table_header = (soc_cancun_hash_table_t*) cmh->cmh_table;
   1420     hash_table_entry = &hash_table_header->table_entry;
   1421     rv = _soc_cancun_hash(hash_table_header, mem, app, &key);
   1422     if(rv != SOC_E_NONE) {
   1423         return rv;
   1424     }
   1425     offset = *(hash_table_entry + key);
   1426     if(offset == 0) {
   1427         return SOC_E_NOT_FOUND;
   1428     }
   1429     hash_table_entry = &hash_table_header->table_entry + offset;
   1430     hash_entry = _soc_cancun_hash_find_entry(hash_table_entry, mem, field, app);
   1431     if(hash_entry == NULL) {
   1432         return SOC_E_NOT_FOUND;
   1433     }
   1434     cmh_map = (soc_cancun_cmh_map_t *) hash_entry;
   1435 
   1436     p = &cmh_map->dest_map_entry;
   1437     if(cmh_map->format == 3) {
   1438         if(cmh_map->dest_mem_num > 1) {
   1439             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1440                 "Only 1 destination memory for CMH format 3 for now\n")));
   1441             return SOC_E_INTERNAL;
   1442         }
   1443         dest_entry->dest_index_num = 0;
   1444         dest_entry->dest_mems[0] = *p++;
   1445         dest_entry->dest_field_num = *p++;
   1446         if (dest_entry->dest_field_num > CANCUN_DEST_FIELD_NUM_MAX) {
   1447             return SOC_E_INTERNAL;
   1448         }
   1449         for(i = 0; i < dest_entry->dest_field_num; i++) {
   1450             dest_entry->dest_fields[i] = *p++;
   1451             dest_entry->dest_values[i] = *p++;
   1452         }
   1453     } else if(cmh_map->format == 4) {
   1454         if(cmh_map->dest_mem_num > CANCUN_DEST_MEM_NUM_MAX) {
   1455             return SOC_E_INTERNAL;
   1456         }
   1457         dest_entry->dest_index_num = cmh_map->dest_mem_num;
   1458         dest_entry->dest_field_num = 0;
   1459         for(i = 0; i < dest_entry->dest_index_num; i++) {
   1460             dest_entry->dest_mems[i] = *p++;
   1461             dest_entry->dest_values[i] = *p++;
   1462         }
   1463     } else {
   1464         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1465             "CMH format %d is not supported yet\n"), cmh_map->format));
   1466         return SOC_E_INTERNAL;
   1467     }
   1468 
   1469     return SOC_E_NONE;
   1470 }
   1471 
   1472 /*
   1473  * Function:
   1474  *      soc_cancun_cch_list
   1475  * Purpose:
   1476  *      Return the memory and field list of CCH coverage
   1477  * Parameters:
   1478  *      unit        - (IN) Unit ID
   1479  *      buf         - (INOUT) buffer to load CCH coverage list
   1480  *      buf_len     - (IN) the length of passing buffer
   1481  * Returns:
   1482  *      SOC_E_NONE
   1483  *      SOC_E_FAIL
   1484  *
   1485  * Note: Output format of CANCUN coverage list
   1486  *      +-------------------+-----------------+--------------+--------------+
   1487  *      | mem_num           | mem_1           | field_num    | field_1      |
   1488  *      +-------------------+-----------------+--------------+--------------+
   1489  *      | field_2           | ...             | mem_n        | field_num_n  |
   1490  *      +-------------------+-----------------+--------------+--------------+
   1491  *      | field_n1          | field_n2        | ...          |              |
   1492  *      +-------------------+-----------------+--------------+--------------+
   1493 */
   1494 int soc_cancun_cch_list (int unit, uint32* buf, uint32 buf_len) {
   1495     soc_cancun_t *pcc = soc_cancun_info[unit];
   1496     soc_cancun_cch_t *cch;
   1497     soc_cancun_hash_table_t *hash_table;
   1498     soc_cancun_list_t *p_mem, *p_fld;
   1499     uint32 *p1, *p2, *hash_table_entry, *buf_end;
   1500     uint32 i, j, key = 0;
   1501     int rv;
   1502 
   1503     if(pcc == NULL) {
   1504         return SOC_E_UNIT;
   1505     } else if (!(pcc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
   1506         return SOC_E_INIT;
   1507     } else if (buf == NULL) {
   1508             return SOC_E_PARAM;
   1509     }
   1510 
   1511     buf_end = buf + buf_len - 1;
   1512     cch = pcc->cch;
   1513     if(cch != NULL) {
   1514         hash_table = (soc_cancun_hash_table_t*) cch->cch_table;
   1515         hash_table_entry = &hash_table->table_entry;
   1516 
   1517         /* mem list is always at key 0 */
   1518         p1 = hash_table_entry + *(hash_table_entry + 0);
   1519         p1 = _soc_cancun_hash_find_entry(p1, 0, INVALIDf, CANCUN_APP_INVALID);
   1520         if(p1 == NULL) {
   1521             return SOC_E_INTERNAL;
   1522         }
   1523 
   1524         p_mem = (soc_cancun_list_t*) p1;
   1525         if(buf > buf_end) {
   1526             return SOC_E_MEMORY;
   1527         }
   1528         *buf++ = p_mem->member_num;
   1529         p1 = &p_mem->members;
   1530         for(i = 0; i < p_mem->member_num; i++) {
   1531             if(buf > buf_end) {
   1532                 return SOC_E_MEMORY;
   1533             }
   1534             *buf++ = *p1;
   1535             rv = _soc_cancun_hash(hash_table, *p1, 0, &key);
   1536             if(rv != SOC_E_NONE) {
   1537                 return rv;
   1538             }
   1539             p2 = hash_table_entry + *(hash_table_entry + key);
   1540             p2 = _soc_cancun_hash_find_entry(p2, *p1, SOC_CANCUN_FIELD_LISTf, 
   1541                                              CANCUN_APP_INVALID);
   1542             if(p2 == NULL) {
   1543                 return SOC_E_INTERNAL;
   1544             }
   1545 
   1546             p_fld = (soc_cancun_list_t*) p2;
   1547             *buf++ = p_fld->member_num;
   1548             p2 = &p_fld->members;
   1549             for(j = 0; j < p_fld->member_num; j++) {
   1550                 if(buf > buf_end) {
   1551                     return SOC_E_MEMORY;
   1552                 }
   1553                 *buf++ = *p2++;
   1554             }
   1555             p1++;
   1556         }
   1557 
   1558         return SOC_E_NONE;
   1559     }
   1560     return SOC_E_INIT;
   1561 }
   1562 
   1563 int soc_cancun_cch_reg_set(int unit, soc_reg_t reg, int index, uint64 data) {
   1564 
   1565     soc_cancun_t *cc = NULL;
   1566     soc_cancun_cch_t *cch = NULL;
   1567     soc_cancun_cch_map_t *cch_map = NULL;
   1568     soc_cancun_hash_table_t *hash_table_header = NULL;
   1569     soc_cancun_list_t *field_list = NULL;
   1570     uint32 *hash_table_entry = NULL, *p_field = NULL;
   1571     uint32 *hash_entry = NULL, *p = NULL;
   1572     uint32  l, key = 0, offset, val_idx = 0;
   1573     uint64 rval, orval, odata64;
   1574     uint64 p64;
   1575     int rv;
   1576 
   1577     cc = soc_cancun_info[unit];
   1578     if (cc == NULL) {
   1579         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1580             "CANCUN is not initialized\n")));
   1581         return SOC_E_INIT;
   1582     } else if (!(cc->flags & SOC_CANCUN_FLAG_CCH_LOADED)) {
   1583         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1584             "CCH file is not loaded\n")));
   1585         return SOC_E_INIT;
   1586     }
   1587 
   1588     /* dealing with array register */
   1589     if (SOC_REG_ARRAY(unit, reg)) {
   1590         assert(index >= 0 && index < 2 * SOC_REG_NUMELS(unit, reg));
   1591         reg += (index + 1);
   1592     }
   1593 
   1594     cch = cc->cch;
   1595     hash_table_header = (soc_cancun_hash_table_t*) cch->cch_table;
   1596     hash_table_entry = &hash_table_header->table_entry;
   1597     rv = _soc_cancun_hash(hash_table_header, reg, 0, &key);
   1598     if (rv != SOC_E_NONE) {
   1599         return rv;
   1600     }
   1601     offset = *(hash_table_entry + key);
   1602     if (offset == 0) {
   1603         return SOC_E_NOT_FOUND;
   1604     }
   1605     hash_table_entry = &hash_table_header->table_entry + offset;
   1606 
   1607     /* Obtain the source field list to write */
   1608     field_list = (soc_cancun_list_t *) \
   1609                  _soc_cancun_hash_find_entry(hash_table_entry, reg,
   1610                      SOC_CANCUN_FIELD_LISTf, CANCUN_APP_INVALID);
   1611     if (field_list == NULL) {
   1612         LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1613             "can't find field list for %s\n"), SOC_REG_NAME(unit, reg)));
   1614         return SOC_E_NOT_FOUND;
   1615     }
   1616 
   1617     /* Go through CCH covered field list for this register */
   1618     if (SOC_BLOCK_IS(SOC_REG_INFO(unit, reg).block, SOC_BLK_CCH)) {
   1619         rv = soc_cancun_pseudo_reg_get(unit, reg, &odata64);
   1620     } else {
   1621         rv = soc_reg_get(unit, reg, REG_PORT_ANY, 0, &odata64);
   1622     }
   1623     if (rv != SOC_E_NONE) {
   1624         return rv;
   1625     }
   1626 
   1627     p_field = &field_list->members;
   1628     for (l = 0; l < field_list->member_num; l++, p_field++) {
   1629         hash_table_entry = &hash_table_header->table_entry;
   1630         rv = _soc_cancun_hash(hash_table_header, reg, *p_field, &key);
   1631         if(rv != SOC_E_NONE) {
   1632             return rv;
   1633         }
   1634         offset = *(hash_table_entry + key);
   1635         if (offset == 0) {
   1636             return SOC_E_NOT_FOUND;
   1637         }
   1638         hash_table_entry = &hash_table_header->table_entry + offset;
   1639         hash_entry = _soc_cancun_hash_find_entry(hash_table_entry, reg,
   1640                                                  *p_field, CANCUN_APP_INVALID);
   1641         if (hash_entry == NULL) {
   1642             return SOC_E_NOT_FOUND;
   1643         }
   1644         cch_map = (soc_cancun_cch_map_t *) hash_entry;
   1645 
   1646         /* Get CCH map entry for current source field */
   1647         p = &cch_map->dest_map_entry;
   1648         orval = soc_reg64_field_get(unit, reg, odata64, *p_field);
   1649         rval = soc_reg64_field_get(unit, reg, data, *p_field);
   1650         if (COMPILER_64_EQ(orval, rval)) {
   1651             /* No value change on this field. Skip */
   1652             continue;
   1653         }
   1654         if (cch_map->src_value_num != 0) {
   1655             for (val_idx = 0; val_idx < cch_map->src_value_num; val_idx++) {
   1656                 COMPILER_64_SET(p64, 0, *p++);
   1657                 if (COMPILER_64_EQ(rval, p64)) {
   1658                     break;
   1659                 }
   1660             }
   1661             if (val_idx >= cch_map->src_value_num) {
   1662                 LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1663                     "can't find source value %0X_%0X for (%s, %s)\n"),
   1664                         COMPILER_64_HI(data),
   1665                         COMPILER_64_LO(data),
   1666                         SOC_REG_NAME(unit, reg),
   1667                         SOC_FIELD_NAME(unit, *p_field)));
   1668                 return SOC_E_NOT_FOUND;
   1669             }
   1670         }
   1671 
   1672         if (cc->flags & SOC_CANCUN_FLAG_DEBUG_MODE) {
   1673             LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1674                 "For reg %s, field %s, value 0x%08X_%08X, CCH writes:\n"),
   1675                  SOC_REG_NAME(unit, reg),
   1676                  SOC_FIELD_NAME(unit, *p_field),
   1677                  COMPILER_64_HI(rval),
   1678                  COMPILER_64_LO(rval)));
   1679         }
   1680 
   1681         SOC_IF_ERROR_RETURN(_soc_cancun_cch_dest_set_with_idx (unit, cch_map, rval, val_idx));
   1682      }
   1683 
   1684     return SOC_E_NONE;
   1685 }
   1686 
   1687 int soc_cancun_pseudo_reg_set(int unit, soc_reg_t reg, uint64 data) {
   1688 
   1689     soc_cancun_t* cc = soc_cancun_info[unit];
   1690     soc_cancun_cch_t *cch;
   1691     uint64 *preg, *flags;
   1692     uint64 flags_read64;
   1693 
   1694     if (!SOC_REG_IS_VALID(unit, reg)) {
   1695         return SOC_E_PARAM;
   1696     }
   1697 
   1698     if(cc == NULL) {
   1699         return SOC_E_UNIT;
   1700     } else if (!(cc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
   1701         return SOC_E_INIT;
   1702     } else {
   1703         cch = cc->cch;
   1704     }
   1705 
   1706     if(cch->pseudo_regs == NULL) {
   1707         return SOC_E_INIT;
   1708     }
   1709 
   1710     if (SOC_BLOCK_IS(SOC_REG_INFO(unit, reg).block, SOC_BLK_CCH)) {
   1711         
   1712         flags = cch->pseudo_regs + (SOC_REG_INFO(unit, reg).offset & 0xFFFF)/
   1713                 (sizeof(uint64)/sizeof(uint8));
   1714         preg = flags + 1;
   1715         COMPILER_64_SET(flags_read64, 0, SOC_CANCUN_PSEUDO_REGS_FLAGS_VALID_READ);
   1716         COMPILER_64_OR(*flags, flags_read64);
   1717         *preg = data;
   1718         return SOC_E_NONE;
   1719     } else {
   1720         return SOC_E_PARAM;
   1721     }
   1722 }
   1723 
   1724 int soc_cancun_pseudo_reg_get(int unit, soc_reg_t reg, uint64 *data) {
   1725 
   1726     soc_cancun_t* cc = soc_cancun_info[unit];
   1727     soc_cancun_cch_t *cch;
   1728     uint64 *preg, *flags;
   1729     uint64 rval64, flags_valid_read64;
   1730 
   1731     if (!SOC_REG_IS_VALID(unit, reg)) {
   1732         return SOC_E_PARAM;
   1733     }
   1734 
   1735     if(cc == NULL) {
   1736         return SOC_E_UNIT;
   1737     } else if (!(cc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
   1738         return SOC_E_INIT;
   1739     } else {
   1740         cch = cc->cch;
   1741     }
   1742 
   1743 
   1744     if (SOC_BLOCK_IS(SOC_REG_INFO(unit, reg).block, SOC_BLK_CCH)) {
   1745         
   1746         flags = cch->pseudo_regs + (SOC_REG_INFO(unit, reg).offset & 0xFFFF)/
   1747                 (sizeof(uint64)/sizeof(uint8));
   1748         preg = flags + 1;
   1749         COMPILER_64_SET(flags_valid_read64, 0, SOC_CANCUN_PSEUDO_REGS_FLAGS_VALID_READ);
   1750         COMPILER_64_AND(*flags, flags_valid_read64);
   1751         /* Load RESET value at first read */
   1752         
   1753         if (COMPILER_64_IS_ZERO(*flags)) {
   1754             COMPILER_64_SET(rval64, SOC_REG_INFO(unit, reg).rst_val_hi,
   1755                                     SOC_REG_INFO(unit, reg).rst_val_lo);
   1756             COMPILER_64_OR(*flags, flags_valid_read64);
   1757             *preg = rval64;
   1758         }
   1759         *data = *preg;
   1760         return SOC_E_NONE;
   1761     } else {
   1762         return SOC_E_PARAM;
   1763     }
   1764 }
   1765 
   1766 int _soc_cancun_cch_dest_set_with_idx (int unit,
   1767         soc_cancun_cch_map_t  *cch_map, uint64 data, uint32 val_idx) {
   1768 
   1769     soc_cancun_t *cc = soc_cancun_info[unit];
   1770     uint32 *p = NULL, *p_val = NULL;
   1771     uint32 i, j, k, bit_offset;
   1772     uint32 d_ind_num, d_fld_num, d_mem, d_ind, d_fld;
   1773     uint32 fld_max, fld_min, fld_bits, fld_words;
   1774     uint32 entbuf[SOC_MAX_MEM_WORDS] = {0};
   1775     uint32 fldbuf[SOC_MAX_MEM_WORDS] = {0};
   1776     uint64 rval, rdata64, fdata64;
   1777     int cch_d_mem_is_reg;
   1778     soc_field_info_t *finfop = NULL;
   1779     soc_mem_info_t *meminfo = NULL;
   1780     uint32 rvalbuf[2];
   1781     uint32 p_shift = 0;
   1782 
   1783     if (cch_map == NULL) {
   1784         return SOC_E_PARAM;
   1785     }
   1786 
   1787     COMPILER_64_COPY(rval, data);
   1788 
   1789     p = &cch_map->dest_map_entry + cch_map->src_value_num;
   1790     for (i = 0; i < cch_map->dest_mem_num; i++) {
   1791         d_mem = *p++;
   1792         d_ind_num = *p++;
   1793         d_fld_num = *p++;
   1794         for (j = 0; j < d_ind_num; j++) {
   1795             d_ind = *p++;
   1796             if (d_mem & SOC_CANCUN_FLAG_REG_ENUM) {
   1797                 cch_d_mem_is_reg = 1;
   1798                 d_mem &= ~SOC_CANCUN_FLAG_REG_ENUM;
   1799                 SOC_IF_ERROR_RETURN(
   1800                     soc_reg_get(unit, d_mem, REG_PORT_ANY, 0, &rdata64));
   1801             } else {
   1802                 cch_d_mem_is_reg = 0;
   1803                 SOC_IF_ERROR_RETURN(
   1804                     soc_mem_read(unit, d_mem, MEM_BLOCK_ANY, d_ind, entbuf));
   1805             }
   1806 
   1807             for (k = 0; k < d_fld_num; k++) {
   1808                 d_fld = *p++;
   1809                 fld_max = *p >> 16 & 0xFFFF;
   1810                 fld_min = *p++ & 0xFFFF;
   1811                 fld_bits = fld_max - fld_min + 1;
   1812                 fld_words = BITS2WORDS(fld_bits);
   1813                 p_shift = 2;
   1814                 if (cch_map->src_value_num != 0) {
   1815                     p_val = p + (val_idx * fld_words);
   1816                     p += cch_map->src_value_num * fld_words;
   1817                     COMPILER_64_SET(fdata64, 0, *p_val);
   1818                     p_shift += cch_map->src_value_num * fld_words;
   1819                 } else {
   1820                     rvalbuf[0] = COMPILER_64_LO(rval);
   1821                     rvalbuf[1] = COMPILER_64_HI(rval);
   1822                     p_val = &rvalbuf[0];
   1823                     COMPILER_64_COPY(fdata64, rval);
   1824                 }
   1825 
   1826                 if (cch_d_mem_is_reg == 1) {
   1827                     SOC_FIND_FIELD(d_fld,
   1828                                    SOC_REG_INFO(unit, d_mem).fields,
   1829                                    SOC_REG_INFO(unit, d_mem).nFields,
   1830                                    finfop);
   1831                     if (finfop == NULL) {
   1832                         return SOC_E_INTERNAL;
   1833                     }
   1834                     if (finfop->len != fld_bits) {
   1835                         uint64 rfdata64;
   1836                         uint64 fmask;
   1837 
   1838                         rfdata64 = soc_reg64_field_get(unit, d_mem, rdata64,
   1839                                         d_fld);
   1840                         bit_offset = fld_min - finfop->bp;
   1841                         COMPILER_64_MASK_CREATE(fmask, fld_bits, 0);
   1842                         COMPILER_64_AND(fdata64, fmask);
   1843                         COMPILER_64_SHL(fdata64, bit_offset);
   1844                         COMPILER_64_SHL(fmask, bit_offset);
   1845                         COMPILER_64_NOT(fmask);
   1846                         COMPILER_64_AND(rfdata64, fmask);
   1847                         COMPILER_64_OR(fdata64, rfdata64);
   1848                     }
   1849                     soc_reg64_field_set(unit, d_mem, &rdata64, d_fld, fdata64);
   1850 
   1851                     if (cc->flags & SOC_CANCUN_FLAG_DEBUG_MODE) {
   1852                         LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1853                             "\t%s.%s = 0x%08X_%08X\n"),
   1854                              SOC_REG_NAME(unit, d_mem),
   1855                              SOC_FIELD_NAME(unit, d_fld),
   1856                              COMPILER_64_HI(fdata64),
   1857                              COMPILER_64_LO(fdata64)));
   1858                     }
   1859                 } else {
   1860                     /* Bit shift if needed */
   1861                     
   1862                     meminfo = &SOC_MEM_INFO(unit, d_mem);
   1863                     SOC_FIND_FIELD(d_fld,
   1864                                    meminfo->fields,
   1865                                    meminfo->nFields,
   1866                                    finfop);
   1867                     if (finfop == NULL) {
   1868                         LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1869                             "\t special field num detected: %d,%d \n"), d_fld_num, k));
   1870                         p -= p_shift;
   1871 
   1872                         break;
   1873                     }
   1874 
   1875                     soc_mem_field_get(unit, d_mem, entbuf, d_fld, fldbuf);
   1876 
   1877                     if (finfop->len != fld_bits) {
   1878                         bit_offset = fld_min - finfop->bp;
   1879                         SHR_BITCOPY_RANGE(fldbuf, bit_offset, p_val, 0, fld_bits);
   1880                     } else {
   1881                         SHR_BITCOPY_RANGE(fldbuf, 0, p_val, 0, fld_bits);
   1882                     }
   1883 
   1884                     soc_mem_field_set(unit, d_mem, entbuf, d_fld, fldbuf);
   1885 
   1886                     if (cc->flags & SOC_CANCUN_FLAG_DEBUG_MODE) {
   1887                         char *fldbuf_str = sal_alloc(sizeof(char) *
   1888                                  ((SOC_MAX_MEM_FIELD_WORDS * 8) + 3),
   1889                                  "soc_cancun_debug_cch_str");
   1890                         if (fldbuf_str != NULL) {
   1891                             _shr_format_long_integer(fldbuf_str, fldbuf,
   1892                                                      BITS2BYTES(finfop->len));
   1893 
   1894                             LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1895                                 "\t%s[%d].%s = %s\n"),
   1896                                  SOC_MEM_NAME(unit, d_mem),
   1897                                  d_ind,
   1898                                  SOC_FIELD_NAME(unit, d_fld),
   1899                                  fldbuf_str));
   1900                             sal_free(fldbuf_str);
   1901                         }
   1902                     }
   1903                 }
   1904             }
   1905 
   1906             if (cch_d_mem_is_reg == 1) {
   1907                 SOC_IF_ERROR_RETURN(soc_reg_set(unit, d_mem,
   1908                     REG_PORT_ANY, 0, rdata64));
   1909             } else {
   1910                 SOC_IF_ERROR_RETURN(soc_mem_write(unit, d_mem,
   1911                     MEM_BLOCK_ALL, d_ind, entbuf));
   1912             }
   1913         }
   1914     }
   1915 
   1916     return SOC_E_NONE;
   1917 
   1918 }
   1919 
   1920 int _soc_cancun_cch_dest_set (int unit,
   1921         soc_cancun_cch_map_t *cch_map, uint64 data) {
   1922         return _soc_cancun_cch_dest_set_with_idx (unit, cch_map, data, 0x0);
   1923 }
   1924 
   1925 /*
   1926  * Function:
   1927  *      soc_cancun_cch_app_set
   1928  * Purpose:
   1929  *      Configure memory field values according to application
   1930  * Parameters:
   1931  *      unit  - (IN) Unit ID
   1932  *      src_app   - (IN) Source application ID
   1933  *      data - (IN) Memory field value
   1934  *
   1935  * Returns:
   1936  *      SOC_E_NONE
   1937  *      SOC_E_FAIL
   1938  *      SOC_E_INTERNAL  - CCH tables are not loaded
   1939  *      SOC_E_PARAM     - Input parameters are invalid
   1940  *      SOC_E_NOT_FOUND - Input mem/reg/field are not found in CCH
   1941  *
   1942  * Note:
   1943  *      CCH entry format 4 is shown as following. *
   1944  *      +----------+-----------------+-------------------+--------------+
   1945  *      | size     | format          | src_mem           | src_field    |
   1946  *      +----------+-----------------+-------------------+--------------+
   1947  *      | src_app  | val_num         | dest_tab_num      | ...          |
   1948  *      +----------+-----------------+-------------------+--------------+
   1949  *      | dest_tab | dest_index_num  | dest_field_num    | ...          |
   1950  *      +----------+-----------------+-------------------+--------------+
   1951  *      | index    | dest_field      | field_max_min_bit | ...          |
   1952  *      +----------+-----------------+-------------------+--------------+
   1953  */
   1954 int soc_cancun_cch_app_set (int unit, uint32 src_app, uint64 data) {
   1955 
   1956     soc_cancun_t *cc = NULL;
   1957     soc_cancun_cch_t *cch = NULL;
   1958     soc_cancun_cch_map_t *cch_map = NULL;
   1959     soc_cancun_hash_table_t *hash_table_header = NULL;
   1960     uint32 *hash_table_entry = NULL;
   1961     uint32 *hash_entry = NULL;
   1962     uint32 offset = 0;
   1963     uint32 key = 0;
   1964     int rv = 0;
   1965 
   1966     cc = soc_cancun_info[unit];
   1967     if (cc == NULL) {
   1968         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1969             "CANCUN is not initialized\n")));
   1970         return SOC_E_INIT;
   1971     } else if (!(cc->flags & SOC_CANCUN_FLAG_CCH_LOADED)) {
   1972         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   1973             "CCH file is not loaded\n")));
   1974         return SOC_E_INIT;
   1975     }
   1976 
   1977     cch = cc->cch;
   1978     hash_table_header = (soc_cancun_hash_table_t*) cch->cch_table;
   1979     hash_table_entry = &hash_table_header->table_entry;
   1980     rv = _soc_cancun_hash (hash_table_header, 0, src_app, &key);
   1981     if (rv != SOC_E_NONE) {
   1982         return rv;
   1983     }
   1984     offset = *(hash_table_entry + key);
   1985     if (offset == 0) {
   1986         return SOC_E_NOT_FOUND;
   1987     }
   1988     hash_table_entry = &hash_table_header->table_entry + offset;
   1989     hash_entry = _soc_cancun_hash_find_entry(hash_table_entry, INVALIDm,
   1990                                              INVALIDf, src_app);
   1991     if (hash_entry == NULL) {
   1992         return SOC_E_NOT_FOUND;
   1993     }
   1994 
   1995     cch_map = (soc_cancun_cch_map_t *) hash_entry;
   1996     SOC_IF_ERROR_RETURN(_soc_cancun_cch_dest_set (unit, cch_map, data));
   1997 
   1998     return SOC_E_NONE;
   1999 }
   2000 
   2001 
   2002 int _soc_cancun_load_status_clear(int unit, soc_cancun_file_type_e file_type) {
   2003     soc_cancun_t *cc = soc_cancun_info[unit];
   2004     uint32 *status;
   2005 
   2006     if(cc == NULL) {
   2007         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   2008             "CANCUN is not initialized\n")));
   2009         return SOC_E_INIT;
   2010     } else {
   2011         status = NULL;
   2012         switch (file_type) {
   2013             case CANCUN_SOC_FILE_TYPE_CIH:
   2014                 status = &cc->cih->status;
   2015                 break;
   2016             case CANCUN_SOC_FILE_TYPE_CMH:
   2017                 status = &cc->cmh->status;
   2018                 break;
   2019             case CANCUN_SOC_FILE_TYPE_CCH:
   2020                 status = &cc->cch->status;
   2021                 break;
   2022             default:
   2023                 return SOC_E_PARAM;
   2024         }
   2025     }
   2026 
   2027     if(status == NULL) {
   2028         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   2029             "CANCUN %s is not loaded\n"),
   2030             soc_chip_type_names[file_type]));
   2031         return SOC_E_INIT;
   2032     }
   2033 
   2034     *status = SOC_CANCUN_LOAD_STATUS_NOT_LOADED;
   2035 
   2036     return SOC_E_NONE;
   2037 }
   2038 
   2039 int soc_cancun_access_scan(int unit, soc_cancun_file_type_e file_type) {
   2040     soc_cancun_t *cc = soc_cancun_info[unit];
   2041     soc_cancun_cmh_t *cmh = NULL;
   2042     soc_cancun_cch_t *cch = NULL;
   2043     soc_cancun_cmh_map_t *cmh_map = NULL;
   2044     soc_cancun_cch_map_t *cch_map = NULL;
   2045     soc_cancun_hash_table_t *hash_table_header;
   2046     uint32 *hash_table_entry, *p;
   2047     uint32 i, j, k, l, offset, entry_num, field_num, index_num, dest_mem, pass = 1;
   2048 
   2049     if(cc == NULL) {
   2050         return SOC_E_UNIT;
   2051     } else if (!(cc->flags & SOC_CANCUN_FLAG_INITIALIZED)) {
   2052         return SOC_E_INIT;
   2053     }
   2054 
   2055     if(file_type == CANCUN_SOC_FILE_TYPE_CMH) {
   2056         cmh = cc->cmh;
   2057         hash_table_header = (soc_cancun_hash_table_t*) cmh->cmh_table;
   2058         for(i = 0; i < hash_table_header->pd; i++) {
   2059             hash_table_entry = &hash_table_header->table_entry;
   2060             offset = *(hash_table_entry + i);
   2061             if(offset == 0) {
   2062                 continue;
   2063             }
   2064             hash_table_entry = &hash_table_header->table_entry + offset;
   2065             entry_num = *hash_table_entry++;
   2066             cmh_map = (soc_cancun_cmh_map_t *) hash_table_entry;
   2067             for(j = 0; j < entry_num; j++) {
   2068                 if (cmh_map->format == 1) {
   2069                     pass &= _soc_cancun_enum_check(unit, 0, cmh_map->src_mem,
   2070                                                    SOC_CANCUN_ENUM_TYPE_MEM);
   2071                     pass &= _soc_cancun_enum_check(unit, cmh_map->src_mem,
   2072                                                cmh_map->src_field, 
   2073                                                SOC_CANCUN_ENUM_TYPE_MEM_FIELD);
   2074                     p = &cmh_map->dest_map_entry + cmh_map->src_value_num;
   2075                     for(k = 0; k < cmh_map->dest_mem_num; k++) {
   2076                         dest_mem = *p++;
   2077                         pass &= _soc_cancun_enum_check(unit, 0, dest_mem,
   2078                                                SOC_CANCUN_ENUM_TYPE_MEM);
   2079                         field_num = *p++;
   2080                         for(l = 0; l < field_num; l++) {
   2081                             pass &= _soc_cancun_enum_check(unit, dest_mem, *p++,
   2082                                                 SOC_CANCUN_ENUM_TYPE_MEM_FIELD);
   2083                         }
   2084                         p += field_num * cmh_map->src_value_num;
   2085                     }
   2086                 /* TO-DO: Add format 2~4 */
   2087                 } else {
   2088                     LOG_DEBUG(BSL_LS_SOC_CANCUN, (BSL_META_U(unit, 
   2089                               "Scan for CMH format %d is not yet supported\n"),
   2090                               cmh_map->format));
   2091                     continue;
   2092                 }
   2093             }
   2094         }
   2095     } else if(file_type == CANCUN_SOC_FILE_TYPE_CCH) {
   2096         cch = cc->cch;
   2097         hash_table_header = (soc_cancun_hash_table_t*) cch->cch_table;
   2098         for(i = 0; i < hash_table_header->pd; i++) {
   2099             hash_table_entry = &hash_table_header->table_entry;
   2100             offset = *(hash_table_entry + i);
   2101             if(offset == 0) {
   2102                 continue;
   2103             }
   2104             hash_table_entry = &hash_table_header->table_entry + offset;
   2105             entry_num = *hash_table_entry++;
   2106             cch_map = (soc_cancun_cch_map_t *) hash_table_entry;
   2107             for(j = 0; j < entry_num; j++) {
   2108                 if(cch_map->src_mem != 0 && cch_map->src_field != 0) {
   2109                     pass &= _soc_cancun_enum_check(unit, 0, cch_map->src_mem,
   2110                             SOC_CANCUN_ENUM_TYPE_REG);
   2111                     if (cch_map->format == 1 ||
   2112                         cch_map->format == 2 ||
   2113                         cch_map->format == 3) {
   2114                         pass &= _soc_cancun_enum_check(unit, cch_map->src_mem,
   2115                                                cch_map->src_field,
   2116                                                SOC_CANCUN_ENUM_TYPE_REG_FIELD);
   2117                         p = &cch_map->dest_map_entry + cch_map->src_value_num;
   2118                         for(k = 0; k < cch_map->dest_mem_num; k++) {
   2119                             dest_mem = *p++;
   2120                             pass &= _soc_cancun_enum_check(unit, 0, dest_mem,
   2121                                                    SOC_CANCUN_ENUM_TYPE_MEM);
   2122                             index_num = *p++;
   2123                             field_num = *p;
   2124                             p += 2;
   2125                             for(l = 0; l < field_num; l++) {
   2126                                 pass &= _soc_cancun_enum_check(unit, dest_mem, *p,
   2127                                                     SOC_CANCUN_ENUM_TYPE_MEM_FIELD);
   2128                                 p += (cch_map->src_value_num + 2);
   2129                             }
   2130                             if(index_num > 1) {
   2131                                 p += (index_num - 1) * field_num *
   2132                                      (2 + cch_map->src_value_num) + 1;
   2133                             }
   2134                         }
   2135                     } else {
   2136                         LOG_DEBUG(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   2137                                   "Scan for CCH format %d is not yet supported\n"),
   2138                                   cch_map->format));
   2139                         continue;
   2140                     }
   2141                 }
   2142                 hash_table_entry += cch_map->entry_size;
   2143                 cch_map = (soc_cancun_cch_map_t *) hash_table_entry;
   2144             }
   2145         }
   2146     } else {
   2147         return SOC_E_PARAM;
   2148     }
   2149 
   2150     if(pass) {
   2151         return SOC_E_NONE;
   2152     } else {
   2153         return SOC_E_FAIL;
   2154     }
   2155 }
   2156 
   2157 /*
   2158  * Internal Functions
   2159  */
   2160 static int _soc_cancun_alloc(soc_cancun_t** cancun) {
   2161     soc_cancun_t* cc;
   2162 
   2163     cc = sal_alloc(sizeof(soc_cancun_t), "soc_cancun_info");
   2164     if(cc == NULL) {
   2165         goto _soc_cancun_alloc_error;
   2166     }
   2167     sal_memset(cc, 0, sizeof(soc_cancun_t));
   2168 
   2169     cc->cih = sal_alloc(sizeof(soc_cancun_cih_t), "soc_cancun_cih");
   2170     if(cc->cih == NULL) {
   2171         goto _soc_cancun_alloc_error;
   2172     }
   2173     sal_memset(cc->cih, 0, sizeof(soc_cancun_cih_t));
   2174 
   2175     cc->cmh = sal_alloc(sizeof(soc_cancun_cmh_t), "soc_cancun_cmh");
   2176     if(cc->cmh == NULL) {
   2177         goto _soc_cancun_alloc_error;
   2178     }
   2179     sal_memset(cc->cmh, 0, sizeof(soc_cancun_cmh_t));
   2180 
   2181     cc->cch = sal_alloc(sizeof(soc_cancun_cch_t), "soc_cancun_cch");
   2182     if(cc->cch == NULL) {
   2183         goto _soc_cancun_alloc_error;
   2184     }
   2185 
   2186     sal_memset(cc->cch, 0, sizeof(soc_cancun_cch_t));
   2187     cc->flow_db = sal_alloc(sizeof(soc_flow_db_t), "soc_flow_db");
   2188     if(cc->flow_db == NULL) {
   2189         goto _soc_cancun_alloc_error;
   2190     }
   2191     sal_memset(cc->flow_db, 0, sizeof(soc_flow_db_t));
   2192 
   2193     cc->ceh = sal_alloc(sizeof(soc_cancun_ceh_t), "soc_cancun_ceh");
   2194     if(cc->ceh == NULL) {
   2195         goto _soc_cancun_alloc_error;
   2196     }
   2197     sal_memset(cc->ceh, 0, sizeof(soc_cancun_ceh_t));
   2198 
   2199     *cancun = cc;
   2200 
   2201     return 0;
   2202 
   2203 _soc_cancun_alloc_error:
   2204     if(cc) {
   2205         if(cc->cih) {
   2206             sal_free(cc->cih);
   2207         }
   2208         if(cc->cmh) {
   2209             sal_free(cc->cmh);
   2210         }
   2211         if(cc->cch) {
   2212             sal_free(cc->cch);
   2213         }
   2214         if (cc->flow_db) {
   2215             sal_free(cc->flow_db);
   2216         }
   2217         if(cc->ceh) {
   2218             sal_free(cc->ceh);
   2219         }
   2220         sal_free(cc);
   2221     }
   2222 
   2223     return -1;
   2224 }
   2225 
   2226 static int _soc_cancun_file_pio_load(int unit, uint8* buf, int buf_words) {
   2227     long schan_msg_len_words, msg_num, i;
   2228     schan_msg_t* msg;
   2229     int index;
   2230 
   2231     schan_msg_len_words = CMIC_SCHAN_WORDS(unit);
   2232     msg_num = buf_words / schan_msg_len_words;
   2233     msg = (schan_msg_t*) buf;
   2234 
   2235     for(i = 0; i < msg_num; i++) {
   2236 #if _PCID_TEST
   2237         {
   2238             int j;
   2239             for(j = 0; j< schan_msg_len_words; j++) {
   2240                 msg->dwords[j] = soc_htonl(msg->dwords[j]);
   2241                 cli_out("0x%x ", msg->dwords[j]);
   2242             }
   2243             cli_out("\n");
   2244             index = 0;
   2245         }
   2246 #else
   2247         index = soc_schan_op(unit, msg, schan_msg_len_words,
   2248                              schan_msg_len_words, 0);
   2249 #endif
   2250         if (index < 0) {
   2251             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   2252                 "S-Channel operation failed: %s\n"), soc_errmsg(index)));
   2253             return SOC_E_FAIL;
   2254         }
   2255         msg++;
   2256     }
   2257 
   2258     return SOC_E_NONE;
   2259 }
   2260 
   2261 static int _soc_cancun_file_cmh_load(int unit, uint8* buf, int buf_words) {
   2262     soc_cancun_cmh_t *cmh = soc_cancun_info[unit]->cmh;
   2263 
   2264     if(cmh == NULL) {
   2265         return SOC_E_INIT;
   2266     } else if (buf_words <= 0) {
   2267         return SOC_E_PARAM;
   2268     }
   2269 
   2270     /* NOTE: We do not have sal_realloc in our libc so need to free and then
   2271      *       re-alloc here for a new CMH load*/
   2272     if(cmh->cmh_table) {
   2273         sal_free(cmh->cmh_table);
   2274     }
   2275     cmh->cmh_table = sal_alloc((BYTES_PER_UINT32 * buf_words),
   2276                                "soc_cancun_cmh_table");
   2277     if(cmh->cmh_table == NULL) {
   2278         return SOC_E_MEMORY;
   2279     }
   2280 
   2281     _soc_cancun_memcpy_letohl((uint32 *)cmh->cmh_table, (uint32 *)buf, buf_words);
   2282 
   2283     return _soc_cancun_cmh_list_update(cmh);
   2284 
   2285 }
   2286 
   2287 static int _soc_cancun_cmh_list_update(soc_cancun_cmh_t *cmh) {
   2288     soc_cancun_hash_table_t *hash_table;
   2289     soc_cancun_cmh_map_t *cmh_map_entry;
   2290     uint32 *p_hask_key, *p_entry, *p_list;
   2291     uint32 entry_num, list_element_count = 0;
   2292     int i;
   2293 
   2294     hash_table = (soc_cancun_hash_table_t*) cmh->cmh_table;
   2295 
   2296     if(cmh->cmh_list) {
   2297         sal_free(cmh->cmh_list);
   2298     }
   2299     cmh->cmh_list = sal_alloc((BYTES_PER_UINT32 *
   2300                               (hash_table->entry_num * 3 + 1)),
   2301                               "soc_cancun_cmh_list");
   2302     if(cmh->cmh_list == NULL) {
   2303         return SOC_E_MEMORY;
   2304     }
   2305 
   2306     p_hask_key = &hash_table->table_entry;
   2307     p_list = cmh->cmh_list + 1;
   2308     for(i = 0; i < hash_table->pd; i++) {
   2309         if(p_hask_key[i] != 0) {
   2310             p_entry = p_hask_key + p_hask_key[i];
   2311             entry_num = *p_entry++;
   2312             cmh_map_entry = (soc_cancun_cmh_map_t*) p_entry;
   2313             while(entry_num-- > 0) {
   2314                 *p_list++ = cmh_map_entry->src_mem;
   2315                 *p_list++ = cmh_map_entry->src_field;
   2316                 *p_list++ = cmh_map_entry->src_app;
   2317                 list_element_count++;
   2318                 if(entry_num > 0) {
   2319                     p_entry += cmh_map_entry->entry_size;
   2320                     cmh_map_entry = (soc_cancun_cmh_map_t*) p_entry;
   2321                 }
   2322             }
   2323         }
   2324     }
   2325     *cmh->cmh_list = list_element_count;
   2326 
   2327     return SOC_E_NONE;
   2328 }
   2329 
   2330 static int _soc_cancun_file_cch_load(int unit, uint8* buf, int buf_words) {
   2331     soc_cancun_cch_t *cch = soc_cancun_info[unit]->cch;
   2332 
   2333     if(cch == NULL) {
   2334         return SOC_E_INIT;
   2335     } else if (buf_words <= 0) {
   2336         return SOC_E_PARAM;
   2337     }
   2338 
   2339     /* NOTE: We do not have sal_realloc in our libc so need to free and then
   2340      *       re-alloc here for a new CCH load*/
   2341     if(cch->cch_table) {
   2342         sal_free(cch->cch_table);
   2343     }
   2344     cch->cch_table = sal_alloc((BYTES_PER_UINT32 * buf_words),
   2345                                "soc_cancun_cch_table");
   2346     if(cch->cch_table == NULL) {
   2347         return SOC_E_MEMORY;
   2348     }
   2349 
   2350     if(cch->pseudo_regs) {
   2351         sal_free(cch->pseudo_regs);
   2352     }
   2353     cch->pseudo_regs = (uint64*) sal_alloc(SOC_CANCUN_PSEUDO_REGS_BLOCK_BYTE_SIZE,
   2354                                            "soc_cancun_cch_pseudo_regs");
   2355     if(cch->pseudo_regs == NULL) {
   2356         return SOC_E_MEMORY;
   2357     }
   2358     sal_memset(cch->pseudo_regs, 0, SOC_CANCUN_PSEUDO_REGS_BLOCK_BYTE_SIZE);
   2359 
   2360 #ifdef BCM_WARM_BOOT_SUPPORT
   2361     if (SOC_WARM_BOOT(unit)) {
   2362         (void)soc_cancun_scache_recovery(unit);
   2363     }
   2364 #endif /* BCM_WARM_BOOT_SUPPORT */
   2365 
   2366     _soc_cancun_memcpy_letohl((uint32 *)cch->cch_table, (uint32 *)buf, buf_words);
   2367 
   2368     return SOC_E_NONE;
   2369 
   2370 }
   2371 
   2372 static int _soc_cancun_file_ceh_load(int unit, uint8* buf, int buf_words)
   2373 {
   2374     uint8 *cur_dst;
   2375     uint8 *cur_src;
   2376     int cur_len;
   2377     int str_tbl_len;
   2378     int rem_len;
   2379     soc_cancun_ceh_t *ceh = soc_cancun_info[unit]->ceh;
   2380 
   2381     if(ceh == NULL) {
   2382         return SOC_E_INIT;
   2383     } else if (buf_words <= 0) {
   2384         return SOC_E_PARAM;
   2385     }
   2386 
   2387     /* NOTE: We do not have sal_realloc in our libc so need to free and then
   2388      *       re-alloc here for a new CEH load*/
   2389     if(ceh->ceh_table) {
   2390         sal_free(ceh->ceh_table);
   2391     }
   2392     ceh->ceh_table = sal_alloc((BYTES_PER_UINT32 * buf_words),
   2393                                "soc_cancun_ceh_table");
   2394     if(ceh->ceh_table == NULL) {
   2395         return SOC_E_MEMORY;
   2396     }
   2397 
   2398     cur_dst = (uint8 *)ceh->ceh_table;
   2399     cur_src = buf;
   2400     cur_len = SOC_CANCUN_CEH_BLOCK_HASH_HEADER_LEN * BYTES_PER_UINT32;
   2401     rem_len = buf_words * BYTES_PER_UINT32;
   2402     
   2403     /* load block and hash header */
   2404     sal_memcpy(cur_dst, cur_src,cur_len);
   2405     soc_cancun_buf_swap32(cur_dst, cur_len);
   2406 
   2407     /* next, string table len */
   2408     cur_dst += cur_len;
   2409     cur_src += cur_len; 
   2410     rem_len -= cur_len;
   2411     cur_len = BYTES_PER_UINT32;
   2412     sal_memcpy(cur_dst, cur_src,cur_len);
   2413     soc_cancun_buf_swap32(cur_dst, cur_len);
   2414 
   2415     /* no endianness to convert for string table. Just copy */
   2416     str_tbl_len = *(uint32 *)cur_dst; 
   2417     cur_dst += cur_len;
   2418     cur_src += cur_len; 
   2419     rem_len -= cur_len;
   2420     cur_len = str_tbl_len - BYTES_PER_UINT32;
   2421     sal_memcpy(cur_dst,cur_src, cur_len);
   2422 
   2423     /* convert rest of buffer */   
   2424     cur_dst += cur_len;
   2425     cur_src += cur_len; 
   2426     rem_len -= cur_len;
   2427     sal_memcpy(cur_dst, cur_src,rem_len);
   2428     soc_cancun_buf_swap32(cur_dst, rem_len);
   2429 
   2430     return SOC_E_NONE;
   2431 }
   2432 
   2433 static int _soc_cancun_hash(soc_cancun_hash_table_t* t, uint32 mem,
   2434                             soc_field_t field, uint32* key) {
   2435 
   2436     if((t == NULL) || (key == NULL)) {
   2437         return SOC_E_PARAM;
   2438     }
   2439 
   2440     /* generalized hash function */
   2441     *key = (t->pa * field + t->pa * mem + t->pc) % t->pd;
   2442 
   2443     return SOC_E_NONE;
   2444 }
   2445 
   2446 static int _soc_cancun_cih_load(int unit, uint8* buf, int num_data_blobs) {
   2447     int i;
   2448     uint32 length, flags;
   2449 
   2450     for (i = 0; i < num_data_blobs; i++) {
   2451         /* Length and flags fields are offset by 8 and 12 bytes from start of
   2452          * each data blob */
   2453         length = *(uint32 *)(buf + SOC_CANCUN_CIH_LENGTH_OFFSET);
   2454         flags = *(uint32 *)(buf + SOC_CANCUN_CIH_FLAG_OFFSET);
   2455 
   2456         /* Blob data format */
   2457         switch (flags & SOC_CANCUN_BLOB_FORMAT_MASK) {
   2458             case SOC_CANCUN_BLOB_FORMAT_PIO:
   2459                 SOC_IF_ERROR_RETURN
   2460                     (_soc_cancun_cih_pio_load(unit, buf, length, flags));
   2461                 buf += (sizeof(uint32) * SOC_CANCUN_CIH_PIO_DATA_BLOB_SIZE);
   2462                 break;
   2463             case SOC_CANCUN_BLOB_FORMAT_DMA:
   2464                 break;
   2465             case SOC_CANCUN_BLOB_FORMAT_FIFO:
   2466                 break;
   2467             case SOC_CANCUN_BLOB_FORMAT_RSVD:
   2468                 break;
   2469             default:
   2470                 return SOC_E_PARAM;
   2471         }
   2472     }
   2473     return SOC_E_NONE;
   2474 }
   2475 
   2476 static int _soc_cancun_cih_pio_load(int unit, uint8* buf, int length,
   2477                                     uint32 flags) {
   2478     schan_msg_t msg;
   2479     int i, index;
   2480     uint32 *p = (uint32 *) buf;
   2481     int rv;
   2482 
   2483     sal_memset(&msg, 0, sizeof(schan_msg_t));
   2484 
   2485     if (flags & SOC_CANCUN_BLOB_FLAG_MEM_ID_PRESENT) {
   2486         return _soc_cancun_cih_mem_load(unit, buf);
   2487     }
   2488 
   2489     /* Special case of TCAM memory loading */
   2490     if (flags & SOC_CANCUN_BLOB_FLAG_TCAM) {
   2491         rv = _soc_cancun_cih_tcam_write(unit, buf);
   2492         return rv;
   2493     }
   2494 
   2495     /* Copy destination address to schan msg structure */
   2496     msg.dwords[1] = *p++;
   2497 
   2498     /* Copy opcode to schan msg structure */
   2499     msg.dwords[0] = *p++;
   2500 
   2501     /* Copy data to schan msg structure */
   2502     p += 2; /* skip length and flag */
   2503     for(i = 0; i < length ; i++) {
   2504         msg.dwords[2+i] = *p++;
   2505     }
   2506 
   2507     for(i = 0; i < length + 2; i++) {
   2508         LOG_VERBOSE(BSL_LS_SOC_CANCUN,
   2509                     (BSL_META_U(unit, "0x%x "), msg.dwords[i]));
   2510     }
   2511     LOG_VERBOSE(BSL_LS_SOC_CANCUN, (BSL_META_U(unit, "\n")));
   2512 
   2513 #if _PCID_TEST
   2514     {
   2515         int j;
   2516         for(j = 0; j < length+2; j++) {
   2517             msg.dwords[j] = soc_htonl(msg.dwords[j]);
   2518             cli_out("0x%x ", msg.dwords[j]);
   2519         }
   2520         cli_out("\n");
   2521         index = 0;
   2522     }
   2523 #else
   2524     index = soc_schan_op(unit, &msg, length+2, length+2, 0);
   2525 #endif
   2526 
   2527     if (index < 0) {
   2528         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   2529             "S-Channel operation failed: %s\n"), soc_errmsg(index)));
   2530         return SOC_E_FAIL;
   2531     }
   2532 
   2533     return SOC_E_NONE;
   2534 
   2535 }
   2536 
   2537 static int _soc_cancun_cih_tcam_write(int unit, uint8 *buf) {
   2538 #define SOC_SBUS_V4_BLOCK_ID_BIT_OFFSET     (19)
   2539 #define SOC_SBUS_V4_BLOCK_ID_BIT_MASK       (0x7F)
   2540     uint32 entry[SOC_MAX_MEM_WORDS];
   2541     soc_mem_t mem;
   2542     uint32 index;
   2543     uint32 offset;
   2544     uint32 block = -1;
   2545     uint32 len;
   2546     uint32 *p = (uint32*) buf;
   2547 
   2548     if(!buf) {
   2549         return SOC_E_INTERNAL;
   2550     }
   2551 
   2552     if (soc_feature(unit, soc_feature_xy_tcam)) {
   2553         if (soc_feature(unit, soc_feature_sbus_format_v4)) {
   2554             block = (*(p + SOC_CANCUN_BLOB_OPCODE_OFFSET) >>
   2555                      SOC_SBUS_V4_BLOCK_ID_BIT_OFFSET)
   2556                     & SOC_SBUS_V4_BLOCK_ID_BIT_MASK;
   2557         } else {
   2558             return SOC_E_UNAVAIL;
   2559         }
   2560 
   2561         mem = soc_addr_to_mem_extended(unit, block, -1, *p);
   2562         if(mem == INVALIDm) {
   2563             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   2564                 "can't find TCAM memory for addr = 0x%x\n"), *p));
   2565             return SOC_E_INTERNAL;
   2566         }
   2567 
   2568         index = SOC_MEM_INFO(unit, mem).index_min +
   2569                 ((*p - SOC_MEM_INFO(unit, mem).base) /
   2570                   SOC_MEM_INFO(unit, mem).gran);
   2571         if(index > SOC_MEM_INFO(unit, mem).index_max) {
   2572             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   2573                 "ERROR: index = %d exceeds max of %s (%d)\n"), index,
   2574                     SOC_MEM_NAME(unit, mem),
   2575                     SOC_MEM_INFO(unit, mem).index_max));
   2576             return SOC_E_INTERNAL;
   2577         }
   2578 
   2579         offset = *p - (SOC_MEM_INFO(unit, mem).base +
   2580                        (index * SOC_MEM_INFO(unit, mem).gran));
   2581 
   2582         len = *(p + SOC_CANCUN_BLOB_LEN_OFFSET);
   2583 
   2584         SOC_IF_ERROR_RETURN(
   2585             soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, &entry));
   2586 
   2587         _soc_cancun_memcpy_letohl((entry + offset), (p + SOC_CANCUN_BLOB_DATA_OFFSET), len);
   2588 
   2589         SOC_IF_ERROR_RETURN(
   2590             soc_mem_write(unit, mem, MEM_BLOCK_ANY, index, &entry));
   2591 
   2592         return SOC_E_NONE;
   2593 
   2594     } else {
   2595         return SOC_E_UNAVAIL;
   2596     }
   2597 }
   2598 
   2599 static int _soc_cancun_cih_mem_load(int unit, uint8 *buf) {
   2600     uint32 entry[SOC_MAX_MEM_WORDS];
   2601     uint32 addr;
   2602     soc_mem_t mem;
   2603     uint32 index;
   2604     uint32 len;
   2605     uint32 *p = (uint32*)buf;
   2606 
   2607     addr = *p;
   2608     mem = addr >> SOC_CANCUN_BLOB_ADDR_MEM_ID_SHIFT;
   2609     index = addr & SOC_CANCUN_BLOB_ADDR_MEM_IDX_MASK;
   2610 
   2611     len = *(p + SOC_CANCUN_BLOB_LEN_OFFSET);
   2612     sal_memset(entry, 0, sizeof(entry));
   2613     sal_memcpy(entry, (p + SOC_CANCUN_BLOB_DATA_OFFSET), len*4);
   2614 
   2615     return soc_mem_write(unit, mem, MEM_BLOCK_ALL, index, &entry);
   2616 }
   2617 
   2618 static uint32* _soc_cancun_hash_find_entry(uint32 *hash_entry, uint32 src_mem,
   2619                                            uint32 src_field, int src_app) {
   2620 
   2621     soc_cancun_entry_hdr_t *p_hdr;
   2622     uint32 entry_num, i;
   2623     uint32 *p;
   2624 
   2625     if(hash_entry == NULL) {
   2626         return NULL;
   2627     }
   2628 
   2629     entry_num = *hash_entry;
   2630     p = hash_entry + 1;
   2631     p_hdr = (soc_cancun_entry_hdr_t*) p;
   2632 
   2633     for(i = 0; i < entry_num; i++) {
   2634         if(p_hdr->src_mem == src_mem) {
   2635         
   2636             if(src_field == INVALIDf ||
   2637                p_hdr->src_field == src_field) {
   2638                
   2639                 if(src_app == CANCUN_APP_INVALID ||
   2640                    p_hdr->src_app == src_app) {
   2641                     return p;
   2642                 }
   2643             }
   2644         }
   2645 
   2646         p = p + p_hdr->entry_size;
   2647         p_hdr = (soc_cancun_entry_hdr_t*) p;
   2648 
   2649     }
   2650 
   2651     return NULL;
   2652 }
   2653 
   2654 static int _soc_cancun_memcpy_letohl(uint32 *des, uint32 *src, uint32 word_len) {
   2655     uint32 i;
   2656 
   2657     if (des == NULL || src == NULL) {
   2658         return SOC_E_INTERNAL;
   2659     }
   2660 
   2661     for (i = 0; i < word_len; i++) {
   2662         *des++ = *src++;
   2663     }
   2664 
   2665     return SOC_E_NONE;
   2666 }
   2667 
   2668 static int _soc_cancun_enum_check(int unit, int regmem, int enum_val, int enum_type) {
   2669     if(enum_type == SOC_CANCUN_ENUM_TYPE_APP) {
   2670         if(enum_val >= CANCUN_APP_NUM) {
   2671             LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit, "app: %d\n"), 
   2672                       enum_val));
   2673             return 0;
   2674         }
   2675         return 1;
   2676     }
   2677 
   2678     if(enum_type == SOC_CANCUN_ENUM_TYPE_MEM) {
   2679         if(!SOC_MEM_IS_VALID(unit, enum_val)) {
   2680             LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit, "%sm\n"), 
   2681                       SOC_MEM_NAME(unit, enum_val)));
   2682             return 0;
   2683         }
   2684         return 1;
   2685     }
   2686 
   2687     if(enum_type == SOC_CANCUN_ENUM_TYPE_REG) {
   2688         if(!SOC_REG_IS_VALID(unit, enum_val)) {
   2689             LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit, "%sr\n"), 
   2690                       SOC_REG_NAME(unit, enum_val)));
   2691             return 0;
   2692         }
   2693         return 1;
   2694     }
   2695 
   2696     if(enum_type == SOC_CANCUN_ENUM_TYPE_MEM_FIELD) {
   2697         if(!SOC_MEM_FIELD_VALID(unit, regmem, enum_val)) {
   2698             LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit, "%sm.%sf\n"), 
   2699                 SOC_MEM_NAME(unit, regmem), SOC_FIELD_NAME(unit, enum_val)));
   2700             return 0;
   2701         }
   2702         return 1;
   2703     }
   2704     if(enum_type == SOC_CANCUN_ENUM_TYPE_REG_FIELD) {
   2705         if(!SOC_REG_FIELD_VALID(unit, regmem, enum_val)) {
   2706             LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit, "%sr.%sf\n"), 
   2707                 SOC_REG_NAME(unit, regmem), SOC_FIELD_NAME(unit, enum_val)));
   2708             return 0;
   2709         }
   2710         return 1;
   2711     }
   2712 
   2713     LOG_INFO(BSL_LS_SOC_CANCUN, (BSL_META_U(unit, "enum type %d not valid\n"), 
   2714                                              enum_type));
   2715     return 0;
   2716 }
   2717 
   2718 /* ZLIB CRC-32 routine */
   2719 uint32 soc_cancun_crc32(uint32 crc, uint8 *buf, int len_bytes) {
   2720 
   2721 #define DO1(buf) crc = soc_crc32_tab[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
   2722 #define DO2(buf)  DO1(buf); DO1(buf);
   2723 #define DO4(buf)  DO2(buf); DO2(buf);
   2724 #define DO8(buf)  DO4(buf); DO4(buf);
   2725 
   2726     if (buf == NULL) return 0L;
   2727     crc = crc ^ 0xffffffffL;
   2728 
   2729     while (len_bytes >= 8)
   2730     {
   2731         DO8(buf);
   2732         len_bytes -= 8;
   2733     }
   2734 
   2735     if (len_bytes) do {
   2736         DO1(buf);
   2737     } while (--len_bytes);
   2738 
   2739     return crc ^ 0xffffffffL;
   2740 }
   2741 
   2742 #ifdef BCM_WARM_BOOT_SUPPORT
   2743 /* Version_1_0:
   2744  * 60 registers * 256 bytes each
   2745  * Version_1_1:
   2746  * Newly added: 100 registers * 256 bytes each
   2747  */
   2748 #define BCM_WB_VERSION_1_0                SOC_SCACHE_VERSION(1, 0)
   2749 #define BCM_WB_VERSION_1_1                SOC_SCACHE_VERSION(1, 1)
   2750 #define BCM_WB_DEFAULT_VERSION            BCM_WB_VERSION_1_1
   2751 
   2752 int
   2753 soc_cancun_scache_alloc(int unit)
   2754 {
   2755     int stable_size;
   2756     int rv = SOC_E_NONE;
   2757     soc_scache_handle_t scache_handle;
   2758     uint8 *cancun_scache_ptr;
   2759     uint32 alloc_size;
   2760 
   2761     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   2762 
   2763     if ((stable_size == 0) || (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit))) {
   2764         return SOC_E_NONE;
   2765     }
   2766 
   2767     alloc_size = SOC_CANCUN_PSEUDO_REGS_BLOCK_BYTE_SIZE;
   2768     SOC_SCACHE_HANDLE_SET(scache_handle, unit, SOC_SCACHE_CANCUN_HANDLE, 0);
   2769 
   2770     rv = soc_versioned_scache_ptr_get(unit, scache_handle,
   2771                                           TRUE, &alloc_size,
   2772                                           &cancun_scache_ptr,
   2773                                           BCM_WB_DEFAULT_VERSION,
   2774                                           NULL);
   2775 
   2776     if (SOC_FAILURE(rv) && (rv != SOC_E_NOT_FOUND)) {
   2777         return rv;
   2778     }
   2779 
   2780     return SOC_E_NONE;
   2781 }
   2782 
   2783 int
   2784 soc_cancun_scache_sync(int unit)
   2785 {
   2786     int stable_size;
   2787     int rv = SOC_E_NONE;
   2788     soc_scache_handle_t scache_handle;
   2789     uint8 *cancun_scache_ptr;
   2790     uint32 alloc_size;
   2791     soc_cancun_cch_t *cch = soc_cancun_info[unit]->cch;
   2792 
   2793     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   2794 
   2795     if ((stable_size == 0) || (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit))) {
   2796         return SOC_E_NONE;
   2797     }
   2798 
   2799     alloc_size = SOC_CANCUN_PSEUDO_REGS_BLOCK_BYTE_SIZE;
   2800     SOC_SCACHE_HANDLE_SET(scache_handle, unit, SOC_SCACHE_CANCUN_HANDLE, 0);
   2801 
   2802     rv = soc_versioned_scache_ptr_get(unit, scache_handle,
   2803                                           FALSE, &alloc_size,
   2804                                           &cancun_scache_ptr,
   2805                                           BCM_WB_DEFAULT_VERSION,
   2806                                           NULL);
   2807 
   2808     if (SOC_FAILURE(rv) && (rv != SOC_E_NOT_FOUND)) {
   2809         return rv;
   2810     }
   2811 
   2812     if((cch != NULL) && (cch->pseudo_regs != NULL)) {
   2813         sal_memcpy(cancun_scache_ptr, cch->pseudo_regs, alloc_size);
   2814     }
   2815 
   2816     return SOC_E_NONE;
   2817 }
   2818 
   2819 int
   2820 soc_cancun_scache_recovery(int unit)
   2821 {
   2822     int stable_size;
   2823     int rv = SOC_E_NONE;
   2824     soc_scache_handle_t scache_handle;
   2825     uint8 *cancun_scache_ptr;
   2826     uint32 alloc_size;
   2827     uint16  recovered_ver = 0;
   2828     soc_cancun_cch_t *cch = soc_cancun_info[unit]->cch;
   2829     uint32 tmp_size = 0;
   2830 
   2831     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   2832 
   2833     if ((stable_size == 0) || (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit))) {
   2834         return SOC_E_NONE;
   2835     }
   2836 
   2837     alloc_size = SOC_CANCUN_PSEUDO_REGS_BLOCK_BYTE_SIZE;
   2838     SOC_SCACHE_HANDLE_SET(scache_handle, unit, SOC_SCACHE_CANCUN_HANDLE, 0);
   2839 
   2840     rv = soc_versioned_scache_ptr_get(unit, scache_handle,
   2841                                           FALSE, &tmp_size,
   2842                                           &cancun_scache_ptr,
   2843                                           BCM_WB_DEFAULT_VERSION,
   2844                                           &recovered_ver);
   2845 
   2846     if (SOC_FAILURE(rv) && (rv != SOC_E_NOT_FOUND)) {
   2847         return rv;
   2848     } else if (rv == SOC_E_NOT_FOUND) {
   2849         return soc_cancun_scache_alloc(unit);
   2850     } else {
   2851         if (tmp_size < alloc_size ) {
   2852             SOC_IF_ERROR_RETURN(soc_cancun_scache_alloc(unit));
   2853         }
   2854     }
   2855     if (cancun_scache_ptr != NULL) {
   2856         if ((cch != NULL) && (cch->pseudo_regs != NULL)) {
   2857             if (recovered_ver >= BCM_WB_VERSION_1_1) {
   2858                 tmp_size = SOC_CANCUN_PSEUDO_REGS_BLOCK_BYTE_SIZE;
   2859             } else if (recovered_ver >= BCM_WB_VERSION_1_0) {
   2860                 tmp_size = SOC_CANCUN_PSEUDO_REGS_BLOCK_BYTE_SIZE_V0;
   2861             }
   2862             sal_memcpy(cch->pseudo_regs, cancun_scache_ptr, tmp_size);
   2863         }
   2864     }
   2865 
   2866     return SOC_E_NONE;
   2867 }
   2868 #endif /* BCM_WARM_BOOT_SUPPORT */
   2869 
   2870 int soc_cancun_branch_id_get(int unit, uint32 cancun_type,
   2871         soc_cancun_file_branch_id_e *branch_id) {
   2872     int rv = SOC_E_NONE;
   2873 
   2874     if ((cancun_type < CANCUN_SOC_FILE_TYPE_CIH) ||
   2875         (cancun_type > CANCUN_SOC_FILE_TYPE_CEH)) {
   2876         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   2877                 "Unsupported cancun type\n")));
   2878         return SOC_E_PARAM;
   2879     }
   2880 
   2881 #ifndef NO_FILEIO
   2882     {
   2883         soc_cancun_t *cc = NULL;
   2884         uint32 version = 0;
   2885 
   2886         rv = soc_cancun_status_get(unit, &cc);
   2887         if(rv != SOC_E_NONE) {
   2888             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   2889                     "can't get CANCUN status. (%s)\n"), soc_errmsg(rv)));
   2890             return rv;
   2891         }
   2892         if (cancun_type == CANCUN_SOC_FILE_TYPE_CCH) {
   2893             version = cc->cch->version;
   2894         } else if (cancun_type == CANCUN_SOC_FILE_TYPE_CMH) {
   2895             version = cc->cmh->version;
   2896         } else if (cancun_type == CANCUN_SOC_FILE_TYPE_CEH) {
   2897             version = cc->ceh->version;
   2898         } else if (cancun_type == CANCUN_SOC_FILE_TYPE_CFH) {
   2899             version = cc->flow_db->version;
   2900         } else {
   2901             /* return CIH version by default */
   2902             version = cc->cih->version;
   2903         }
   2904 
   2905         *branch_id = (version >> CANCUN_VERSION_OFFSET_BRANCH_ID) & 0xF;
   2906     }
   2907 #else
   2908     {
   2909     LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit, "No file system\n")));
   2910 
   2911     return SOC_E_UNAVAIL;
   2912     }
   2913 #endif
   2914 
   2915     return rv;
   2916 }
   2917 
   2918 
   2919 /*
   2920  * Function:
   2921  *      soc_cancun_udf_abstr_type_info_get
   2922  * Purpose:
   2923  *      Get udf abstact packet type info
   2924  * Parameters:
   2925  *      unit  - (IN) Unit ID
   2926  *      abstract_type   - (IN) abstract type
   2927  *      parser   - (IN) parser identifier
   2928  *      max_stages - (IN) size of stage info array
   2929  *      hfe_prof_ptr_arr - (IN) HFE profile pointer array associated to
   2930  *                              each stage for a given abstract type.
   2931  *      stage_info_arr - (OUT) Array of Stage Info structures
   2932  *      actual_stage_num - (OUT) num of stages associated given abstract type.
   2933  *      hfe_prof_ptr_arr_len - (OUT) HFE prof pointer array len.
   2934  *
   2935  * Returns:
   2936  *      SOC_E_NONE
   2937  *      SOC_E_FAIL
   2938  *      SOC_E_INTERNAL  - UDF DB is not loaded
   2939  *      SOC_E_PARAM     - Input parameters are invalid
   2940  *      SOC_E_NOT_FOUND - stage info is not found
   2941  *
   2942  * Note:
   2943  *      CCH entry format 5 (UDF) is shown as following. *
   2944  *      +------------+-----------------+-------------------+-------------------+
   2945  *      | size       | format          | src_mem(INVALID)  | src_field(INVALID)|
   2946  *      +------------+-----------------+-------------------+-------------------+
   2947  *      | src_app    | stage_info_num  |   size            | policy_mem        |
   2948  *      +------------+-----------------+-------------------+-------------------+
   2949  *      |hfe_pro_ptr | start_pos       |    flags          | size              |
   2950  *      +------------+-----------------+-------------------+-------------------+
   2951  *      | policy_mem | hfe_pro_ptr     |   start_pos       | flags             |
   2952  *      +------------+-----------------+-------------------+-------------------+
   2953  */
   2954 int soc_cancun_udf_abstr_type_info_get(int unit,
   2955         uint32 abstract_type,
   2956         uint32 parser,
   2957         uint32 max_stages,
   2958         uint32 **hfe_prof_ptr_arr,
   2959         soc_cancun_udf_stage_info_t *stage_info_arr,
   2960         uint32 *actual_stage_num,
   2961         uint32 *hfe_prof_ptr_arr_len) {
   2962 
   2963     soc_cancun_t *cc = NULL;
   2964     soc_cancun_cch_t *cch = NULL;
   2965     soc_cancun_hash_table_t *hash_table_header = NULL;
   2966     soc_cancun_cch_map_t *cch_map = NULL;
   2967     uint32 *hash_table_entry = NULL;
   2968     uint32 *hash_entry = NULL;
   2969     uint32 offset = 0;
   2970     uint32 key = 0;
   2971     uint8 stg;
   2972     int rv = 0;
   2973     uint32 src_app = 0;
   2974     uint32 stage_info_num = 0;
   2975 
   2976     cc = soc_cancun_info[unit];
   2977     if (cc == NULL) {
   2978         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   2979             "CANCUN is not initialized\n")));
   2980         return SOC_E_INIT;
   2981     } else if (!(cc->flags & SOC_CANCUN_FLAG_CCH_LOADED)) {
   2982         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   2983             "CCH file is not loaded\n")));
   2984         return SOC_E_INIT;
   2985     }
   2986 
   2987     cch = cc->cch;
   2988     hash_table_header = (soc_cancun_hash_table_t*) cch->cch_table;
   2989     hash_table_entry = &hash_table_header->table_entry;
   2990     /* combine parse and abstract type as "srcapp" */
   2991     src_app = (parser << 16) + abstract_type;
   2992     rv = _soc_cancun_hash (hash_table_header, 0, src_app, &key);
   2993     if (rv != SOC_E_NONE) {
   2994         return rv;
   2995     }
   2996     offset = *(hash_table_entry + key);
   2997     if (offset == 0) {
   2998         return SOC_E_NOT_FOUND;
   2999     }
   3000     hash_table_entry = &hash_table_header->table_entry + offset;
   3001     hash_entry = _soc_cancun_hash_find_entry(hash_table_entry, INVALIDm,
   3002                                              INVALIDf, src_app);
   3003     if (hash_entry == NULL) {
   3004         return SOC_E_NOT_FOUND;
   3005     }
   3006 
   3007     cch_map = (soc_cancun_cch_map_t *) hash_entry;
   3008 
   3009     stage_info_num = cch_map->src_value_num;
   3010     if (actual_stage_num != NULL) {
   3011         *actual_stage_num = stage_info_num;
   3012     }
   3013 
   3014     if (max_stages > stage_info_num) {
   3015         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   3016             "stage_info_num (%d) less than expected (%d)\n"),
   3017             stage_info_num, max_stages));
   3018         return SOC_E_PARAM;
   3019     }
   3020 
   3021     if (hfe_prof_ptr_arr_len != NULL) {
   3022         uint32 *info_ptr;
   3023         soc_cancun_udf_stage_info_t *abstr_type_info;
   3024 
   3025         info_ptr = &(cch_map->dest_mem_num);
   3026         for (stg = 0; stg < stage_info_num; stg++) {
   3027             abstr_type_info = (soc_cancun_udf_stage_info_t *)info_ptr;
   3028             hfe_prof_ptr_arr_len[stg] = abstr_type_info->hfe_prof_ptr_arr_len;
   3029             info_ptr += 6;    /* increment till hfe_prof_ptr */
   3030             info_ptr += hfe_prof_ptr_arr_len[stg];
   3031         }
   3032     }
   3033 
   3034     if (stage_info_arr != NULL) {
   3035         uint8 ct;
   3036         uint32 *info_ptr;
   3037         soc_cancun_udf_stage_info_t *info_arr = stage_info_arr;
   3038 
   3039         info_ptr = &(cch_map->dest_mem_num);
   3040         for (stg = 0; stg < max_stages; stg++) {
   3041             info_arr->size = *info_ptr;
   3042             info_ptr++;
   3043             info_arr->policy_mem = *info_ptr;
   3044             info_ptr++;
   3045             info_arr->start_pos = *info_ptr;
   3046             info_ptr++;
   3047             info_arr->unavail_contbmap = *info_ptr;
   3048             info_ptr++;
   3049             info_arr->flags = *info_ptr;
   3050             info_ptr++;
   3051             info_arr->hfe_prof_ptr_arr_len = *info_ptr;
   3052             info_ptr++;
   3053 
   3054             if (hfe_prof_ptr_arr[stg] == NULL) {
   3055                 LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   3056                    "NULL hfe_prof_ptr for stage:%d\n"), stg));
   3057                 return SOC_E_PARAM;
   3058             }
   3059 
   3060             info_arr->hfe_profile_ptr = hfe_prof_ptr_arr[stg];
   3061             for (ct = 0; ct < info_arr->hfe_prof_ptr_arr_len; ct++) {
   3062                 info_arr->hfe_profile_ptr[ct] = *info_ptr;
   3063                 info_ptr++;
   3064             }
   3065             info_arr++;
   3066         }
   3067     }
   3068 
   3069     return SOC_E_NONE;
   3070 }
   3071 
   3072 int soc_cancun_version_get(int unit, uint32* cancun_ver) {
   3073     int rv = SOC_E_NONE;
   3074 
   3075 #ifndef NO_FILEIO
   3076     {
   3077         soc_cancun_t *cc = NULL;
   3078 
   3079         rv = soc_cancun_status_get(unit, &cc);
   3080         if(rv != SOC_E_NONE) {
   3081             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   3082                     "can't get CANCUN status. (%s)\n"), soc_errmsg(rv)));
   3083             return rv;
   3084         }
   3085         *cancun_ver = (cc->cih->version & (~CANCUN_VERSION_REVISION_MASK));
   3086     }
   3087 #else
   3088     {
   3089         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit, "No file system\n")));
   3090 
   3091         return SOC_E_UNAVAIL;
   3092     }
   3093 #endif
   3094 
   3095     return rv;
   3096 }
   3097 
   3098 int soc_cancun_revision_get(int unit, uint32* revision) {
   3099     int rv = SOC_E_NONE;
   3100 
   3101 #ifndef NO_FILEIO
   3102     {
   3103         soc_cancun_t *cc = NULL;
   3104 
   3105         rv = soc_cancun_status_get(unit, &cc);
   3106         if(rv != SOC_E_NONE) {
   3107             LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit,
   3108                     "can't get CANCUN status. (%s)\n"), soc_errmsg(rv)));
   3109             return rv;
   3110         }
   3111         *revision = (cc->cih->version >> CANCUN_VERSION_OFFSET_REVISION) & 0xF;
   3112     }
   3113 #else
   3114     {
   3115         LOG_ERROR(BSL_LS_SOC_CANCUN, (BSL_META_U(unit, "No file system\n")));
   3116 
   3117         return SOC_E_UNAVAIL;
   3118     }
   3119 #endif
   3120 
   3121     return rv;
   3122 }