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

l3x.c (55139B)


      1 /* 
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        l3x.c
      8  *
      9  * Provides:
     10  *      soc_internal_l3x_read
     11  *      soc_internal_l3x_write
     12  *      soc_internal_l3x_init
     13  *      soc_internal_l3x_del
     14  *      soc_internal_l3x_ins
     15  *
     16  * Requires:    
     17  */
     18 
     19 #include <shared/bsl.h>
     20 
     21 #include <soc/mem.h>
     22 #include <soc/hash.h>
     23 #include <soc/drv.h>
     24 #include <soc/l3x.h>
     25 #ifdef BCM_TRIDENT2_SUPPORT
     26 #include <soc/trident2.h>
     27 #endif /* BCM_TRIDENT2_SUPPORT */
     28 #ifdef BCM_TOMAHAWK_SUPPORT
     29 #include <soc/tomahawk.h>
     30 #endif /* BCM_TOMAHAWK_SUPPORT */
     31 #ifdef BCM_MONTEREY_SUPPORT
     32 #include <soc/monterey.h>
     33 #endif /* BCM_MONTEREY_SUPPORT */
     34 #ifdef BCM_APACHE_SUPPORT
     35 #include <soc/apache.h>
     36 #endif /* BCM_APACHE_SUPPORT */
     37 #include "pcid.h"
     38 #include "mem.h"
     39 #include "cmicsim.h"
     40 
     41 #ifdef BCM_XGS_SWITCH_SUPPORT
     42 #ifdef BCM_FIREBOLT_SUPPORT
     43 /* 
     44  * Firebolt L3 Table Simulation
     45  *
     46  * The L3 table is hashed.
     47  *
     48  * L3_ENTRY_IPV4_UNICAST,L3_ENTRY_IPV4_MULTICAST,
     49  * L3_ENTRY_IPV6_UNICAST, L3_ENTRY_IPV6_MULTICAST
     50  * are "virtual" table which aggregates the
     51  * L3_ENTRY_HIT_ONLY | L3_ENTRY_ONLY
     52  * tables.
     53  */
     54 enum {
     55         ENT3f,
     56         ENT2f,
     57         ENT1f,
     58         ENT0f
     59 } soc_L3_ENTRY_DUMMYm_ftype;
     60 
     61 static soc_field_info_t soc_L3_ENTRY_DUMMYm_fields[] = {
     62     { ENT3f, 96, 288, SOCF_LE },
     63     { ENT2f, 96, 192, SOCF_LE },
     64     { ENT1f, 96, 96, SOCF_LE },
     65     { ENT0f, 96, 0, SOCF_LE },
     66 };
     67 static soc_mem_info_t l3_minfo = {
     68                         /* mem            L3_XXXm */
     69                         /* flags       */ 0, 
     70                         /* cmp_fn      */ _soc_mem_cmp_undef,
     71                         /* *null_entry */ _soc_mem_entry_null_zeroes,
     72                         /* index_min   */ 0,
     73                         /* index_max   */ 0,
     74                         /* minblock    */ 0,
     75                         /* maxblock    */ 0,
     76                         /* blocks      */ 0,
     77                         /* blocks_hi   */ 0,
     78                         /* base        */ 0,
     79                         /* gran        */ 1,
     80                         /* bytes       */ 25,
     81                         /* nFields     */ 4, /* Used */
     82                         /* *fields     */ soc_L3_ENTRY_DUMMYm_fields, /* Used */
     83                         };
     84 
     85 #define     L3_ENTRY_IS_ALIGNED(o, a) (((o) % (a)) == 0)
     86 
     87 int
     88 soc_internal_l3x2_read(pcid_info_t * pcid_info, soc_mem_t mem, uint32 addr,
     89                       uint32 *entry)
     90 {
     91     int         unit;
     92     int         offset;
     93     uint32      ent[SOC_MAX_MEM_WORDS];
     94     int         bit;
     95     int         bucket;
     96     int         index;
     97     int 	bucket_size;
     98     int         blk;
     99     soc_block_t sblk;
    100     uint8       at = 0;
    101 
    102     unit = pcid_info->unit;
    103     offset = (addr ^ SOC_MEM_INFO(unit, mem).base) & 0xfffff;
    104 
    105     memset(entry, 0, 4 * soc_mem_entry_words(unit, mem));
    106     memset(ent, 0, 4 * soc_mem_entry_words(unit, mem));
    107 
    108     bucket_size = L3_BUCKET_SIZE(unit);
    109 
    110     /*
    111      * Fix l3_minfo using info from L3_ENTRY_ONLYm table
    112      */    
    113     soc_L3_ENTRY_DUMMYm_fields[3].len = soc_L3_ENTRY_DUMMYm_fields[2].len = 
    114     soc_L3_ENTRY_DUMMYm_fields[1].len = soc_L3_ENTRY_DUMMYm_fields[0].len = 
    115                             soc_mem_entry_bits(unit, L3_ENTRY_ONLYm);
    116     soc_L3_ENTRY_DUMMYm_fields[3].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 0;
    117     soc_L3_ENTRY_DUMMYm_fields[2].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 1;
    118     soc_L3_ENTRY_DUMMYm_fields[1].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 2;
    119     soc_L3_ENTRY_DUMMYm_fields[0].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 3;
    120 
    121     /*
    122      * We could assert on V6 and IPMC bits depending which table
    123      * is being read/written. But that won't be good for diags.
    124      */    
    125     switch(mem) {
    126         case L3_ENTRY_IPV4_MULTICASTm:
    127 #ifdef BCM_TRIUMPH_SUPPORT
    128             if (SOC_IS_TR_VL(unit)) {
    129                 /* Uses two slots per entry */
    130                 index = offset * 2;
    131                 bucket = index / bucket_size;
    132                 bit = (index % bucket_size);
    133                 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm);
    134                 sblk = SOC_BLOCK2SCH(unit, blk);
    135                 soc_internal_extended_read_mem(pcid_info, sblk, at,
    136                           soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    137                                            blk, index + 0, &at), entry);
    138 
    139                 soc_internal_extended_read_mem(pcid_info, sblk, at,
    140                           soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    141                                            blk, index + 1, &at), ent);
    142                 soc_meminfo_field_set(mem, &l3_minfo, entry, ENT1f, ent);
    143 
    144                 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm);
    145                 sblk = SOC_BLOCK2SCH(unit, blk);
    146                 soc_internal_extended_read_mem(pcid_info, sblk, at,
    147                           soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 
    148                                            blk, bucket, &at), ent);
    149                 soc_mem_field32_set(unit, L3_ENTRY_IPV4_MULTICASTm, entry,
    150                                     HIT_0f, (ent[0] >> (bit + 0)) & 1);
    151                 soc_mem_field32_set(unit, L3_ENTRY_IPV4_MULTICASTm, entry,
    152                                     HIT_1f, (ent[0] >> (bit + 1)) & 1);
    153                 break;
    154             }
    155 #endif
    156             /* fallthrough */
    157         case L3_ENTRY_IPV4_UNICASTm:
    158             /* Uses one slot per entry */
    159             index = offset;
    160             bucket = index / bucket_size;
    161             bit = (index % bucket_size);
    162             blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm);
    163             sblk = SOC_BLOCK2SCH(unit, blk);
    164             soc_internal_extended_read_mem(pcid_info, sblk, at,
    165                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    166                                        blk, index + 0, &at), entry);
    167             blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm);
    168             sblk = SOC_BLOCK2SCH(unit, blk);
    169             soc_internal_extended_read_mem(pcid_info, sblk, at,
    170                       soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 
    171                                        blk, bucket, &at), ent);
    172             soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, entry,
    173                                 HITf, (ent[0] >> bit) & 1);
    174                 
    175             break;
    176         case L3_ENTRY_IPV6_UNICASTm:
    177             /* Uses two slots per entry */
    178             index = offset * 2;
    179             bucket = index / bucket_size;
    180             bit = (index % bucket_size);
    181             blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm);
    182             sblk = SOC_BLOCK2SCH(unit, blk);
    183             soc_internal_extended_read_mem(pcid_info, sblk, at,
    184                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    185                                        blk, index + 0, &at), entry);
    186 
    187             soc_internal_extended_read_mem(pcid_info, sblk, at,
    188                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    189                                        blk, index + 1, &at), ent);
    190             soc_meminfo_field_set(mem, &l3_minfo, entry, ENT1f, ent);
    191 
    192             blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm);
    193             sblk = SOC_BLOCK2SCH(unit, blk);
    194             soc_internal_extended_read_mem(pcid_info, sblk, at,
    195                       soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 
    196                                        blk, bucket, &at), ent);
    197             soc_mem_field32_set(unit, L3_ENTRY_IPV6_UNICASTm, entry,
    198                                 HIT_0f, (ent[0] >> (bit + 0)) & 1);
    199             soc_mem_field32_set(unit, L3_ENTRY_IPV6_UNICASTm, entry,
    200                                 HIT_1f, (ent[0] >> (bit + 1)) & 1);
    201             break;
    202         case L3_ENTRY_IPV6_MULTICASTm:
    203             /* Uses four slots per entry */
    204             index = offset * 4;
    205             bucket = index / bucket_size;
    206             bit = (index % bucket_size);
    207             blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm);
    208             sblk = SOC_BLOCK2SCH(unit, blk);
    209             soc_internal_extended_read_mem(pcid_info, sblk, at,
    210                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    211                                        blk, index + 0, &at), entry);
    212 
    213             soc_internal_extended_read_mem(pcid_info, sblk, at,
    214                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    215                                        blk, index + 1, &at), ent);
    216             soc_meminfo_field_set(mem, &l3_minfo, entry, ENT1f, ent);
    217 
    218             soc_internal_extended_read_mem(pcid_info, sblk, at,
    219                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    220                                        blk, index + 2, &at), ent);
    221             soc_meminfo_field_set(mem, &l3_minfo, entry, ENT2f, ent);
    222 
    223             soc_internal_extended_read_mem(pcid_info, sblk, at,
    224                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    225                                        blk, index + 3, &at), ent);
    226             soc_meminfo_field_set(mem, &l3_minfo, entry, ENT3f, ent);
    227 
    228             blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm);
    229             sblk = SOC_BLOCK2SCH(unit, blk);
    230             soc_internal_extended_read_mem(pcid_info, sblk, at,
    231                       soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 
    232                                        blk, bucket, &at), ent);
    233             soc_mem_field32_set(unit, L3_ENTRY_IPV6_MULTICASTm, entry,
    234                                 HIT_0f, (ent[0] >> (bit + 0)) & 1);
    235             soc_mem_field32_set(unit, L3_ENTRY_IPV6_MULTICASTm, entry,
    236                                 HIT_1f, (ent[0] >> (bit + 1)) & 1);
    237             soc_mem_field32_set(unit, L3_ENTRY_IPV6_MULTICASTm, entry,
    238                                 HIT_2f, (ent[0] >> (bit + 2)) & 1);
    239             soc_mem_field32_set(unit, L3_ENTRY_IPV6_MULTICASTm, entry,
    240                                 HIT_3f, (ent[0] >> (bit + 3)) & 1);
    241             break;
    242         default: return(-1);
    243     }
    244     return(0);
    245 }
    246 
    247 int
    248 soc_internal_l3x2_write(pcid_info_t * pcid_info, soc_mem_t mem, uint32 addr,
    249                        uint32 *entry)
    250 {
    251     int         unit;
    252     int         offset;
    253     uint32      ent[SOC_MAX_MEM_WORDS];
    254     int         bit;
    255     int         bucket;
    256     int         index;
    257     int         hit;
    258     int		bucket_size;
    259     int         blk;
    260     soc_block_t sblk;
    261     uint8       at = 0;
    262 
    263     unit = pcid_info->unit;
    264     offset = (addr ^ SOC_MEM_INFO(unit, mem).base) & 0xfffff;
    265     memset(ent, 0, 4 * soc_mem_entry_words(unit, mem));
    266 
    267     bucket_size = L3_BUCKET_SIZE(unit);
    268 
    269     /*
    270      * Fix l3_minfo using info from L3_ENTRY_ONLYm table
    271      */    
    272     soc_L3_ENTRY_DUMMYm_fields[3].len = soc_L3_ENTRY_DUMMYm_fields[2].len = 
    273     soc_L3_ENTRY_DUMMYm_fields[1].len = soc_L3_ENTRY_DUMMYm_fields[0].len = 
    274                             soc_mem_entry_bits(unit, L3_ENTRY_ONLYm);
    275     soc_L3_ENTRY_DUMMYm_fields[3].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 0;
    276     soc_L3_ENTRY_DUMMYm_fields[2].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 1;
    277     soc_L3_ENTRY_DUMMYm_fields[1].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 2;
    278     soc_L3_ENTRY_DUMMYm_fields[0].bp = soc_L3_ENTRY_DUMMYm_fields[0].len * 3;
    279 
    280     /*
    281      * We could assert on V6 and IPMC bits depending which table
    282      * is being read/written. But that won't be good for diags.
    283      */    
    284     switch(mem) {
    285         case L3_ENTRY_IPV4_MULTICASTm:
    286 #ifdef BCM_TRIUMPH_SUPPORT
    287             if (SOC_IS_TR_VL(unit)) {
    288                 /* Uses two slots per entry */
    289                 index = offset * 2;
    290                 bucket = index / bucket_size;
    291                 bit = (index % bucket_size);
    292                 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm);
    293                 sblk = SOC_BLOCK2SCH(unit, blk);
    294                 soc_meminfo_field_get(mem, &l3_minfo, entry, ENT0f, ent, SOC_MAX_MEM_WORDS);
    295                 soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0);
    296                 soc_internal_extended_write_mem(pcid_info, sblk, at,
    297                           soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    298                                            blk, index + 0, &at), ent);
    299 
    300                 soc_meminfo_field_get(mem, &l3_minfo, entry, ENT1f, ent, SOC_MAX_MEM_WORDS);
    301                 soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0);
    302                 soc_internal_extended_write_mem(pcid_info, sblk, at,
    303                           soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    304                                            blk, index + 1, &at), ent);
    305     
    306                 blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm);
    307                 sblk = SOC_BLOCK2SCH(unit, blk);
    308                 soc_internal_extended_read_mem(pcid_info, sblk, at,
    309                           soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 
    310                                            blk, bucket, &at), ent);
    311                 ent[0] &= (~((0x3 << (bit))));
    312                 hit = soc_mem_field32_get(unit, L3_ENTRY_IPV4_MULTICASTm,
    313                                           entry, HIT_0f);
    314                 ent[0] |= ((hit & 1) << (bit + 0));
    315                 hit = soc_mem_field32_get(unit, L3_ENTRY_IPV4_MULTICASTm,
    316                                           entry, HIT_1f);
    317                 ent[0] |= ((hit & 1) << (bit + 1));
    318                 soc_internal_extended_write_mem(pcid_info, sblk, at,
    319                           soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 
    320                                            blk, bucket, &at), ent);
    321 
    322                 break;
    323             }
    324 #endif
    325             /* fallthrough */
    326         case L3_ENTRY_IPV4_UNICASTm:
    327             /* Uses one slot per entry */
    328             index = offset;
    329             bucket = index / bucket_size;
    330             bit = (index % bucket_size);
    331             blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm);
    332             sblk = SOC_BLOCK2SCH(unit, blk);
    333             soc_internal_extended_read_mem(pcid_info, sblk, at,
    334                       soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 
    335                                        blk, bucket, &at), ent);
    336             ent[0] &= (~((0x1 << (bit))));
    337             hit = soc_mem_field32_get(unit, L3_ENTRY_IPV4_UNICASTm,
    338                                       entry, HITf);
    339             ent[0] |= ((hit  & 1) << (bit));
    340             soc_internal_extended_write_mem(pcid_info, sblk, at,
    341                       soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 
    342                                        blk, bucket, &at), ent);
    343                 
    344             blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm);
    345             sblk = SOC_BLOCK2SCH(unit, blk);
    346             soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, entry, HITf, 0);
    347             soc_internal_extended_write_mem(pcid_info, sblk, at,
    348                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    349                                        blk, index + 0, &at), entry);
    350             break;
    351         case L3_ENTRY_IPV6_UNICASTm:
    352             /* Uses two slots per entry */
    353             index = offset * 2;
    354             bucket = index / bucket_size;
    355             bit = (index % bucket_size);
    356             blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm);
    357             sblk = SOC_BLOCK2SCH(unit, blk);
    358             soc_meminfo_field_get(mem, &l3_minfo, entry, ENT0f, ent, SOC_MAX_MEM_WORDS);
    359             soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0);
    360             soc_internal_extended_write_mem(pcid_info, sblk, at,
    361                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    362                                        blk, index + 0, &at), ent);
    363 
    364             soc_meminfo_field_get(mem, &l3_minfo, entry, ENT1f, ent, SOC_MAX_MEM_WORDS);
    365             soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0);
    366             soc_internal_extended_write_mem(pcid_info, sblk, at,
    367                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    368                                        blk, index + 1, &at), ent);
    369 
    370             blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm);
    371             sblk = SOC_BLOCK2SCH(unit, blk);
    372             soc_internal_extended_read_mem(pcid_info, sblk, at,
    373                       soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 
    374                                        blk, bucket, &at), ent);
    375             ent[0] &= (~((0x3 << (bit))));
    376             hit = soc_mem_field32_get(unit, L3_ENTRY_IPV6_UNICASTm,
    377                                       entry, HIT_0f);
    378             ent[0] |= ((hit & 1) << (bit + 0));
    379             hit = soc_mem_field32_get(unit, L3_ENTRY_IPV6_UNICASTm,
    380                                       entry, HIT_1f);
    381             ent[0] |= ((hit & 1) << (bit + 1));
    382             soc_internal_extended_write_mem(pcid_info, sblk, at,
    383                       soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 
    384                                        blk, bucket, &at), ent);
    385 
    386             break;
    387         case L3_ENTRY_IPV6_MULTICASTm:
    388             /* Uses four slots per entry */
    389             index = offset * 4;
    390             bucket = index / bucket_size;
    391             bit = (index % bucket_size);
    392             blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm);
    393             sblk = SOC_BLOCK2SCH(unit, blk);
    394             soc_meminfo_field_get(mem, &l3_minfo, entry, ENT0f, ent, SOC_MAX_MEM_WORDS);
    395             soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0);
    396             soc_internal_extended_write_mem(pcid_info, sblk, at,
    397                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    398                                        blk, index + 0, &at), ent);
    399 
    400             soc_meminfo_field_get(mem, &l3_minfo, entry, ENT1f, ent, SOC_MAX_MEM_WORDS);
    401             soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0);
    402             soc_internal_extended_write_mem(pcid_info, sblk, at,
    403                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    404                                        blk, index + 1, &at), ent);
    405 
    406             soc_meminfo_field_get(mem, &l3_minfo, entry, ENT2f, ent, SOC_MAX_MEM_WORDS);
    407             soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0);
    408             soc_internal_extended_write_mem(pcid_info, sblk, at,
    409                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    410                                        blk, index + 2, &at), ent);
    411 
    412             soc_meminfo_field_get(mem, &l3_minfo, entry, ENT3f, ent, SOC_MAX_MEM_WORDS);
    413             soc_mem_field32_set(unit, L3_ENTRY_IPV4_UNICASTm, ent, HITf, 0);
    414             soc_internal_extended_write_mem(pcid_info, sblk, at,
    415                       soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, 
    416                                        blk, index + 3, &at), ent);
    417 
    418             blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_HIT_ONLYm);
    419             sblk = SOC_BLOCK2SCH(unit, blk);
    420             soc_internal_extended_read_mem(pcid_info, sblk, at,
    421                       soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 
    422                                        blk, bucket, &at), ent);
    423             hit = soc_mem_field32_get(unit, L3_ENTRY_IPV6_MULTICASTm,
    424                                       entry, HIT_0f);
    425             ent[0] &= (~((0xf << (bit))));
    426             ent[0] |= ((hit & 1) << (bit + 0));
    427             hit = soc_mem_field32_get(unit, L3_ENTRY_IPV6_MULTICASTm,
    428                                       entry, HIT_1f);
    429             ent[0] |= ((hit & 1) << (bit + 1));
    430             hit = soc_mem_field32_get(unit, L3_ENTRY_IPV6_MULTICASTm,
    431                                       entry, HIT_2f);
    432             ent[0] |= ((hit & 1) << (bit + 2));
    433             hit = soc_mem_field32_get(unit, L3_ENTRY_IPV6_MULTICASTm,
    434                                       entry, HIT_3f);
    435             ent[0] |= ((hit & 1) << (bit + 3));
    436             soc_internal_extended_write_mem(pcid_info, sblk, at,
    437                       soc_mem_addr_get(unit, L3_ENTRY_HIT_ONLYm, 0, 
    438                                        blk, bucket, &at), ent);
    439             break;
    440         default: return(-1);
    441     }
    442     return(0);
    443 }
    444 
    445 int
    446 soc_internal_l3x2_entry_size_get(pcid_info_t *pcid_info, void *entry,
    447                                  soc_mem_t *mem, int *num_vbits)
    448 {
    449     int unit = pcid_info->unit;
    450 
    451 #ifdef BCM_TRX_SUPPORT
    452     if (SOC_MEM_FIELD_VALID(unit, L3_ENTRY_ONLYm, KEY_TYPEf)) {
    453         int key_type;
    454 
    455         key_type = soc_mem_field32_get(unit, L3_ENTRY_ONLYm,
    456                                        entry, KEY_TYPEf);
    457 #ifdef BCM_TOMAHAWK_SUPPORT
    458         if (SOC_IS_TOMAHAWKX(unit)) {
    459             switch (key_type) {
    460             case TH_L3_HASH_KEY_TYPE_V4UC:
    461             case TH_L3_HASH_KEY_TYPE_TRILL:
    462                 *num_vbits = 1;
    463                 *mem = L3_ENTRY_IPV4_UNICASTm;
    464                 break;
    465             case TH_L3_HASH_KEY_TYPE_V4UC_EXT:
    466             case TH_L3_HASH_KEY_TYPE_V4MC:
    467             case TH_L3_HASH_KEY_TYPE_DST_NAT:
    468             case TH_L3_HASH_KEY_TYPE_DST_NAPT:
    469                 *num_vbits = 2;
    470                 *mem = L3_ENTRY_IPV4_MULTICASTm;
    471                 break;
    472             case TH_L3_HASH_KEY_TYPE_V6UC:
    473                 *num_vbits = 2;
    474                 *mem = L3_ENTRY_IPV6_UNICASTm;
    475                 break;
    476             case TH_L3_HASH_KEY_TYPE_V6UC_EXT:
    477             case TH_L3_HASH_KEY_TYPE_V6MC:
    478                 *num_vbits = 4;
    479                 *mem = L3_ENTRY_IPV6_MULTICASTm;
    480                 break;
    481             default:
    482                 return -1;
    483             }
    484         } else
    485 #endif /* BCM_TOMAHAWK_SUPPORT */
    486 #ifdef BCM_TRIDENT2_SUPPORT
    487         if (SOC_IS_TD2_TT2(unit)) {
    488             switch (key_type) {
    489             case TD2_L3_HASH_KEY_TYPE_V4UC:
    490             case TD2_L3_HASH_KEY_TYPE_TRILL:
    491             case TD2_L3_HASH_KEY_TYPE_FCOE_DOMAIN:
    492             case TD2_L3_HASH_KEY_TYPE_FCOE_HOST:
    493             case TD2_L3_HASH_KEY_TYPE_FCOE_SRC_MAP:
    494                 *num_vbits = 1;
    495                 *mem = L3_ENTRY_IPV4_UNICASTm;
    496                 break;
    497             case TD2_L3_HASH_KEY_TYPE_V4UC_EXT:
    498             case TD2_L3_HASH_KEY_TYPE_V4MC:
    499             case TD2_L3_HASH_KEY_TYPE_V4L2MC:
    500             case TD2_L3_HASH_KEY_TYPE_V4L2VPMC:
    501             case TD2_L3_HASH_KEY_TYPE_FCOE_DOMAIN_EXT:
    502             case TD2_L3_HASH_KEY_TYPE_FCOE_HOST_EXT:
    503             case TD2_L3_HASH_KEY_TYPE_FCOE_SRC_MAP_EXT:
    504             case TD2_L3_HASH_KEY_TYPE_DST_NAT:
    505             case TD2_L3_HASH_KEY_TYPE_DST_NAPT:
    506                 *num_vbits = 2;
    507                 *mem = L3_ENTRY_IPV4_MULTICASTm;
    508                 break;
    509             case TD2_L3_HASH_KEY_TYPE_V6UC:
    510                 *num_vbits = 2;
    511                 *mem = L3_ENTRY_IPV6_UNICASTm;
    512                 break;
    513             case TD2_L3_HASH_KEY_TYPE_V6UC_EXT:
    514             case TD2_L3_HASH_KEY_TYPE_V6MC:
    515             case TD2_L3_HASH_KEY_TYPE_V6L2MC:
    516             case TD2_L3_HASH_KEY_TYPE_V6L2VPMC:
    517                 *num_vbits = 4;
    518                 *mem = L3_ENTRY_IPV6_MULTICASTm;
    519                 break;
    520             default:
    521                 return -1;
    522             }
    523         } else
    524 #endif /* BCM_TRIDENT2_SUPPORT */
    525         {
    526             switch (key_type) {
    527             case TR_L3_HASH_KEY_TYPE_V4UC:
    528                 *num_vbits = 1;
    529                 *mem = L3_ENTRY_IPV4_UNICASTm;
    530                 break;
    531             case TR_L3_HASH_KEY_TYPE_V4MC:
    532                 *num_vbits = SOC_IS_TR_VL(unit) ? 2 : 1;
    533                 *mem = L3_ENTRY_IPV4_MULTICASTm;
    534                 break;
    535             case TR_L3_HASH_KEY_TYPE_V6UC:
    536                 *num_vbits = 2;
    537                 *mem = L3_ENTRY_IPV6_UNICASTm;
    538                 break;
    539             case TR_L3_HASH_KEY_TYPE_V6MC:
    540                 *num_vbits = 4;
    541                 *mem = L3_ENTRY_IPV6_MULTICASTm;
    542                 break;
    543             case TR_L3_HASH_KEY_TYPE_LMEP:
    544                 *num_vbits = 1;
    545                 *mem = L3_ENTRY_IPV4_UNICASTm;
    546                 break;
    547             case TR_L3_HASH_KEY_TYPE_RMEP:
    548                 *num_vbits = 1;
    549                 *mem = L3_ENTRY_IPV4_UNICASTm;
    550                 break;
    551             case TR_L3_HASH_KEY_TYPE_TRILL:
    552                 *num_vbits = 1;
    553                 *mem = L3_ENTRY_ONLYm;
    554                 break;
    555             default:
    556                 return -1;
    557             }
    558         }
    559     } else
    560 #endif /* BCM_TRX_SUPPORT */
    561     if (soc_mem_field32_get(unit, L3_ENTRY_IPV4_UNICASTm, entry, V6f)) {
    562         if (soc_mem_field32_get(unit, L3_ENTRY_IPV4_UNICASTm, entry, IPMCf)) {
    563             *mem = L3_ENTRY_IPV6_MULTICASTm;
    564             *num_vbits = 4;
    565         } else {
    566             *mem = L3_ENTRY_IPV6_UNICASTm;
    567             *num_vbits = 2;
    568         }
    569     } else {
    570         *num_vbits = 1;
    571         if (soc_mem_field32_get(unit, L3_ENTRY_IPV4_UNICASTm, entry, IPMCf)) {
    572             *mem = L3_ENTRY_IPV4_MULTICASTm;
    573         } else {
    574             *mem = L3_ENTRY_IPV4_UNICASTm;
    575         }
    576     }
    577 
    578     return 0;
    579 }
    580 
    581 STATIC int
    582 soc_internal_l3x2_bucket_get(pcid_info_t *pcid_info, int bank, void *entry)
    583 {
    584     uint32  rval[SOC_MAX_MEM_WORDS];
    585     int     bucket, hash_sel;
    586     int     unit = pcid_info->unit;
    587     int     blk;
    588     uint8   acc_type;
    589     uint32  addr;
    590 
    591 #ifdef BCM_TRIDENT2_SUPPORT
    592     if (SOC_IS_TD2_TT2(unit)) {
    593         int hash_offset, use_lsb, index;
    594         soc_reg_t reg;
    595         static const soc_field_t fields[] = {
    596             BANK2_HASH_OFFSETf, BANK3_HASH_OFFSETf, BANK4_HASH_OFFSETf,
    597             BANK5_HASH_OFFSETf, BANK6_HASH_OFFSETf, BANK7_HASH_OFFSETf,
    598             BANK8_HASH_OFFSETf, BANK9_HASH_OFFSETf
    599         };
    600         int is_shared_bank;
    601         uint32 (*entry_hash_proc)(int unit, int bank, int hash_offset,
    602                                int use_lsb, uint32 *entry);
    603 
    604 #if defined(BCM_TOMAHAWK_SUPPORT)
    605         if (SOC_IS_TOMAHAWKX(unit)) {
    606             static const soc_field_t l3_fields[] = {
    607                 L3_ENTRY_BANK_4f, L3_ENTRY_BANK_5f, L3_ENTRY_BANK_6f,
    608                 L3_ENTRY_BANK_7f
    609             };
    610 
    611             entry_hash_proc = soc_th_l3x_entry_hash;
    612             if (bank < 4) {
    613                 is_shared_bank = FALSE;
    614                 index = bank + 4;
    615             } else {
    616                 is_shared_bank = TRUE;
    617                 addr = soc_reg_addr_get(unit, ISS_LOG_TO_PHY_BANK_MAPr,
    618                                         REG_PORT_ANY, 0,
    619                                         SOC_REG_ADDR_OPTION_NONE,
    620                                         &blk, &acc_type);
    621                 soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr,
    622                                                rval);
    623                 index = soc_reg_field_get(unit, ISS_LOG_TO_PHY_BANK_MAPr,
    624                                           rval[0], l3_fields[bank - 4]);
    625             }
    626         } else
    627 #endif /*TOMAHAWK_SUPPORT */
    628 
    629 #if defined(BCM_APACHE_SUPPORT)
    630         if (SOC_IS_APACHE(unit)) {
    631             static const soc_field_t l3_fields[] = {
    632                 L3_ENTRY_BANK_4f, L3_ENTRY_BANK_5f, L3_ENTRY_BANK_6f,
    633                 L3_ENTRY_BANK_7f
    634             };
    635             entry_hash_proc = soc_ap_l3x_entry_hash;
    636             if (bank < 4) {
    637                 is_shared_bank = FALSE;
    638                 index = bank + 4;
    639             } else {
    640                 is_shared_bank = TRUE;
    641                 addr = soc_reg_addr_get(unit, ISS_LOG_TO_PHY_BANK_MAPr,
    642                                         REG_PORT_ANY, 0,
    643                                         SOC_REG_ADDR_OPTION_NONE,
    644                                         &blk, &acc_type);
    645                 soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr,
    646                                                rval);
    647                 index = soc_reg_field_get(unit, ISS_LOG_TO_PHY_BANK_MAPr,
    648                                           rval[0], l3_fields[bank - 4]);
    649            }
    650         } else
    651 #endif /*BCM_APACHE_SUPPORT */ 
    652 
    653         {
    654             entry_hash_proc = soc_td2_l3x_entry_hash;
    655             is_shared_bank = bank < 6;
    656             index = bank - 2;
    657         }
    658 
    659         reg = L3_TABLE_HASH_CONTROLr;
    660         addr = soc_reg_addr_get(unit, reg, REG_PORT_ANY, 0,
    661                                 SOC_REG_ADDR_OPTION_NONE, &blk, &acc_type);
    662         soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, rval);
    663         use_lsb = soc_reg_field_get(unit, reg, rval[0], HASH_ZERO_OR_LSBf);
    664 
    665         if (is_shared_bank) {
    666             reg = SHARED_TABLE_HASH_CONTROLr;
    667             addr = soc_reg_addr_get(unit, reg, REG_PORT_ANY, 0,
    668                                     SOC_REG_ADDR_OPTION_NONE, &blk,
    669                                     &acc_type);
    670             soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr,
    671                                            rval);
    672         }
    673         hash_offset = soc_reg_field_get(unit, reg, rval[0], fields[index]);
    674         bucket = entry_hash_proc(unit, bank, hash_offset, use_lsb, entry);
    675     } else
    676 #endif /* BCM_TRIDENT2_SUPPORT */
    677     {
    678         hash_sel = -1;
    679         if (bank == 1) {
    680             addr = soc_reg_addr_get(unit, L3_AUX_HASH_CONTROLr, REG_PORT_ANY,
    681                                     0, SOC_REG_ADDR_OPTION_NONE,
    682                                     &blk, &acc_type);
    683             soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr,
    684                                            rval);
    685             if (soc_reg_field_get(unit, L3_AUX_HASH_CONTROLr, rval[0],
    686                                   ENABLEf)) {
    687                 hash_sel = soc_reg_field_get(unit, L3_AUX_HASH_CONTROLr,
    688                                              rval[0], HASH_SELECTf);
    689             }
    690         }
    691         if (hash_sel == -1) {
    692             addr = soc_reg_addr_get(unit, HASH_CONTROLr, REG_PORT_ANY, 0,
    693                                     SOC_REG_ADDR_OPTION_NONE, &blk,
    694                                     &acc_type);
    695             soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr,
    696                                            rval);
    697             hash_sel = soc_reg_field_get(unit, HASH_CONTROLr, rval[0],
    698                                          L3_HASH_SELECTf);
    699         }
    700 
    701         bucket = soc_fb_l3x_entry_hash(unit, hash_sel, entry);
    702     }
    703 
    704     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    705                 (BSL_META_U(unit,
    706                             "bank %d bucket %d\n"), bank, bucket));
    707 
    708     return bucket;
    709 }
    710 
    711 STATIC void
    712 soc_internal_l3x2_bank_map_get(pcid_info_t *pcid_info, uint32 *bank_map,
    713                                int *bank_start, int *bank_inc,
    714                                int *do_first_fit)
    715 {
    716     uint32 rval[SOC_MAX_MEM_WORDS];
    717     int    unit = pcid_info->unit;
    718     int    blk;
    719     uint8  acc_type;
    720     uint32 addr;
    721 
    722 #ifdef BCM_MONTEREY_SUPPORT
    723      if (SOC_IS_MONTEREY(pcid_info->unit)) {
    724          *bank_map = 0x3c0;
    725          *bank_start = 9;
    726          *bank_inc = -1;
    727         if (do_first_fit != NULL) {
    728             *do_first_fit = FALSE;
    729         }
    730      }  else 
    731 #endif 
    732 #if defined(BCM_TOMAHAWK_SUPPORT) || defined(BCM_APACHE_SUPPORT)
    733     if (SOC_IS_TOMAHAWKX(pcid_info->unit) || SOC_IS_APACHE(unit)) {
    734         uint32 shared_bank_map;
    735         int bit_count;
    736 
    737 #ifdef BCM_APACHE_SUPPORT
    738      if (SOC_IS_APACHE(pcid_info->unit)) {
    739           addr = soc_reg_addr_get(unit, L3_ISS_BANK_CONFIGr, REG_PORT_ANY, 0,
    740                SOC_REG_ADDR_OPTION_NONE, &blk, &acc_type);
    741           soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, rval);
    742           shared_bank_map = soc_reg_field_get(unit, L3_ISS_BANK_CONFIGr,
    743                rval[0], L3_ENTRY_BANK_CONFIGf);
    744      } else
    745 #endif
    746      {	
    747           addr = soc_reg_addr_get(unit, ISS_BANK_CONFIGr, REG_PORT_ANY, 0,
    748                SOC_REG_ADDR_OPTION_NONE, &blk, &acc_type);
    749           soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, rval);
    750           shared_bank_map = soc_reg_field_get(unit, ISS_BANK_CONFIGr,
    751                rval[0], L3_ENTRY_BANK_CONFIGf);
    752      }
    753         /* calculate number of 1's in shared_bank_map */
    754         bit_count = shared_bank_map - ((shared_bank_map >> 1) & 0x5);
    755         bit_count = ((bit_count & 0xc) >> 2) + (bit_count & 0x3);
    756 
    757         *bank_map = (1 << (bit_count + 4)) - 1;
    758         *bank_start = 0;
    759         *bank_inc = 1;
    760         if (do_first_fit != NULL) {
    761             *do_first_fit = FALSE;
    762         }
    763     } else
    764 #endif /* BCM_TOMAHAWK_SUPPORT || BCM_APACHE_SUPPORT */
    765 #ifdef BCM_TRIDENT2_SUPPORT
    766     if (SOC_IS_TD2_TT2(pcid_info->unit)) {
    767         int    mode;
    768 
    769         addr = soc_reg_addr_get(unit, L3_TABLE_HASH_CONTROLr, REG_PORT_ANY, 0,
    770                                 SOC_REG_ADDR_OPTION_NONE, &blk, &acc_type);
    771         soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, rval);
    772         mode = soc_reg_field_get(unit, L3_TABLE_HASH_CONTROLr, rval[0], MODEf);
    773         switch (mode) {
    774         case 1:
    775             *bank_map = 0x3e0;
    776             break;
    777         case 2:
    778             *bank_map = 0x3f0;
    779             break;
    780         case 3:
    781             *bank_map = 0x3f8;
    782             break;
    783         default:
    784             *bank_map = 0x3c0;
    785         }
    786         *bank_start = 9;
    787         *bank_inc = -1;
    788         if (do_first_fit != NULL) {
    789             *do_first_fit = FALSE;
    790         }
    791     } else
    792 #endif /* BCM_TRIDENT2_SUPPORT */
    793     {
    794         *bank_map = 0x3;
    795         *bank_start = 0;
    796         *bank_inc = 1;
    797         addr = soc_reg_addr_get(unit, L3_AUX_HASH_CONTROLr, REG_PORT_ANY, 0,
    798                                 SOC_REG_ADDR_OPTION_NONE, &blk, &acc_type);
    799         soc_internal_extended_read_reg(pcid_info, blk, acc_type, addr, rval);
    800         if (do_first_fit != NULL) {
    801             *do_first_fit =
    802                 soc_reg_field_get(unit, L3_AUX_HASH_CONTROLr, rval[0],
    803                                   INSERT_LEAST_FULL_HALFf) ? FALSE : TRUE;
    804         }
    805     }
    806 }
    807 
    808 STATIC void
    809 soc_internal_l3x2_bank_size_get(pcid_info_t *pcid_info, int bank,
    810                                 int *entries_per_bank, int *entries_per_row,
    811                                 int *entries_per_bucket, int *bank_base,
    812                                 int *bucket_offset)
    813 {
    814     /*
    815      * entry index =
    816      *     bank_base + bucket * entries_per_row + bucket_offset + slot;
    817      */
    818 
    819 #ifdef BCM_APACHE_SUPPORT
    820     if (SOC_IS_APACHE(pcid_info->unit)) {
    821         (void)soc_apache_hash_bank_info_get(pcid_info->unit, L3_ENTRY_ONLYm,
    822                                             bank, entries_per_bank,
    823                                             entries_per_row,
    824                                             entries_per_bucket,
    825                                             bank_base, bucket_offset);
    826     } else
    827 #endif /* BCM_TOMAHAWK_SUPPORT */
    828 
    829 
    830 #ifdef BCM_TOMAHAWK_SUPPORT
    831     if (SOC_IS_TOMAHAWKX(pcid_info->unit)) {
    832         (void)soc_tomahawk_hash_bank_info_get(pcid_info->unit, L3_ENTRY_ONLYm,
    833                                              bank, entries_per_bank,
    834                                              entries_per_row,
    835                                              entries_per_bucket,
    836                                              bank_base, bucket_offset);
    837     } else
    838 #endif /* BCM_TOMAHAWK_SUPPORT */
    839 #ifdef BCM_TRIDENT2_SUPPORT
    840     if (SOC_IS_TD2_TT2(pcid_info->unit)) {
    841         (void)soc_trident2_hash_bank_info_get(pcid_info->unit, L3_ENTRY_ONLYm,
    842                                               bank, entries_per_bank,
    843                                               entries_per_row,
    844                                               entries_per_bucket,
    845                                               bank_base, bucket_offset);
    846     } else
    847 #endif /* BCM_TRIDENT2_SUPPORT */
    848     {
    849         /*
    850          * first half of entries (slot 0) in each bucket are for bank 0
    851          * the other half of entries (slot 1) in each bucket are for bank 1
    852          */
    853         if (entries_per_bank != NULL) {
    854             *entries_per_bank =
    855                 soc_mem_index_count(pcid_info->unit, L3_ENTRY_ONLYm) / 2;
    856         }
    857         *entries_per_row = SOC_L3X_BUCKET_SIZE(pcid_info->unit);
    858         *entries_per_bucket = *entries_per_row / 2;
    859         *bank_base = 0;
    860         *bucket_offset = bank * *entries_per_bucket;
    861     }
    862 }
    863 
    864 int
    865 soc_internal_l3x2_entry_ins(pcid_info_t *pcid_info, uint32 inv_bank_map,
    866                             void *entry, uint32 *result)
    867 {
    868     uint32          tmp[SOC_MAX_MEM_WORDS];
    869     uint32          ent[SOC_MAX_MEM_WORDS];
    870     int             rv;
    871     uint32          bank_map;
    872     int             bank, entries_per_bank, bank_start, bank_inc, free_bank;
    873     int             bucket, entries_per_row, bank_base, free_bucket;
    874     int             slot, entries_per_bucket, bucket_offset, free_slot;
    875     int             sub_slot;
    876     int             index, free_index;
    877     int             first_free_slot, free_slot_count, do_first_fit;
    878     int             best_free_slot_count, best_entries_per_bank;
    879     int             num_vbits;
    880     int             validslot_cnt;
    881     soc_mem_t       mem;
    882     int             ss_field[] = {ENT0f, ENT1f, ENT2f, ENT3f};
    883     int             unit = pcid_info->unit;
    884     schan_genresp_t *genresp = (schan_genresp_t *) result;
    885     schan_genresp_v2_t *genresp_v2 = (schan_genresp_v2_t *) result;
    886     int             blk;
    887     soc_block_t     sblk;
    888     uint8           acc_type;
    889     uint32          addr;
    890 
    891     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    892                 (BSL_META_U(unit,
    893                             "L3_ENTRY Insert\n")));
    894 
    895     rv = soc_internal_l3x2_entry_size_get(pcid_info, entry, &mem, &num_vbits);
    896     if (rv < 0) {
    897         return rv;
    898     }
    899 
    900     sal_memset(ent, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
    901     sal_memset(tmp, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
    902 
    903     blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm);
    904     sblk = SOC_BLOCK2SCH(unit, blk);
    905 
    906     free_index = -1;
    907 
    908     soc_internal_l3x2_bank_map_get(pcid_info, &bank_map, &bank_start,
    909                                    &bank_inc, &do_first_fit);
    910     bank_map &= ~inv_bank_map;
    911 
    912     best_free_slot_count = 0;
    913     for (bank = bank_start; bank_map != 0; bank += bank_inc) {
    914         if (!(bank_map & (1 << bank))) {
    915             continue;
    916         }
    917         bank_map &= ~(1 << bank);
    918 
    919         soc_internal_l3x2_bank_size_get(pcid_info, bank, &entries_per_bank,
    920                                         &entries_per_row, &entries_per_bucket,
    921                                         &bank_base, &bucket_offset);
    922         bucket = soc_internal_l3x2_bucket_get(pcid_info, bank, entry);
    923         free_slot_count = 0;
    924         first_free_slot = -1;
    925         for (slot = 0; slot < entries_per_bucket; slot += num_vbits) {
    926             validslot_cnt = 0;
    927             for (sub_slot = 0; sub_slot < num_vbits; sub_slot++) {
    928                 index = bank_base + bucket * entries_per_row + bucket_offset +
    929                     slot + sub_slot;
    930                 addr = soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, blk, index,
    931                                         &acc_type);
    932                 soc_internal_extended_read_mem(pcid_info, sblk, acc_type, addr,
    933                                                tmp);
    934                 if (soc_mem_field32_get(unit, L3_ENTRY_ONLYm, tmp, VALIDf)) {
    935                     soc_meminfo_field_set(mem, &l3_minfo, ent,
    936                                           ss_field[sub_slot], tmp);
    937                     validslot_cnt++;
    938                 }
    939             }
    940 
    941             if (validslot_cnt == num_vbits) {
    942                 if (_soc_mem_cmp_l3x2(unit, entry, ent) == 0) {
    943                     if (num_vbits > 0) {
    944                         index /= num_vbits;
    945                     }
    946                     addr = soc_mem_addr_get(unit, mem, 0, blk, index, &acc_type);
    947 
    948                     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    949                                 (BSL_META_U(unit,
    950                                             "write sblk %d acc_type %d bank %d "
    951                                             "bucket %d, slot %d, index %d\n"),
    952                                  sblk, acc_type, bank, bucket, slot, index));
    953 
    954                     /* Overwrite the existing entry */
    955                     soc_internal_extended_write_mem(pcid_info, sblk, acc_type,
    956                                                     addr, entry);
    957 
    958                     if (soc_feature(unit, soc_feature_generic_table_ops)) {
    959                         /* Copy old entry immediately after response word */
    960                         memcpy(&result[1], ent,
    961                                soc_mem_entry_bytes(unit, mem));
    962                         result[0] = 0;
    963                         if (soc_feature(unit, soc_feature_new_sbus_format) &&
    964                             !soc_feature(unit, soc_feature_new_sbus_old_resp) ) {
    965                             genresp_v2->type = SCHAN_GEN_RESP_TYPE_REPLACED;
    966                             genresp_v2->index = index;
    967                         } else {
    968                             genresp->type = SCHAN_GEN_RESP_TYPE_REPLACED;
    969                             genresp->index = index;
    970                         }
    971                     }
    972                     PCIM(pcid_info, CMIC_SCHAN_CTRL) &= ~SC_MSG_NAK_TST;
    973 
    974                     return 0;
    975                 }
    976             } else if (validslot_cnt == 0) {
    977                 free_slot_count++;
    978                 if (first_free_slot == -1) {
    979                     first_free_slot = slot;
    980                 }
    981             }
    982         }
    983         if (free_slot_count > 0) {
    984             if (do_first_fit) {
    985                 if (free_index != -1) {
    986                     continue;
    987                 }
    988             } else {
    989                 if (free_slot_count < best_free_slot_count) {
    990                     continue;
    991                 } else if (free_slot_count == best_free_slot_count) {
    992                     if (entries_per_bank < best_entries_per_bank) {
    993                         continue;
    994                     } else if (entries_per_bank == best_entries_per_bank) {
    995                         if (free_index != -1 && bank > free_bank) {
    996                             continue;
    997                         }
    998                     }
    999                 }
   1000                 best_free_slot_count = free_slot_count;
   1001                 best_entries_per_bank = entries_per_bank;
   1002             }
   1003             free_index = (index + 1 - entries_per_bucket + first_free_slot) /
   1004                 num_vbits;
   1005             free_bank = bank;
   1006             free_bucket = bucket;
   1007             free_slot = first_free_slot;
   1008         }
   1009     }
   1010 
   1011     /* Find first unused slot in bucket */
   1012     if (free_index != -1) {
   1013         index = free_index;
   1014         addr = soc_mem_addr_get(unit, mem, 0, blk, index, &acc_type);
   1015 
   1016         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1017                     (BSL_META_U(unit,
   1018                                 "write sblk %d acc_type %d bank %d bucket %d, "
   1019                                 "slot %d, index %d\n"),
   1020                      sblk, acc_type, free_bank, free_bucket, free_slot, index));
   1021 
   1022         /* Write the entry */
   1023         soc_internal_extended_write_mem(pcid_info, sblk, acc_type, addr,
   1024                                         entry);
   1025 
   1026         if (soc_feature(unit, soc_feature_generic_table_ops)) {
   1027             result[0] = 0;
   1028             if (soc_feature(unit, soc_feature_new_sbus_format) &&
   1029                 !soc_feature(unit, soc_feature_new_sbus_old_resp) ) {
   1030                 genresp_v2->type = SCHAN_GEN_RESP_TYPE_INSERTED;
   1031                 genresp_v2->index = index;
   1032             } else {
   1033                 genresp->type = SCHAN_GEN_RESP_TYPE_INSERTED;
   1034                 genresp->index = index;
   1035             }
   1036         }
   1037         PCIM(pcid_info, CMIC_SCHAN_CTRL) &= ~SC_MSG_NAK_TST;
   1038 
   1039         return 0;
   1040     }
   1041 
   1042     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1043                 (BSL_META_U(unit,
   1044                             "Bucket full\n")));
   1045     if (soc_feature(unit, soc_feature_generic_table_ops)) {
   1046         result[0] = 0;
   1047         if (soc_feature(unit, soc_feature_new_sbus_format) &&
   1048             !soc_feature(unit, soc_feature_new_sbus_old_resp) ) {
   1049             genresp_v2->type = SCHAN_GEN_RESP_TYPE_FULL;
   1050         } else {
   1051             genresp->type = SCHAN_GEN_RESP_TYPE_FULL;
   1052         }
   1053     }
   1054     PCIM(pcid_info, CMIC_SCHAN_CTRL) |= SC_MSG_NAK_TST;
   1055 
   1056     return 0;
   1057 }
   1058 
   1059 int
   1060 soc_internal_l3x2_entry_del(pcid_info_t *pcid_info, uint32 inv_bank_map,
   1061                             void *entry, uint32 *result)
   1062 {
   1063     uint32          tmp[SOC_MAX_MEM_WORDS];
   1064     uint32          ent[SOC_MAX_MEM_WORDS];
   1065     int             rv;
   1066     uint32          bank_map;
   1067     int             bank, bank_start, bank_inc;
   1068     int             bucket, entries_per_row, bank_base;
   1069     int             slot, entries_per_bucket, bucket_offset;
   1070     int             sub_slot;
   1071     int             index;
   1072     int             num_vbits;
   1073     int             validslot_cnt;
   1074     soc_mem_t       mem;
   1075     int             ss_field[] = {ENT0f, ENT1f, ENT2f, ENT3f};
   1076     int             unit = pcid_info->unit;
   1077     schan_genresp_t *genresp = (schan_genresp_t *) result;
   1078     schan_genresp_v2_t *genresp_v2 = (schan_genresp_v2_t *) result;
   1079     int             blk;
   1080     soc_block_t     sblk;
   1081     uint8           acc_type;
   1082     uint32          addr;
   1083 
   1084     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1085                 (BSL_META_U(unit,
   1086                             "L3_ENTRY Delete\n")));
   1087 
   1088     rv = soc_internal_l3x2_entry_size_get(pcid_info, entry, &mem, &num_vbits);
   1089     if (rv < 0) {
   1090         return rv;
   1091     }
   1092 
   1093     sal_memset(ent, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
   1094     sal_memset(tmp, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
   1095 
   1096     blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm);
   1097     sblk = SOC_BLOCK2SCH(unit, blk);
   1098 
   1099     soc_internal_l3x2_bank_map_get(pcid_info, &bank_map, &bank_start,
   1100                                    &bank_inc, NULL);
   1101     bank_map &= ~inv_bank_map;
   1102 
   1103     for (bank = bank_start; bank_map != 0; bank += bank_inc) {
   1104         if (!(bank_map & (1 << bank))) {
   1105             continue;
   1106         }
   1107         bank_map &= ~(1 << bank);
   1108 
   1109         soc_internal_l3x2_bank_size_get(pcid_info, bank, NULL,
   1110                                         &entries_per_row, &entries_per_bucket,
   1111                                         &bank_base, &bucket_offset);
   1112         bucket = soc_internal_l3x2_bucket_get(pcid_info, bank, entry);
   1113 
   1114         for (slot = 0; slot < entries_per_bucket; slot += num_vbits) {
   1115             validslot_cnt = 0;
   1116             for (sub_slot = 0; sub_slot < num_vbits; sub_slot++) {
   1117                 index = bank_base + bucket * entries_per_row + bucket_offset +
   1118                     slot + sub_slot;
   1119                 addr = soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, blk, index,
   1120                                         &acc_type);
   1121                 soc_internal_extended_read_mem(pcid_info, sblk, acc_type, addr,
   1122                                                tmp);
   1123                 if (soc_mem_field32_get(unit, L3_ENTRY_ONLYm, tmp, VALIDf)) {
   1124                     soc_meminfo_field_set(mem, &l3_minfo, ent,
   1125                                           ss_field[sub_slot], tmp);
   1126                     validslot_cnt++;
   1127                 } else {
   1128                     break;
   1129                 }
   1130             }
   1131 
   1132             if (validslot_cnt == num_vbits) {
   1133                 if (_soc_mem_cmp_l3x2(unit, entry, ent) == 0) {
   1134                     if (num_vbits > 0) {
   1135                         index /= num_vbits;
   1136                     }
   1137                     addr = soc_mem_addr_get(unit, mem, 0, blk, index, &acc_type);
   1138 
   1139                     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1140                                 (BSL_META_U(unit,
   1141                                             "delete sblk %d acc_type %d bank %d "
   1142                                             "bucket %d, slot %d, index %d\n"),
   1143                                  sblk, acc_type, bank, bucket, slot, index));
   1144 
   1145                     if (soc_feature(unit, soc_feature_generic_table_ops)) {
   1146                         /* Copy entry immediately after response word */
   1147                         memcpy(&result[1], ent,
   1148                                soc_mem_entry_bytes(unit, mem));
   1149                     }
   1150 
   1151                     /* Invalidate entry */
   1152                     memset(tmp, 0, sizeof(tmp));
   1153                     soc_internal_extended_write_mem(pcid_info, sblk, acc_type,
   1154                                                     addr, (uint32 *)tmp);
   1155 
   1156                     if (soc_feature(unit, soc_feature_generic_table_ops)) {
   1157                         result[0] = 0;
   1158                         if (soc_feature(unit, soc_feature_new_sbus_format) &&
   1159                             !soc_feature(unit, soc_feature_new_sbus_old_resp) ) {
   1160                             genresp_v2->type = SCHAN_GEN_RESP_TYPE_DELETED;
   1161                             genresp_v2->index = index;
   1162                         } else {
   1163                             genresp->type = SCHAN_GEN_RESP_TYPE_DELETED;
   1164                             genresp->index = index;
   1165                         }
   1166                     }
   1167                     PCIM(pcid_info, CMIC_SCHAN_CTRL) &= ~SC_MSG_NAK_TST;
   1168 
   1169                     return 0;
   1170                 }
   1171             }
   1172         }
   1173     }
   1174 
   1175     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1176                 (BSL_META_U(unit,
   1177                             "soc_internal_l3x2_entry_del: Not found\n")));
   1178 
   1179     if (soc_feature(unit, soc_feature_generic_table_ops)) {
   1180         result[0] = 0;
   1181         if (soc_feature(unit, soc_feature_new_sbus_format) &&
   1182             !soc_feature(unit, soc_feature_new_sbus_old_resp) ) {
   1183             genresp_v2->type = SCHAN_GEN_RESP_TYPE_NOT_FOUND;
   1184         } else {
   1185             genresp->type = SCHAN_GEN_RESP_TYPE_NOT_FOUND;
   1186         }
   1187     } else {
   1188         result[0] = 0xffffffff;
   1189     }
   1190     PCIM(pcid_info, CMIC_SCHAN_CTRL) |= SC_MSG_NAK_TST;
   1191 
   1192     return 0;
   1193 }
   1194 int
   1195 soc_internal_l3x2_entry_lkup(pcid_info_t * pcid_info, uint32 inv_bank_map,
   1196                              void *entry, uint32 *result)
   1197 {
   1198     uint32          tmp[SOC_MAX_MEM_WORDS];
   1199     uint32          ent[SOC_MAX_MEM_WORDS];
   1200     int             rv;
   1201     uint32          bank_map;
   1202     int             bank, bank_start, bank_inc;
   1203     int             bucket, entries_per_row, bank_base;
   1204     int             slot, entries_per_bucket, bucket_offset;
   1205     int             sub_slot;
   1206     int             index;
   1207     int             num_vbits;
   1208     int             validslot_cnt;
   1209     int             index_bit_offset;
   1210     int             entry_dw;
   1211     soc_mem_t       mem;
   1212     int             ss_field[] = {ENT0f, ENT1f, ENT2f, ENT3f};
   1213     int             unit = pcid_info->unit;
   1214     schan_genresp_t *genresp = (schan_genresp_t *) result;
   1215     schan_genresp_v2_t *genresp_v2 = (schan_genresp_v2_t *) result;
   1216     int             blk;
   1217     soc_block_t     sblk;
   1218     uint8           acc_type;
   1219     uint32          addr;
   1220 
   1221     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1222                 (BSL_META_U(unit,
   1223                             "L3_ENTRY Lookup\n")));
   1224 
   1225     rv = soc_internal_l3x2_entry_size_get(pcid_info, entry, &mem, &num_vbits);
   1226     if (rv < 0) {
   1227         return rv;
   1228     }
   1229 
   1230     sal_memset(ent, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
   1231     sal_memset(tmp, 0, SOC_MAX_MEM_WORDS * sizeof(uint32));
   1232 
   1233     blk = SOC_MEM_BLOCK_ANY(unit, L3_ENTRY_ONLYm);
   1234     sblk = SOC_BLOCK2SCH(unit, blk);
   1235 
   1236     soc_internal_l3x2_bank_map_get(pcid_info, &bank_map, &bank_start,
   1237                                    &bank_inc, NULL);
   1238     bank_map &= ~inv_bank_map;
   1239 
   1240     for (bank = bank_start; bank_map != 0; bank += bank_inc) {
   1241         if (!(bank_map & (1 << bank))) {
   1242             continue;
   1243         }
   1244         bank_map &= ~(1 << bank);
   1245 
   1246         soc_internal_l3x2_bank_size_get(pcid_info, bank, NULL,
   1247                                         &entries_per_row, &entries_per_bucket,
   1248                                         &bank_base, &bucket_offset);
   1249         bucket = soc_internal_l3x2_bucket_get(pcid_info, bank, entry);
   1250 
   1251         for (slot = 0; slot < entries_per_bucket; slot += num_vbits) {
   1252             validslot_cnt = 0;
   1253             for (sub_slot = 0; sub_slot < num_vbits; sub_slot++) {
   1254                 index = bank_base + bucket * entries_per_row + bucket_offset +
   1255                     slot + sub_slot;
   1256                 addr = soc_mem_addr_get(unit, L3_ENTRY_ONLYm, 0, blk, index,
   1257                                         &acc_type);
   1258                 soc_internal_extended_read_mem(pcid_info, sblk, acc_type, addr,
   1259                                                tmp);
   1260                 if (soc_mem_field32_get(unit, L3_ENTRY_ONLYm, tmp, VALIDf)) {
   1261                     soc_meminfo_field_set(mem, &l3_minfo, ent,
   1262                                           ss_field[sub_slot], tmp);
   1263                     validslot_cnt++;
   1264                 } else {
   1265                     break;
   1266                 }
   1267             }
   1268 
   1269             if (validslot_cnt == num_vbits) {
   1270                 if (_soc_mem_cmp_l3x2(unit, entry, ent) == 0) {
   1271                     if (num_vbits > 0) {
   1272                         index /= num_vbits;
   1273                     }
   1274                     addr = soc_mem_addr_get(unit, mem, 0, blk, index, &acc_type);
   1275 
   1276                     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1277                                 (BSL_META_U(unit,
   1278                                             "found sblk %d acc_type %d bank %d "
   1279                                             "bucket %d, slot %d, index %d\n"),
   1280                                  sblk, acc_type, bank, bucket, slot, index));
   1281 
   1282                     if (soc_feature(unit, soc_feature_generic_table_ops)) {
   1283                         /* Copy entry immediately after response word */
   1284                         memcpy(&result[1], ent,
   1285                                soc_mem_entry_bytes(unit, mem));
   1286 
   1287                         result[0] = 0;
   1288                         if (soc_feature(unit, soc_feature_new_sbus_format) &&
   1289                             !soc_feature(unit, soc_feature_new_sbus_old_resp) ) {
   1290                             genresp_v2->type = SCHAN_GEN_RESP_TYPE_FOUND;
   1291                             genresp_v2->index = index;
   1292                         } else {
   1293                             genresp->type = SCHAN_GEN_RESP_TYPE_FOUND;
   1294                             genresp->index = index;
   1295                         }
   1296                     } else {
   1297                         entry_dw = soc_mem_entry_words(unit, mem);
   1298                         index_bit_offset = soc_mem_entry_bits(unit, mem) % 32;
   1299                         for(slot = 0; slot < entry_dw - 1; slot++) {
   1300                             result[slot] = ent[slot];
   1301                         }
   1302                         if (index_bit_offset) {
   1303                             result[slot] =
   1304                                 (ent[slot] & ((1 << index_bit_offset) - 1)) |
   1305                                 ((index & ((1 << (32 - index_bit_offset)) - 1))
   1306                                  << index_bit_offset);
   1307                             result[slot + 1] =
   1308                                 (index >> (32 - index_bit_offset)) &
   1309                                 ((soc_mem_index_max(unit, mem)) >>
   1310                                 (32 - index_bit_offset));
   1311                         } else {
   1312                             result[slot] = index;
   1313                             result[slot + 1] = 0;
   1314                         }
   1315                     }
   1316                     PCIM(pcid_info, CMIC_SCHAN_CTRL) &= ~SC_MSG_NAK_TST;
   1317 
   1318                     return 0;
   1319                 }
   1320             }
   1321         }
   1322     }
   1323 
   1324     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1325                 (BSL_META_U(unit,
   1326                             "soc_internal_l3x2_entry_lkup: Not found\n")));
   1327 
   1328     if (soc_feature(unit, soc_feature_generic_table_ops)) {
   1329         result[0] = 0;
   1330         if (soc_feature(unit, soc_feature_new_sbus_format) &&
   1331             !soc_feature(unit, soc_feature_new_sbus_old_resp) ) {
   1332             genresp_v2->type = SCHAN_GEN_RESP_TYPE_NOT_FOUND;
   1333         } else {
   1334             genresp->type = SCHAN_GEN_RESP_TYPE_NOT_FOUND;
   1335         }
   1336     } else {
   1337         result[0] = 0xffffffff;
   1338     }
   1339     PCIM(pcid_info, CMIC_SCHAN_CTRL) |= SC_MSG_NAK_TST;
   1340 
   1341     return 0;
   1342 }
   1343 #endif /* BCM_FIREBOLT_SUPPORT */
   1344 #endif