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

profile_mem.c (112424B)


      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  * Provides generic routines for managing HW profile tables.
      8  */
      9 
     10 #include <soc/profile_mem.h>
     11 #include <soc/error.h>
     12 #include <soc/drv.h>
     13 
     14 #ifdef BCM_TOMAHAWK3_SUPPORT
     15 #include <soc/tomahawk3.h>
     16 #endif
     17 
     18 /*
     19  * Function:
     20  *      soc_profile_mem_t_init
     21  * Purpose:
     22  *      Initialize a soc_profile_mem_t structure.
     23  *
     24  * Parameters:
     25  *      profile_mem - (IN) Pointer to profile memory structure
     26  * Returns:
     27  *      void
     28  */
     29 void
     30 soc_profile_mem_t_init(soc_profile_mem_t *profile)
     31 {
     32     if (NULL != profile) {
     33         profile->tables = NULL;
     34         profile->table_count = 0;
     35         profile->flags = 0;
     36     }
     37 }
     38 
     39 STATIC void
     40 _soc_profile_mem_free(soc_profile_mem_t *profile)
     41 {
     42     soc_profile_mem_table_t *table;
     43     int table_index;
     44 
     45     if (profile->tables == NULL) {
     46         return;
     47     }
     48 
     49     for (table_index = 0; table_index < profile->table_count; table_index++) {
     50         table = &profile->tables[table_index];
     51         if (table->data_mask != NULL) {
     52             sal_free(table->data_mask);
     53             table->data_mask = NULL;
     54         }
     55         if (table->entries != NULL) {
     56             sal_free(table->entries);
     57             table->entries = NULL;
     58         }
     59         if (table->cache_p != NULL) {
     60             sal_free(table->cache_p);
     61             table->cache_p = NULL;
     62         }
     63     }
     64     sal_free(profile->tables);
     65     profile->tables = NULL;
     66 }
     67 
     68 /*
     69  * Function:
     70  *      soc_profile_mem_index_create
     71  * Purpose:
     72  *      Create a shadow copy and refcounts of a profile table.
     73  *      If called during WARM BOOT, the shadow copy is populated with
     74  *      the HW contents, otherwise, both the shadow copy and the
     75  *      HW entries are cleared.
     76  *
     77  * Parameters:
     78  *      unit              - (IN) Unit
     79  *      mem_array         - (IN) Pointer to memory id array
     80  *      entry_words_array - (IN) Pointer to entry size array
     81  *      index_min_array   - (IN) (optional) Pointer to index min array
     82  *                               default is soc_mem_index_min
     83  *      index_max_array   - (IN) (optional) Pointer to index max array
     84  *                               default is soc_mem_index_max
     85  *      data_mask_array   - (IN) (optional) Pointer to data mask array
     86  *                               default is to compare the entire entry
     87  *                               (include padding)
     88  *      table_count       - (IN) Number of entries in memory id array
     89  *      profile           - (IN) Pointer to profile memory structure
     90  * Returns:
     91  *      SOC_E_XXX
     92  */
     93 int
     94 soc_profile_mem_index_create(int unit,
     95                              soc_mem_t *mem_array,
     96                              int *entry_words_array,
     97                              int *index_min_array,
     98                              int *index_max_array,
     99                              void **data_mask_array,
    100                              int table_count,
    101                              soc_profile_mem_t *profile)
    102 {
    103     soc_profile_mem_table_t *table;
    104     int rv;
    105     int alloc_size;
    106     int num_entries, table_index, i;
    107 #ifdef BCM_TOMAHAWK3_SUPPORT
    108     int pipe, mem_per_pipe;
    109     uint32 pipe_map;
    110 #endif
    111     soc_mem_t mem;
    112     uint32 *data_mask_p, *cache_p;
    113     void *null_entry = NULL;
    114 
    115     if (profile == NULL) {
    116         return SOC_E_INIT;
    117     }
    118 
    119     if (mem_array == NULL || entry_words_array == NULL ||
    120         table_count == 0) {
    121         return SOC_E_PARAM;
    122     }
    123 
    124     if (profile->tables != NULL) {
    125         _soc_profile_mem_free(profile);
    126     }
    127 
    128     alloc_size = table_count * sizeof(soc_profile_mem_table_t);
    129     profile->tables = sal_alloc(alloc_size, "Profile Mem Tables");
    130     if (profile->tables == NULL) {
    131         return SOC_E_MEMORY;
    132     }
    133     sal_memset(profile->tables, 0, alloc_size);
    134     profile->table_count = table_count;
    135 
    136     for (table_index = 0; table_index < table_count; table_index++) {
    137         table = &profile->tables[table_index];
    138         table->mem = mem_array[table_index];
    139         if (index_min_array == NULL) {
    140             table->index_min = soc_mem_index_min(unit, table->mem);
    141         } else {
    142             table->index_min = index_min_array[table_index];
    143         }
    144         if (index_max_array == NULL) {
    145             table->index_max = soc_mem_index_max(unit, table->mem);
    146         } else {
    147             table->index_max = index_max_array[table_index];
    148         }
    149         if (table->index_max < table->index_min) {
    150             _soc_profile_mem_free(profile);
    151             return SOC_E_PARAM;
    152         }
    153         table->entry_words = entry_words_array[table_index];
    154 
    155         if (data_mask_array != NULL && data_mask_array[table_index] != NULL) {
    156             alloc_size = table->entry_words * sizeof(uint32);
    157             table->data_mask = sal_alloc(alloc_size, "Profile Mem Data Mask");
    158             if (table->data_mask == NULL) {
    159                 _soc_profile_mem_free(profile);
    160                 return SOC_E_MEMORY;
    161             }
    162             sal_memset(table->data_mask, 0, alloc_size);
    163             data_mask_p = data_mask_array[table_index];
    164             for (i = 0; i < table->entry_words; i++) {
    165                 table->data_mask[i] = data_mask_p[i];
    166             }
    167         }
    168 
    169         num_entries = table->index_max - table->index_min + 1;
    170         alloc_size = num_entries * sizeof(soc_profile_mem_entry_t);
    171         table->entries = sal_alloc(alloc_size, "Profile Mem Entries");
    172         if (table->entries == NULL) {
    173             _soc_profile_mem_free(profile);
    174             return SOC_E_MEMORY;
    175         }
    176         sal_memset(table->entries, 0, alloc_size);
    177 
    178         alloc_size = num_entries * table->entry_words * sizeof(uint32);
    179         table->cache_p = sal_alloc(alloc_size, "Profile Mem Cache");
    180         if (table->cache_p == NULL) {
    181             _soc_profile_mem_free(profile);
    182             return SOC_E_MEMORY;
    183         }
    184         sal_memset(table->cache_p, 0, alloc_size);
    185     }
    186 
    187     if (SOC_WARM_BOOT(unit)) {
    188         for (table_index = 0; table_index < profile->table_count;
    189              table_index++) {
    190             table = &profile->tables[table_index];
    191             num_entries = table->index_max - table->index_min + 1;
    192             for (i = 0; i < num_entries; i++) {
    193                 cache_p = &table->cache_p[table->entry_words * i];
    194 #ifdef BCM_TOMAHAWK3_SUPPORT
    195                 if (SOC_IS_TOMAHAWK3(unit) &&
    196                         SOC_MEM_UNIQUE_ACC(unit, table->mem)) {
    197 
    198                     mem_per_pipe =
    199                         (table->index_max + 1) / _TH3_PIPES_PER_DEV;
    200                     pipe = i / mem_per_pipe;
    201 
    202                     soc_tomahawk3_pipe_map_get(unit, &pipe_map);
    203                     /* skip if the pipe isn't valid (half chip) */
    204                     if ((pipe_map & (1 << pipe)) == 0) {
    205                         continue;
    206                     }
    207 
    208                     mem = SOC_MEM_UNIQUE_ACC(unit, table->mem)[pipe];
    209                     rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY,
    210                                   table->index_min + i%mem_per_pipe, cache_p);
    211                 } else
    212 #endif
    213                 {
    214                     mem = table->mem;
    215                     rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY,
    216                                   table->index_min + i, cache_p);
    217                 }
    218                 if (rv < 0) {
    219                     _soc_profile_mem_free(profile);
    220                     return rv;
    221                 }
    222             }
    223         }
    224     } else {
    225         /* Clear HW memory */
    226         for (table_index = 0; table_index < profile->table_count;
    227              table_index++) {
    228             table = &profile->tables[table_index];
    229 #ifdef BCM_RCPU_SUPPORT
    230             if (SOC_IS_RCPU_ONLY(unit)) {
    231                 /* 
    232                  * Avoid clearing below profile tables to make remote switch
    233                  * able to tx/rx RCPU packets.
    234                  */
    235                 if (ING_VLAN_TAG_ACTION_PROFILEm == table->mem ||
    236                     EGR_VLAN_TAG_ACTION_PROFILEm == table->mem) {
    237                     return SOC_E_NONE;
    238                 }
    239             }
    240 #endif /* BCM_RCPU_SUPPORT */
    241 
    242             if (SOC_HW_RESET(unit) &&
    243                 soc_mem_clearable_on_reset(unit, table->mem, COPYNO_ALL)){
    244                 continue;
    245             }
    246 
    247             /* If the profile is setup as a non-default index_min/max, we will
    248                call 'soc_mem_array_fill_range' to clear the memory, else
    249                call the generic 'soc_mem_clear', this is done so that the
    250                additional capabilities provided within the generic call like
    251                'h/w acceleration' can be utilized in most cases. */
    252             if((table->index_min != soc_mem_index_min(unit, table->mem)) ||
    253                (table->index_max != soc_mem_index_max(unit, table->mem))) {
    254 
    255                 /* Allocate a null-entry to use below */
    256                 null_entry = soc_cm_salloc(unit,
    257                                            WORDS2BYTES(table->entry_words),
    258                                            "profile create mem clear");
    259 
    260                 /* Bail on out of memory */
    261                 if(null_entry == NULL) {
    262                     _soc_profile_mem_free(profile);
    263                     return SOC_E_MEMORY;
    264                 }
    265 
    266                 sal_memcpy(null_entry,
    267                            soc_mem_entry_null(unit, table->mem),
    268                            soc_mem_entry_words(unit, table->mem) * 
    269                            sizeof(uint32));
    270 
    271                 rv = soc_mem_array_fill_range(unit,
    272                                               0, /* Flags - unused */
    273                                               table->mem,
    274                                               0, /* min_ar_index - unused */
    275                                               0, /* max_ar_index - unused */
    276                                               COPYNO_ALL,
    277                                               table->index_min,
    278                                               table->index_max,
    279                                               null_entry);
    280 
    281                 /* Free the allocated null_ptr memory */
    282                 soc_cm_sfree(unit, null_entry);
    283                 null_entry = NULL;
    284             } else {
    285                 rv = soc_mem_clear(unit, table->mem, COPYNO_ALL, TRUE);
    286             }
    287 
    288             if (rv < 0) {
    289                 _soc_profile_mem_free(profile);
    290                 return rv;
    291             }
    292         }
    293     }
    294 
    295     return SOC_E_NONE;
    296 }
    297 
    298 int
    299 soc_profile_mem_create(int unit,
    300                        soc_mem_t *mem_array,
    301                        int *entry_words_array,
    302                        int table_count,
    303                        soc_profile_mem_t *profile)
    304 {
    305     return soc_profile_mem_index_create(unit, mem_array, entry_words_array,
    306                                         NULL, NULL, NULL, table_count,
    307                                         profile);
    308 }
    309 
    310 /*
    311  * Function:
    312  *      soc_profile_mem_destroy
    313  * Purpose:
    314  *      Destroy the shadow copy and refcounts of a profile table.
    315  *
    316  * Parameters:
    317  *      unit        - (IN) Unit
    318  *      profile_mem - (IN) Pointer to profile memory structure
    319  * Returns:
    320  *      SOC_E_XXX
    321  */
    322 int
    323 soc_profile_mem_destroy(int unit,
    324                         soc_profile_mem_t *profile)
    325 {
    326     if (profile == NULL) {
    327         return SOC_E_PARAM;
    328     }
    329 
    330     _soc_profile_mem_free(profile);
    331     return SOC_E_NONE;
    332 }
    333 
    334 STATIC int
    335 _soc_profile_mem_check(int unit, soc_profile_mem_t *profile,
    336                        int base0)                       
    337 {
    338     soc_profile_mem_table_t *table;
    339     int num_entries, num_sets, entries_per_set, ref_count;
    340     int set, table_index, i, base;
    341 
    342     table = &profile->tables[0];
    343     entries_per_set = table->entries[base0].entries_per_set;
    344 
    345     if (profile->table_count == 1 && entries_per_set == 1) {
    346         return SOC_E_NONE;
    347     }
    348 
    349     num_entries = table->index_max - table->index_min + 1;
    350     num_sets = num_entries / entries_per_set;
    351     set = base0 / entries_per_set;
    352 
    353     ref_count = table->entries[base0].ref_count;
    354     for (table_index = 0; table_index < profile->table_count; table_index++) {
    355         table = &profile->tables[table_index];
    356         num_entries = table->index_max - table->index_min + 1;
    357         entries_per_set = num_entries / num_sets;
    358         base = set * entries_per_set;
    359         for (i = 0; i < entries_per_set; i++) {
    360             if (table->entries[base + i].entries_per_set != entries_per_set ||
    361                 table->entries[base + i].ref_count != ref_count) {
    362                 return SOC_E_INTERNAL;
    363             }
    364         }
    365     }
    366 
    367     return SOC_E_NONE;
    368 }
    369 
    370 /*
    371  * Function:
    372  *      soc_profile_mem_sw_state_set
    373  * Purpose:
    374  *      Add a set of entries (one or more entries) to a profile table. This
    375  *      routine searches for a matching set in the profile table. If a matching
    376  *      set is found, the ref count for that entry is incremented and
    377  *      its base index is returned. If a matching set is not found then then
    378  *      entry is updated at the incoming index (index0).
    379  *      No write to HW is done in this routine as this sets only SW state. 
    380  *
    381  * Parameters:
    382  *      unit             - (IN) Unit
    383  *      profile          - (IN) Pointer to profile memory structure
    384  *      entries_array    - (IN) Array of pointer to table entries set
    385  *      entries_per_set0 - (IN) Number of entries in the set for table 0
    386  *      index0           - (IN) Base index to the entries in HW for table 0
    387  *                                    
    388  * Returns:
    389  *      SOC_E_XXX
    390  */
    391 int
    392 soc_profile_mem_sw_state_set(int unit,
    393                              soc_profile_mem_t *profile,
    394                              void **entries_array,
    395                              int entries_per_set0,
    396                              uint32 index0)
    397 {
    398     soc_profile_mem_table_t *table;
    399     int index_min, num_entries, num_sets, entries_per_set;
    400     int set, table_index, i, j, base, base0, free_set;
    401     int entry_words, data_words;
    402     int alloc_size, rv = SOC_E_NONE;
    403     uint32 entry[SOC_MAX_MEM_WORDS];
    404     uint32 mask[SOC_MAX_MEM_WORDS];
    405     uint32 *cache_p, *entry_p, *mask_p, *range_p, *ent_p;
    406 
    407     if (profile == NULL || entries_array == NULL || entries_per_set0 <= 0) {
    408         return SOC_E_PARAM;
    409     }
    410 
    411     if (profile->tables == NULL || profile->table_count == 0) {
    412         return SOC_E_INIT;
    413     }
    414 
    415     table = &profile->tables[0];
    416     num_entries = table->index_max - table->index_min + 1;
    417 
    418     if (num_entries % entries_per_set0) {
    419         return SOC_E_PARAM;
    420     }
    421 
    422     num_sets = num_entries / entries_per_set0;
    423 
    424     for (table_index = 0; table_index < profile->table_count; table_index++) {
    425         table = &profile->tables[table_index];
    426         num_entries = table->index_max - table->index_min + 1;
    427         if (entries_array[table_index] == NULL) {
    428             return SOC_E_PARAM;
    429         }
    430 
    431         if (num_entries % num_sets) {
    432             return SOC_E_PARAM;
    433         }
    434     }
    435 
    436     sal_memset(mask, 0xff, sizeof(mask));
    437 
    438     /*
    439      * Search for an existing set that has the same configuration.
    440      */
    441     free_set = -1;
    442     for (set = 0; set < num_sets; set++) {
    443         base0 = set * entries_per_set0;
    444 
    445         /* Skip unused entries. */
    446         if (profile->tables[0].entries[base0].ref_count == 0) {
    447             if (free_set != -1) {
    448                 continue;
    449             }
    450 
    451             /* Preserve location of free slot. */
    452             free_set = set;
    453             if (profile->table_count == 1 && entries_per_set0 == 1) {
    454                 continue;
    455             }
    456 
    457             for (table_index = 0; table_index < profile->table_count;
    458                  table_index++) {
    459                 table = &profile->tables[table_index];
    460                 num_entries = table->index_max - table->index_min + 1;
    461                 entries_per_set = num_entries / num_sets;
    462                 base = set * entries_per_set;
    463                 for (i = 0; i < entries_per_set; i++) {
    464                     if (table->entries[base + i].ref_count) {
    465                         free_set = -1;
    466                         break;
    467                     }
    468                 }
    469                 if (free_set == -1) {
    470                     break;
    471                 }
    472             }
    473             /* If non-shared, break out of main loop on first empty entry */
    474             if ((profile->flags & SOC_PROFILE_MEM_F_NO_SHARE) &&
    475                 free_set >= 0) {
    476                 break;
    477             }
    478             continue;
    479         }
    480 
    481         /* If non-shared, continue looking for empty entry */
    482         if (profile->flags & SOC_PROFILE_MEM_F_NO_SHARE) {
    483             continue;
    484         }
    485 
    486         /* Skip set of different size */
    487         if (profile->tables[0].entries[base0].entries_per_set !=
    488             entries_per_set0) {
    489             continue;
    490         }
    491 
    492         /* Compare the new set of entries against the cache */
    493         for (table_index = 0; table_index < profile->table_count;
    494              table_index++) {
    495             table = &profile->tables[table_index];
    496             num_entries = table->index_max - table->index_min + 1;
    497             entries_per_set = num_entries / num_sets;
    498             base = set * entries_per_set;
    499             entry_words = table->entry_words;
    500             data_words = soc_mem_entry_words(unit, table->mem);
    501             entry_p = entries_array[table_index];
    502             cache_p = &table->cache_p[base * entry_words];
    503             mask_p = table->data_mask == NULL ? mask : table->data_mask;
    504             for (i = 0; i < entries_per_set; i++) {
    505                 for (j = 0; j < data_words; j++) {
    506                     if ((cache_p[j] ^ entry_p[j]) & mask_p[j]) {
    507                         break;
    508                     }
    509                 }
    510                 if (j < data_words) {
    511                     break;
    512                 }
    513                 entry_p += entry_words;
    514                 cache_p += entry_words;
    515             }
    516             if (i != entries_per_set) {
    517                 break;
    518             }
    519         }
    520         if (table_index != profile->table_count) {
    521             continue;
    522         }
    523 
    524         /* Do optional data integrity check */
    525         SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0));
    526 
    527         /* Matched set found */
    528         for (table_index = 0; table_index < profile->table_count;
    529              table_index++) {
    530             table = &profile->tables[table_index];
    531             num_entries = table->index_max - table->index_min + 1;
    532             entries_per_set = num_entries / num_sets;
    533             base = set * entries_per_set;
    534             for (i = 0; i < entries_per_set; i++) {
    535                 table->entries[base + i].ref_count++;
    536             }
    537         }
    538         return SOC_E_NONE;
    539     }
    540 
    541     /* set the incoming index as free index so that entry is added at same place */
    542     free_set = index0;
    543 
    544     for (table_index = 0; table_index < profile->table_count; table_index++) {
    545         table = &profile->tables[table_index];
    546         index_min = table->index_min;
    547         num_entries = table->index_max - table->index_min + 1;
    548         entries_per_set = num_entries / num_sets;
    549         base = free_set * entries_per_set;
    550         entry_words = table->entry_words;
    551         data_words = soc_mem_entry_words(unit, table->mem);
    552         entry_p = entries_array[table_index];
    553         cache_p = &table->cache_p[base * entry_words];
    554 
    555         if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) {
    556             alloc_size =  WORDS2BYTES(entry_words) * entries_per_set;
    557             range_p = soc_cm_salloc(unit, alloc_size, "profile update");
    558             if (NULL == range_p) {
    559                 return SOC_E_MEMORY;
    560             }
    561             sal_memset((void *)range_p, 0, alloc_size);
    562 
    563             if (table->data_mask != NULL) {
    564                 /* Read full entry from HW when profile only covers
    565                  * part of the table. */
    566                 rv = soc_mem_read_range(unit, table->mem, MEM_BLOCK_ANY,
    567                                         index_min + base,
    568                                         index_min + base + entries_per_set - 1,
    569                                         range_p);
    570             }
    571 
    572             if (SOC_SUCCESS(rv)) {
    573                 for (i = 0; i < entries_per_set; i++) {
    574                     ent_p =
    575                         soc_mem_table_idx_to_pointer(unit, table->mem,
    576                                                      uint32 *, range_p, i);
    577 
    578                     if (table->data_mask != NULL) {
    579                         /* Replace partial entry with new content */
    580                         for (j = 0; j < data_words; j++) {
    581                             ent_p[j] &= ~table->data_mask[j];
    582                             ent_p[j] |= entry_p[j] & table->data_mask[j];
    583                         }
    584                     } else {
    585                         /* Write entire new entry */
    586                         sal_memcpy(ent_p, entry_p,
    587                                    data_words * sizeof(uint32));
    588                     }
    589                     entry_p += entry_words;
    590                 }
    591             }
    592 
    593             if (SOC_SUCCESS(rv)) {
    594                 /* Copy entry into the software cache. */
    595                 entry_p = entries_array[table_index];
    596 
    597                 for (i = 0; i < entries_per_set; i++) {
    598                     sal_memcpy(cache_p, entry_p,
    599                                data_words * sizeof(uint32));
    600                     entry_p += entry_words;
    601                     cache_p += entry_words;
    602 
    603                     table->entries[base + i].ref_count++;
    604                     table->entries[base + i].entries_per_set =
    605                         entries_per_set;
    606                 }
    607             }
    608 
    609             soc_cm_sfree(unit, range_p);
    610             if (SOC_FAILURE(rv)) {
    611                 return rv;
    612             }            
    613         } else {
    614             for (i = 0; i < entries_per_set; i++) {
    615                 if (table->data_mask != NULL) {
    616                     /* Read original entry from hardware profile table */
    617                     SOC_IF_ERROR_RETURN
    618                         (soc_mem_read(unit, table->mem, MEM_BLOCK_ANY,
    619                                       index_min + base + i, entry));
    620 
    621                     /* Replace partial entry with new content */
    622                     for (j = 0; j < data_words; j++) {
    623                         entry[j] &= ~table->data_mask[j];
    624                         entry[j] |= entry_p[j] & table->data_mask[j];
    625                     }
    626 
    627                 }
    628 
    629                 /* Copy entry into the software cache. */
    630                 sal_memcpy(cache_p, entry_p, data_words * sizeof(uint32));
    631                 entry_p += entry_words;
    632                 cache_p += entry_words;
    633 
    634                 table->entries[base + i].ref_count++;
    635                 table->entries[base + i].entries_per_set = entries_per_set;
    636             }
    637         }
    638     }
    639 
    640     return SOC_E_NONE;
    641 }
    642 
    643 /*
    644  * Function:
    645  *      soc_profile_mem_add_unique
    646  * Purpose:
    647  *      Add a set of entries (one or more entries) to a profile table. This
    648  *      routine searches for a matching set in the profile table. If a matching
    649  *      set is found, the ref count for that entry is incremented and
    650  *      its base index is returned. If a matching set is not found and a free
    651  *      set is found, the HW table is updated, the ref count is incremented,
    652  *      and the base index of the set is returned. If no free set is found, an
    653  *      error is returned.
    654  *
    655  *      This is for when memory is split and UNIQUE per pipe
    656  *
    657  *
    658  * Parameters:
    659  *      unit             - (IN) Unit
    660  *      profile          - (IN) Pointer to profile memory structure
    661  *      entries_array    - (IN) Array of pointer to table entries set
    662  *      entries_per_set0 - (IN) Number of entries in the set for table 0
    663  *      pipe             - (IN) Pipe to affect
    664  *      index0           - (OUT) Base index to the entries in HW for table 0
    665  *
    666  * Returns:
    667  *      SOC_E_XXX
    668  *
    669  * Notes:
    670  * For example
    671  * Usually a profile structure is formed by single memory table. However if a
    672  * profile structure is formed by the combination of 2 tables (table1 and
    673  * table2 in this example). Each entry in table1 is 2 words long, and each
    674  * entry in table2 is 3 words long. Argument entries_per_set is uniform on all
    675  * tables (4 in this example).
    676  *   +------------------+     +--------------------------+
    677  *   | entries_array[0] |---> |  table1[0], 2 words long |
    678  *   +------------------+     +--------------------------+
    679  *   | entries_array[1] |-+   |  table1[1]               |
    680  *   +------------------+ |   +--------------------------+
    681  *                        |   |  table1[2]               |
    682  *                        |   +--------------------------+
    683  *                        |   |  table1[3]               |
    684  *                        |   +--------------------------+
    685  *                        |   +---------------------------------+
    686  *                        +-> |  table2[0], 3 words long        |
    687  *                            +---------------------------------+
    688  *                            |  table2[1]                      |
    689  *                            +---------------------------------+
    690  *                            |  table2[2]                      |
    691  *                            +---------------------------------+
    692  *                            |  table2[3]                      |
    693  *                            +---------------------------------+
    694  *
    695  * The code for above example may look like:
    696  * {
    697  *     void *entries[2];
    698  *     table1_entry_t table1[4];
    699  *     table2_entry_t table2[4];
    700  *     int entries_per_set0;
    701  *     uint32 index[2];
    702  *
    703  *     fill table1[0], table1[1], table1[2], table1[3]
    704  *     fill table2[0], table2[1], table2[2], table2[3]
    705  *     entries[0] = &table1;
    706  *     entries[1] = &table2;
    707  *     entries_per_set0 = 4;
    708  *     soc_profile_mem_add_unique(unit, profile_mem, &entries, entries_per_set0,
    709  *                         pipe, index);
    710  * }
    711  */
    712 int
    713 soc_profile_mem_add_unique(int unit,
    714                     soc_profile_mem_t *profile,
    715                     void **entries_array,
    716                     int entries_per_set0,
    717                     int pipe,
    718                     uint32 *index0)
    719 {
    720     soc_profile_mem_table_t *table;
    721     int index_min, num_entries, num_sets, entries_per_set;
    722     int set, table_index, i, j, base, base0, free_set;
    723     int entry_words, data_words;
    724     int alloc_size, rv = SOC_E_NONE;
    725     uint32 entry[SOC_MAX_MEM_WORDS];
    726     uint32 mask[SOC_MAX_MEM_WORDS];
    727     uint32 *cache_p, *entry_p, *mask_p, *range_p, *ent_p;
    728     soc_mem_t mem = INVALIDm;
    729     int mod, entries_per_pipe;
    730 
    731     int set_start, set_end;
    732 
    733     /* COVERITY: Intentional, stack use of 5192 bytes */
    734     /* coverity[stack_use_callee_max : FALSE] */
    735     /* coverity[stack_use_overflow : FALSE] */
    736     /* coverity[stack_use_return : FALSE] */
    737 
    738     if (profile == NULL || entries_array == NULL || entries_per_set0 <= 0 ||
    739         index0 == NULL) {
    740         return SOC_E_PARAM;
    741     }
    742 
    743     if (profile->tables == NULL || profile->table_count == 0) {
    744         return SOC_E_INIT;
    745     }
    746 
    747     table = &profile->tables[0];
    748     num_entries = table->index_max - table->index_min + 1;
    749     
    750     if (NULL == SOC_MEM_UNIQUE_ACC(unit, table->mem)) {
    751         return SOC_E_PARAM;
    752     }
    753 
    754     if (num_entries % entries_per_set0) {
    755         return SOC_E_PARAM;
    756     }
    757 
    758     num_sets = num_entries / entries_per_set0;
    759 
    760     for (table_index = 0; table_index < profile->table_count; table_index++) {
    761         table = &profile->tables[table_index];
    762         num_entries = table->index_max - table->index_min + 1;
    763         if (entries_array[table_index] == NULL) {
    764             return SOC_E_PARAM;
    765         }
    766 
    767         if (num_entries % num_sets) {
    768             return SOC_E_PARAM;
    769         }
    770     }
    771 
    772     sal_memset(mask, 0xff, sizeof(mask));
    773 
    774     /*
    775      * Search for an existing set that has the same configuration.
    776      */
    777 
    778     /* Start searching at the entries at the start of the pipe.
    779      * Example: If pipe 1 was passed in, start the search at the
    780      * the pipe 1 section of the profile table, which follows
    781      * the pipe 0 section of the profile table.
    782      *
    783      *       UNIQUE MEM          DUPLICATE MEM
    784      *      -----------          ----------
    785      *     0|PIPE0 MEM|         0|MEM     |
    786      *      |PIPE1 MEM|          |        |
    787      *      |PIPE2 MEM|          |        |
    788      *      |...      |          |...     |
    789      *   159|PIPE7 MEM|       159|        |
    790      *      -----------          ----------
    791  */
    792     entries_per_pipe = SOC_MEM_SIZE(unit, profile->tables[0].mem);
    793     set_start = pipe * entries_per_pipe;
    794     set_end =   (pipe + 1) * entries_per_pipe;
    795 
    796     free_set = -1;
    797     for (set = set_start; set < set_end; set++) {
    798         base0 = set * entries_per_set0;
    799 
    800         /* Skip unused entries. */
    801         if (profile->tables[0].entries[base0].ref_count == 0) {
    802             if (free_set != -1) {
    803                 continue;
    804             }
    805 
    806             /* Preserve location of free slot. */
    807             free_set = set;
    808             if (profile->table_count == 1 && entries_per_set0 == 1) {
    809                 continue;
    810             }
    811 
    812             for (table_index = 0; table_index < profile->table_count;
    813                  table_index++) {
    814                 table = &profile->tables[table_index];
    815                 num_entries = table->index_max - table->index_min + 1;
    816                 entries_per_set = num_entries / num_sets;
    817                 base = set * entries_per_set;
    818                 for (i = 0; i < entries_per_set; i++) {
    819                     if (table->entries[base + i].ref_count) {
    820                         free_set = -1;
    821                         break;
    822                     }
    823                 }
    824                 if (free_set == -1) {
    825                     break;
    826                 }
    827             }
    828             /* If non-shared, break out of main loop on first empty entry */
    829             if ((profile->flags & SOC_PROFILE_MEM_F_NO_SHARE) &&
    830                 free_set >= 0) {
    831                 break;
    832             }
    833             continue;
    834         }
    835 
    836         /* If non-shared, continue looking for empty entry */
    837         if (profile->flags & SOC_PROFILE_MEM_F_NO_SHARE) {
    838             continue;
    839         }
    840 
    841         /* Skip set of different size */
    842         if (profile->tables[0].entries[base0].entries_per_set !=
    843             entries_per_set0) {
    844             continue;
    845         }
    846 
    847         /* Compare the new set of entries against the cache */
    848         for (table_index = 0; table_index < profile->table_count;
    849              table_index++) {
    850             table = &profile->tables[table_index];
    851             num_entries = table->index_max - table->index_min + 1;
    852             entries_per_set = num_entries / num_sets;
    853             base = set * entries_per_set;
    854             entry_words = table->entry_words;
    855             data_words = soc_mem_entry_words(unit, table->mem);
    856             entry_p = entries_array[table_index];
    857             cache_p = &table->cache_p[base * entry_words];
    858             mask_p = table->data_mask == NULL ? mask : table->data_mask;
    859             for (i = 0; i < entries_per_set; i++) {
    860                 for (j = 0; j < data_words; j++) {
    861                     if ((cache_p[j] ^ entry_p[j]) & mask_p[j]) {
    862                         break;
    863                     }
    864                 }
    865                 if (j < data_words) {
    866                     break;
    867                 }
    868                 entry_p += entry_words;
    869                 cache_p += entry_words;
    870             }
    871             if (i != entries_per_set) {
    872                 break;
    873             }
    874         }
    875         if (table_index != profile->table_count) {
    876             continue;
    877         }
    878 
    879         /* Do optional data integrity check */
    880         SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0));
    881 
    882         /* Matched set found */
    883         for (table_index = 0; table_index < profile->table_count;
    884              table_index++) {
    885             table = &profile->tables[table_index];
    886             num_entries = table->index_max - table->index_min + 1;
    887             entries_per_set = num_entries / num_sets;
    888             base = set * entries_per_set;
    889             for (i = 0; i < entries_per_set; i++) {
    890                 table->entries[base + i].ref_count++;
    891             }
    892         }
    893 
    894         /* Return the index based on the pipe, not on the profile table */
    895         *index0 = (base0%entries_per_pipe) + profile->tables[0].index_min;
    896 
    897         return SOC_E_NONE;
    898     }
    899 
    900     if (free_set == -1) {
    901         return SOC_E_RESOURCE;
    902     }
    903 
    904     for (table_index = 0; table_index < profile->table_count; table_index++) {
    905         table = &profile->tables[table_index];
    906         index_min = table->index_min;
    907         num_entries = table->index_max - table->index_min + 1;
    908         entries_per_set = num_entries / num_sets;
    909         base = free_set * entries_per_set;
    910         entry_words = table->entry_words;
    911         data_words = soc_mem_entry_words(unit, table->mem);
    912         entry_p = entries_array[table_index];
    913         cache_p = &table->cache_p[base * entry_words];
    914 
    915         if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) {
    916             alloc_size =  WORDS2BYTES(entry_words) * entries_per_set;
    917             range_p = soc_cm_salloc(unit, alloc_size, "profile update");
    918             if (NULL == range_p) {
    919                 return SOC_E_MEMORY;
    920             }
    921 
    922             sal_memset((void *)range_p, 0, alloc_size);
    923 
    924             mem = table->mem;
    925             entries_per_set = num_entries / num_sets;
    926             base = free_set * entries_per_set;
    927 
    928             /* Unique Memories in the profile memory table need to
    929              * be written to hardware per pipe, while non
    930              * unique memories do not */
    931             if (SOC_MEM_UNIQUE_ACC(unit, mem)) {
    932                 mem = SOC_MEM_UNIQUE_ACC(unit, mem)[pipe];
    933                 mod = entries_per_pipe;
    934             } else {
    935                 mod = 1;
    936             }
    937 
    938             if (table->data_mask != NULL) {
    939                 /* Read full entry from HW when profile only covers
    940                  * part of the table. */
    941 
    942                 /* This reads from one pipe at a time */
    943                 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
    944                                         index_min + base%mod,
    945                                         index_min + base%mod + entries_per_set - 1,
    946                                         range_p);
    947             }
    948 
    949             if (SOC_SUCCESS(rv)) {
    950                 for (i = 0; i < entries_per_set; i++) {
    951                     ent_p =
    952                         soc_mem_table_idx_to_pointer(unit, mem,
    953                                                      uint32 *, range_p, i);
    954 
    955                     if (table->data_mask != NULL) {
    956                         /* Replace partial entry with new content */
    957                         for (j = 0; j < data_words; j++) {
    958                             ent_p[j] &= ~table->data_mask[j];
    959                             ent_p[j] |= entry_p[j] & table->data_mask[j];
    960                         }
    961                     } else {
    962                         /* Write entire new entry */
    963                         sal_memcpy(ent_p, entry_p,
    964                                    data_words * sizeof(uint32));
    965                     }
    966                     entry_p += entry_words;
    967                 }
    968             }
    969 
    970             if (SOC_SUCCESS(rv)) {
    971                 /* Write back the modified entries */
    972                 /* This writes to one pipe at a time */
    973                 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL,
    974                                          index_min + base%mod,
    975                                          index_min + base%mod + entries_per_set - 1,
    976                                          range_p);
    977             }
    978 
    979             if (SOC_SUCCESS(rv)) {
    980                 /* Copy entry into the software cache. */
    981                 entry_p = entries_array[table_index];
    982 
    983                 /* Restore base for writing into contiguous mem */
    984                 base = free_set * entries_per_set;
    985 
    986                 for (i = 0; i < entries_per_set; i++) {
    987                     sal_memcpy(cache_p, entry_p,
    988                                data_words * sizeof(uint32));
    989                     entry_p += entry_words;
    990                     cache_p += entry_words;
    991 
    992                     table->entries[base + i].ref_count++;
    993                     table->entries[base + i].entries_per_set =
    994                         entries_per_set;
    995                 }
    996             }
    997 
    998             soc_cm_sfree(unit, range_p);
    999             if (SOC_FAILURE(rv)) {
   1000                 return rv;
   1001             }
   1002         } else {
   1003             for (i = 0; i < entries_per_set; i++) {
   1004                 mem = table->mem;
   1005                 base = free_set * entries_per_set;
   1006                 if (SOC_MEM_UNIQUE_ACC(unit, mem)) {
   1007                     mem = SOC_MEM_UNIQUE_ACC(unit, mem)[pipe];
   1008                     mod = entries_per_pipe;
   1009                 } else {
   1010                     mod = 1;
   1011                 }
   1012                 if (table->data_mask != NULL) {
   1013                     /* Read original entry from hardware profile table */
   1014                     SOC_IF_ERROR_RETURN
   1015                         (soc_mem_read(unit, mem, MEM_BLOCK_ANY,
   1016                                       index_min + base%mod + i, entry));
   1017 
   1018                     /* Replace partial entry with new content */
   1019                     for (j = 0; j < data_words; j++) {
   1020                         entry[j] &= ~table->data_mask[j];
   1021                         entry[j] |= entry_p[j] & table->data_mask[j];
   1022                     }
   1023 
   1024                     /* Write modified entry into hardware profile table */
   1025                     SOC_IF_ERROR_RETURN
   1026                         (soc_mem_write(unit, mem, MEM_BLOCK_ALL,
   1027                                        index_min + base%mod + i, entry));
   1028                 } else {
   1029                     /* Write entire new entry into hardware profile table */
   1030                     SOC_IF_ERROR_RETURN
   1031                         (soc_mem_write(unit, mem, MEM_BLOCK_ALL,
   1032                                        index_min + base%mod + i, entry_p));
   1033                 }
   1034 
   1035                 /* Copy entry into the software cache. */
   1036                 sal_memcpy(cache_p, entry_p, data_words * sizeof(uint32));
   1037                 entry_p += entry_words;
   1038                 cache_p += entry_words;
   1039 
   1040                 table->entries[base + i].ref_count++;
   1041                 table->entries[base + i].entries_per_set = entries_per_set;
   1042             }
   1043         }
   1044     }
   1045 
   1046     /* Return the index based on the pipe, not on the profile table */
   1047     *index0 = (free_set%entries_per_pipe) * entries_per_set0 + profile->tables[0].index_min;
   1048 
   1049     return SOC_E_NONE;
   1050 }
   1051 
   1052 /*
   1053  * Function:
   1054  *      soc_profile_mem_add
   1055  * Purpose:
   1056  *      Add a set of entries (one or more entries) to a profile table. This
   1057  *      routine searches for a matching set in the profile table. If a matching
   1058  *      set is found, the ref count for that entry is incremented and
   1059  *      its base index is returned. If a matching set is not found and a free
   1060  *      set is found, the HW table is updated, the ref count is incremented,
   1061  *      and the base index of the set is returned. If no free set is found, an
   1062  *      error is returned
   1063  *
   1064  * Parameters:
   1065  *      unit             - (IN) Unit
   1066  *      profile          - (IN) Pointer to profile memory structure
   1067  *      entries_array    - (IN) Array of pointer to table entries set
   1068  *      entries_per_set0 - (IN) Number of entries in the set for table 0
   1069  *      index0           - (OUT) Base index to the entries in HW for table 0
   1070  *                                    
   1071  * Returns:
   1072  *      SOC_E_XXX
   1073  *
   1074  * Notes:
   1075  * For example
   1076  * Usually a profile structure is formed by single memory table. However if a
   1077  * profile structure is formed by the combination of 2 tables (table1 and
   1078  * table2 in this example). Each entry in table1 is 2 words long, and each
   1079  * entry in table2 is 3 words long. Argument entries_per_set is uniform on all
   1080  * tables (4 in this example).
   1081  *   +------------------+     +--------------------------+
   1082  *   | entries_array[0] |---> |  table1[0], 2 words long |
   1083  *   +------------------+     +--------------------------+
   1084  *   | entries_array[1] |-+   |  table1[1]               |
   1085  *   +------------------+ |   +--------------------------+
   1086  *                        |   |  table1[2]               |
   1087  *                        |   +--------------------------+
   1088  *                        |   |  table1[3]               |
   1089  *                        |   +--------------------------+
   1090  *                        |   +---------------------------------+
   1091  *                        +-> |  table2[0], 3 words long        |
   1092  *                            +---------------------------------+
   1093  *                            |  table2[1]                      |
   1094  *                            +---------------------------------+
   1095  *                            |  table2[2]                      |
   1096  *                            +---------------------------------+
   1097  *                            |  table2[3]                      |
   1098  *                            +---------------------------------+
   1099  *
   1100  * The code for above example may look like:
   1101  * {
   1102  *     void *entries[2];
   1103  *     table1_entry_t table1[4];
   1104  *     table2_entry_t table2[4];
   1105  *     int entries_per_set0;
   1106  *     uint32 index[2];
   1107  *
   1108  *     fill table1[0], table1[1], table1[2], table1[3]
   1109  *     fill table2[0], table2[1], table2[2], table2[3]
   1110  *     entries[0] = &table1;
   1111  *     entries[1] = &table2;
   1112  *     entries_per_set0 = 4;
   1113  *     soc_profile_mem_add(unit, profile_mem, &entries, entries_per_set0,
   1114  *                         index);
   1115  * }
   1116  */
   1117 int
   1118 soc_profile_mem_add(int unit,
   1119                     soc_profile_mem_t *profile,
   1120                     void **entries_array,
   1121                     int entries_per_set0,
   1122                     uint32 *index0)
   1123 {
   1124     soc_profile_mem_table_t *table;
   1125     int index_min, num_entries, num_sets, entries_per_set;
   1126     int set, table_index, i, j, base, base0, free_set;
   1127     int entry_words, data_words;
   1128     int alloc_size, rv = SOC_E_NONE;
   1129     uint32 entry[SOC_MAX_MEM_WORDS];
   1130     uint32 mask[SOC_MAX_MEM_WORDS];
   1131     uint32 *cache_p, *entry_p, *mask_p, *range_p, *ent_p;
   1132 
   1133     /* COVERITY: Intentional, stack use of 5192 bytes */
   1134     /* coverity[stack_use_callee_max : FALSE] */
   1135     /* coverity[stack_use_overflow : FALSE] */
   1136     /* coverity[stack_use_return : FALSE] */
   1137 
   1138     if (profile == NULL || entries_array == NULL || entries_per_set0 <= 0 ||
   1139         index0 == NULL) {
   1140         return SOC_E_PARAM;
   1141     }
   1142 
   1143     if (profile->tables == NULL || profile->table_count == 0) {
   1144         return SOC_E_INIT;
   1145     }
   1146 
   1147     table = &profile->tables[0];
   1148     num_entries = table->index_max - table->index_min + 1;
   1149 
   1150     if (num_entries % entries_per_set0) {
   1151         return SOC_E_PARAM;
   1152     }
   1153 
   1154     num_sets = num_entries / entries_per_set0;
   1155 
   1156     for (table_index = 0; table_index < profile->table_count; table_index++) {
   1157         table = &profile->tables[table_index];
   1158         num_entries = table->index_max - table->index_min + 1;
   1159         if (entries_array[table_index] == NULL) {
   1160             return SOC_E_PARAM;
   1161         }
   1162 
   1163         if (num_entries % num_sets) {
   1164             return SOC_E_PARAM;
   1165         }
   1166     }
   1167 
   1168     sal_memset(mask, 0xff, sizeof(mask));
   1169 
   1170     /*
   1171      * Search for an existing set that has the same configuration.
   1172      */
   1173     free_set = -1;
   1174     for (set = 0; set < num_sets; set++) {
   1175         base0 = set * entries_per_set0;
   1176 
   1177         /* Skip unused entries. */
   1178         if (profile->tables[0].entries[base0].ref_count == 0) {
   1179             if (free_set != -1) {
   1180                 continue;
   1181             }
   1182 
   1183             /* Preserve location of free slot. */
   1184             free_set = set;
   1185             if (profile->table_count == 1 && entries_per_set0 == 1) {
   1186                 continue;
   1187             }
   1188 
   1189             for (table_index = 0; table_index < profile->table_count;
   1190                  table_index++) {
   1191                 table = &profile->tables[table_index];
   1192                 num_entries = table->index_max - table->index_min + 1;
   1193                 entries_per_set = num_entries / num_sets;
   1194                 base = set * entries_per_set;
   1195                 for (i = 0; i < entries_per_set; i++) {
   1196                     if (table->entries[base + i].ref_count) {
   1197                         free_set = -1;
   1198                         break;
   1199                     }
   1200                 }
   1201                 if (free_set == -1) {
   1202                     break;
   1203                 }
   1204             }
   1205             /* If non-shared, break out of main loop on first empty entry */
   1206             if ((profile->flags & SOC_PROFILE_MEM_F_NO_SHARE) &&
   1207                 free_set >= 0) {
   1208                 break;
   1209             }
   1210             continue;
   1211         }
   1212 
   1213         /* If non-shared, continue looking for empty entry */
   1214         if (profile->flags & SOC_PROFILE_MEM_F_NO_SHARE) {
   1215             continue;
   1216         }
   1217 
   1218         /* Skip set of different size */
   1219         if (profile->tables[0].entries[base0].entries_per_set !=
   1220             entries_per_set0) {
   1221             continue;
   1222         }
   1223 
   1224         /* Compare the new set of entries against the cache */
   1225         for (table_index = 0; table_index < profile->table_count;
   1226              table_index++) {
   1227             table = &profile->tables[table_index];
   1228             num_entries = table->index_max - table->index_min + 1;
   1229             entries_per_set = num_entries / num_sets;
   1230             base = set * entries_per_set;
   1231             entry_words = table->entry_words;
   1232             data_words = soc_mem_entry_words(unit, table->mem);
   1233             entry_p = entries_array[table_index];
   1234             cache_p = &table->cache_p[base * entry_words];
   1235             mask_p = table->data_mask == NULL ? mask : table->data_mask;
   1236             for (i = 0; i < entries_per_set; i++) {
   1237                 for (j = 0; j < data_words; j++) {
   1238                     if ((cache_p[j] ^ entry_p[j]) & mask_p[j]) {
   1239                         break;
   1240                     }
   1241                 }
   1242                 if (j < data_words) {
   1243                     break;
   1244                 }
   1245                 entry_p += entry_words;
   1246                 cache_p += entry_words;
   1247             }
   1248             if (i != entries_per_set) {
   1249                 break;
   1250             }
   1251         }
   1252         if (table_index != profile->table_count) {
   1253             continue;
   1254         }
   1255 
   1256         /* Do optional data integrity check */
   1257         SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0));
   1258 
   1259         /* Matched set found */
   1260         for (table_index = 0; table_index < profile->table_count;
   1261              table_index++) {
   1262             table = &profile->tables[table_index];
   1263             num_entries = table->index_max - table->index_min + 1;
   1264             entries_per_set = num_entries / num_sets;
   1265             base = set * entries_per_set;
   1266             for (i = 0; i < entries_per_set; i++) {
   1267                 table->entries[base + i].ref_count++;
   1268             }
   1269         }
   1270         *index0 = base0 + profile->tables[0].index_min;
   1271 
   1272         return SOC_E_NONE;
   1273     }
   1274 
   1275     if (free_set == -1) {
   1276         return SOC_E_RESOURCE;
   1277     }
   1278 
   1279     for (table_index = 0; table_index < profile->table_count; table_index++) {
   1280         table = &profile->tables[table_index];
   1281         index_min = table->index_min;
   1282         num_entries = table->index_max - table->index_min + 1;
   1283         entries_per_set = num_entries / num_sets;
   1284         base = free_set * entries_per_set;
   1285         entry_words = table->entry_words;
   1286         data_words = soc_mem_entry_words(unit, table->mem);
   1287         entry_p = entries_array[table_index];
   1288         cache_p = &table->cache_p[base * entry_words];
   1289 
   1290         if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) {
   1291             alloc_size =  WORDS2BYTES(entry_words) * entries_per_set;
   1292             range_p = soc_cm_salloc(unit, alloc_size, "profile update");
   1293             if (NULL == range_p) {
   1294                 return SOC_E_MEMORY;
   1295             }
   1296             sal_memset((void *)range_p, 0, alloc_size);
   1297 
   1298             if (table->data_mask != NULL) {
   1299                 /* Read full entry from HW when profile only covers
   1300                  * part of the table. */
   1301                 rv = soc_mem_read_range(unit, table->mem, MEM_BLOCK_ANY,
   1302                                         index_min + base,
   1303                                         index_min + base + entries_per_set - 1,
   1304                                         range_p);
   1305             }
   1306 
   1307             if (SOC_SUCCESS(rv)) {
   1308                 for (i = 0; i < entries_per_set; i++) {
   1309                     ent_p =
   1310                         soc_mem_table_idx_to_pointer(unit, table->mem,
   1311                                                      uint32 *, range_p, i);
   1312 
   1313                     if (table->data_mask != NULL) {
   1314                         /* Replace partial entry with new content */
   1315                         for (j = 0; j < data_words; j++) {
   1316                             ent_p[j] &= ~table->data_mask[j];
   1317                             ent_p[j] |= entry_p[j] & table->data_mask[j];
   1318                         }
   1319                     } else {
   1320                         /* Write entire new entry */
   1321                         sal_memcpy(ent_p, entry_p,
   1322                                    data_words * sizeof(uint32));
   1323                     }
   1324                     entry_p += entry_words;
   1325                 }
   1326             }
   1327 
   1328             if (SOC_SUCCESS(rv)) {
   1329                 /* Write back the modified entries */
   1330                 rv = soc_mem_write_range(unit, table->mem, MEM_BLOCK_ALL,
   1331                                          index_min + base,
   1332                                          index_min + base + entries_per_set - 1,
   1333                                          range_p);
   1334             }
   1335 
   1336             if (SOC_SUCCESS(rv)) {
   1337                 /* Copy entry into the software cache. */
   1338                 entry_p = entries_array[table_index];
   1339 
   1340                 for (i = 0; i < entries_per_set; i++) {
   1341                     sal_memcpy(cache_p, entry_p,
   1342                                data_words * sizeof(uint32));
   1343                     entry_p += entry_words;
   1344                     cache_p += entry_words;
   1345 
   1346                     table->entries[base + i].ref_count++;
   1347                     table->entries[base + i].entries_per_set =
   1348                         entries_per_set;
   1349                 }
   1350             }
   1351 
   1352             soc_cm_sfree(unit, range_p);
   1353             if (SOC_FAILURE(rv)) {
   1354                 return rv;
   1355             }            
   1356         } else {
   1357             for (i = 0; i < entries_per_set; i++) {
   1358                 if (table->data_mask != NULL) {
   1359                     /* Read original entry from hardware profile table */
   1360                     SOC_IF_ERROR_RETURN
   1361                         (soc_mem_read(unit, table->mem, MEM_BLOCK_ANY,
   1362                                       index_min + base + i, entry));
   1363 
   1364                     /* Replace partial entry with new content */
   1365                     for (j = 0; j < data_words; j++) {
   1366                         entry[j] &= ~table->data_mask[j];
   1367                         entry[j] |= entry_p[j] & table->data_mask[j];
   1368                     }
   1369 
   1370                     /* Write modified entry into hardware profile table */
   1371                     SOC_IF_ERROR_RETURN
   1372                         (soc_mem_write(unit, table->mem, MEM_BLOCK_ALL,
   1373                                        index_min + base + i, entry));
   1374                 } else {
   1375                     /* Write entire new entry into hardware profile table */
   1376                     SOC_IF_ERROR_RETURN
   1377                         (soc_mem_write(unit, table->mem, MEM_BLOCK_ALL,
   1378                                        index_min + base + i, entry_p));
   1379                 }
   1380 
   1381                 /* Copy entry into the software cache. */
   1382                 sal_memcpy(cache_p, entry_p, data_words * sizeof(uint32));
   1383                 entry_p += entry_words;
   1384                 cache_p += entry_words;
   1385 
   1386                 table->entries[base + i].ref_count++;
   1387                 table->entries[base + i].entries_per_set = entries_per_set;
   1388             }
   1389         }
   1390     }
   1391     *index0 = free_set * entries_per_set0 + profile->tables[0].index_min;
   1392 
   1393     return SOC_E_NONE;
   1394 }
   1395 
   1396 int 
   1397 soc_profile_mem_search (int unit,
   1398                          soc_profile_mem_t *profile,
   1399                          void ** entries_array,
   1400                          int entries_per_set0,
   1401                           uint32 *index0)
   1402 {
   1403     soc_profile_mem_table_t *table;
   1404     int num_entries, num_sets, entries_per_set;
   1405     int set, table_index, i, j, base, base0;
   1406     int entry_words, data_words;
   1407     int rv = SOC_E_NONE;
   1408     uint32 mask[SOC_MAX_MEM_WORDS];
   1409     uint32 *cache_p, *entry_p, *mask_p;
   1410 
   1411     if (profile == NULL || entries_array == NULL || entries_per_set0 <= 0 ||
   1412             index0 == NULL) {
   1413         return SOC_E_PARAM;
   1414     }
   1415 
   1416     if (profile->tables == NULL || profile->table_count == 0) {
   1417         return SOC_E_INIT;
   1418     }
   1419 
   1420     sal_memset(mask, 0xff, sizeof(mask));
   1421     table = &profile->tables[0];
   1422     num_entries = table->index_max - table->index_min + 1;
   1423 
   1424     if (num_entries % entries_per_set0) {
   1425         return SOC_E_PARAM;
   1426     }
   1427 
   1428     num_sets = num_entries / entries_per_set0;
   1429     for (set = 0; set < num_sets; set++) {
   1430         base0 = set * entries_per_set0;
   1431 
   1432         if (profile->tables[0].entries[base0].ref_count == 0) {
   1433             continue;
   1434         }
   1435         for (table_index = 0; table_index < profile->table_count;
   1436                 table_index++) {
   1437             table = &profile->tables[table_index];
   1438             num_entries = table->index_max - table->index_min + 1;
   1439             entries_per_set = num_entries / num_sets;
   1440             base = set * entries_per_set;
   1441             entry_words = table->entry_words;
   1442             data_words = soc_mem_entry_words(unit, table->mem);
   1443             entry_p = entries_array[table_index];
   1444             cache_p = &table->cache_p[base * entry_words];
   1445             mask_p = table->data_mask == NULL ? mask : table->data_mask;
   1446             for (i = 0; i < entries_per_set; i++) {
   1447                 for (j = 0; j < data_words; j++) {
   1448                     if ((cache_p[j] ^ entry_p[j]) & mask_p[j]) {
   1449                         break;
   1450                     }
   1451                 }
   1452                 if (j < data_words) {
   1453                     break;
   1454                 }
   1455                 entry_p += entry_words;
   1456                 cache_p += entry_words;
   1457             }
   1458             if (i != entries_per_set) {
   1459                 break;
   1460             }
   1461 
   1462         }
   1463         if (table_index != profile->table_count) {
   1464              continue;
   1465         }
   1466 
   1467         *index0 = (base0 + profile->tables[0].index_min)/entries_per_set0;
   1468         return SOC_E_EXISTS;
   1469     }
   1470     return rv;
   1471 }
   1472 
   1473 int
   1474 soc_profile_mem_single_table_add(int unit,
   1475                                  soc_profile_mem_t *profile,
   1476                                  void *entries,
   1477                                  int entries_per_set,
   1478                                  int *index)
   1479 {
   1480     void *entries_array[1];
   1481 
   1482     entries_array[0] = entries;
   1483     return soc_profile_mem_add(unit, profile, entries_array,
   1484                                entries_per_set, (uint32 *)index);
   1485 }
   1486 
   1487 /*
   1488  * Function:
   1489  *      soc_profile_mem_delete_unique
   1490  * Purpose:
   1491  *      Delete the reference to the set of entries (one or more entries) at
   1492  *      the specified base index of the specified pipe
   1493  *
   1494  *      This is for when memory is split and UNIQUE per pipe
   1495  *
   1496  * Parameters:
   1497  *      unit    - (IN) Unit
   1498  *      profile - (IN) Pointer to profile memory structure
   1499  *      index0  - (IN) Base index to the entries in HW for table 0
   1500  *      pipe    - (IN) Pipe to affect
   1501  * Returns:
   1502  *      SOC_E_XXX
   1503  */
   1504 int
   1505 soc_profile_mem_delete_unique(int unit,
   1506                        soc_profile_mem_t *profile,
   1507                        uint32 index0, int pipe)
   1508 {
   1509     soc_profile_mem_table_t *table;
   1510     int index_min, num_entries, num_sets, entries_per_set;
   1511     int set, table_index, i, j, base, base0;
   1512     int alloc_size, rv = SOC_E_NONE;
   1513     int entry_words, data_words;
   1514     uint32 *range_p, *ent_p;
   1515     void *null_entry;
   1516     soc_mem_t mem = INVALIDm;
   1517     int mod, entries_per_pipe;
   1518 
   1519     if (profile == NULL) {
   1520         return SOC_E_PARAM;
   1521     }
   1522 
   1523     if (profile->tables == NULL || profile->table_count == 0) {
   1524         return SOC_E_INIT;
   1525     }
   1526 
   1527     table = &profile->tables[0];
   1528     num_entries = table->index_max - table->index_min + 1;
   1529     if (index0 < table->index_min || index0 > table->index_max) {
   1530         return SOC_E_PARAM;
   1531     }
   1532 
   1533     if (NULL == SOC_MEM_UNIQUE_ACC(unit, table->mem)) {
   1534         return SOC_E_PARAM;
   1535     }
   1536 
   1537     entries_per_pipe = SOC_MEM_SIZE(unit, table->mem);
   1538 
   1539     base0 = index0 - table->index_min;
   1540     /* Offset the base to the appropriate pipe */
   1541     base0 += pipe*entries_per_pipe;
   1542 
   1543     if (table->entries[base0].ref_count == 0) {
   1544         return SOC_E_NOT_FOUND;
   1545     }
   1546 
   1547     entries_per_set = table->entries[base0].entries_per_set;
   1548 
   1549     if (base0 % entries_per_set) {
   1550         return SOC_E_PARAM;
   1551     }
   1552 
   1553     num_sets = num_entries / entries_per_set;
   1554     set = base0 / entries_per_set;
   1555 
   1556     /* Do optional data integrity check */
   1557     SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0));
   1558 
   1559     for (table_index = 0; table_index < profile->table_count; table_index++) {
   1560         table = &profile->tables[table_index];
   1561         num_entries = table->index_max - table->index_min + 1;
   1562         entries_per_set = num_entries / num_sets;
   1563         base = set * entries_per_set;
   1564         for (i = 0; i < entries_per_set; i++) {
   1565             table->entries[base + i].ref_count--;
   1566         }
   1567     }
   1568 
   1569     if (profile->tables[0].entries[base0].ref_count != 0) {
   1570         return SOC_E_NONE;
   1571     }
   1572 
   1573     for (table_index = 0; table_index < profile->table_count; table_index++) {
   1574         table = &profile->tables[table_index];
   1575         index_min = table->index_min;
   1576         num_entries = table->index_max - table->index_min + 1;
   1577         entries_per_set = num_entries / num_sets;
   1578         base = set * entries_per_set;
   1579 
   1580         if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) {
   1581             entry_words = table->entry_words;
   1582             alloc_size =  WORDS2BYTES(entry_words) * entries_per_set;
   1583             range_p = soc_cm_salloc(unit, alloc_size, "profile update");
   1584             if (NULL == range_p) {
   1585                 return SOC_E_MEMORY;
   1586             }
   1587 
   1588             sal_memset((void *)range_p, 0, alloc_size);
   1589             mem = table->mem;
   1590             entries_per_set = num_entries / num_sets;
   1591             base = set * entries_per_set;
   1592 
   1593             /* If the memory is unique, need to write to its proper index
   1594              * by removing the pipe offset */
   1595             if (SOC_MEM_UNIQUE_ACC(unit, mem)) {
   1596                 mem = SOC_MEM_UNIQUE_ACC(unit, mem)[pipe];
   1597                 mod = entries_per_pipe;
   1598             } else {
   1599                 mod = 1;
   1600             }
   1601 
   1602             if (table->data_mask != NULL) {
   1603                 /* Read full entry from HW when profile only covers
   1604                  * part of the table. */
   1605                 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
   1606                                         index_min + base%mod,
   1607                                         index_min + base%mod + entries_per_set - 1,
   1608                                         range_p);
   1609             }
   1610 
   1611             if (SOC_SUCCESS(rv)) {
   1612                 null_entry = soc_mem_entry_null(unit, mem);
   1613                 data_words = soc_mem_entry_words(unit, mem);
   1614                 for (i = 0; i < entries_per_set; i++) {
   1615                     ent_p =
   1616                         soc_mem_table_idx_to_pointer(unit, mem,
   1617                                                      uint32 *, range_p, i);
   1618 
   1619                     if (table->data_mask != NULL) {
   1620                         /* Clear partial entry */
   1621                         for (j = 0; j < data_words; j++) {
   1622                             ent_p[j] &= ~table->data_mask[j];
   1623                         }
   1624                     } else {
   1625                         /* Write entire new entry */
   1626                         sal_memcpy(ent_p, null_entry,
   1627                                    data_words * sizeof(uint32));
   1628                     }
   1629                 }
   1630             }
   1631 
   1632             if (SOC_SUCCESS(rv)) {
   1633                 /* Write back the modified entries */
   1634                 rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ANY,
   1635                                          index_min + base%mod,
   1636                                          index_min + base%mod + entries_per_set - 1,
   1637                                          range_p);
   1638             }
   1639 
   1640             soc_cm_sfree(unit, range_p);
   1641             if (SOC_FAILURE(rv)) {
   1642                 return rv;
   1643             }
   1644         } else {
   1645             
   1646             mem = table->mem;
   1647             if (SOC_MEM_UNIQUE_ACC(unit, mem)) {
   1648                 mem = SOC_MEM_UNIQUE_ACC(unit, mem)[pipe];
   1649                 mod = entries_per_pipe;
   1650             } else {
   1651                 mod = 1;
   1652             }
   1653 
   1654             for (i = 0; i < entries_per_set; i++) {
   1655                 /* Insert the new entries into profile table */
   1656                 SOC_IF_ERROR_RETURN
   1657                     (soc_mem_write(unit, table->mem, MEM_BLOCK_ANY,
   1658                                    index_min + base%mod + i,
   1659                                    soc_mem_entry_null(unit, table->mem)));
   1660             }
   1661         }
   1662     }
   1663 
   1664     return SOC_E_NONE;
   1665 }
   1666 /*
   1667  * Function:
   1668  *      soc_profile_mem_delete
   1669  * Purpose:
   1670  *      Delete the reference to the set of entries (one or more entries) at
   1671  *      the specified base index.
   1672  *
   1673  * Parameters:
   1674  *      unit    - (IN) Unit
   1675  *      profile - (IN) Pointer to profile memory structure
   1676  *      index0  - (IN) Base index to the entries in HW for table 0
   1677  * Returns:
   1678  *      SOC_E_XXX
   1679  */
   1680 int
   1681 soc_profile_mem_delete(int unit,
   1682                        soc_profile_mem_t *profile,
   1683                        uint32 index0)
   1684 {
   1685     soc_profile_mem_table_t *table;
   1686     int index_min, num_entries, num_sets, entries_per_set;
   1687     int set, table_index, i, j, base, base0;
   1688     int alloc_size, rv = SOC_E_NONE;
   1689     int entry_words, data_words;
   1690     uint32 *range_p, *ent_p;
   1691     void *null_entry;
   1692 
   1693     if (profile == NULL) {
   1694         return SOC_E_PARAM;
   1695     }
   1696 
   1697     if (profile->tables == NULL || profile->table_count == 0) {
   1698         return SOC_E_INIT;
   1699     }
   1700 
   1701     table = &profile->tables[0];
   1702     num_entries = table->index_max - table->index_min + 1;
   1703     if (index0 < table->index_min || index0 > table->index_max) {
   1704         return SOC_E_PARAM;
   1705     }
   1706 
   1707     base0 = index0 - table->index_min;
   1708 
   1709     if (table->entries[base0].ref_count == 0) {
   1710         return SOC_E_NOT_FOUND;
   1711     }
   1712 
   1713     entries_per_set = table->entries[base0].entries_per_set;
   1714 
   1715     if (base0 % entries_per_set) {
   1716         return SOC_E_PARAM;
   1717     }
   1718 
   1719     num_sets = num_entries / entries_per_set;
   1720     set = base0 / entries_per_set;
   1721 
   1722     /* Do optional data integrity check */
   1723     SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0));
   1724 
   1725     for (table_index = 0; table_index < profile->table_count; table_index++) {
   1726         table = &profile->tables[table_index];
   1727         num_entries = table->index_max - table->index_min + 1;
   1728         entries_per_set = num_entries / num_sets;
   1729         base = set * entries_per_set;
   1730         for (i = 0; i < entries_per_set; i++) {
   1731             table->entries[base + i].ref_count--;
   1732         }
   1733     }
   1734 
   1735     if (profile->tables[0].entries[base0].ref_count != 0) {
   1736         return SOC_E_NONE;
   1737     }
   1738 
   1739     for (table_index = 0; table_index < profile->table_count; table_index++) {
   1740         table = &profile->tables[table_index];
   1741         index_min = table->index_min;
   1742         num_entries = table->index_max - table->index_min + 1;
   1743         entries_per_set = num_entries / num_sets;
   1744         base = set * entries_per_set;
   1745 
   1746         if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) {
   1747             entry_words = table->entry_words;
   1748             alloc_size =  WORDS2BYTES(entry_words) * entries_per_set;
   1749             range_p = soc_cm_salloc(unit, alloc_size, "profile update");
   1750             if (NULL == range_p) {
   1751                 return SOC_E_MEMORY;
   1752             }
   1753             sal_memset((void *)range_p, 0, alloc_size);
   1754 
   1755             if (table->data_mask != NULL) {
   1756                 /* Read full entry from HW when profile only covers
   1757                  * part of the table. */
   1758                 rv = soc_mem_read_range(unit, table->mem, MEM_BLOCK_ANY,
   1759                                         index_min + base,
   1760                                         index_min + base + entries_per_set - 1,
   1761                                         range_p);
   1762             }
   1763 
   1764             if (SOC_SUCCESS(rv)) {
   1765                 null_entry = soc_mem_entry_null(unit, table->mem);
   1766                 data_words = soc_mem_entry_words(unit, table->mem);
   1767                 for (i = 0; i < entries_per_set; i++) {
   1768                     ent_p =
   1769                         soc_mem_table_idx_to_pointer(unit, table->mem,
   1770                                                      uint32 *, range_p, i);
   1771 
   1772                     if (table->data_mask != NULL) {
   1773                         /* Clear partial entry */
   1774                         for (j = 0; j < data_words; j++) {
   1775                             ent_p[j] &= ~table->data_mask[j];
   1776                         }
   1777                     } else {
   1778                         /* Write entire new entry */
   1779                         sal_memcpy(ent_p, null_entry,
   1780                                    data_words * sizeof(uint32));
   1781                     }
   1782                 }
   1783             }
   1784 
   1785             if (SOC_SUCCESS(rv)) {
   1786                 /* Write back the modified entries */
   1787                 rv = soc_mem_write_range(unit, table->mem, MEM_BLOCK_ANY,
   1788                                          index_min + base,
   1789                                          index_min + base + entries_per_set - 1,
   1790                                          range_p);
   1791             }
   1792 
   1793             soc_cm_sfree(unit, range_p);
   1794             if (SOC_FAILURE(rv)) {
   1795                 return rv;
   1796             }            
   1797         } else {
   1798             
   1799             for (i = 0; i < entries_per_set; i++) {
   1800                 /* Insert the new entries into profile table */
   1801                 SOC_IF_ERROR_RETURN
   1802                     (soc_mem_write(unit, table->mem, MEM_BLOCK_ANY,
   1803                                    index_min + base + i,
   1804                                    soc_mem_entry_null(unit, table->mem)));
   1805             }
   1806         }
   1807     }
   1808 
   1809     return SOC_E_NONE;
   1810 }
   1811 
   1812 /*
   1813  * Function:
   1814  *      soc_profile_mem_set
   1815  * Purpose:
   1816  *      Update existing non-shared entry.
   1817  *
   1818  * Parameters:
   1819  *      unit            - (IN) Unit
   1820  *      profile         - (IN) Pointer to profile memory structure
   1821  *      entries_array   - (IN) Array of pointer to table entries set
   1822  *      index0          - (IN) Base index to update
   1823  * Returns:
   1824  *      SOC_E_XXX
   1825  */
   1826 int
   1827 soc_profile_mem_set(int unit,
   1828                     soc_profile_mem_t *profile,
   1829                     void **entries_array,
   1830                     uint32 index0)
   1831 {
   1832     soc_profile_mem_table_t *table;
   1833     int index_min, num_entries, num_sets, entries_per_set;
   1834     int set, table_index, i, base, base0;
   1835     int entry_words, data_words;
   1836     int alloc_size, rv = SOC_E_NONE;
   1837     uint32 *cache_p, *entry_p, *range_p, *ent_p;
   1838 
   1839     if (profile == NULL) {
   1840         return SOC_E_PARAM;
   1841     }
   1842 
   1843     if (profile->tables == NULL || profile->table_count == 0) {
   1844         return SOC_E_INIT;
   1845     }
   1846 
   1847     table = &profile->tables[0];
   1848     num_entries = table->index_max - table->index_min + 1;
   1849     if (index0 < table->index_min || index0 > table->index_max) {
   1850         return SOC_E_PARAM;
   1851     }
   1852 
   1853     base0 = index0 - table->index_min;
   1854 
   1855     if (table->entries[base0].ref_count == 0) {
   1856         return SOC_E_NOT_FOUND;
   1857     }
   1858 
   1859     entries_per_set = table->entries[base0].entries_per_set;
   1860 
   1861     if (base0 % entries_per_set) {
   1862         return SOC_E_PARAM;
   1863     }
   1864 
   1865     num_sets = num_entries / entries_per_set;
   1866     set = base0 / entries_per_set;
   1867 
   1868     /* Do optional data integrity check */
   1869     SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0));
   1870 
   1871     for (table_index = 0; table_index < profile->table_count; table_index++) {
   1872         table = &profile->tables[table_index];
   1873         index_min = table->index_min;
   1874         num_entries = table->index_max - table->index_min + 1;
   1875         entries_per_set = num_entries / num_sets;
   1876         base = set * entries_per_set;
   1877         entry_words = table->entry_words;
   1878         data_words = soc_mem_entry_words(unit, table->mem);
   1879         entry_p = entries_array[table_index];
   1880         cache_p = &table->cache_p[base * entry_words];
   1881 
   1882         if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) {
   1883             alloc_size =  WORDS2BYTES(entry_words) * entries_per_set;
   1884             range_p = soc_cm_salloc(unit, alloc_size, "profile update");
   1885 
   1886             
   1887 
   1888             if (NULL == range_p) {
   1889                 return SOC_E_MEMORY;
   1890             }
   1891             sal_memset((void *)range_p, 0, alloc_size);
   1892 
   1893             if (SOC_SUCCESS(rv)) {
   1894                 for (i = 0; i < entries_per_set; i++) {
   1895                     ent_p =
   1896                         soc_mem_table_idx_to_pointer(unit, table->mem,
   1897                                                      uint32 *, range_p, i);
   1898                     /* Write entire new entry */
   1899                     sal_memcpy(ent_p, entry_p,
   1900                                data_words * sizeof(uint32));
   1901                     entry_p += entry_words;
   1902                 }
   1903             }
   1904 
   1905             if (SOC_SUCCESS(rv)) {
   1906                 /* Write back the modified entries */
   1907                 rv = soc_mem_write_range(unit, table->mem, MEM_BLOCK_ANY,
   1908                                          index_min + base,
   1909                                          index_min + base + entries_per_set - 1,
   1910                                          range_p);
   1911 
   1912                 if (SOC_SUCCESS(rv)) {
   1913                     /* Copy entry into the software cache. */
   1914                     entry_p = entries_array[table_index];
   1915 
   1916                     for (i = 0; i < entries_per_set; i++) {
   1917                         sal_memcpy(cache_p, entry_p,
   1918                                    data_words * sizeof(uint32));
   1919                         entry_p += entry_words;
   1920                         cache_p += entry_words;
   1921 
   1922                         table->entries[base + i].ref_count++;
   1923                         table->entries[base + i].entries_per_set =
   1924                             entries_per_set;
   1925                     }
   1926                 }
   1927             }
   1928 
   1929             soc_cm_sfree(unit, range_p);
   1930             if (SOC_FAILURE(rv)) {
   1931                 return rv;
   1932             }            
   1933         } else {
   1934             for (i = 0; i < entries_per_set; i++) {
   1935                 /* Write the new entries into profile table */
   1936                 SOC_IF_ERROR_RETURN(soc_mem_write(unit, table->mem, MEM_BLOCK_ANY,
   1937                                                   index_min + base + i, entry_p));
   1938 
   1939                 /* Copy entry into the software cache. */
   1940                 sal_memcpy(cache_p, entry_p, data_words * sizeof(uint32));
   1941                 entry_p += entry_words;
   1942                 cache_p += entry_words;
   1943 
   1944             }
   1945         }
   1946     }
   1947 
   1948     return SOC_E_NONE;
   1949 }
   1950 
   1951 int
   1952 soc_profile_mem_index_get(int unit,
   1953                           soc_profile_mem_t *profile,
   1954                           soc_mem_t mem,
   1955                           int *index)
   1956 {
   1957     int i;
   1958     soc_profile_mem_table_t *table;
   1959     if (profile == NULL) {
   1960         return SOC_E_PARAM;
   1961     }
   1962     if (profile->tables == NULL || profile->table_count == 0) {
   1963         return SOC_E_INIT;
   1964     }
   1965 
   1966     for (i = 0; i < profile->table_count; i++) {
   1967         table = &profile->tables[i];
   1968         if (table->mem == mem) {
   1969             *index = i;
   1970             return SOC_E_NONE;
   1971         }
   1972     }
   1973 
   1974     return SOC_E_NOT_FOUND;
   1975 }
   1976 
   1977 /*
   1978  * Function:
   1979  *      soc_profile_mem_get
   1980  * Purpose:
   1981  *      Get a set of entries (one or more entries) at the specified index.
   1982  *
   1983  * Parameters:
   1984  *      unit          - (IN) Unit
   1985  *      profile       - (IN) Pointer to profile memory structure
   1986  *      index0        - (IN) Base index to the entries in HW for table 0
   1987  *      count         - (IN) Array of number of entries to retrieve
   1988  *      entries_array - (OUT) Array of pointer to table entries set
   1989  * Returns:
   1990  *      SOC_E_XXX
   1991  */
   1992 int
   1993 soc_profile_mem_get(int unit,
   1994                     soc_profile_mem_t *profile,
   1995                     int index0,
   1996                     int count,
   1997                     void **entries_array)
   1998 {
   1999     soc_profile_mem_table_t *table;
   2000     int num_entries, num_sets, entries_per_set;
   2001     int set, table_index, i, j, base, base0;
   2002     int entry_words, data_words;
   2003     uint32 *cache_p, *entry_p;
   2004 
   2005     if (profile == NULL || count <= 0) {
   2006         return SOC_E_PARAM;
   2007     }
   2008 
   2009     if (profile->tables == NULL || profile->table_count == 0) {
   2010         return SOC_E_INIT;
   2011     }
   2012 
   2013     table = &profile->tables[0];
   2014     num_entries = table->index_max - table->index_min + 1;
   2015     if (index0 < table->index_min || index0 > table->index_max) {
   2016         return SOC_E_PARAM;
   2017     }
   2018 
   2019     base0 = index0 - table->index_min;
   2020 
   2021     if (table->entries[base0].ref_count == 0) {
   2022         return SOC_E_NOT_FOUND;
   2023     }
   2024 
   2025     entries_per_set = table->entries[base0].entries_per_set;
   2026 
   2027     if (base0 % entries_per_set) {
   2028         return SOC_E_PARAM;
   2029     }
   2030 
   2031     num_sets = num_entries / entries_per_set;
   2032     set = base0 / entries_per_set;
   2033 
   2034     /* Do optional data integrity check */
   2035     SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0));
   2036 
   2037     for (table_index = 0; table_index < profile->table_count; table_index++) {
   2038         table = &profile->tables[table_index];
   2039         num_entries = table->index_max - table->index_min + 1;
   2040         entries_per_set = num_entries / num_sets;
   2041         base = set * entries_per_set;
   2042         entry_words = table->entry_words;
   2043         data_words = soc_mem_entry_words(unit, table->mem);
   2044         entry_p = entries_array[table_index];
   2045         cache_p = &table->cache_p[base * entry_words];
   2046 
   2047         for (i = 0; i < entries_per_set; i++) {
   2048             if (i >= count) {
   2049                 break;
   2050             }
   2051             /* Copy entry from the software cache. (include pad) */
   2052             if (table->data_mask != NULL) {
   2053                 for (j = 0; j < data_words; j++) {
   2054                     entry_p[j] = cache_p[j] & table->data_mask[j];
   2055                 }
   2056             } else {
   2057                 sal_memcpy(entry_p, cache_p, entry_words * sizeof(uint32));
   2058             }
   2059             entry_p += entry_words;
   2060             cache_p += entry_words;
   2061         }
   2062     }
   2063 
   2064     return SOC_E_NONE;
   2065 }
   2066 
   2067 int
   2068 soc_profile_mem_single_table_get(int unit,
   2069                                  soc_profile_mem_t *profile,
   2070                                  int index,
   2071                                  int count,
   2072                                  void *entries)
   2073 {
   2074     void *entries_array[1];
   2075 
   2076     entries_array[0] = entries;
   2077     return soc_profile_mem_get(unit, profile, index, count, entries_array);
   2078 }
   2079 
   2080 /*
   2081  * Function:
   2082  *      soc_profile_mem_reference_unique
   2083  * Purpose:
   2084  *      Add the reference to the set of entries (one or more entries) at
   2085  *      the specified base index.
   2086  *
   2087  * Parameters:
   2088  *      unit             - (IN) Unit
   2089  *      profile          - (IN) Pointer to profile memory structure
   2090  *      index0           - (IN) Base index to the entries in HW for table 0
   2091  *      entries_per_set0 - (IN) Number of entries in the set for table 0
   2092  *                              (for WARM BOOT only)
   2093  *      pipe             - (IN) Pipe to affect
   2094  * Returns:
   2095  *      SOC_E_XXX
   2096  */
   2097 int
   2098 soc_profile_mem_reference_unique(int unit,
   2099                           soc_profile_mem_t *profile,
   2100                           int index0,
   2101                           int entries_per_set0,
   2102                           int pipe)
   2103 {
   2104     soc_profile_mem_table_t *table;
   2105     int num_entries, num_sets, entries_per_set;
   2106     int set, table_index, i, base, base0, entries_per_pipe;
   2107 
   2108     if (profile == NULL) {
   2109         return SOC_E_PARAM;
   2110     }
   2111 
   2112     if (SOC_WARM_BOOT(unit)) {
   2113         if (entries_per_set0 <= 0) {
   2114             return SOC_E_PARAM;
   2115         }
   2116     }
   2117 
   2118     if (profile->tables == NULL || profile->table_count == 0) {
   2119         return SOC_E_INIT;
   2120     }
   2121 
   2122     table = &profile->tables[0];
   2123     num_entries = table->index_max - table->index_min + 1;
   2124     if (index0 < table->index_min || index0 > table->index_max) {
   2125         return SOC_E_PARAM;
   2126     }
   2127 
   2128     if (NULL == SOC_MEM_UNIQUE_ACC(unit, table->mem)) {
   2129         return SOC_E_PARAM;
   2130     }
   2131 
   2132     entries_per_pipe = SOC_MEM_SIZE(unit, table->mem);
   2133 
   2134     base0 = index0 - table->index_min;
   2135     /* Offset the base to the appropriate pipe */
   2136     base0 += pipe*entries_per_pipe;
   2137 
   2138     if (SOC_WARM_BOOT(unit)) {
   2139         if (num_entries % entries_per_set0) {
   2140             return SOC_E_PARAM;
   2141         }
   2142         entries_per_set = entries_per_set0;
   2143     } else {
   2144         if (table->entries[base0].ref_count == 0) {
   2145             return SOC_E_NOT_FOUND;
   2146         }
   2147 
   2148         entries_per_set = table->entries[base0].entries_per_set;
   2149     }
   2150 
   2151     if (base0 % entries_per_set) {
   2152         return SOC_E_PARAM;
   2153     }
   2154 
   2155     num_sets = num_entries / entries_per_set;
   2156     set = base0 / entries_per_set;
   2157 
   2158 #if 0
   2159     /* Do optional data integrity check */
   2160     SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0));
   2161 #endif
   2162 
   2163     for (table_index = 0; table_index < profile->table_count; table_index++) {
   2164         table = &profile->tables[table_index];
   2165         num_entries = table->index_max - table->index_min + 1;
   2166         entries_per_set = num_entries / num_sets;
   2167         base = set * entries_per_set;
   2168         for (i = 0; i < entries_per_set; i++) {
   2169             table->entries[base + i].ref_count++;
   2170             table->entries[base + i].entries_per_set = entries_per_set;
   2171         }
   2172     }
   2173 
   2174     return SOC_E_NONE;
   2175 }
   2176 
   2177 
   2178 /*
   2179  * Function:
   2180  *      soc_profile_mem_reference
   2181  * Purpose:
   2182  *      Add the reference to the set of entries (one or more entries) at
   2183  *      the specified base index.
   2184  *
   2185  * Parameters:
   2186  *      unit             - (IN) Unit
   2187  *      profile          - (IN) Pointer to profile memory structure
   2188  *      index0           - (IN) Base index to the entries in HW for table 0
   2189  *      entries_per_set0 - (IN) Number of entries in the set for table 0
   2190  *                              (for WARM BOOT only)
   2191  * Returns:
   2192  *      SOC_E_XXX
   2193  */
   2194 int
   2195 soc_profile_mem_reference(int unit,
   2196                           soc_profile_mem_t *profile,
   2197                           int index0,
   2198                           int entries_per_set0)
   2199 {
   2200     soc_profile_mem_table_t *table;
   2201     int num_entries, num_sets, entries_per_set;
   2202     int set, table_index, i, base, base0;
   2203 
   2204     if (profile == NULL) {
   2205         return SOC_E_PARAM;
   2206     }
   2207 
   2208     if (SOC_WARM_BOOT(unit)) {
   2209         if (entries_per_set0 <= 0) {
   2210             return SOC_E_PARAM;
   2211         }
   2212     }
   2213 
   2214     if (profile->tables == NULL || profile->table_count == 0) {
   2215         return SOC_E_INIT;
   2216     }
   2217 
   2218     table = &profile->tables[0];
   2219     num_entries = table->index_max - table->index_min + 1;
   2220     if (index0 < table->index_min || index0 > table->index_max) {
   2221         return SOC_E_PARAM;
   2222     }
   2223 
   2224     base0 = index0 - table->index_min;
   2225 
   2226     if (SOC_WARM_BOOT(unit)) {
   2227         if (num_entries % entries_per_set0) {
   2228             return SOC_E_PARAM;
   2229         }
   2230         entries_per_set = entries_per_set0;
   2231     } else {
   2232         if (table->entries[base0].ref_count == 0) {
   2233             return SOC_E_NOT_FOUND;
   2234         }
   2235 
   2236         entries_per_set = table->entries[base0].entries_per_set;
   2237     }
   2238 
   2239     if (base0 % entries_per_set) {
   2240         return SOC_E_PARAM;
   2241     }
   2242 
   2243     num_sets = num_entries / entries_per_set;
   2244     set = base0 / entries_per_set;
   2245 
   2246 #if 0
   2247     /* Do optional data integrity check */
   2248     SOC_IF_ERROR_RETURN(_soc_profile_mem_check(unit, profile, base0));
   2249 #endif
   2250 
   2251     for (table_index = 0; table_index < profile->table_count; table_index++) {
   2252         table = &profile->tables[table_index];
   2253         num_entries = table->index_max - table->index_min + 1;
   2254         entries_per_set = num_entries / num_sets;
   2255         base = set * entries_per_set;
   2256         for (i = 0; i < entries_per_set; i++) {
   2257             table->entries[base + i].ref_count++;
   2258             table->entries[base + i].entries_per_set = entries_per_set;
   2259         }
   2260     }
   2261 
   2262     return SOC_E_NONE;
   2263 }
   2264 
   2265 /*
   2266  * Function:
   2267  *      soc_profile_mem_ref_count_get
   2268  * Purpose:
   2269  *      Get the reference count of the cached entry at the specified index.
   2270  *
   2271  * Parameters:
   2272  *      unit        - (IN) Unit
   2273  *      profile     - (IN) Pointer to profile memory structure
   2274  *      index0      - (IN) Base index to the entries in HW for table 0
   2275  *      ref_count   - (OUT) Reference count
   2276  * Returns:
   2277  *      SOC_E_XXX
   2278  */
   2279 int
   2280 soc_profile_mem_ref_count_get(int unit,
   2281                               soc_profile_mem_t *profile,
   2282                               int index0,
   2283                               int *ref_count)
   2284 {
   2285     soc_profile_mem_table_t *table;
   2286     int base0;
   2287 
   2288     if (profile == NULL || ref_count == NULL) {
   2289         return SOC_E_PARAM;
   2290     }
   2291 
   2292     if (profile->tables == NULL || profile->table_count == 0) {
   2293         return SOC_E_INIT;
   2294     }
   2295 
   2296     table = &profile->tables[0];
   2297     if (index0 < table->index_min || index0 > table->index_max) {
   2298         return SOC_E_PARAM;
   2299     }
   2300 
   2301     base0 = index0 - table->index_min;
   2302 
   2303     *ref_count = table->entries[base0].ref_count;
   2304 
   2305     return SOC_E_NONE;
   2306 }
   2307 
   2308 /*
   2309  * Function:
   2310  *      soc_profile_mem_fields32_modify_unique
   2311  * Purpose:
   2312  *      Modify the specified fields (of maximum size 32-bits)
   2313  *      for all valid (non-zero reference count) entries of a
   2314  *      profile table in the profile set.
   2315  *      For simplicity, only one table in a profile
   2316  *      set may be modified at a time.
   2317  *
   2318  *      This is for when memory is split and UNIQUE per pipe. It will
   2319  *      modify ALL memories, not just a single pipe
   2320  *
   2321  * Parameters:
   2322  *      unit             - (IN) Unit
   2323  *      profile          - (IN) Pointer to profile memory structure
   2324  *      table_id         - (IN) Profile set index of table to modify
   2325  *      field_count      - (IN) Number of field/value pairs to modify
   2326  *      fields           - (IN) Array of table fields to modify
   2327  *      values           - (IN) Array of table values to modify
   2328  *                                    
   2329  * Returns:
   2330  *      SOC_E_XXX
   2331  */
   2332 int
   2333 soc_profile_mem_fields32_modify_unique(int unit,
   2334                                 soc_profile_mem_t *profile,
   2335                                 int table_id,
   2336                                 int field_count,
   2337                                 soc_field_t *fields,
   2338                                 uint32 *values)
   2339 {
   2340     soc_profile_mem_table_t *table;
   2341     int index_min, modify_entries;
   2342     int offset, fix;
   2343     int index, start_index, end_index;
   2344     int entry_words, data_words, word;
   2345     int alloc_size, rv = SOC_E_NONE;
   2346     uint32 entry[SOC_MAX_MEM_WORDS];
   2347     uint32 *cache_p, *mask_p, *range_p, *ent_p;
   2348     int i, entries_per_pipe;
   2349     soc_mem_t mem;
   2350 
   2351     /* COVERITY: Intentional, stack use of 5192 bytes */
   2352     /* coverity[stack_use_callee_max : FALSE] */
   2353     /* coverity[stack_use_overflow : FALSE] */
   2354     /* coverity[stack_use_return : FALSE] */
   2355 
   2356     if ((profile == NULL) ||
   2357         (field_count <= 0) || (fields == NULL) || (values == 0)){
   2358         return SOC_E_PARAM;
   2359     }
   2360 
   2361     if (profile->tables == NULL || profile->table_count == 0) {
   2362         return SOC_E_INIT;
   2363     }
   2364 
   2365     if ((table_id < 0) || (table_id >= profile->table_count)) {
   2366         return SOC_E_PARAM;
   2367     }
   2368 
   2369 
   2370     table = &profile->tables[table_id];
   2371 
   2372     if (NULL == (SOC_MEM_UNIQUE_ACC(unit, table->mem))) {
   2373         return SOC_E_PARAM;
   2374     }
   2375 
   2376     entries_per_pipe = SOC_MEM_SIZE(unit, table->mem);
   2377 
   2378     index_min = table->index_min;
   2379 
   2380     for (i = 0; i < SOC_INFO(unit).num_pipe; i++) {
   2381         /* Record range of modified entries in table */
   2382         start_index = end_index = -1;
   2383         for (index = i*entries_per_pipe;
   2384              index < (i+1)*entries_per_pipe; index++) {
   2385              /* Skip unused entries. */
   2386             if (table->entries[index].ref_count == 0) {
   2387                 continue;
   2388             }
   2389 
   2390             /* Update range of modified entries */
   2391             if (start_index < 0) {
   2392                 start_index = index;
   2393             }
   2394             end_index = index;
   2395         }
   2396 
   2397         mem = SOC_MEM_UNIQUE_ACC(unit, table->mem)[i];
   2398 
   2399         /* Knowing the range, we can create the modification buffer */
   2400         modify_entries = end_index - start_index + 1;
   2401         entry_words = table->entry_words;
   2402         data_words = soc_mem_entry_words(unit, mem);
   2403         cache_p = &table->cache_p[start_index * entry_words];
   2404 
   2405         /* Verify fields fit within data_mask of table, if any */
   2406         if (table->data_mask != NULL) {
   2407             mask_p = table->data_mask;
   2408             sal_memset(entry, 0, sizeof(entry));
   2409             for (fix = 0; fix < field_count; fix++) {
   2410                 soc_mem_field32_set(unit, mem, entry,
   2411                                     fields[fix], values[fix]);
   2412             }
   2413             for (word = 0; word < data_words; word++) {
   2414                 if ((entry[word] & mask_p[word]) != entry[word]) {
   2415                     break;
   2416                 }
   2417                 /* coverity[dead_error_condition] */
   2418                 if (word < data_words) {
   2419                     return SOC_E_PARAM;
   2420                 }
   2421             }
   2422         }
   2423 
   2424         /*
   2425          * Use DMA to update regardless of range since this is expected
   2426          * to be a bulk operation.
   2427          */
   2428         alloc_size =  WORDS2BYTES(entry_words) * modify_entries;
   2429         range_p = soc_cm_salloc(unit, alloc_size, "profile update");
   2430         if (NULL == range_p) {
   2431             return SOC_E_MEMORY;
   2432         }
   2433         sal_memset((void *)range_p, 0, alloc_size);
   2434 
   2435         /* Read full entry from "HW" */
   2436         rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY,
   2437                                 index_min + start_index%entries_per_pipe,
   2438                                 index_min + end_index%entries_per_pipe,
   2439                                 range_p);
   2440 
   2441         if (SOC_SUCCESS(rv)) {
   2442             for (offset = 0; offset < modify_entries; offset++) {
   2443                 ent_p =
   2444                     soc_mem_table_idx_to_pointer(unit, mem,
   2445                                                  uint32 *, range_p, offset);
   2446 
   2447                 /* Update entries in working buffer */
   2448                 for (fix = 0; fix < field_count; fix++) {
   2449                     soc_mem_field32_set(unit, mem, ent_p,
   2450                                         fields[fix], values[fix]);
   2451                 }
   2452             }
   2453         }
   2454 
   2455         if (SOC_SUCCESS(rv)) {
   2456             /* Write back the modified entries */
   2457             rv = soc_mem_write_range(unit, mem, MEM_BLOCK_ALL,
   2458                                      index_min + start_index%entries_per_pipe,
   2459                                      index_min + end_index%entries_per_pipe,
   2460                                      range_p);
   2461         }
   2462 
   2463         if (SOC_SUCCESS(rv)) {
   2464             /* Now that the write to HW succeeded, commit changes to
   2465              * profile cache */
   2466             for (offset = 0; offset < modify_entries; offset++) {
   2467                 ent_p =
   2468                     soc_mem_table_idx_to_pointer(unit, mem,
   2469                                                  uint32 *, range_p, offset);
   2470 
   2471                 /* Update cache */
   2472                 sal_memcpy(cache_p, ent_p,
   2473                            data_words * sizeof(uint32));
   2474                 cache_p += entry_words;
   2475             }
   2476         }
   2477         soc_cm_sfree(unit, range_p);
   2478     }
   2479 
   2480     return rv;
   2481 }
   2482 
   2483 
   2484 /*
   2485  * Function:
   2486  *      soc_profile_mem_fields32_modify
   2487  * Purpose:
   2488  *      Modify the specified fields (of maximum size 32-bits)
   2489  *      for all valid (non-zero reference count) entries of a
   2490  *      profile table in the profile set.
   2491  *      For simplicity, only one table in a profile
   2492  *      set may be modified at a time.
   2493  *
   2494  * Parameters:
   2495  *      unit             - (IN) Unit
   2496  *      profile          - (IN) Pointer to profile memory structure
   2497  *      table_id         - (IN) Profile set index of table to modify
   2498  *      field_count      - (IN) Number of field/value pairs to modify
   2499  *      fields           - (IN) Array of table fields to modify
   2500  *      values           - (IN) Array of table values to modify
   2501  *
   2502  * Returns:
   2503  *      SOC_E_XXX
   2504  */
   2505 int
   2506 soc_profile_mem_fields32_modify(int unit,
   2507                                 soc_profile_mem_t *profile,
   2508                                 int table_id,
   2509                                 int field_count,
   2510                                 soc_field_t *fields,
   2511                                 uint32 *values)
   2512 {
   2513     soc_profile_mem_table_t *table;
   2514     int index_min, num_entries, modify_entries;
   2515     int offset, fix;
   2516     int index, start_index, end_index;
   2517     int entry_words, data_words, word;
   2518     int alloc_size, rv = SOC_E_NONE;
   2519     uint32 entry[SOC_MAX_MEM_WORDS];
   2520     uint32 *cache_p, *mask_p, *range_p, *ent_p;
   2521 
   2522     /* COVERITY: Intentional, stack use of 5192 bytes */
   2523     /* coverity[stack_use_callee_max : FALSE] */
   2524     /* coverity[stack_use_overflow : FALSE] */
   2525     /* coverity[stack_use_return : FALSE] */
   2526 
   2527     if ((profile == NULL) ||
   2528         (field_count <= 0) || (fields == NULL) || (values == 0)){
   2529         return SOC_E_PARAM;
   2530     }
   2531 
   2532     if (profile->tables == NULL || profile->table_count == 0) {
   2533         return SOC_E_INIT;
   2534     }
   2535 
   2536     if ((table_id < 0) || (table_id >= profile->table_count)) {
   2537         return SOC_E_PARAM;
   2538     }
   2539 
   2540     table = &profile->tables[table_id];
   2541     num_entries = table->index_max - table->index_min + 1;
   2542     index_min = table->index_min;
   2543 
   2544     /* Record range of modified entries in table */
   2545     start_index = end_index = -1;
   2546     for (index = 0; index < num_entries; index++) {
   2547          /* Skip unused entries. */
   2548         if (table->entries[index].ref_count == 0) {
   2549             continue;
   2550         }
   2551 
   2552         /* Update range of modified entries */
   2553         if (start_index < 0) {
   2554             start_index = index;
   2555         }
   2556         end_index = index;
   2557     }
   2558 
   2559     /* Knowing the range, we can create the modification buffer */
   2560     modify_entries = end_index - start_index + 1;
   2561     entry_words = table->entry_words;
   2562     data_words = soc_mem_entry_words(unit, table->mem);
   2563     cache_p = &table->cache_p[start_index * entry_words];
   2564 
   2565     /* Verify fields fit within data_mask of table, if any */
   2566     if (table->data_mask != NULL) {
   2567         mask_p = table->data_mask;
   2568         sal_memset(entry, 0, sizeof(entry));
   2569         for (fix = 0; fix < field_count; fix++) {
   2570             soc_mem_field32_set(unit, table->mem, entry,
   2571                                 fields[fix], values[fix]);
   2572         }
   2573         for (word = 0; word < data_words; word++) {
   2574             if ((entry[word] & mask_p[word]) != entry[word]) {
   2575                 break;
   2576             }
   2577 	    /* coverity[dead_error_condition] */
   2578             if (word < data_words) {
   2579                 return SOC_E_PARAM;
   2580             }
   2581         }
   2582     }
   2583 
   2584     /*
   2585      * Use DMA to update regardless of range since this is expected
   2586      * to be a bulk operation.
   2587      */
   2588     alloc_size =  WORDS2BYTES(entry_words) * modify_entries;
   2589     range_p = soc_cm_salloc(unit, alloc_size, "profile update");
   2590     if (NULL == range_p) {
   2591         return SOC_E_MEMORY;
   2592     }
   2593     sal_memset((void *)range_p, 0, alloc_size);
   2594 
   2595     /* Read full entry from "HW" */
   2596     rv = soc_mem_read_range(unit, table->mem, MEM_BLOCK_ANY,
   2597                             index_min + start_index,
   2598                             index_min + end_index,
   2599                             range_p);
   2600 
   2601     if (SOC_SUCCESS(rv)) {
   2602         for (offset = 0; offset < modify_entries; offset++) {
   2603             ent_p =
   2604                 soc_mem_table_idx_to_pointer(unit, table->mem,
   2605                                              uint32 *, range_p, offset);
   2606 
   2607             /* Update entries in working buffer */
   2608             for (fix = 0; fix < field_count; fix++) {
   2609                 soc_mem_field32_set(unit, table->mem, ent_p,
   2610                                     fields[fix], values[fix]);
   2611             }
   2612         }
   2613     }
   2614 
   2615     if (SOC_SUCCESS(rv)) {
   2616         /* Write back the modified entries */
   2617         rv = soc_mem_write_range(unit, table->mem, MEM_BLOCK_ALL,
   2618                                  index_min + start_index,
   2619                                  index_min + end_index,
   2620                                  range_p);
   2621     }
   2622 
   2623     if (SOC_SUCCESS(rv)) {
   2624         /* Now that the write to HW succeeded, commit changes to
   2625          * profile cache */
   2626         for (offset = 0; offset < modify_entries; offset++) {
   2627             ent_p =
   2628                 soc_mem_table_idx_to_pointer(unit, table->mem,
   2629                                              uint32 *, range_p, offset);
   2630 
   2631             /* Update cache */
   2632             sal_memcpy(cache_p, ent_p,
   2633                        data_words * sizeof(uint32));
   2634             cache_p += entry_words;
   2635         }
   2636     }
   2637 
   2638     soc_cm_sfree(unit, range_p);
   2639 
   2640     return rv;
   2641 }
   2642 
   2643 /*
   2644  * Function:
   2645  *      soc_profile_mem_fields32_modify
   2646  * Purpose:
   2647  *      Modify the specified field (of maximum size 32-bits)
   2648  *      for all valid (non-zero reference count) entries of the
   2649  *      indicated profile table of the profile set.
   2650  *
   2651  * Parameters:
   2652  *      unit             - (IN) Unit
   2653  *      profile          - (IN) Pointer to profile memory structure
   2654  *      table_id         - (IN) Profile set index of table to modify
   2655  *      field            - (IN) Table field to modify
   2656  *      value            - (IN) Table value to modify
   2657  *                                    
   2658  * Returns:
   2659  *      SOC_E_XXX
   2660  */
   2661 int
   2662 soc_profile_mem_field32_modify(int unit,
   2663                                soc_profile_mem_t *profile,
   2664                                int table_id,
   2665                                soc_field_t field,
   2666                                uint32 value)
   2667 {
   2668     return soc_profile_mem_fields32_modify(unit, profile, table_id,
   2669                                            1, &field, &value);
   2670 }
   2671 
   2672 /*
   2673  * Function:
   2674  *      soc_profile_reg_t_init
   2675  * Purpose:
   2676  *      Initialize a soc_profile_reg_t structure.
   2677  *
   2678  * Parameters:
   2679  *      profile_reg - (IN) Pointer to profile register structure
   2680  * Returns:
   2681  *      void
   2682  */
   2683 void
   2684 soc_profile_reg_t_init(soc_profile_reg_t *profile_reg)
   2685 {
   2686     if (NULL != profile_reg) {
   2687         sal_memset(profile_reg, 0, sizeof(soc_profile_reg_t));
   2688     }
   2689 }
   2690 
   2691 /*
   2692  * Function:
   2693  *      soc_profile_reg_create
   2694  * Purpose:
   2695  *      Create a shadow copy and refcounts of a profile table.
   2696  *      If called during WARM BOOT, the shadow copy is populated with
   2697  *      the HW contents, otherwise, both the shadow copy and the
   2698  *      HW entries are cleared.
   2699  *
   2700  * Parameters:
   2701  *      unit        - (IN) Unit
   2702  *      regs        - (IN) Pointer to register id array
   2703  *      regs_count  - (IN) Number of entries in register id array
   2704  *      profile_reg - (IN) Pointer to profile register structure
   2705  * Returns:
   2706  *      SOC_E_XXX
   2707  */
   2708 int
   2709 soc_profile_reg_create(int unit,
   2710                        soc_reg_t *regs,
   2711                        int regs_count,
   2712                        soc_profile_reg_t *profile_reg)
   2713 {
   2714     soc_reg_t reg;
   2715     int rv;
   2716     int num_entries, reg_idx, i;
   2717     int alloc_size;
   2718     uint64 *cache_p;
   2719     uint64 rval;
   2720 
   2721     if (profile_reg == NULL) {
   2722         return SOC_E_INIT;
   2723     }
   2724 
   2725     if (regs == NULL || !regs_count) {
   2726         return SOC_E_PARAM;
   2727     }
   2728 
   2729     num_entries = SOC_REG_NUMELS(unit, regs[0]);
   2730     if (num_entries <= 0) {
   2731         return SOC_E_BADID;
   2732     }
   2733     for (reg_idx = 1; reg_idx < regs_count; reg_idx++) {
   2734        /*  Not needed, as is overwritten later. Coverity complains also.
   2735         reg = regs[reg_idx];
   2736         */
   2737         /* Make sure index mechanism is consistent across all registers */
   2738         if (SOC_REG_NUMELS(unit, regs[0]) != num_entries) {
   2739             return SOC_E_PARAM;
   2740         }
   2741     }
   2742 
   2743     alloc_size = num_entries * \
   2744         (sizeof(soc_profile_reg_entry_t) + regs_count * sizeof(uint64)) +
   2745          regs_count * sizeof(soc_reg_t);
   2746 
   2747     /* If profile_reg->regs is NULL, init the profile_reg for the first
   2748      * time, otherwise simply check for null pointers */
   2749     if (profile_reg->regs != NULL) {
   2750         if (profile_reg->entries == NULL) {
   2751             return SOC_E_INTERNAL;
   2752         }
   2753     } else {
   2754         profile_reg->entries = sal_alloc(alloc_size,  "Profile Reg Entries");
   2755         if (profile_reg->entries == NULL) {
   2756             return SOC_E_MEMORY;
   2757         }
   2758     }
   2759     sal_memset(profile_reg->entries, 0, alloc_size);
   2760 
   2761     cache_p = (uint64 *)&profile_reg->entries[num_entries];
   2762     for (i = 0; i < num_entries; i++) {
   2763         profile_reg->entries[i].cache_p = cache_p;
   2764         cache_p += regs_count;
   2765     }
   2766     profile_reg->regs = (soc_reg_t *)cache_p;
   2767     for (reg_idx = 0; reg_idx < regs_count; reg_idx++) {
   2768         profile_reg->regs[reg_idx] = regs[reg_idx];
   2769     }
   2770     profile_reg->regs_count = regs_count;
   2771 
   2772     if (SOC_WARM_BOOT(unit)) {
   2773         for (i = 0; i < num_entries; i++) {
   2774             cache_p = profile_reg->entries[i].cache_p;
   2775             for (reg_idx = 0; reg_idx < profile_reg->regs_count; reg_idx++) {
   2776                 reg = profile_reg->regs[reg_idx];
   2777                 rv = soc_reg_get(unit, reg, REG_PORT_ANY, i, cache_p);
   2778                 if (rv < 0) {
   2779                     sal_free(profile_reg->entries);
   2780                     profile_reg->regs = NULL;
   2781                     profile_reg->entries = NULL;
   2782                     return rv;
   2783                 }
   2784                 cache_p++;
   2785             }
   2786         }
   2787     } else {
   2788         /* Clear HW memory */
   2789         COMPILER_64_ZERO(rval);
   2790         for (i = 0; i < num_entries; i++) {
   2791             for (reg_idx = 0; reg_idx < profile_reg->regs_count; reg_idx++) {
   2792                 reg = profile_reg->regs[reg_idx];
   2793                 rv = soc_reg_set(unit, reg, REG_PORT_ANY, i, rval);
   2794                 if (rv < 0) {
   2795                     sal_free(profile_reg->entries);
   2796                     profile_reg->regs = NULL;
   2797                     profile_reg->entries = NULL;
   2798                     return rv;
   2799                 }
   2800             }
   2801         }
   2802     }
   2803 
   2804     return SOC_E_NONE;
   2805 }
   2806 
   2807 int
   2808 soc_profile_reg_single_reg_create(int unit,
   2809                                   soc_reg_t reg,
   2810                                   soc_profile_reg_t *profile_reg)
   2811 {
   2812     return soc_profile_reg_create(unit, &reg, 1, profile_reg);
   2813 }
   2814 
   2815 /*
   2816  * Function:
   2817  *      soc_profile_reg_destroy
   2818  * Purpose:
   2819  *      Destroy the shadow copy and refcounts of a profile table.
   2820  *
   2821  * Parameters:
   2822  *      unit        - (IN) Unit
   2823  *      profile_reg - (IN) Pointer to profile register structure
   2824  * Returns:
   2825  *      SOC_E_XXX
   2826  */
   2827 int
   2828 soc_profile_reg_destroy(int unit,
   2829                         soc_profile_reg_t *profile_reg)
   2830 {
   2831     if (profile_reg != NULL) {
   2832         if (profile_reg->entries != NULL) {
   2833             sal_free(profile_reg->entries);
   2834         }
   2835         profile_reg->regs = NULL;
   2836         profile_reg->entries = NULL;
   2837         return SOC_E_NONE;
   2838     }
   2839     return SOC_E_PARAM;
   2840 }
   2841 
   2842 /*
   2843  * Function:
   2844  *      soc_profile_reg_add
   2845  * Purpose:
   2846  *      Add a set of entries (one or more entries) to a profile table. This
   2847  *      routine searches for a matching set in the profile table. If a matching
   2848  *      set is found, the ref count for that entry is incremented and
   2849  *      its base index is returned. If a matching set is not found and a free
   2850  *      set is found, the HW table is updated, the ref count is incremented,
   2851  *      and the base index of the set is returned. If no free set is found, an
   2852  *      error is returned
   2853  *
   2854  * Parameters:
   2855  *      unit            - (IN) Unit
   2856  *      profile_reg     - (IN) Pointer to profile register structure
   2857  *      entries         - (IN) Array of pointer to register entries set
   2858  *      entries_per_set - (IN) Number of entries in the set
   2859  *      index           - (OUT) Base index for the entries allocated in HW
   2860  * Returns:
   2861  *      SOC_E_XXX
   2862  */
   2863 int
   2864 soc_profile_reg_add(int unit,
   2865                     soc_profile_reg_t *profile_reg,
   2866                     uint64 **entries,
   2867                     int entries_per_set,
   2868                     uint32 *index)
   2869 {
   2870     soc_reg_t reg;
   2871     int base, free_index;
   2872     int num_entries, reg_idx, i;
   2873     uint64 *cache_p, *entry_p;
   2874 
   2875     if (profile_reg == NULL || profile_reg->regs == NULL ||
   2876         profile_reg->entries == NULL) {
   2877         return SOC_E_INIT;
   2878     }
   2879 
   2880     num_entries = SOC_REG_NUMELS(unit, profile_reg->regs[0]);
   2881     if (num_entries <= 0) {
   2882         return SOC_E_INTERNAL;
   2883     }
   2884 
   2885     if (entries == NULL || index == NULL ||
   2886         entries_per_set < 1 || entries_per_set > num_entries) {
   2887         return SOC_E_PARAM;
   2888     }
   2889 
   2890     /*
   2891      * Search for an existing entry that has the same configuration.
   2892      */
   2893     free_index = -1;
   2894     for (base = 0; base < num_entries; base += entries_per_set) {
   2895         /* Skip unused entries. */
   2896         if (profile_reg->entries[base].ref_count == 0) {
   2897             if (free_index == -1) {
   2898                 /* Preserve location of free slot. */
   2899                 free_index = base;
   2900                 for (i = 1; i < entries_per_set; i++) {
   2901                     if (profile_reg->entries[base + i].ref_count) {
   2902                         free_index = -1;
   2903                         break;
   2904                     }
   2905                 }
   2906             }
   2907             continue;
   2908         }
   2909 
   2910         for (i = 0; i < entries_per_set; i++) {
   2911             if (profile_reg->entries[base + i].entries_per_set !=
   2912                 entries_per_set) {
   2913                 break;
   2914             }
   2915             for (reg_idx = 0; reg_idx < profile_reg->regs_count; reg_idx++) {
   2916                 reg = profile_reg->regs[reg_idx];
   2917                 entry_p = &entries[reg_idx][i];
   2918                 cache_p = &profile_reg->entries[base + i].cache_p[reg_idx];
   2919                 if (COMPILER_64_NE(*cache_p, *entry_p)) {
   2920                     break;
   2921                 }
   2922             }
   2923             if (reg_idx != profile_reg->regs_count) {
   2924                 break;
   2925             }
   2926         }
   2927         if (i == entries_per_set) {
   2928             for (i = 0; i < entries_per_set; i++) {
   2929                 profile_reg->entries[base + i].ref_count++;
   2930             }
   2931             *index = base;
   2932             return SOC_E_NONE;
   2933         }
   2934         if (profile_reg->entries[base].entries_per_set > entries_per_set) {
   2935             base += profile_reg->entries[base].entries_per_set -
   2936                     entries_per_set;
   2937         }
   2938     }
   2939 
   2940     if (free_index == -1) {
   2941         return SOC_E_RESOURCE;
   2942     }
   2943 
   2944     for (i = 0; i < entries_per_set; i++) {
   2945         for (reg_idx = 0; reg_idx < profile_reg->regs_count; reg_idx++) {
   2946             reg = profile_reg->regs[reg_idx];
   2947             entry_p = &entries[reg_idx][i];
   2948             cache_p = &profile_reg->entries[free_index + i].cache_p[reg_idx];
   2949 
   2950             if (profile_reg->profile_flag & SOC_PROFILE_FLAG_XPE_SINGLE_ACC) {
   2951                 int xpe;
   2952                 for (xpe = 0; xpe < NUM_XPE(unit); xpe++) {
   2953                     int inst = xpe | SOC_REG_ADDR_INSTANCE_MASK;
   2954                     /* Insert the new entries into profile table */
   2955                     SOC_IF_ERROR_RETURN(soc_reg_set(unit, reg, inst,
   2956                                                     free_index + i, *entry_p));
   2957                 }
   2958             } else {
   2959                 /* Insert the new entries into profile table */
   2960                 SOC_IF_ERROR_RETURN(soc_reg_set(unit, reg, REG_PORT_ANY,
   2961                                                 free_index + i, *entry_p));
   2962             }
   2963 
   2964             /* Copy entry into the software cache. */
   2965             *cache_p = *entry_p;
   2966         }
   2967         profile_reg->entries[free_index + i].ref_count++;
   2968         profile_reg->entries[free_index + i].entries_per_set = entries_per_set;
   2969     }
   2970     *index = free_index;
   2971     return SOC_E_NONE;
   2972 }
   2973 
   2974 /*
   2975  * Function:
   2976  *      soc_profile_reg_delete
   2977  * Purpose:
   2978  *      Delete the reference to the set of entries (one or more entries) at
   2979  *      the specified index.
   2980  *
   2981  * Parameters:
   2982  *      unit        - (IN) Unit
   2983  *      profile_reg - (IN) Pointer to profile register structure
   2984  *      index       - (IN) Base index for the entries allocated in HW
   2985  * Returns:
   2986  *      SOC_E_XXX
   2987  */
   2988 int
   2989 soc_profile_reg_delete(int unit,
   2990                        soc_profile_reg_t *profile_reg,
   2991                        uint32 index)
   2992 {
   2993     soc_reg_t reg;
   2994     int num_entries, entries_per_set, reg_idx, i;
   2995     uint64 rval;
   2996 
   2997     if (profile_reg == NULL || profile_reg->regs == NULL ||
   2998         profile_reg->entries == NULL) {
   2999         return SOC_E_INIT;
   3000     }
   3001 
   3002     num_entries = SOC_REG_NUMELS(unit, profile_reg->regs[0]);
   3003     if (num_entries <= 0) {
   3004         return SOC_E_INTERNAL;
   3005     }
   3006 
   3007     if ((int)index >= num_entries) {
   3008         return SOC_E_PARAM;
   3009     }
   3010 
   3011     if (profile_reg->entries[index].ref_count == 0) {
   3012         return SOC_E_NOT_FOUND;
   3013     }
   3014 
   3015     entries_per_set = profile_reg->entries[index].entries_per_set;
   3016     if (index % entries_per_set) {
   3017         return SOC_E_BADID;
   3018     }
   3019 
   3020     profile_reg->entries[index].ref_count--;
   3021     for (i = 1; i < entries_per_set; i++) {
   3022         profile_reg->entries[index + i].ref_count--;
   3023         if (profile_reg->entries[index + i].ref_count !=
   3024             profile_reg->entries[index].ref_count ||
   3025             profile_reg->entries[index + i].entries_per_set !=
   3026             profile_reg->entries[index].entries_per_set) {
   3027             return SOC_E_INTERNAL;
   3028         }
   3029     }
   3030 
   3031     if (profile_reg->entries[index].ref_count != 0) {
   3032         return SOC_E_NONE;
   3033     }
   3034 
   3035     COMPILER_64_ZERO(rval);
   3036     for (i = 0; i < entries_per_set; i++) {
   3037         for (reg_idx = 0; reg_idx < profile_reg->regs_count; reg_idx++) {
   3038             /* Clear the entry in the HW */
   3039             reg = profile_reg->regs[reg_idx];
   3040             if (profile_reg->profile_flag & SOC_PROFILE_FLAG_XPE_SINGLE_ACC) {
   3041                 int xpe;
   3042                 for (xpe = 0; xpe < NUM_XPE(unit); xpe++) {
   3043                     int inst = xpe | SOC_REG_ADDR_INSTANCE_MASK;
   3044                     SOC_IF_ERROR_RETURN(soc_reg_set(unit, reg, inst,
   3045                                                     index + i, rval));
   3046                 }
   3047             } else {
   3048                 SOC_IF_ERROR_RETURN(soc_reg_set(unit, reg, REG_PORT_ANY,
   3049                                                 index + i, rval));
   3050             }
   3051         }
   3052     }
   3053 
   3054     return SOC_E_NONE;
   3055 }
   3056 
   3057 /*
   3058  * Function:
   3059  *      soc_profile_reg_get
   3060  * Purpose:
   3061  *      Get a set of entries (one or more entries) at the specified index.
   3062  *
   3063  * Parameters:
   3064  *      unit        - (IN) Unit
   3065  *      profile_reg - (IN) Pointer to profile register structure
   3066  *      index       - (IN) Base index for the entries allocated in HW
   3067  *      count       - (IN) Number of entries to retreive
   3068  *      entries     - (OUT) Array of pointer to register entries set
   3069  * Returns:
   3070  *      SOC_E_XXX
   3071  */
   3072 int
   3073 soc_profile_reg_get(int unit,
   3074                     soc_profile_reg_t *profile_reg,
   3075                     uint32 index,
   3076                     int count,
   3077                     uint64 **entries)
   3078 {
   3079     int num_entries, reg_idx, i;
   3080     uint64 *cache_p, *entry_p;
   3081 
   3082     if (profile_reg == NULL || profile_reg->regs == NULL ||
   3083         profile_reg->entries == NULL) {
   3084         return SOC_E_INIT;
   3085     }
   3086 
   3087     num_entries = SOC_REG_NUMELS(unit, profile_reg->regs[0]);
   3088     if (num_entries <= 0) {
   3089         return SOC_E_INTERNAL;
   3090     }
   3091 
   3092     if (entries == NULL || (int)index >= num_entries || count <= 0) {
   3093         return SOC_E_PARAM;
   3094     }
   3095 
   3096     if (profile_reg->entries[index].ref_count == 0) {
   3097         return SOC_E_NOT_FOUND;
   3098     }
   3099 
   3100     if (count > profile_reg->entries[index].entries_per_set) {
   3101         return SOC_E_PARAM;
   3102     }
   3103 
   3104     if (index % profile_reg->entries[index].entries_per_set) {
   3105         return SOC_E_BADID;
   3106     }
   3107 
   3108     for (i = 1; i < count; i++) {
   3109         /* Do some optional data integrity check */
   3110         if (profile_reg->entries[index + i].ref_count !=
   3111             profile_reg->entries[index].ref_count ||
   3112             profile_reg->entries[index + i].entries_per_set !=
   3113             profile_reg->entries[index].entries_per_set) {
   3114             return SOC_E_INTERNAL;
   3115         }
   3116     }
   3117 
   3118     for (i = 0; i < count; i++) {
   3119         for (reg_idx = 0; reg_idx < profile_reg->regs_count; reg_idx++) {
   3120             entry_p = &entries[reg_idx][i];
   3121             cache_p = &profile_reg->entries[index + i].cache_p[reg_idx];
   3122 
   3123             /* Copy entry from the software cache. */
   3124             *entry_p = *cache_p;
   3125         }
   3126     }
   3127 
   3128     return SOC_E_NONE;
   3129 }
   3130 
   3131 /*
   3132  * Function:
   3133  *      soc_profile_reg_reference
   3134  * Purpose:
   3135  *      Add the reference to the set of entries (one or more entries) at
   3136  *      the specified base index.
   3137  *
   3138  * Parameters:
   3139  *      unit            - (IN) Unit
   3140  *      profile_reg     - (IN) Pointer to profile register structure
   3141  *      index           - (IN) Base index for the entries allocated in HW
   3142  * Returns:
   3143  *      SOC_E_XXX
   3144  */
   3145 int
   3146 soc_profile_reg_reference(int unit,
   3147                           soc_profile_reg_t *profile_reg,
   3148                           uint32 index,
   3149                           int entries_per_set_override)
   3150 {
   3151     int num_entries, entries_per_set, i;
   3152 
   3153     if (profile_reg == NULL || profile_reg->regs == NULL ||
   3154         profile_reg->entries == NULL) {
   3155         return SOC_E_INIT;
   3156     }
   3157 
   3158     num_entries = SOC_REG_NUMELS(unit, profile_reg->regs[0]);
   3159     if (num_entries <= 0) {
   3160         return SOC_E_INTERNAL;
   3161     }
   3162 
   3163     if ((int)index >= num_entries) {
   3164         return SOC_E_PARAM;
   3165     }
   3166 
   3167     if ((profile_reg->entries[index].ref_count == 0) && 
   3168         (!SOC_WARM_BOOT(unit))) {
   3169         return SOC_E_NOT_FOUND;
   3170     }
   3171 
   3172     if (SOC_WARM_BOOT(unit)) {
   3173         /* During WB, use the passed in entries_per_set_override value */
   3174         if ((entries_per_set_override < 1) || 
   3175             (entries_per_set_override > num_entries)) {
   3176             return SOC_E_PARAM;
   3177         }
   3178         profile_reg->entries[index].entries_per_set = 
   3179             entries_per_set_override;
   3180     }
   3181     entries_per_set = profile_reg->entries[index].entries_per_set;
   3182     if (index % entries_per_set) {
   3183         return SOC_E_BADID;
   3184     }
   3185 
   3186     profile_reg->entries[index].ref_count++;
   3187     for (i = 1; i < entries_per_set; i++) {
   3188         profile_reg->entries[index + i].ref_count++;
   3189         if (SOC_WARM_BOOT(unit)) {
   3190             /* During WB, use the passed in entries_per_set_override value */
   3191             profile_reg->entries[index + i].entries_per_set = 
   3192                 entries_per_set_override;
   3193         }
   3194         /* Do some optional data integrity check */
   3195         if (profile_reg->entries[index + i].ref_count !=
   3196             profile_reg->entries[index].ref_count ||
   3197             profile_reg->entries[index + i].entries_per_set !=
   3198             profile_reg->entries[index].entries_per_set) {
   3199             return SOC_E_INTERNAL;
   3200         }
   3201     }
   3202 
   3203     return SOC_E_NONE;
   3204 }
   3205 
   3206 /*
   3207  * Function:
   3208  *      soc_profile_reg_ref_count_get
   3209  * Purpose:
   3210  *      Get the reference count of the cached entry at the specified index.
   3211  *
   3212  * Parameters:
   3213  *      unit        - (IN) Unit
   3214  *      profile_reg - (IN) Pointer to profile register structure
   3215  *      index       - (IN) Base index for the entries allocated in HW
   3216  *      ref_count   - (OUT) Reference count
   3217  * Returns:
   3218  *      SOC_E_XXX
   3219  */
   3220 int
   3221 soc_profile_reg_ref_count_get(int unit,
   3222                               soc_profile_reg_t *profile_reg,
   3223                               uint32 index, int *ref_count)
   3224 {
   3225     int num_entries, entries_per_set;
   3226 
   3227     if (profile_reg == NULL || profile_reg->regs == NULL ||
   3228         profile_reg->entries == NULL || ref_count == NULL) {
   3229         return SOC_E_INIT;
   3230     }
   3231 
   3232     num_entries = SOC_REG_NUMELS(unit, profile_reg->regs[0]);
   3233     if (num_entries <= 0) {
   3234         return SOC_E_INTERNAL;
   3235     }
   3236 
   3237     if ((int)index >= num_entries) {
   3238         return SOC_E_PARAM;
   3239     }
   3240 
   3241     if (profile_reg->entries[index].ref_count == 0) {
   3242         *ref_count = 0;
   3243         return SOC_E_NONE;
   3244     }
   3245 
   3246     entries_per_set = profile_reg->entries[index].entries_per_set;
   3247     if (index % entries_per_set) {
   3248         return SOC_E_BADID;
   3249     }
   3250 
   3251     *ref_count = profile_reg->entries[index].ref_count;
   3252 
   3253     return SOC_E_NONE;
   3254 }
   3255 
   3256 /*
   3257  * Function:
   3258  *     soc_profile_mem_write_mode_get
   3259  * Purpose:
   3260  *      Get dma or pio write operation mode
   3261  *      for a profile table mem.
   3262  *
   3263  * Parameters:
   3264  *      unit            - (IN) Unit
   3265  *      profile         - (IN) Pointer to profile memory structure
   3266  *      index0          - (IN) Base index to get mode
   3267  *      mode            - (OUT) table write mode
   3268  * Returns:
   3269  *      SOC_E_XXX
   3270  */
   3271 int
   3272 soc_profile_mem_write_mode_get(int unit,
   3273                     soc_profile_mem_t *profile,
   3274                     uint32 index0, int *mode)
   3275 {
   3276     soc_profile_mem_table_t *table;
   3277     int entries_per_set;
   3278     int base0;
   3279 
   3280     if (profile == NULL) {
   3281         return SOC_E_PARAM;
   3282     }
   3283 
   3284     if (profile->tables == NULL || profile->table_count == 0) {
   3285         return SOC_E_INIT;
   3286     }
   3287 
   3288     table = &profile->tables[0];
   3289     if (index0 < table->index_min || index0 > table->index_max) {
   3290         return SOC_E_PARAM;
   3291     }
   3292 
   3293     base0 = index0 - table->index_min;
   3294 
   3295     if (table->entries[base0].ref_count == 0) {
   3296         return SOC_E_NOT_FOUND;
   3297     }
   3298 
   3299     entries_per_set = table->entries[base0].entries_per_set;
   3300 
   3301     if (base0 % entries_per_set) {
   3302         return SOC_E_PARAM;
   3303     }
   3304 
   3305     if (entries_per_set >= SOC_PROFILE_MEM_DMA_THRESHHOLD) {
   3306         *mode = SOC_PROFILE_MEM_WRITE_DMA_MODE;
   3307     } else {
   3308         *mode = SOC_PROFILE_MEM_WRITE_PIO_MODE;
   3309     }
   3310 
   3311     return SOC_E_NONE;
   3312 }