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

alpm_tcam.c (52590B)


      1 /*
      2  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      3  * 
      4  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      5  * 
      6  * File:    alpm_tcam.c
      7  * Purpose: ALPM TCAM management. device independent implementation.
      8  * Requires:
      9  */
     10 
     11 /* Implementation notes:
     12  */
     13 #include <shared/bsl.h>
     14 
     15 #include <soc/mem.h>
     16 #include <soc/drv.h>
     17 #include <soc/debug.h>
     18 #include <soc/error.h>
     19 #include <soc/lpm.h>
     20 #include <soc/trident2.h>
     21 #include <soc/tomahawk.h>
     22 #include <shared/bsl.h>
     23 
     24 #include <shared/util.h>
     25 #include <shared/l3.h>
     26 
     27 #if defined(ALPM_ENABLE)
     28 
     29 #include <bcm/l3.h>
     30 
     31 #include <bcm_int/esw/l3.h>
     32 #include <bcm_int/esw/firebolt.h>
     33 #include <bcm_int/esw/alpm.h>
     34 #include <bcm_int/esw/alpm_util.h>
     35 
     36 /* Internal function declaration */
     37 
     38 #define _TCAM_ZONE_CNT  4
     39 #define _TCAM_ZID_CNT   32
     40 
     41 typedef struct _tcam_zone_state_s {
     42     int start;  /* start index for this prefix length */
     43     int end;    /* End index for this prefix length */
     44     int prev;   /* Prev (Lo to Hi) prefix length with non zero entry count */
     45     int next;   /* Next (Hi to Lo) prefix length with non zero entry count */
     46     int vent;   /* valid entries */
     47     int fent;   /* free entries */
     48 } _tcam_zone_state_t;
     49 
     50 typedef enum _tz_db_e {
     51     _tcamZoneDBInvalid = 0,
     52     _tcamZoneDBV4All = 1,
     53     _tcamZoneDBV4Prv = 2,
     54     _tcamZoneDBV4Glb = 3,
     55     _tcamZoneDBV6All = 4,
     56     _tcamZoneDBV6Prv = 5,
     57     _tcamZoneDBV6Glb = 6,
     58     _tcamZoneDBMixAll = 7,
     59     _tcamZoneDBMixPrv = 8,
     60     _tcamZoneDBMixGlb = 9,
     61     _tcamZoneDBCnt = 10,
     62 } _tz_db_t;
     63 
     64 char *_tz_db_str[] = {
     65     "Invalid",
     66     "V4",
     67     "V4 Private",
     68     "V4 Global ",
     69     "V6",
     70     "V6 Private",
     71     "V6 Global ",
     72     "Mixed",
     73     "Mixed Private",
     74     "Mixed Global ",
     75     "Count"
     76 };
     77 
     78 typedef struct _tcam_zone_s {
     79     _tcam_zone_state_t   *state;
     80 
     81     /* TCAM Zone management */
     82     _tz_db_t        tz_db_type;
     83     uint16          tz_num_inst;
     84     uint16          tz_ent_per_inst;
     85     uint16          tz_min_v6;
     86     uint16          tz_base_idx;
     87     uint16          tz_tbl_sz;
     88 
     89     /* Calculated variables */
     90     uint16          _tz_ent_cnt;
     91     uint16          _tz_max_idx;
     92 } _tcam_zone_t;
     93 
     94 typedef struct _tcam_ctrl_s {
     95     _tcam_zone_t *tcam_zn[_TCAM_ZID_CNT];
     96     int          tcam_zn_cnt;
     97 } _tcam_ctrl_t;
     98 
     99 typedef struct _tcam_zone_st_s {
    100     int cnt_used;
    101     int cnt_free;
    102 } _tcam_zone_st_t;
    103 
    104 _tcam_ctrl_t *_tcam_control[SOC_MAX_NUM_DEVICES];
    105 
    106 #define TCAMC(u)                         (_tcam_control[u])
    107 #define _TCAM_INIT_CHECK(u)              (TCAMC(u) != NULL)
    108 #define _TCAMZ_CNT(u)                    (TCAMC(u)->tcam_zn_cnt)
    109 #define _TCAMZ(u, zid)                   (TCAMC(u)->tcam_zn[zid])
    110 #define _TCAM_STATE(u, zid)              (_TCAMZ(u, zid)->state)
    111 #define _TCAM_STATE_START(u, zid, pfx)   (_TCAMZ(u, zid)->state[pfx].start)
    112 #define _TCAM_STATE_END(u, zid, pfx)     (_TCAMZ(u, zid)->state[pfx].end)
    113 #define _TCAM_STATE_PREV(u, zid, pfx)    (_TCAMZ(u, zid)->state[pfx].prev)
    114 #define _TCAM_STATE_NEXT(u, zid, pfx)    (_TCAMZ(u, zid)->state[pfx].next)
    115 #define _TCAM_STATE_VENT(u, zid, pfx)    (_TCAMZ(u, zid)->state[pfx].vent)
    116 #define _TCAM_STATE_FENT(u, zid, pfx)    (_TCAMZ(u, zid)->state[pfx].fent)
    117 
    118 #define _TCAMZ_INITED(u, zid)            (_TCAMZ(u, zid) && _TCAMZ(u, zid)->tz_num_inst != 0)
    119 #define _TCAMZ_DB_TYPE(u, zid)           (_TCAMZ(u, zid)->tz_db_type)
    120 #define _TCAMZ_PFX_MIN_V6(u, zid)        (_TCAMZ(u, zid)->tz_min_v6)
    121 #define _TCAMZ_PFX_ENT_PER_INST(u, zid)  (_TCAMZ(u, zid)->tz_ent_per_inst)
    122 #define _TCAMZ_PFX_BASE_IDX(u, zid)      (_TCAMZ(u, zid)->tz_base_idx)
    123 #define _TCAMZ_PFX_TBL_SZ(u, zid)        (_TCAMZ(u, zid)->tz_tbl_sz)
    124 #define _TCAMZ_PFX_MAX_ENTS(u, zid)      (_TCAMZ(u, zid)->_tz_ent_cnt)
    125 #define _TCAMZ_PFX_MAX_IDX(u, zid)       (_TCAMZ(u, zid)->_tz_max_idx)
    126 
    127 #define _PFX_IS_PKM_64B(u, zid, pfx)     ((pfx) % _TCAMZ_PFX_ENT_PER_INST(u, zid) \
    128                                          >= _TCAMZ_PFX_MIN_V6(u, zid) && \
    129                                          (pfx) != _TCAMZ_PFX_MAX_IDX(u, zid))
    130 /*
    131  * P: Paired, Z: Zoned, MC: IPMC, VRF 0: Global.
    132  * PKM: 32B(0) !32B(1)
    133  *
    134  * ------------------------------------------
    135  * | MC |  P | Z | VRF | PKM |  Zone | Inst |
    136  * ------------------------------------------
    137  * | 0  |  0 | 0 | 0   | 32B |  Mix  | 0,2  | 0b00000 0  ZoneA
    138  * | 0  |  0 | 0 | 0   | 64B |  Mix  | 0,2  | 0b00001 1  -->ZoneA
    139  * | 0  |  0 | 0 | 1   | 32B |  Mix  | 1    | 0b00010 2  -->ZoneA
    140  * | 0  |  0 | 0 | 1   | 64B |  Mix  | 1    | 0b00011 3  -->ZoneA
    141  * | 0  |  0 | 1 | 0   | 32B |  MxG  | 0,1  | 0b00100 4  B
    142  * | 0  |  0 | 1 | 0   | 64B |  MxG  | 0,1  | 0b00101 5  -->ZoneB
    143  * | 0  |  0 | 1 | 1   | 32B |  MxP  | 0    | 0b00110 6  C
    144  * | 0  |  0 | 1 | 1   | 64B |  MxP  | 0    | 0b00111 7  -->ZoneC
    145  * | 0  |  1 | 0 | 0   | 32B |  V4   | 0,2  | 0b01000 8  D
    146  * | 0  |  1 | 0 | 0   | 128 |  V6   | 0,2  | 0b01001 9  E
    147  * | 0  |  1 | 0 | 1   | 32B |  V4   | 1    | 0b01010 10 -->ZoneD
    148  * | 0  |  1 | 0 | 1   | 128 |  V6   | 1    | 0b01011 11 -->ZoneE
    149  * | 0  |  1 | 1 | 0   | 32B |  V4G  | 0,1  | 0b01100 12 F
    150  * | 0  |  1 | 1 | 0   | 128 |  V6G  | 0,1  | 0b01101 13 G
    151  * | 0  |  1 | 1 | 1   | 32B |  V4P  | 0    | 0b01110 14 H
    152  * | 0  |  1 | 1 | 1   | 128 |  V6P  | 0    | 0b01111 15 I
    153  * ------------------------------------------
    154  * ------------------------------------------
    155  * | MC |  P | Z | VRF | PKM |  Zone | Inst |
    156  * ------------------------------------------
    157  * | 1  |  0 | 0 | 0   | 32B |  Mix  | 3,5  | 0b10000 -->ZoneA
    158  * | 1  |  0 | 0 | 0   | 64B |  Mix  | 3,5  | 0b10001 -->ZoneA
    159  * | 1  |  0 | 0 | 1   | 32B |  Mix  | 4    | 0b10010 -->ZoneA
    160  * | 1  |  0 | 0 | 1   | 64B |  Mix  | 4    | 0b10011 -->ZoneA
    161  * | 1  |  0 | 1 | 0   | 32B |  MxP  | 1,3  | 0b10100 -->ZoneC
    162  * | 1  |  0 | 1 | 0   | 64B |  MxP  | 1,3  | 0b10101 -->ZoneC
    163  * | 1  |  0 | 1 | 1   | 32B |  MxP  | 2    | 0b10110 -->ZoneC
    164  * | 1  |  0 | 1 | 1   | 64B |  MxP  | 2    | 0b10111 -->ZoneC
    165  * | 1  |  1 | 0 | 0   | 32B |  V4   | 3,5  | 0b11000 -->ZoneD
    166  * | 1  |  1 | 0 | 0   | 128 |  V6   | 3,5  | 0b11001 -->ZoneE
    167  * | 1  |  1 | 0 | 1   | 32B |  V4   | 4    | 0b11010 -->ZoneD
    168  * | 1  |  1 | 0 | 1   | 128 |  V6   | 4    | 0b11011 -->ZoneE
    169  * | 1  |  1 | 1 | 0   | 32B |  V4P  | 1,3  | 0b11100 -->ZoneH
    170  * | 1  |  1 | 1 | 0   | 128 |  V6P  | 1,3  | 0b11101 -->ZoneI
    171  * | 1  |  1 | 1 | 1   | 32B |  V4P  | 2    | 0b11110 -->ZoneH
    172  * | 1  |  1 | 1 | 1   | 128 |  V6P  | 2    | 0b11111 -->ZoneI
    173  * ------------------------------------------
    174  */
    175 
    176 /* Zone combination count */
    177 typedef enum tz_comb_e {
    178     tZoneInvalid,
    179     tZoneAC64,       /* 1 */
    180     tZoneBP64Glb,    /* 2 */
    181     tZoneCP64Prv,    /* 3 */
    182     tZoneDC128V4,    /* 4 */
    183     tZoneEC128V6,    /* 5 */
    184     tZoneFP128V4Glb, /* 6 */
    185     tZoneGP128V6Glb, /* 7 */
    186     tZoneHP128V4Prv, /* 8 */
    187     tZoneIP128V6Prv, /* 9 */
    188     tZone__Count
    189 } tz_comb_t;
    190 
    191 static _tz_db_t tcam_zone_type[tZone__Count] = {
    192     _tcamZoneDBInvalid,
    193     _tcamZoneDBMixAll,  /* ZoneA, Combined-64 */
    194     _tcamZoneDBMixGlb,  /* ZoneB, Parallel-64 (Global) */
    195     _tcamZoneDBMixPrv,  /* ZoneC, Parallel-64 (Private) */
    196     _tcamZoneDBV4All,   /* ZoneD, Combined-128 (V4) */
    197     _tcamZoneDBV6All,   /* ZoneE, Combined-128 (V6) */
    198     _tcamZoneDBV4Glb,   /* ZoneF, Parallel-128 (V4 Global) */
    199     _tcamZoneDBV6Glb,   /* ZoneG, Parallel-128 (V6 Global) */
    200     _tcamZoneDBV4Prv,   /* ZoneH, Parallel-128 (V4 Private) */
    201     _tcamZoneDBV6Prv,   /* ZoneI, Parallel-128 (V6 Private) */
    202 };
    203 
    204 /* Number of instance in the zone */
    205 static uint16 tcam_zone_num_inst[tZone__Count] = {
    206     0,
    207     3,                  /* ZoneA */
    208     2,                  /* ZoneB */
    209     1,                  /* ZoneC */
    210     3,                  /* ZoneD */
    211     3,                  /* ZoneE */
    212     2,                  /* ZoneF */
    213     2,                  /* ZoneG */
    214     1,                  /* ZoneH */
    215     1,                  /* ZoneI */
    216 };
    217 
    218 static uint16 tcam_zone_num_inst_ipmc_war[tZone__Count] = {
    219     0,
    220     6,                  /* ZoneA */
    221     2,                  /* ZoneB */
    222     4,                  /* ZoneC */
    223     6,                  /* ZoneD */
    224     6,                  /* ZoneE */
    225     2,                  /* ZoneF */
    226     2,                  /* ZoneG */
    227     4,                  /* ZoneH */
    228     4,                  /* ZoneI */
    229 };
    230 
    231 /* 4 means 4 combinations for Pair_128_mode + alpm_mode
    232  * _TCAM_ZONE_CNT:
    233  *    bit1 : 0 Glb, 1 Prv
    234  *    bit0 : 0 V4,  1 V6
    235  */
    236 static tz_comb_t   tz_conf[4][_TCAM_ZONE_CNT] = {
    237     /* Combined-64 */
    238     {tZoneAC64, tZoneInvalid, tZoneInvalid, tZoneInvalid},
    239     /* Combined-128 bit0 V4|V6 */
    240     {tZoneDC128V4, tZoneEC128V6, tZoneInvalid, tZoneInvalid},
    241     /* Parallel-64  bit1 Glb|Prv */
    242     {tZoneBP64Glb, tZoneInvalid, tZoneCP64Prv, tZoneInvalid},
    243     /* Parallel-128 bit1 Glb|Prv bit0 V4|V6 */
    244     {tZoneFP128V4Glb, tZoneGP128V6Glb, tZoneHP128V4Prv, tZoneIP128V6Prv},
    245 };
    246 
    247 #define _TCAMZ_ZID_TO_ZN(zid)  (zid & 0x3)
    248 #define _TCAMZ_ZID_MAKE_FROM_ZN(mc, p, z, zn)   \
    249     (!!(mc) << 4 | !!(p) << 3 | !!(z) << 2 | (zn & 0x3))
    250 #define _TCAMZ_ZID_MAKE(mc, p, z, vrf, pkm)     \
    251     (!!(mc) << 4 | !!(p) << 3 | !!(z) << 2 | !!(vrf) << 1 | !!(pkm))
    252 #define _TCAMZ_ZID_IS_V6_ONLY(zid)  ((zid) & 0x1)
    253 
    254 static _tcam_zone_t tz_ctrl[SOC_MAX_NUM_DEVICES][_TCAM_ZONE_CNT];
    255 
    256 /*
    257  *   TCAM (1 Zone)                  >>>> Combined + 64B.
    258  * --------------- index 0
    259  * |             |
    260  * |    Zone 0   |      ---- _tcamZoneDBMixAll
    261  * |             |
    262  * --------------- index size-1
    263  *
    264  *   TCAM (2 Zones)                 >>>> Parallel + 64B.
    265  * --------------- index 0
    266  * |    Zone 0   |      ---- _tcamZoneDBMixPrv
    267  * --------------- index size/2-1
    268  * |    Zone 1   |      ---- _tcamZoneDBMixGlb
    269  * --------------- index size-1
    270  *
    271  *   TCAM (2 Zones)                 >>>> Combined + 128B.
    272  * --------------- index 0
    273  * |    Zone 0   |      ---- _tcamZoneDBV4All
    274  * --------------- index size(L3_DEFIP_PAIR_128)-1
    275  * --------------- index 0
    276  * |    Zone 1   |      ---- _tcamZoneDBV6All
    277  * --------------- index size(L3_DEFIP)-1
    278  *
    279  *   TCAM (4 Zones)                 >>>> Parallel + 128B.
    280  * --------------- index 0
    281  * |    Zone 0   |      ---- _tcamZoneDBV4Prv
    282  * --------------- index size(L3_DEFIP_PAIR_128)/2-1
    283  * |    Zone 1   |      ---- _tcamZoneDBV4Glb
    284  * --------------- index size(L3_DEFIP_PAIR_128)-1
    285  * --------------- index 0
    286  * |    Zone 2   |      ---- _tcamZoneDBV6Prv
    287  * --------------- index size(L3_DEFIP)/2-1
    288  * |    Zone 3   |      ---- _tcamZoneDBV6Glb
    289  * --------------- index size(L3_DEFIP)-1
    290  */
    291 void
    292 _tcam_zone_ctrl_config(int u, int zn, _tz_db_t db_type, uint16 num_inst,
    293                        uint16 base_idx, uint16 tbl_sz)
    294 {
    295     uint16 ent_per_inst = 0, v6_min = 0;
    296     _tcam_zone_t *tz;
    297 
    298     tz = &tz_ctrl[u][zn];
    299 
    300     switch (db_type) {
    301         case _tcamZoneDBV4All:
    302         case _tcamZoneDBV4Prv:
    303         case _tcamZoneDBV4Glb:
    304             ent_per_inst = 32 + 2 + 1;
    305             v6_min = ent_per_inst + 1;
    306             break;
    307         case _tcamZoneDBV6All:
    308         case _tcamZoneDBV6Prv:
    309         case _tcamZoneDBV6Glb:
    310             ent_per_inst = 128 + 2 + 1;
    311             v6_min = 0;
    312             break;
    313         case _tcamZoneDBMixAll:
    314         case _tcamZoneDBMixPrv:
    315         case _tcamZoneDBMixGlb:
    316             ent_per_inst = 64 + 32 + 2 + 1;
    317             v6_min = 32 + 1;
    318             break;
    319         default:
    320             assert(0);
    321             break;
    322     }
    323 
    324     tz->tz_db_type      = db_type;
    325     tz->tz_num_inst     = num_inst;
    326     tz->tz_ent_per_inst = ent_per_inst;
    327     tz->tz_min_v6       = v6_min;
    328     tz->tz_tbl_sz       = tbl_sz;
    329     tz->tz_base_idx     = base_idx;
    330     tz->_tz_ent_cnt     = num_inst * ent_per_inst;
    331     tz->_tz_max_idx     = tz->_tz_ent_cnt - 1;
    332 
    333     return ;
    334 }
    335 
    336 int
    337 _tcam_zone_db_type_to_pkm(int u, _tz_db_t db_type)
    338 {
    339     int pkm = ALPM_PKM_32B;
    340     switch (db_type) {
    341         case _tcamZoneDBV6All:
    342         case _tcamZoneDBV6Prv:
    343         case _tcamZoneDBV6Glb:
    344             pkm = ALPM_PKM_128;
    345             break;
    346         default:
    347             break;
    348     }
    349 
    350     return pkm;
    351 }
    352 
    353 int
    354 _tcam_zone_init(int u)
    355 {
    356     int rv = BCM_E_NONE, zn, zid, j, comb;
    357     int max_pfx_len, pfx_st_sz, zone_cnt = 0;
    358 
    359     int          pkm;
    360     _tz_db_t db_type;
    361     uint16  num_inst;
    362     uint16  base_idx;
    363     int       tbl_sz;
    364 
    365     comb = !!ALPM_TCAM_ZONED(u) << 1 | !!ALPM_128B(u);
    366     for (zn = 0; zn < _TCAM_ZONE_CNT; zn++) {
    367         tz_comb_t tzc = tz_conf[comb][zn];
    368         if (tzc == tZoneInvalid) {
    369             continue;
    370         }
    371 
    372         db_type = tcam_zone_type[tzc];
    373         pkm = _tcam_zone_db_type_to_pkm(u, db_type);
    374         tbl_sz = tcam_table_size(u, pkm) >> !!ALPM_TCAM_ZONED(u);
    375         if (db_type == _tcamZoneDBV6Glb ||
    376             db_type == _tcamZoneDBV4Glb ||
    377             db_type == _tcamZoneDBMixGlb) {
    378             base_idx = tbl_sz;
    379         } else {
    380             base_idx = 0;
    381         }
    382 
    383         num_inst = (soc_feature(u, soc_feature_td3_lpm_ipmc_war)) ?
    384                     tcam_zone_num_inst_ipmc_war[tzc] :
    385                     tcam_zone_num_inst[tzc];
    386         _tcam_zone_ctrl_config(u, zn, db_type, num_inst,
    387                                base_idx, (uint16)tbl_sz);
    388         zone_cnt ++;
    389     }
    390 
    391     TCAMC(u)->tcam_zn_cnt = zone_cnt;
    392 
    393     /* Mapping to tz_ctrl(uc) */
    394     for (zn = 0; zn < _TCAM_ZONE_CNT; zn++) {
    395         int zn2 = zn;
    396         tz_comb_t tzc;
    397 
    398         tzc = tz_conf[comb][zn];
    399         zid = _TCAMZ_ZID_MAKE_FROM_ZN(0, ALPM_128B(u), ALPM_TCAM_ZONED(u), zn);
    400         if (tzc == tZoneInvalid) {
    401             /* IP type don't care */
    402             if (!ALPM_128B(u) && (zn & 0x1)) {
    403                 zn2 = zn2 & 0x2;
    404             }
    405             /* VRF type don't care */
    406             if (!ALPM_TCAM_ZONED(u) && (zn & 0x2)) {
    407                 zn2 = zn2 & 0x1;
    408             }
    409         }
    410         _TCAMZ(u, zid) = &tz_ctrl[u][zn2];
    411         ALPM_VERB(("uc zid %d -> zn %d\n", zid, zn2));
    412     }
    413 
    414     if (soc_feature(u, soc_feature_td3_lpm_ipmc_war)) {
    415         for (zn = 0; zn < _TCAM_ZONE_CNT; zn++) {
    416             int zn2 = zn;
    417 
    418             zid = _TCAMZ_ZID_MAKE_FROM_ZN(1, ALPM_128B(u), ALPM_TCAM_ZONED(u), zn);
    419 
    420             /* IP type don't care */
    421             if (!ALPM_128B(u) && (zn & 0x1)) {
    422                 zn2 = zn2 & 0x2;
    423             }
    424 
    425             if (ALPM_TCAM_ZONED(u)) {
    426                 /* VRF type don't care */
    427                 if (!(zn & 0x2)) {
    428                     zn2 = zn2 | 0x2;
    429                 }
    430             } else {
    431                 /* VRF type don't care */
    432                 if (zn & 0x2) {
    433                     zn2 = zn2 & 0x1;
    434                 }
    435             }
    436             _TCAMZ(u, zid) = &tz_ctrl[u][zn2];
    437             ALPM_VERB(("mc zid %d -> zn %d\n", zid, zn2));
    438         }
    439     }
    440 
    441     /* TCAM State init */
    442     for (zn = 0; zn < _TCAM_ZONE_CNT; zn++) {
    443         int max_idx, zid;
    444 
    445         zid = _TCAMZ_ZID_MAKE_FROM_ZN(0, ALPM_128B(u), ALPM_TCAM_ZONED(u), zn);
    446         if (_TCAMZ(u, zid) == NULL) {
    447             continue;
    448         }
    449 
    450         max_idx = _TCAMZ_PFX_MAX_IDX(u, zid);
    451         max_pfx_len = _TCAMZ_PFX_MAX_ENTS(u, zid);
    452         pfx_st_sz = sizeof(_tcam_zone_state_t) * max_pfx_len;
    453         ALPM_REALLOC_EG(_TCAM_STATE(u, zid), pfx_st_sz, "LPM_pfx_info");
    454         for (j = 0; j < max_pfx_len; j++) {
    455             _TCAM_STATE_START(u, zid, j)  = -1;
    456             _TCAM_STATE_END(u, zid, j)    = -1;
    457             _TCAM_STATE_PREV(u, zid, j)   = -1;
    458             _TCAM_STATE_NEXT(u, zid, j)   = -1;
    459             _TCAM_STATE_VENT(u, zid, j)   = 0;
    460             _TCAM_STATE_FENT(u, zid, j)   = 0;
    461         }
    462 
    463         _TCAM_STATE_FENT(u, zid, max_idx) = _TCAMZ_PFX_TBL_SZ(u, zid);
    464         _TCAM_STATE_END(u, zid, max_idx) = _TCAMZ_PFX_BASE_IDX(u, zid) - 1;
    465     }
    466 
    467 bad:
    468     return rv;
    469 }
    470 
    471 static int
    472 _tcam_zone_zid_get(int u, int vrf, int ipt, int in_pair_mode, int mc)
    473 {
    474     int zid;
    475     mc = soc_feature(u, soc_feature_td3_lpm_ipmc_war) && mc;
    476     zid = _TCAMZ_ZID_MAKE(mc, in_pair_mode, ALPM_TCAM_ZONED(u),
    477                           !ALPM_VRF_IS_GBL(u, vrf), ipt);
    478     return zid;
    479 }
    480 
    481 int
    482 _tcam_zone_inst_id_get(int u, int vrf, int mc)
    483 {
    484     int inst_id;
    485 
    486     if (ALPM_TCAM_ZONED(u)) {
    487         if (soc_feature(u, soc_feature_td3_lpm_ipmc_war) && mc) {
    488             switch (vrf) {
    489             case BCM_L3_VRF_GLOBAL:
    490                 inst_id = 1;
    491                 break;
    492             case BCM_L3_VRF_OVERRIDE:
    493                 inst_id = 3;
    494                 break;
    495             default:
    496                 inst_id = 2;
    497                 break;
    498             }
    499         } else {
    500             switch (vrf) {
    501             case BCM_L3_VRF_GLOBAL:
    502                 inst_id = 0;
    503                 break;
    504             case BCM_L3_VRF_OVERRIDE:
    505                 inst_id = 1;
    506                 break;
    507             default:
    508                 inst_id = 0;
    509                 break;
    510             }
    511         }
    512     } else {
    513         if (soc_feature(u, soc_feature_td3_lpm_ipmc_war) && mc) {
    514             switch (vrf) {
    515             case BCM_L3_VRF_GLOBAL:
    516                 inst_id = 3;
    517                 break;
    518             case BCM_L3_VRF_OVERRIDE:
    519                 inst_id = 5;
    520                 break;
    521             default:
    522                 inst_id = 4;
    523                 break;
    524             }
    525         } else {
    526             switch (vrf) {
    527             case BCM_L3_VRF_GLOBAL:
    528                 inst_id = 0;
    529                 break;
    530             case BCM_L3_VRF_OVERRIDE:
    531                 inst_id = 2;
    532                 break;
    533             default:
    534                 inst_id = 1;
    535                 break;
    536             }
    537         }
    538     }
    539 
    540     return inst_id;
    541 }
    542 
    543 static void
    544 _tcam_zone_status(int u, int zid, _tcam_zone_st_t *tz_st)
    545 {
    546     int i, max_pfx_len;
    547 
    548     sal_memset(tz_st, 0, sizeof(*tz_st));
    549     max_pfx_len = _TCAMZ_PFX_MAX_IDX(u, zid);
    550     for (i = max_pfx_len; i >= 0 ; i--) {
    551         if (i != _TCAMZ_PFX_MAX_IDX(u, zid) && (_TCAM_STATE_START(u, zid, i) == -1)) {
    552             continue;
    553         }
    554 
    555         tz_st->cnt_free += _TCAM_STATE_FENT(u, zid, i);
    556         tz_st->cnt_used += _TCAM_STATE_VENT(u, zid, i);
    557     }
    558 
    559     return ;
    560 }
    561 
    562 static int
    563 _tcam_trie_lookup(int u, _bcm_defip_cfg_t *lpm_cfg, int *key_index)
    564 {
    565     int              rv = BCM_E_NOT_FOUND;
    566     alpm_lib_trie_t  *pvt_trie;
    567     _alpm_pvt_node_t *pvt_node;
    568 
    569     int             ipt = ALPM_LPM_IPT(u, lpm_cfg);
    570     int             vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg);
    571 
    572     pvt_trie = ACB_PVT_TRIE(ACB_TOP(u), vrf_id, ipt);
    573     if (pvt_trie != NULL) {
    574         rv = alpm_lib_trie_search(pvt_trie, lpm_cfg->user_data,
    575                     lpm_cfg->defip_sub_len,
    576                     (alpm_lib_trie_node_t **)&pvt_node);
    577         if (BCM_SUCCESS(rv)) {
    578             *key_index = PVT_IDX(pvt_node);
    579         }
    580     }
    581     return rv;
    582 }
    583 
    584 static int
    585 _tcam_trie_update(int u, uint32 *key, int len, int vrf_id, int ipt, int key_idx)
    586 {
    587     int                 rv = BCM_E_NOT_FOUND;
    588     alpm_lib_trie_t     *pvt_trie;
    589     _alpm_pvt_node_t    *pvt_node;
    590 
    591     pvt_trie = ACB_PVT_TRIE(ACB_TOP(u), vrf_id, ipt);
    592     if (pvt_trie != NULL) {
    593         rv = alpm_lib_trie_search(pvt_trie, key, len, (alpm_lib_trie_node_t **)&pvt_node);
    594         if (BCM_SUCCESS(rv)) {
    595             PVT_IDX(pvt_node) = key_idx;
    596         }
    597     }
    598 
    599     return rv;
    600 }
    601 
    602 int
    603 _tcam_trie_update_by_cfg(int u, _bcm_defip_cfg_t *lpm_cfg, int key_idx)
    604 {
    605     int rv;
    606     int ipt = ALPM_LPM_IPT(u, lpm_cfg);
    607     int vrf_id = ALPM_LPM_VRF_ID(u, lpm_cfg);
    608 
    609     rv = _tcam_trie_update(u, lpm_cfg->user_data, lpm_cfg->defip_sub_len,
    610                            vrf_id, ipt, key_idx);
    611 
    612     return rv;
    613 }
    614 
    615 int
    616 tcam_entry_valid(int u, int pkm, void *e, int sub_idx)
    617 {
    618     int vld = 0;
    619 
    620     vld = ALPM_DRV(u)->tcam_entry_valid(u, pkm, e, sub_idx);
    621 
    622     return vld;
    623 }
    624 
    625 static int
    626 _tcam_entry_valid_set(int u, int pkm, void *e, int sub_idx, int val)
    627 {
    628     int rv = BCM_E_NONE;
    629 
    630     rv = ALPM_DRV(u)->tcam_entry_valid_set(u, pkm, e, sub_idx, val);
    631 
    632     return rv;
    633 }
    634 
    635 static int
    636 _tcam_trie_update_by_ent(int u, int pkm, void *e, int hw_idx)
    637 {
    638     int         i, rv = BCM_E_NONE;
    639     uint32      pfx[5];
    640     int         pfx_len, vrf_id;
    641 
    642     if (pkm == ALPM_PKM_32B) {
    643         /* For IPv4(32B packing mode), check and update both 2 entries */
    644         for (i = 0; i < 2; i++) {
    645             if (tcam_entry_valid(u, pkm, e, i)) {
    646                 ALPM_IER(tcam_entry_vrf_id_get(u, pkm, e, i, &vrf_id));
    647                 ALPM_IER(tcam_entry_pfx_len_get(u, pkm, e, i, &pfx_len));
    648                 ALPM_IER(alpm_trie_ent_to_pfx(u, pkm, e, i, pfx_len, pfx));
    649                 rv = _tcam_trie_update(u, pfx, pfx_len, vrf_id, ALPM_PKM2IPT(pkm),
    650                                        hw_idx << 1 | i);
    651             }
    652         }
    653     } else {
    654         if (tcam_entry_valid(u, pkm, e, 0)) {
    655             ALPM_IER(tcam_entry_vrf_id_get(u, pkm, e, 0, &vrf_id));
    656             ALPM_IER(tcam_entry_pfx_len_get(u, pkm, e, 0, &pfx_len));
    657             ALPM_IER(alpm_trie_ent_to_pfx(u, pkm, e, 0, pfx_len, pfx));
    658             rv = _tcam_trie_update(u, pfx, pfx_len, vrf_id, ALPM_PKM2IPT(pkm), hw_idx);
    659         }
    660     }
    661 
    662     return rv;
    663 }
    664 
    665 /**********************************************
    666 * TCAM Management functions *
    667  */
    668 
    669 /*
    670  * TCAM based PIVOT implementation. Each table entry can hold two IPV4 PIVOTs or
    671  * one IPV6 PIVOT entry. VRF independent routes placed at the beginning or
    672  * at the end of table based on application provided entry vrf id
    673  * (BCM_L3_VRF_OVERRIDE/BCM_L3_VRF_GLOBAL).
    674  *
    675  *              _PFX_MAX_INDEX
    676  * lpm_prefix_index[98].begin ---> ===============================
    677  *                                 ==                           ==
    678  *                                 ==    0                      ==
    679  * lpm_prefix_index[98].end   ---> ===============================
    680  *
    681  * lpm_prefix_index[97].begin ---> ===============================
    682  *                                 ==                           ==
    683  *                                 ==    IPV6  Prefix Len = 64  ==
    684  * lpm_prefix_index[97].end   ---> ===============================
    685  *
    686  *
    687  *
    688  * lpm_prefix_index[x].begin --->  ===============================
    689  *                                 ==                           ==
    690  *                                 ==                           ==
    691  * lpm_prefix_index[x].end   --->  ===============================
    692  *
    693  *
    694  *              _PFX_MIN_V6
    695  * lpm_prefix_index[33].begin ---> ===============================
    696  *                                 ==                           ==
    697  *                                 ==    IPV6  Prefix Len = 0   ==
    698  * lpm_prefix_index[33].end   ---> ===============================
    699  *
    700  *
    701  * lpm_prefix_index[32].begin ---> ===============================
    702  *                                 ==                           ==
    703  *                                 ==    IPV4  Prefix Len = 32  ==
    704  * lpm_prefix_index[32].end   ---> ===============================
    705  *
    706  *
    707  *
    708  * lpm_prefix_index[0].begin --->  ===============================
    709  *                                 ==                           ==
    710  *                                 ==    IPV4  Prefix Len = 0   ==
    711  * lpm_prefix_index[0].end   --->  ===============================
    712  */
    713 
    714 int
    715 tcam_entry_vrf_id_get(int u, int pkm, void *e, int sub_idx, int *vrf_id)
    716 {
    717     int         rv = BCM_E_UNAVAIL;
    718 
    719     rv = ALPM_DRV(u)->tcam_entry_vrf_id_get(u, pkm, e, sub_idx, vrf_id);
    720 
    721     return rv;
    722 }
    723 
    724 int
    725 tcam_entry_pfx_len_get(int u, int pkm, void *e, int sub_idx, int *pfx_len)
    726 {
    727     int         rv = BCM_E_UNAVAIL;
    728 
    729     rv = ALPM_DRV(u)->tcam_entry_pfx_len_get(u, pkm, e, sub_idx, pfx_len);
    730 
    731     return rv;
    732 }
    733 
    734 /*
    735  * x | y
    736  * --------------------
    737  * 0 | 0 : entry0_to_0
    738  * 0 | 1 : entry0_to_1
    739  * 1 | 0 : entry1_to_0
    740  * 1 | 1 : entry1_to_1
    741  * src and dst can be same
    742  */
    743 static int
    744 _tcam_entry_x_to_y(int u, int pkm, void *src, void *dst,
    745                    int copy_hit, int x, int y)
    746 {
    747     int         rv = BCM_E_UNAVAIL;
    748     rv = ALPM_DRV(u)->tcam_entry_x_to_y(u, pkm, src, dst, copy_hit, x, y);
    749 
    750     return rv;
    751 }
    752 
    753 static int
    754 _tcam_entry_from_cfg(int u, int pkm, _bcm_defip_cfg_t *lpm_cfg, void *e, int x, uint32 write_flags)
    755 {
    756     int         rv = BCM_E_UNAVAIL;
    757 
    758     rv = ALPM_DRV(u)->tcam_entry_from_cfg(u, pkm, lpm_cfg, e, x, write_flags);
    759     return rv;
    760 }
    761 
    762 int
    763 tcam_entry_to_cfg(int u, int pkm, void *e, int x, _bcm_defip_cfg_t *lpm_cfg)
    764 {
    765     int         rv = BCM_E_UNAVAIL;
    766 
    767     rv = ALPM_DRV(u)->tcam_entry_to_cfg(u, pkm, e, x, lpm_cfg);
    768     return rv;
    769 }
    770 
    771 int
    772 tcam_entry_read(int u, int pkm, void *e, int index, int s_index)
    773 {
    774     int         rv = BCM_E_UNAVAIL;
    775     _alpm_cb_t *acb;
    776 
    777     acb = ACB_TOP(u);
    778     rv = ALPM_DRV(u)->mem_entry_read(u, acb, acb->pvt_tbl[pkm], index, e, FALSE);
    779 
    780     return rv;
    781 }
    782 
    783 int
    784 tcam_entry_read_no_cache(int u, int pkm, void *e, int index, int s_index)
    785 {
    786     int         rv = BCM_E_UNAVAIL;
    787     _alpm_cb_t *acb;
    788 
    789     acb = ACB_TOP(u);
    790     rv = ALPM_DRV(u)->mem_entry_read(u, acb, acb->pvt_tbl[pkm], index, e, TRUE);
    791 
    792     return rv;
    793 }
    794 
    795 int
    796 _tcam_entry_write(int u, int pkm, void *e, int index, int s_index)
    797 {
    798     int         rv = BCM_E_UNAVAIL;
    799     _alpm_cb_t *acb;
    800 
    801     acb = ACB_TOP(u);
    802     rv = ALPM_DRV(u)->mem_entry_write(u, acb, NULL, acb->pvt_tbl[pkm], index, e);
    803 
    804     return rv;
    805 }
    806 
    807 /*
    808  *           key[4] = {key[0], key[1], key[2], key[3]}
    809  * ipv4:     key[4] =
    810  *               {IP_ADDR0f, 0, 0, 0}
    811  * ipv6-64:  key[4] =
    812  *               {0, 0, IP_ADDR0f, IP_ADDR1f}
    813  * ipv6-128: key[4] =
    814  *               {IP_ADDR0_LWRf, IP_ADDR1_LWRf, IP_ADDR0_UPRf, IP_ADDR1_UPRf}
    815  */
    816 int
    817 tcam_entry_to_key(int u, int pkm, void *e, int sub_idx, uint32 *key)
    818 {
    819     int         rv = BCM_E_UNAVAIL;
    820 
    821     rv = ALPM_DRV(u)->tcam_entry_to_key(u, pkm, e, sub_idx, key);
    822 
    823     return rv;
    824 }
    825 
    826 /*
    827  *      Create a slot for the new entry rippling the entries if required
    828  */
    829 static int
    830 _tcam_entry_shift(int u, int pkm, int from_ent, int to_ent)
    831 {
    832     int         rv;
    833     uint32      e[SOC_MAX_MEM_FIELD_WORDS];
    834 
    835     ALPM_IER(tcam_entry_read(u, pkm, e, from_ent, from_ent));
    836     rv = _tcam_trie_update_by_ent(u, pkm, e, to_ent);
    837     if (BCM_SUCCESS(rv)) {
    838         rv = _tcam_entry_write(u, pkm, e, to_ent, from_ent);
    839     }
    840 
    841     return rv;
    842 }
    843 
    844 /*
    845  * Lower index -> Higher index
    846  * Higher priority -> Lower priority
    847  * L3_DEFIP_PAIR_128 -> L3_DEFIP
    848  *  --------  0
    849  *  |      |
    850  *  |      |  |
    851  *  |      | \|/
    852  *  |      |  *
    853  *  |      |
    854  *  -------- 1023
    855  */
    856 static int
    857 _tcam_shift_pfx_up(int u, int pfx, int zid)
    858 {
    859     int         pkm;
    860     uint32      e[SOC_MAX_MEM_FIELD_WORDS];
    861     int         from_ent;
    862     int         to_ent;
    863     uint32      v0, v1;
    864     int         rv = BCM_E_NONE;
    865 
    866     to_ent = _TCAM_STATE_END(u, zid, pfx) + 1;
    867 
    868     pkm = _tcam_zone_db_type_to_pkm(u, _TCAMZ_DB_TYPE(u, zid));
    869     if (pkm != ALPM_PKM_128) {
    870         pkm = _PFX_IS_PKM_64B(u, zid, pfx);
    871     }
    872 
    873     if (pkm == ALPM_PKM_32B) {
    874         from_ent = _TCAM_STATE_END(u, zid, pfx);
    875         ALPM_IER(tcam_entry_read(u, pkm, e, from_ent, from_ent));
    876         v0 = tcam_entry_valid(u, pkm, e, 0);
    877         v1 = tcam_entry_valid(u, pkm, e, 1);
    878 
    879         if ((v0 == 0) || (v1 == 0)) {
    880             /* Last entry is half full -> keep it last. */
    881             _tcam_trie_update_by_ent(u, pkm, e, to_ent);
    882             ALPM_IER(_tcam_entry_write(u, pkm, e, to_ent, from_ent));
    883             to_ent--;
    884         }
    885     }
    886 
    887     from_ent = _TCAM_STATE_START(u, zid, pfx);
    888     if (from_ent != to_ent) {
    889         ALPM_IER(_tcam_entry_shift(u, pkm, from_ent, to_ent));
    890     }
    891     _TCAM_STATE_START(u, zid, pfx) += 1;
    892     _TCAM_STATE_END(u, zid, pfx) += 1;
    893 
    894     return rv;
    895 }
    896 
    897 /*
    898  * Higher index -> Lower index
    899  * Lower priority -> Higher priority
    900  * L3_DEFIP -> L3_DEFIP_PAIR_128
    901  *
    902  *  --------  0
    903  *  |      |
    904  *  |      |  *
    905  *  |      | /|\
    906  *  |      |  |
    907  *  |      |
    908  *  -------- 1023
    909  */
    910 static int
    911 _tcam_shift_pfx_down(int u, int pfx, int zid)
    912 {
    913     int         pkm;
    914     uint32      e[SOC_MAX_MEM_FIELD_WORDS];
    915     int         from_ent;
    916     int         to_ent;
    917     int         prev_ent;
    918     uint32      v0, v1;
    919     int         rv = BCM_E_NONE;
    920 
    921     to_ent = _TCAM_STATE_START(u, zid, pfx) - 1;
    922 
    923     /* Don't move empty prefix . */
    924     if (_TCAM_STATE_VENT(u, zid, pfx) == 0) {
    925         _TCAM_STATE_START(u, zid, pfx) = to_ent;
    926         _TCAM_STATE_END(u, zid, pfx) = to_ent - 1;
    927         return BCM_E_NONE;
    928     }
    929 
    930     pkm = _tcam_zone_db_type_to_pkm(u, _TCAMZ_DB_TYPE(u, zid));
    931     if (pkm != ALPM_PKM_128) {
    932         pkm = _PFX_IS_PKM_64B(u, zid, pfx);
    933     }
    934 
    935     if (pkm == ALPM_PKM_32B &&
    936         _TCAM_STATE_END(u, zid, pfx) != _TCAM_STATE_START(u, zid, pfx)) {
    937 
    938         from_ent = _TCAM_STATE_END(u, zid, pfx);
    939 
    940         ALPM_IER(tcam_entry_read(u, pkm, e, from_ent, from_ent));
    941         v0 = tcam_entry_valid(u, pkm, e, 0);
    942         v1 = tcam_entry_valid(u, pkm, e, 1);
    943 
    944         if ((v0 == 0) || (v1 == 0)) {
    945             /* Last entry is half full -> keep it last. */
    946             /* Shift entry before last to start - 1 position. */
    947             prev_ent = from_ent - 1;
    948             ALPM_IER(_tcam_entry_shift(u, pkm, prev_ent, to_ent));
    949 
    950             _tcam_trie_update_by_ent(u, pkm, e, prev_ent);
    951             ALPM_IER(_tcam_entry_write(u, pkm, e, prev_ent, from_ent));
    952         } else {
    953             /* Last entry is full -> just shift it to start - 1  position. */
    954             _tcam_trie_update_by_ent(u, pkm, e, to_ent);
    955             ALPM_IER(_tcam_entry_write(u, pkm, e, to_ent, from_ent));
    956         }
    957 
    958     } else  {
    959         from_ent = _TCAM_STATE_END(u, zid, pfx);
    960         ALPM_IER(_tcam_entry_shift(u, pkm, from_ent, to_ent));
    961     }
    962     _TCAM_STATE_START(u, zid, pfx) -= 1;
    963     _TCAM_STATE_END(u, zid, pfx) -= 1;
    964 
    965     return rv;
    966 }
    967 
    968 /*
    969  *      Create a slot for the new entry rippling the entries if required
    970  *      returned update=1 if half-free entry, update=0 if full-free entry.
    971  */
    972 static int
    973 _tcam_free_slot_create(int u, int pkm, int zid, int pfx, int *free_slot, int *update)
    974 {
    975     uint32      e[SOC_MAX_MEM_FIELD_WORDS];
    976     int         prev_pfx;
    977     int         next_pfx;
    978     int         free_pfx;
    979     int         curr_pfx;
    980     int         from_ent;
    981     uint32      v0, v1;
    982 
    983     if (_TCAM_STATE_VENT(u, zid, pfx) == 0) {
    984         /*
    985          * Find the  prefix position. Only prefix with valid
    986          * entries are in the list.
    987          * next -> high to low prefix. low to high index
    988          * prev -> low to high prefix. high to low index
    989          * Unused prefix length _PFX_MAX_INDEX is the head of the
    990          * list and is node corresponding to this is always
    991          * present.
    992          */
    993         curr_pfx = _TCAMZ_PFX_MAX_IDX(u, zid);
    994         while (_TCAM_STATE_NEXT(u, zid, curr_pfx) > pfx) {
    995             curr_pfx = _TCAM_STATE_NEXT(u, zid, curr_pfx);
    996         }
    997         /* Insert the new prefix */
    998         next_pfx = _TCAM_STATE_NEXT(u, zid, curr_pfx);
    999         if (next_pfx != -1) {
   1000             _TCAM_STATE_PREV(u, zid, next_pfx) = pfx;
   1001         }
   1002         _TCAM_STATE_NEXT(u, zid, pfx) = _TCAM_STATE_NEXT(u, zid, curr_pfx);
   1003         _TCAM_STATE_PREV(u, zid, pfx) = curr_pfx;
   1004         _TCAM_STATE_NEXT(u, zid, curr_pfx) = pfx;
   1005 
   1006         _TCAM_STATE_FENT(u, zid, pfx) =
   1007             (_TCAM_STATE_FENT(u, zid, curr_pfx) + 1) / 2;
   1008         _TCAM_STATE_FENT(u, zid, curr_pfx) -= _TCAM_STATE_FENT(u, zid, pfx);
   1009         _TCAM_STATE_START(u, zid, pfx) = _TCAM_STATE_END(u, zid, curr_pfx) +
   1010                                     _TCAM_STATE_FENT(u, zid, curr_pfx) + 1;
   1011         _TCAM_STATE_END(u, zid, pfx) = _TCAM_STATE_START(u, zid, pfx) - 1;
   1012         _TCAM_STATE_VENT(u, zid, pfx) = 0;
   1013     } else if (pkm == ALPM_PKM_32B) {
   1014         /* For IPv4 Check if alternate entry is free */
   1015         from_ent = _TCAM_STATE_START(u, zid, pfx);
   1016         ALPM_IER(tcam_entry_read(u, pkm, e, from_ent, from_ent));
   1017         v0 = tcam_entry_valid(u, pkm, e, 0);
   1018         v1 = tcam_entry_valid(u, pkm, e, 1);
   1019 
   1020         if ((v0 == 0) || (v1 == 0)) {
   1021             *free_slot = (from_ent << 1) + ((v1 == 0) ? 1 : 0);
   1022             *update = 1; /* half-free entry */
   1023             return BCM_E_NONE;
   1024         }
   1025 
   1026         from_ent = _TCAM_STATE_END(u, zid, pfx);
   1027         ALPM_IER(tcam_entry_read(u, pkm, e, from_ent, from_ent));
   1028         v0 = tcam_entry_valid(u, pkm, e, 0);
   1029         v1 = tcam_entry_valid(u, pkm, e, 1);
   1030 
   1031         if ((v0 == 0) || (v1 == 0)) {
   1032             *free_slot = (from_ent << 1) + ((v1 == 0) ? 1 : 0);
   1033             *update = 1; /* half-free entry */
   1034             return BCM_E_NONE;
   1035         }
   1036     }
   1037 
   1038     free_pfx = pfx;
   1039     while (_TCAM_STATE_FENT(u, zid, free_pfx) == 0) {
   1040         /* pkm <= ALPM_PKM_64B: starting from higher index.
   1041          * else starting from lower index
   1042          */
   1043         free_pfx = _TCAM_STATE_NEXT(u, zid, free_pfx);
   1044         if (free_pfx == -1) {
   1045             /* No free entries on this side try the other side */
   1046             free_pfx = pfx;
   1047             break;
   1048         }
   1049     }
   1050 
   1051     while (_TCAM_STATE_FENT(u, zid, free_pfx) == 0) {
   1052         free_pfx = _TCAM_STATE_PREV(u, zid, free_pfx);
   1053         if (free_pfx == -1) {
   1054             if (_TCAM_STATE_VENT(u, zid, pfx) == 0) {
   1055                 /* We failed to allocate entries for a newly allocated prefix.*/
   1056                 prev_pfx = _TCAM_STATE_PREV(u, zid, pfx);
   1057                 next_pfx = _TCAM_STATE_NEXT(u, zid, pfx);
   1058                 if (-1 != prev_pfx) {
   1059                     _TCAM_STATE_NEXT(u, zid, prev_pfx) = next_pfx;
   1060                 }
   1061                 if (-1 != next_pfx) {
   1062                     _TCAM_STATE_PREV(u, zid, next_pfx) = prev_pfx;
   1063                 }
   1064             }
   1065             return BCM_E_FULL;
   1066         }
   1067     }
   1068 
   1069     /*
   1070      * Ripple entries to create free space
   1071      */
   1072     while (free_pfx > pfx) {
   1073         next_pfx = _TCAM_STATE_NEXT(u, zid, free_pfx);
   1074         ALPM_IER(_tcam_shift_pfx_down(u, next_pfx, zid));
   1075         _TCAM_STATE_FENT(u, zid, free_pfx) -= 1;
   1076         _TCAM_STATE_FENT(u, zid, next_pfx) += 1;
   1077         free_pfx = next_pfx;
   1078     }
   1079 
   1080     while (free_pfx < pfx) {
   1081         ALPM_IER(_tcam_shift_pfx_up(u, free_pfx, zid));
   1082         _TCAM_STATE_FENT(u, zid, free_pfx) -= 1;
   1083         prev_pfx = _TCAM_STATE_PREV(u, zid, free_pfx);
   1084         _TCAM_STATE_FENT(u, zid, prev_pfx) += 1;
   1085         free_pfx = prev_pfx;
   1086     }
   1087 
   1088     _TCAM_STATE_VENT(u, zid, pfx) += 1;
   1089     _TCAM_STATE_FENT(u, zid, pfx) -= 1;
   1090     _TCAM_STATE_END(u, zid, pfx) += 1;
   1091 
   1092     *free_slot = _TCAM_STATE_END(u, zid, pfx) << ((pkm) ? 0 : 1);
   1093     *update = 0; /* full-free entry */
   1094 
   1095     return BCM_E_NONE;
   1096 }
   1097 
   1098 /*
   1099  * Delete a slot and adjust entry pointers if required.
   1100  */
   1101 static int
   1102 _tcam_free_slot_delete(int u, int pkm, int zid, int pfx, int slot)
   1103 {
   1104     int         prev_pfx, next_pfx;
   1105     int         fidx, tidx;
   1106     uint32      ef[SOC_MAX_MEM_FIELD_WORDS];
   1107     uint32      e[SOC_MAX_MEM_FIELD_WORDS];
   1108     void        *et;
   1109     int         rv = BCM_E_NONE;
   1110 
   1111     fidx    = _TCAM_STATE_END(u, zid, pfx);
   1112     tidx    = slot;
   1113 
   1114     if (pkm == ALPM_PKM_32B) {
   1115         tidx >>= 1;
   1116         ALPM_IER(tcam_entry_read(u, pkm, ef, fidx, fidx));
   1117         if (fidx != tidx) {
   1118             ALPM_IER(tcam_entry_read(u, pkm, e, tidx, tidx));
   1119             et = e;
   1120         } else {
   1121             et = ef;
   1122         }
   1123 
   1124         if (tcam_entry_valid(u, pkm, ef, 1)) {
   1125             rv = _tcam_entry_x_to_y(u, pkm, ef, et, TRUE, 1, slot & 1);
   1126             (void)_tcam_entry_valid_set(u, pkm, ef, 1, 0);
   1127         } else {
   1128             rv = _tcam_entry_x_to_y(u, pkm, ef, et, TRUE, 0, slot & 1);
   1129             (void)_tcam_entry_valid_set(u, pkm, ef, 0, 0);
   1130             _TCAM_STATE_VENT(u, zid, pfx) -= 1;
   1131             _TCAM_STATE_FENT(u, zid, pfx) += 1;
   1132             _TCAM_STATE_END(u, zid, pfx) -= 1;
   1133         }
   1134 
   1135         /* not true for OVERRIDE routes */
   1136         if (tidx != fidx) {
   1137             ALPM_IER(_tcam_trie_update_by_ent(u, pkm, et, tidx));
   1138             ALPM_IER(_tcam_entry_write(u, pkm, et, tidx, tidx));
   1139         }
   1140         ALPM_IER(_tcam_trie_update_by_ent(u, pkm, ef, fidx));
   1141         ALPM_IER(_tcam_entry_write(u, pkm, ef, fidx, fidx));
   1142     } else { /* IPV6 */
   1143         _TCAM_STATE_VENT(u, zid, pfx) -= 1;
   1144         _TCAM_STATE_FENT(u, zid, pfx) += 1;
   1145         _TCAM_STATE_END(u, zid, pfx)  -= 1;
   1146         if (tidx != fidx) {
   1147             ALPM_IER(tcam_entry_read(u, pkm, ef, fidx, fidx));
   1148             ALPM_IER(_tcam_trie_update_by_ent(u, pkm, ef, tidx));
   1149             ALPM_IER(_tcam_entry_write(u, pkm, ef, tidx, fidx));
   1150         }
   1151         /* v6-64 indices are still raw in pivot tcam */
   1152         sal_memset(ef, 0, sizeof(ef));
   1153         ALPM_IER(_tcam_entry_write(u, pkm, ef, fidx, fidx));
   1154     }
   1155 
   1156     if (_TCAM_STATE_VENT(u, zid, pfx) == 0) {
   1157         /* remove from the list */
   1158         prev_pfx = _TCAM_STATE_PREV(u, zid, pfx); /* Always present */
   1159         assert(prev_pfx != -1);
   1160         next_pfx = _TCAM_STATE_NEXT(u, zid, pfx);
   1161         _TCAM_STATE_NEXT(u, zid, prev_pfx) = next_pfx;
   1162         _TCAM_STATE_FENT(u, zid, prev_pfx) += _TCAM_STATE_FENT(u, zid, pfx);
   1163         _TCAM_STATE_FENT(u, zid, pfx) = 0;
   1164         if (next_pfx != -1) {
   1165             _TCAM_STATE_PREV(u, zid, next_pfx) = prev_pfx;
   1166         }
   1167         _TCAM_STATE_NEXT(u, zid, pfx) = -1;
   1168         _TCAM_STATE_PREV(u, zid, pfx) = -1;
   1169         _TCAM_STATE_START(u, zid, pfx) = -1;
   1170         _TCAM_STATE_END(u, zid, pfx) = -1;
   1171     }
   1172 
   1173     return rv;
   1174 }
   1175 
   1176 /*
   1177  * Extract vrf weighted prefix lenght from vrf_id, pkm, key_len.
   1178  */
   1179 static void
   1180 tcam_pfx_len_get(int u, int ipv6, int zid, int inst_id, int key_len, int *pfx_len)
   1181 {
   1182     int ipv6_min;
   1183 
   1184     ipv6_min = _TCAMZ_PFX_MIN_V6(u, zid);
   1185 
   1186     if (ipv6) {
   1187         key_len += ipv6_min;
   1188     }
   1189 
   1190     /* In ALPM the arragnement of VRF is at he begining followed by VRF
   1191        override and global */
   1192     *pfx_len = key_len + inst_id * _TCAMZ_PFX_ENT_PER_INST(u, zid);
   1193     return;
   1194 }
   1195 
   1196 static void
   1197 _tcam_gpfx_len_get(
   1198     int u, int defip_vrf, int ipv6, int zid,
   1199     _bcm_defip_cfg_t *lpm_cfg, int *pfx_len)
   1200 {
   1201     int inst_id;
   1202 
   1203     /* Calculate vrf weighted prefix lengh. */
   1204     inst_id = _tcam_zone_inst_id_get(u, defip_vrf, lpm_cfg->defip_flags & BCM_L3_IPMC);
   1205     tcam_pfx_len_get(u, ipv6, zid, inst_id, lpm_cfg->defip_sub_len, pfx_len);
   1206 
   1207     return;
   1208 }
   1209 
   1210 static int
   1211 _tcam_cfg_write(int u, _bcm_defip_cfg_t *lpm_cfg, int index, int s_index,
   1212                 int update, uint32 write_flags)
   1213 {
   1214     int         rv = BCM_E_NONE;
   1215     int         hw_idx;
   1216     int         pkm = ALPM_LPM_PKM(u, lpm_cfg);
   1217     uint32      e[SOC_MAX_MEM_FIELD_WORDS];
   1218     _alpm_tcam_write_t *tcam_write = lpm_cfg->tcam_write;
   1219 
   1220     hw_idx = (pkm == ALPM_PKM_32B) ? index >> 1 : index;
   1221 
   1222     /* Entry already present. Update the entry */
   1223     if (pkm == ALPM_PKM_32B) {
   1224         if (update) {
   1225             ALPM_IER(tcam_entry_read(u, pkm, e, hw_idx, s_index));
   1226         } else {
   1227             sal_memset(e, 0, sizeof(e));
   1228         }
   1229         /* Need to clear entry if both entry0 & 1 are invalid? */
   1230         rv = _tcam_entry_from_cfg(u, pkm, lpm_cfg, e, index & 1, write_flags);
   1231     } else {
   1232         sal_memset(e, 0, sizeof(e));
   1233         rv = _tcam_entry_from_cfg(u, pkm, lpm_cfg, e, 0, write_flags);
   1234     }
   1235 
   1236     if (BCM_SUCCESS(rv)) {
   1237         if (tcam_write != NULL) { /* case new L1 pvt add during L2 bkt split */
   1238             tcam_write->hw_idx = hw_idx;
   1239             sal_memcpy(tcam_write->ent, e, sizeof(e));
   1240         } else {
   1241             rv = _tcam_entry_write(u, pkm, e, hw_idx, s_index);
   1242         }
   1243     }
   1244 
   1245     return rv;
   1246 }
   1247 
   1248 /*
   1249  * _tcam_cfg_match (Exact match for the key. Will match both IP address
   1250  * and mask)
   1251  *
   1252  * OUT index_ptr: return key location
   1253  * OUT pfx_len: Key prefix length. vrf+32+pfx len for single wide(64b)
   1254  */
   1255 static int
   1256 _tcam_cfg_match(int u, _bcm_defip_cfg_t *lpm_cfg, int *index_ptr)
   1257 {
   1258     int         key_index = 0;
   1259     int         rv = BCM_E_NONE;
   1260 
   1261     if (_tcam_trie_lookup(u, lpm_cfg, &key_index) == BCM_E_NONE) {
   1262         *index_ptr = key_index;
   1263     } else {
   1264         rv = BCM_E_NOT_FOUND;
   1265     }
   1266 
   1267     return rv;
   1268 }
   1269 
   1270 static int
   1271 _tcam_cfg_insert(int u, int zid, _bcm_defip_cfg_t *lpm_cfg, uint32 write_flags)
   1272 {
   1273     int rv;
   1274     int index, pfx, pkm, update = 0; /* for 32B only */
   1275 
   1276     pkm = ALPM_LPM_PKM(u, lpm_cfg);
   1277     _tcam_gpfx_len_get(u, lpm_cfg->defip_vrf, !!pkm, zid, lpm_cfg, &pfx);
   1278     rv = _tcam_free_slot_create(u, pkm, zid, pfx, &index, &update);
   1279     if (BCM_SUCCESS(rv)) {
   1280         lpm_cfg->defip_index = index;
   1281         rv = _tcam_cfg_write(u, lpm_cfg, index, index, update, write_flags);
   1282     }
   1283 
   1284     return rv;
   1285 }
   1286 
   1287 int
   1288 bcm_esw_alpm_tcam_avail(int u, int vrf_id, int ipt, int key_len, int mc)
   1289 {
   1290     int pfx, zid, fent, cnt = 0;
   1291 
   1292     if (!TCAMC(u)) {
   1293         return 0;
   1294     }
   1295 
   1296     zid = _tcam_zone_zid_get(u, ALPM_VRF_ID_TO_VRF(u, vrf_id), ipt, ALPM_128B(u), mc);
   1297     pfx = _TCAMZ_PFX_MAX_IDX(u, zid);
   1298     while (pfx >= 0) {
   1299         fent = _TCAM_STATE_FENT(u, zid, pfx);
   1300         if (fent > 0) {
   1301             cnt += fent;
   1302         }
   1303         pfx = _TCAM_STATE_NEXT(u, zid, pfx);
   1304     }
   1305 
   1306     return cnt;
   1307 }
   1308 
   1309 int
   1310 bcm_esw_alpm_tcam_state_free_get(int u, int zn, int *free_cnt, int *used_cnt)
   1311 {
   1312     int i, zn_min, zn_max;
   1313     int fcnt = 0, vcnt = 0;
   1314 
   1315     if (!TCAMC(u)) {
   1316         return BCM_E_NONE;
   1317     }
   1318 
   1319     if (zn < 0 || zn >= _TCAM_ZONE_CNT) {
   1320         zn_min = 0;
   1321         zn_max = _TCAM_ZONE_CNT - 1;
   1322     } else {
   1323         zn_min = zn_max = zn;
   1324     }
   1325 
   1326     for (i = zn_min; i <= zn_max; i++) {
   1327         int zid;
   1328         _tcam_zone_st_t tz_st;
   1329 
   1330         zid = _TCAMZ_ZID_MAKE_FROM_ZN(0, ALPM_128B(u), ALPM_TCAM_ZONED(u), i);
   1331         if (!_TCAMZ_INITED(u, zid)) {
   1332             continue;
   1333         }
   1334         _tcam_zone_status(u, zid, &tz_st);
   1335 
   1336         fcnt += tz_st.cnt_free;
   1337         vcnt += tz_st.cnt_used;
   1338     }
   1339 
   1340     if (free_cnt) {
   1341         *free_cnt = fcnt;
   1342     }
   1343     if (used_cnt) {
   1344         *used_cnt = vcnt;
   1345     }
   1346 
   1347     return BCM_E_NONE;
   1348 }
   1349 
   1350 void
   1351 bcm_esw_alpm_tcam_zone_state_dump(int u)
   1352 {
   1353     int i, zn;
   1354     int max_pfx_len;
   1355 
   1356     for (zn = 0; zn < _TCAM_ZONE_CNT; zn++) {
   1357         int zid;
   1358 
   1359         if (tz_conf[!!ALPM_TCAM_ZONED(u) << 1 | !!ALPM_128B(u)][zn] == tZoneInvalid) {
   1360             continue;
   1361         }
   1362 
   1363         zid = _TCAMZ_ZID_MAKE_FROM_ZN(0, ALPM_128B(u), ALPM_TCAM_ZONED(u), zn);
   1364         if (!_TCAMZ_INITED(u, zid)) {
   1365             continue;
   1366         }
   1367 
   1368         cli_out("Zone %d (%s) :\n", zn, _tz_db_str[_TCAMZ_DB_TYPE(u, zid)]);
   1369         max_pfx_len = _TCAMZ_PFX_MAX_IDX(u, zid);
   1370         for (i = max_pfx_len; i >= 0 ; i--) {
   1371             if ((i != _TCAMZ_PFX_MAX_IDX(u, zid)) &&
   1372                 _TCAM_STATE_START(u, zid, i) == -1 &&
   1373                 _TCAM_STATE_FENT(u, zid, i) == 0) {
   1374                 continue;
   1375             }
   1376 
   1377             cli_out("\tPFX = %3d P = %3d N = %3d START = %5d END = %5d "
   1378                     "VENT = %5d FENT = %5d\n", i,
   1379                     _TCAM_STATE_PREV(u, zid, i),
   1380                     _TCAM_STATE_NEXT(u, zid, i),
   1381                     _TCAM_STATE_START(u, zid, i),
   1382                     _TCAM_STATE_END(u, zid, i),
   1383                     _TCAM_STATE_VENT(u, zid, i),
   1384                     _TCAM_STATE_FENT(u, zid, i));
   1385         }
   1386         cli_out("\n");
   1387     }
   1388 }
   1389 
   1390 void
   1391 bcm_esw_alpm_tcam_zone_dump(int u, char *pfx_str)
   1392 {
   1393     int zn;
   1394     int free_tcam = 0, used_tcam = 0, tot_tcam;
   1395 
   1396     for (zn = 0; zn < _TCAM_ZONE_CNT; zn++) {
   1397         int zid;
   1398 
   1399         if (tz_conf[!!ALPM_TCAM_ZONED(u) << 1 | !!ALPM_128B(u)][zn] == tZoneInvalid) {
   1400             continue;
   1401         }
   1402 
   1403         zid = _TCAMZ_ZID_MAKE_FROM_ZN(0, ALPM_128B(u), ALPM_TCAM_ZONED(u), zn);
   1404         if (!_TCAMZ_INITED(u, zid)) {
   1405             continue;
   1406         }
   1407 
   1408         (void)bcm_esw_alpm_tcam_state_free_get(u, zn, &free_tcam, &used_tcam);
   1409         tot_tcam = used_tcam + free_tcam;
   1410         if (tot_tcam == 0) {
   1411             tot_tcam = 1; /* avoid divide by 0 */
   1412         }
   1413         cli_out("%sTCAM zone %d(%s): %4d (used), %4d (free), Usage: %d.%d%%\n",
   1414                 pfx_str, zn, _tz_db_str[_TCAMZ_DB_TYPE(u, zid)],
   1415                 used_tcam, free_tcam,
   1416                 used_tcam * 100 / tot_tcam,
   1417                 (used_tcam * 1000 / tot_tcam) % 10);
   1418     }
   1419 
   1420     return ;
   1421 }
   1422 
   1423 /*
   1424  * De-initialize the start/end tracking pointers for each prefix length
   1425  */
   1426 int
   1427 bcm_esw_alpm_tcam_deinit(int u)
   1428 {
   1429     int i, zid;
   1430 
   1431     if (!soc_feature(u, soc_feature_lpm_tcam)) {
   1432         return BCM_E_UNAVAIL;
   1433     }
   1434 
   1435     for (zid = 0; zid < _TCAM_ZID_CNT; zid++) {
   1436         if (_TCAMZ_INITED(u, zid) &&
   1437             _TCAM_STATE(u, zid) != NULL) {
   1438             alpm_util_free(_TCAM_STATE(u, zid));
   1439             _TCAM_STATE(u, zid) = NULL;
   1440         }
   1441     }
   1442 
   1443     for (i = 0; i < _TCAM_ZID_CNT; i++) {
   1444         _TCAMZ(u, i) = NULL;
   1445     }
   1446 
   1447     if (_TCAM_INIT_CHECK(u)) {
   1448         alpm_util_free(TCAMC(u));
   1449         TCAMC(u) = NULL;
   1450     }
   1451 
   1452     return BCM_E_NONE;
   1453 }
   1454 
   1455 /*
   1456  * Initialize the start/end tracking pointers for each prefix length
   1457  */
   1458 int
   1459 bcm_esw_alpm_tcam_init(int u)
   1460 {
   1461     int rv = BCM_E_NONE;
   1462 
   1463     if (!soc_feature(u, soc_feature_lpm_tcam)) {
   1464         return BCM_E_UNAVAIL;
   1465     }
   1466 
   1467     if (_TCAM_INIT_CHECK(u)) {
   1468         /* this is a reinit. clean up old state */
   1469         if (bcm_esw_alpm_tcam_deinit(u) < 0) {
   1470             return BCM_E_UNAVAIL;
   1471         }
   1472     }
   1473 
   1474     ALPM_ALLOC_EG(TCAMC(u), sizeof(_tcam_ctrl_t), "TCAMC");
   1475     ALPM_IEG(_tcam_zone_init(u));
   1476 
   1477     return rv;
   1478 
   1479 bad:
   1480     (void)bcm_esw_alpm_tcam_deinit(u);
   1481     return rv;
   1482 }
   1483 
   1484 /*
   1485  * ALPM TCAM cleanup
   1486  */
   1487 int
   1488 bcm_esw_alpm_tcam_cleanup(int u)
   1489 {
   1490     int rv = BCM_E_NONE;
   1491 
   1492     if (!soc_feature(u, soc_feature_lpm_tcam)) {
   1493         return BCM_E_UNAVAIL;
   1494     }
   1495 
   1496     ALPM_REALLOC_EG(TCAMC(u), sizeof(_tcam_ctrl_t), "TCAMC");
   1497     ALPM_IEG(_tcam_zone_init(u));
   1498 
   1499 bad:
   1500     return rv;
   1501 }
   1502 
   1503 /*
   1504  * Implementation using _mem_read/write using entry rippling technique
   1505  * Advantage: A completely sorted table is not required. Lookups can be slow
   1506  * as it will perform a linear search on the entries for a given prefix length.
   1507  * No device access necessary for the search if the table is cached. Auxiliary
   1508  * Small number of entries need to be moved around (97 worst case)
   1509  * for performing insert/update/delete. However CPU needs to do all
   1510  * the work to move the entries.
   1511  */
   1512 
   1513 /*
   1514  * bcm_esw_alpm_tcam_insert
   1515  * For IPV4 assume only both IP_ADDR0 is valid
   1516  * Moving multiple entries around in h/w vs  doing a linear search in s/w
   1517  */
   1518 int
   1519 bcm_esw_alpm_tcam_insert(int u, _bcm_defip_cfg_t *lpm_cfg, uint32 write_flags)
   1520 {
   1521     int         index;
   1522     int         rv = BCM_E_NONE;
   1523 
   1524     rv = _tcam_cfg_match(u, lpm_cfg, &index);
   1525     if (rv == BCM_E_NOT_FOUND) {
   1526         int zid;
   1527         zid = _tcam_zone_zid_get(u, lpm_cfg->defip_vrf,
   1528                                  ALPM_LPM_IPT(u, lpm_cfg), ALPM_128B(u),
   1529                                  lpm_cfg->defip_flags & BCM_L3_IPMC);
   1530         rv = _tcam_cfg_insert(u, zid, lpm_cfg, write_flags);
   1531     } else if (rv == BCM_E_NONE) {
   1532         /* Found */
   1533         rv = _tcam_cfg_write(u, lpm_cfg, index, index, 1, write_flags);
   1534     }
   1535 
   1536     return rv;
   1537 }
   1538 
   1539 /*
   1540  * bcm_esw_alpm_tcam_delete
   1541  */
   1542 int
   1543 bcm_esw_alpm_tcam_delete(int u, _bcm_defip_cfg_t *lpm_cfg)
   1544 {
   1545     int         index, ipt;
   1546     int         rv = BCM_E_NONE;
   1547 
   1548     rv = _tcam_cfg_match(u, lpm_cfg, &index);
   1549     if (rv == BCM_E_NONE) {
   1550         int zid, pkm, pfx, defip_vrf;
   1551         defip_vrf = lpm_cfg->defip_vrf;
   1552 
   1553         pkm = ALPM_LPM_PKM(u, lpm_cfg);
   1554         ipt = ALPM_PKM2IPT(pkm);
   1555         zid = _tcam_zone_zid_get(u, defip_vrf, ipt, ALPM_128B(u),
   1556                                  lpm_cfg->defip_flags & BCM_L3_IPMC);
   1557         lpm_cfg->defip_index = index;
   1558         _tcam_gpfx_len_get(u, defip_vrf, ipt, zid, lpm_cfg, &pfx);
   1559         rv = _tcam_free_slot_delete(u, pkm, zid, pfx, index);
   1560     }
   1561 
   1562     if (BCM_SUCCESS(rv)) {
   1563         ; /* VRF_PIVOT_REF_DEC(u, vrf_id, vrf, pkm); */
   1564     }
   1565 
   1566     return(rv);
   1567 }
   1568 
   1569 /*
   1570  * bcm_esw_alpm_tcam_match
   1571  * (Exact match for the key. Will match both IP address and mask)
   1572  */
   1573 int
   1574 bcm_esw_alpm_tcam_match(int u, _bcm_defip_cfg_t *lpm_cfg, int *index_ptr)
   1575 {
   1576     int     rv;
   1577     int     hw_idx;
   1578     int     pkm = ALPM_LPM_PKM(u, lpm_cfg);
   1579     uint32  e[SOC_MAX_MEM_FIELD_WORDS];
   1580 
   1581     rv = _tcam_cfg_match(u, lpm_cfg, index_ptr);
   1582     if (BCM_SUCCESS(rv)) {
   1583         /*
   1584          * If entry is ipv4 copy to the "zero" half of the,
   1585          * buffer, "zero" half of lpm_entry if the  original entry
   1586          * is in the "one" half.
   1587          */
   1588         hw_idx = *index_ptr;
   1589         if (pkm == ALPM_PKM_32B) {
   1590             hw_idx >>= 1;
   1591         }
   1592 
   1593         ALPM_IER(tcam_entry_read(u, pkm, e, hw_idx, hw_idx));
   1594 
   1595         if (pkm == ALPM_PKM_32B) {
   1596             rv = tcam_entry_to_cfg(u, pkm, e, (*index_ptr & 0x1), lpm_cfg);
   1597         } else {
   1598             rv = tcam_entry_to_cfg(u, pkm, e, 0, lpm_cfg);
   1599         }
   1600     }
   1601     return rv;
   1602 }
   1603 
   1604 /* ********************* *
   1605  * TCAM warmboot support *
   1606  */
   1607 
   1608 /*
   1609  * Function:
   1610  *      tcam_wb_reinit_done
   1611  * Purpose:
   1612  *      Update all TCAM state once entry reinit done from warmboot.
   1613  * Parameters:
   1614  *      u        - (IN)Device unit number.
   1615  * Returns:
   1616  *      BCM_E_XXX
   1617  */
   1618 int
   1619 tcam_wb_reinit_done(int u)
   1620 {
   1621     int idx;
   1622     int prev_idx;
   1623     int defip_table_size;
   1624     int zn;
   1625 
   1626     for (zn = 0; zn < _TCAM_ZONE_CNT; zn++) {
   1627         int zid, pkm;
   1628 
   1629         zid = _TCAMZ_ZID_MAKE_FROM_ZN(0, ALPM_128B(u), ALPM_TCAM_ZONED(u), zn);
   1630 
   1631         if (!_TCAMZ_INITED(u, zid)) {
   1632             continue;
   1633         }
   1634 
   1635         prev_idx = _TCAMZ_PFX_MAX_IDX(u, zid);
   1636         pkm = _tcam_zone_db_type_to_pkm(u, _TCAMZ_DB_TYPE(u, zid));
   1637         defip_table_size = tcam_table_size(u, pkm);
   1638 
   1639         if (ALPM_MODE_CHK(u, BCM_ALPM_MODE_COMBINED)) {
   1640             /* Combined search mode */
   1641             _TCAM_STATE_PREV(u, zid, _TCAMZ_PFX_MAX_IDX(u, zid)) = -1;
   1642 
   1643             for (idx = _TCAMZ_PFX_MAX_IDX(u, zid); idx > -1; idx--) {
   1644                 if (_TCAM_STATE_START(u, zid, idx) == -1) {
   1645                     continue;
   1646                 }
   1647 
   1648                 _TCAM_STATE_PREV(u, zid, idx) = prev_idx;
   1649                 _TCAM_STATE_NEXT(u, zid, prev_idx) = idx;
   1650 
   1651                 _TCAM_STATE_FENT(u, zid, prev_idx) =                   \
   1652                                  _TCAM_STATE_START(u, zid, idx) -      \
   1653                                  _TCAM_STATE_END(u, zid, prev_idx) - 1;
   1654                 prev_idx = idx;
   1655 
   1656             }
   1657 
   1658             _TCAM_STATE_NEXT(u, zid, prev_idx) = -1;
   1659             _TCAM_STATE_FENT(u, zid, prev_idx) =                       \
   1660                              defip_table_size -                       \
   1661                              _TCAM_STATE_END(u, zid, prev_idx) - 1;
   1662         } else {
   1663             int tab_idx_max = 0;
   1664             /* Parallel search mode
   1665              *
   1666              *    Configured VRF Range
   1667              *    {0 - (ALPM_MAX_PFX_INDEX/3)}
   1668              *    Global VRF Range
   1669              *    {((ALPM_MAX_PFX_INDEX/1) + 1) - (ALPM_MAX_PFX_INDEX/2) }
   1670              *    Override VRF Range
   1671              *    {((ALPM_MAX_PFX_INDEX/2) + 1) - (ALPM_MAX_PFX_INDEX) }
   1672              */
   1673 
   1674             /*
   1675              * Global and Overide VRF range are treated as single block and
   1676              * both blocks will be linked
   1677              */
   1678             _TCAM_STATE_PREV(u, zid, _TCAMZ_PFX_MAX_IDX(u, zid)) = -1;
   1679             for (idx = _TCAMZ_PFX_MAX_IDX(u, zid); idx > -1; idx--) {
   1680                 if (-1 == _TCAM_STATE_START(u, zid, idx)) {
   1681                     continue;
   1682                 }
   1683 
   1684                 _TCAM_STATE_PREV(u, zid, idx) = prev_idx;
   1685                 _TCAM_STATE_NEXT(u, zid, prev_idx) = idx;
   1686 
   1687                 _TCAM_STATE_FENT(u, zid, prev_idx) =                    \
   1688                                  _TCAM_STATE_START(u, zid, idx) -       \
   1689                                  _TCAM_STATE_END(u, zid, prev_idx) - 1;
   1690 
   1691                 prev_idx = idx;
   1692             }
   1693             /*
   1694              * _TCAM_ZONE_CNT:
   1695              *    bit1 : 0 Glb, 1 Prv
   1696              *    bit0 : 0 V4,  1 V6
   1697              */
   1698             if (zn & 0x2) {
   1699                 tab_idx_max = defip_table_size / 2;
   1700             } else {
   1701                 tab_idx_max = defip_table_size;
   1702             }
   1703 
   1704             _TCAM_STATE_NEXT(u, zid, prev_idx) = -1;
   1705             _TCAM_STATE_FENT(u, zid, prev_idx) =
   1706                 tab_idx_max - _TCAM_STATE_END(u, zid, prev_idx) - 1;
   1707         }
   1708 
   1709     } /* for zn */
   1710 
   1711     return (BCM_E_NONE);
   1712 }
   1713 
   1714 /*
   1715  * Function:
   1716  *      tcam_wb_reinit
   1717  * Purpose:
   1718  *      TCAM entry state reinit from warmboot.
   1719  * Parameters:
   1720  *      u        - (IN)Device unit number.
   1721  *      pkm      - (In)Packing mode (32B, 64B, 128)
   1722  *      vrf_id   - (In)VRF ID
   1723  *      idx      - (In)Memory Index
   1724  *      key_len  - (In)Key prefix length
   1725  * Returns:
   1726  *      BCM_E_XXX
   1727  */
   1728 int
   1729 tcam_wb_reinit(int u, int vrf_id, int pkm, int idx, int key_len, int mc)
   1730 {
   1731     int zid, inst_id;
   1732     int pfx_len, ipt;
   1733 
   1734     ipt = ALPM_PKM2IPT(pkm);
   1735     zid = _tcam_zone_zid_get(u, ALPM_VRF_ID_TO_VRF(u, vrf_id), ipt, ALPM_128B(u), mc);
   1736     inst_id = _tcam_zone_inst_id_get(u, ALPM_VRF_ID_TO_VRF(u, vrf_id), mc);
   1737 
   1738     tcam_pfx_len_get(u, pkm, zid, inst_id, key_len, &pfx_len);
   1739 
   1740     if (_TCAM_STATE_VENT(u, zid, pfx_len) == 0) {
   1741         _TCAM_STATE_START(u, zid, pfx_len) = idx;
   1742         _TCAM_STATE_END(u, zid, pfx_len) = idx;
   1743     } else {
   1744         _TCAM_STATE_END(u, zid, pfx_len) = idx;
   1745     }
   1746 
   1747     _TCAM_STATE_VENT(u, zid, pfx_len)++;
   1748 
   1749     return (BCM_E_NONE);
   1750 }
   1751 
   1752 #endif /* ALPM_ENABLE */
   1753