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

field_grp.c (362384B)


      1  /*
      2   * 
      3   *
      4   *
      5   * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      6   * 
      7   * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      8   *
      9   * File:       field_grp.c
     10   * Purpose:    BCM56960 Field Processor Group management functions.
     11   */
     12 
     13 #include <soc/defs.h>
     14 #if defined(BCM_TOMAHAWK_SUPPORT) && defined(BCM_FIELD_SUPPORT)
     15 #include <shared/bsl.h>
     16 #include <soc/mem.h>
     17 #include <soc/drv.h>
     18 #include <soc/tomahawk.h>
     19 #include <bcm_int/esw/tomahawk.h>
     20 #include <bcm_int/esw/helix5.h>
     21 #include <bcm_int/esw/tomahawk3.h>
     22 #include <bcm/field.h>
     23 #include <bcm_int/esw/field.h>
     24 #include <bcm_int/esw/udf.h>
     25 
     26 #if defined(BCM_HELIX5_SUPPORT)
     27 #include <bcm_int/esw/helix5.h>
     28 #endif
     29 
     30 #if defined(BCM_ESW_SUPPORT)
     31 #include <bcm_int/esw/xgs4.h>
     32 #endif
     33 int th_prio_set_with_no_free_entries = FALSE;
     34 
     35 /* Local functions prototypes. */
     36 STATIC int
     37 _field_th_group_add(int unit, _field_group_add_fsm_t *fsm_ptr);
     38 STATIC int
     39 _field_th_lt_default_tcam_entry_install(int unit, bcm_field_entry_t lt_entry,
     40                                         int group_expand, int part_index,
     41                                         _field_lt_slice_t *lt_fs);
     42 STATIC int
     43 _field_th_ingress_group_expand_slice_install(int unit, _field_stage_t *stage_fc,
     44                                          _field_group_t *fg, uint8 slice_number,
     45                                          int part_index, int group_slice_prio);
     46 STATIC int
     47 _field_th_ingress_group_expand_install(int unit, _field_stage_t *stage_fc,
     48                                        _field_group_t *fg, int entry_part,
     49                                        _field_lt_slice_t *lt_fs);
     50 #define IS_POST_MUX_QUALIFIER(qid) \
     51             ((_BCM_FIELD_IS_PBMP_QUALIFIER(qid)) \
     52                 || (bcmFieldQualifyNatDstRealmId == qid) \
     53                 || (bcmFieldQualifyNatNeeded == qid) \
     54                 || (bcmFieldQualifyDrop == qid) \
     55                 || (bcmFieldQualifyDstTrunk == qid) \
     56                 || (bcmFieldQualifyDstMultipath == qid) \
     57                 || (bcmFieldQualifyDstMultipathOverlay == qid) \
     58                 || (bcmFieldQualifyDstMultipathUnderlay == qid) \
     59                 || (bcmFieldQualifyDstL2MulticastGroup == qid) \
     60                 || (bcmFieldQualifyDstL3MulticastGroup == qid) \
     61                 || (bcmFieldQualifyDstL3EgressNextHops == qid) \
     62                 || (bcmFieldQualifyDstL3Egress == qid) \
     63                 || (bcmFieldQualifyDstPort == qid) \
     64                 || (bcmFieldQualifyDstMimGport == qid) \
     65                 || (bcmFieldQualifyDstNivGport == qid) \
     66                 || (bcmFieldQualifyDstVxlanGport == qid) \
     67                 || (bcmFieldQualifyDstVlanGport == qid) \
     68                 || (bcmFieldQualifyDstMplsGport == qid) \
     69                 || (bcmFieldQualifyDstWlanGport == qid) \
     70                 || (bcmFieldQualifyDstMimGports == qid) \
     71                 || (bcmFieldQualifyDstNivGports == qid) \
     72                 || (bcmFieldQualifyDstVxlanGports == qid) \
     73                 || (bcmFieldQualifyDstVlanGports == qid) \
     74                 || (bcmFieldQualifyDstMplsGports == qid) \
     75                 || (bcmFieldQualifyDstWlanGports == qid) \
     76                 || ((int)_bcmFieldQualifyExactMatchHitStatusLookup0 == (int)qid) \
     77                 || ((int)_bcmFieldQualifyExactMatchHitStatusLookup1 == (int)qid) \
     78                 || ((int)_bcmFieldQualifyExactMatchActionClassIdLookup0 == (int)qid) \
     79                 || ((int)_bcmFieldQualifyExactMatchActionClassIdLookup1 == (int)qid))
     80 
     81 #define IS_EXT_OVERLAID_POST_MUXERS(ace_flags, ext_flags) \
     82           (((ace_flags & _FP_POST_MUX_NAT_DST_REALM_ID) &&  \
     83             (ext_flags & _FP_EXT_ATTR_NOT_WITH_NAT_DST_REALM_ID)) || \
     84            ((ace_flags & _FP_POST_MUX_NAT_NEEDED) && \
     85             (ext_flags & _FP_EXT_ATTR_NOT_WITH_NAT_NEEDED)) || \
     86            ((ace_flags & _FP_POST_MUX_EM_HIT_STATUS_LOOKUP_0) && \
     87             (ext_flags & _FP_EXT_ATTR_NOT_WITH_EM_HIT_STATUS_LOOKUP_0)) || \
     88            ((ace_flags & _FP_POST_MUX_EM_HIT_STATUS_LOOKUP_1) && \
     89             (ext_flags & _FP_EXT_ATTR_NOT_WITH_EM_HIT_STATUS_LOOKUP_1)) || \
     90            ((ace_flags & _FP_POST_MUX_EM_ACTION_CLASSID_LOOKUP_0) && \
     91             (ext_flags & _FP_EXT_ATTR_NOT_WITH_EM_ACTION_CLASSID_LOOKUP_0)) || \
     92            ((ace_flags & _FP_POST_MUX_EM_ACTION_CLASSID_LOOKUP_1) && \
     93             (ext_flags & _FP_EXT_ATTR_NOT_WITH_EM_ACTION_CLASSID_LOOKUP_1)) || \
     94            ((ace_flags & _FP_POST_MUX_DROP) && \
     95             (ext_flags & _FP_EXT_ATTR_NOT_WITH_DROP)) || \
     96            ((ace_flags & _FP_POST_MUX_SRC_DST_CONT_1_SLI_B) && \
     97             (ext_flags & _FP_EXT_ATTR_NOT_WITH_SRC_DST_CONT_1_B)) || \
     98            ((ace_flags & _FP_POST_MUX_SRC_DST_CONT_0_SLI_B) && \
     99             (ext_flags & _FP_EXT_ATTR_NOT_WITH_SRC_DST_CONT_0_B)) || \
    100            ((ace_flags & _FP_POST_MUX_SRC_DST_CONT_1_SLI_C) && \
    101             (ext_flags & _FP_EXT_ATTR_NOT_WITH_SRC_DST_CONT_1_C)) || \
    102            ((ace_flags & _FP_POST_MUX_SRC_DST_CONT_0_SLI_C) && \
    103             (ext_flags & _FP_EXT_ATTR_NOT_WITH_SRC_DST_CONT_0_C)) || \
    104            ((ace_flags & _FP_POST_MUX_SRC_DST_CONT_1) &&  \
    105             (ext_flags & _FP_EXT_ATTR_NOT_WITH_SRC_DST_CONT_1)) || \
    106            ((ace_flags & _FP_POST_MUX_SRC_DST_CONT_0) && \
    107             (ext_flags & _FP_EXT_ATTR_NOT_WITH_SRC_DST_CONT_0)))
    108 
    109 
    110 #define IS_EXT_OVERLAID_IPBM(ace_flags, ext_flags) \
    111                    ((ace_flags & _FP_POST_MUX_IPBM) && \
    112                     (ext_flags & _FP_EXT_ATTR_NOT_WITH_IPBM))
    113 
    114 
    115 #define _NUM_CHUNKS_PER_GRAN 50
    116 #define _NUM_GRAN 5
    117 
    118 #define GRAN_BASE(gran, base)            \
    119         {                                \
    120            if (gran == 32) {             \
    121                base = 0;                 \
    122            } else if (gran == 16) {      \
    123                base = 1;                 \
    124            } else if (gran == 8) {       \
    125                base = 2;                 \
    126            } else if (gran == 4) {       \
    127                base = 3;                 \
    128            } else if (gran == 2) {       \
    129                base = 4;                 \
    130            }                             \
    131         }
    132 
    133 /*
    134  * Enum to define IPBM_SOURCE
    135  */
    136 typedef enum _bcmFieldIpbmSource_e {
    137    _bcmFieldIpbmSourcePipeLocal = 0,   /* Port Based Selective Mask.      */
    138    _bcmFieldIpbmSourcePort      = 1,   /* Ttrunk Based Selective Mask.    */
    139    _bcmFieldIpbmSourceVp        = 2,   /* Source VP based Selective Mask. */
    140    _bcmFieldIpbmSourceDevPort   = 3    /* IPBM Index based selective Mask.*/
    141 } _bcmFieldIpbmSource_t;
    142 
    143 
    144 
    145 /*
    146  * Function:
    147  *     _field_th_group_add_initialize
    148  * Purpose:
    149  *     Perform fsm initialization & execute basic checks
    150  *     required before field group creation.
    151  * Parameters:
    152  *     unit     - (IN)     BCM device number.
    153  *     fsm_ptr  - (IN/OUT) State machine tracking structure.
    154  * Returns:
    155  *     BCM_E_XXX.
    156  */
    157 STATIC int
    158 _field_th_group_add_initialize(int unit, _field_group_add_fsm_t *fsm_ptr)
    159 {
    160     _field_group_t *fg_temp; /* Pointer to an existing Field Group.  */
    161     _field_stage_id_t stage; /* Field Processor stage ID.            */
    162 
    163     /* Input parameters check. */
    164     if (NULL == fsm_ptr) {
    165         return (BCM_E_PARAM);
    166     }
    167 
    168     /* Save current FSM state in previous state. */
    169     fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state;
    170 
    171     if (BCM_SUCCESS(_field_group_get(unit, fsm_ptr->group_id, &fg_temp))) {
    172         LOG_ERROR(BSL_LS_BCM_FP,
    173             (BSL_META_U(unit, "FP(unit %d) Error: group=%d already exists.\n"),
    174              unit, fsm_ptr->group_id));
    175         fsm_ptr->rv = (BCM_E_EXISTS);
    176     }
    177 
    178     /* Get Field Stage control pointer. */
    179     if (BCM_SUCCESS(fsm_ptr->rv)) {
    180         fsm_ptr->rv = _field_control_get(unit, &fsm_ptr->fc);
    181     }
    182 
    183     /* Get pipeline stage from qualifiers set.  */
    184     if (BCM_SUCCESS(fsm_ptr->rv)) {
    185         fsm_ptr->rv = _bcm_field_group_stage_get(unit, &fsm_ptr->qset, &stage);
    186         if ((_BCM_FIELD_STAGE_INGRESS != stage) &&
    187             (_BCM_FIELD_STAGE_EXACTMATCH != stage) &&
    188             (_BCM_FIELD_STAGE_FLOWTRACKER != stage)) {
    189             fsm_ptr->rv = BCM_E_INTERNAL;
    190         }
    191     }
    192 
    193     /*
    194      * Attempt IntraSlice Double wide Groups if stage supports it.
    195      * Note: TH IFP stage default comes up in IntraSlice Double wide mode.
    196      */
    197     if (BCM_SUCCESS(fsm_ptr->rv)
    198         && soc_feature(unit, soc_feature_field_intraslice_double_wide)
    199         && (fsm_ptr->fc->flags & _FP_INTRASLICE_ENABLE)
    200         && (stage != _BCM_FIELD_STAGE_EXACTMATCH)) {
    201         fsm_ptr->flags |= _BCM_FP_GROUP_ADD_INTRA_SLICE;
    202     }
    203 
    204     /* Get Field Stage Control Pointer. */
    205     if (BCM_SUCCESS(fsm_ptr->rv)) {
    206         fsm_ptr->rv = _field_stage_control_get(unit, stage, &fsm_ptr->stage_fc);
    207     }
    208 
    209     if (BCM_SUCCESS(fsm_ptr->rv)) {
    210         /* Verify if requested QSET is supported by the stage. */
    211         if (FALSE == _field_qset_is_subset(&fsm_ptr->qset,
    212                     &fsm_ptr->stage_fc->_field_supported_qset)) {
    213             LOG_INFO(BSL_LS_BCM_FP,
    214                     (BSL_META_U(unit, "FP(unit %d) Error: Qualifier set is not"
    215                                 " supported by the device.\n"), unit));
    216             fsm_ptr->rv = (BCM_E_UNAVAIL);
    217         }
    218     }
    219 
    220     /* Verify Group Priority for flowtracker stage */
    221 #if defined(BCM_FLOWTRACKER_SUPPORT)
    222     if (BCM_SUCCESS(fsm_ptr->rv) &&
    223         soc_feature(unit, soc_feature_field_flowtracker_support) &&
    224         (fsm_ptr->stage_fc->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER)) {
    225         if (fsm_ptr->priority != 0) {
    226             fsm_ptr->rv = (BCM_E_CONFIG);
    227             LOG_INFO(BSL_LS_BCM_FP,
    228                     (BSL_META_U(unit, "FP(unit %d) Error: Field Group Priority"
    229                                 " not supported at this stage.\n"), unit));
    230         }
    231     }
    232 #endif
    233 
    234     if (BCM_FAILURE(fsm_ptr->rv)) {
    235         /* Error return hence perform clean up. */
    236         fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
    237     } else {
    238         /* Proceed to group allocation state. */
    239         fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_ALLOC;
    240     }
    241 
    242     /* Execute the state machine for the new state. */
    243     return (BCM_E_NONE);
    244 }
    245 
    246 #if 0
    247 /*
    248  * Function:
    249  *     _field_th_group_priority_validate
    250  * Purpose:
    251  *     Validate group prioirty value, if specified priority value is NOT
    252  *     BCM_FIELD_GROUP_PRIO_ANY then it must be unique.
    253  * Parameters:
    254  *     unit     - (IN  BCM device number.
    255  *     stage_fc - (IN) Field stage control structure.
    256  *     fg       - (IN) Field group structure.
    257  * Returns:
    258  *     BCM_E_XXX
    259  */
    260 STATIC int
    261 _field_th_group_priority_validate(int unit, _field_stage_t *stage_fc,
    262                                   _field_group_t *fg)
    263 {
    264     int lt_idx;                  /* Logical Table iterator.    */
    265     _field_lt_config_t *lt_info; /* Logical Table information. */
    266 
    267     /* Input parameters check. */
    268     if ((NULL == stage_fc) || (NULL == fg)) {
    269         return (BCM_E_PARAM);
    270     }
    271 
    272     /*
    273      * If Group doesn't care about priority, one of the available
    274      * priorities is allocated. Hence return done.
    275      */
    276     if (BCM_FIELD_GROUP_PRIO_ANY == fg->priority) {
    277         return (BCM_E_NONE);
    278     }
    279 
    280     /*
    281      * Two Field groups cannot have the same priority value as hardware
    282      * behavior is Indeterministic if packet matches rules in both the groups
    283      * that have same Group/Action priority value.
    284      */
    285     for (lt_idx = 0; lt_idx < stage_fc->num_logical_tables; lt_idx++) {
    286         lt_info = stage_fc->lt_info[fg->instance][lt_idx];
    287         if ((TRUE == lt_info->valid) && (fg->priority == lt_info->priority)) {
    288             LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
    289                 "FP(unit %d) Error: Group=%d Priority=%d already in-use.\n"),
    290                  unit, fg->gid, fg->priority));
    291             return (BCM_E_PARAM);
    292         }
    293     }
    294 
    295     return (BCM_E_NONE);
    296 }
    297 #endif /* 0 */
    298 
    299 /*
    300  * Function:
    301  *     _field_th_group_add_alloc
    302  * Purpose:
    303  *     Allocate & initialize field group structure.
    304  * Parameters:
    305  *     unit     - (IN) BCM device number.
    306  *     fsm_ptr  - (IN/OUT) State machine tracking structure.
    307  * Returns:
    308  *     BCM_E_XXX.
    309  */
    310 STATIC int
    311 _field_th_group_add_alloc(int unit, _field_group_add_fsm_t *fsm_ptr)
    312 {
    313     int idx;                    /* Iterator variable.               */
    314     int mem_sz;                 /* Memory size to be allocated.     */
    315     _field_group_t *fg = NULL;  /* New group inforation structure.  */
    316 
    317     /* Input parameters check. */
    318     if (NULL == fsm_ptr) {
    319         return (BCM_E_PARAM);
    320     }
    321 
    322     /* Save current state as previous state. */
    323     fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state;
    324 
    325     /* Determine field group structure buffer size. */
    326     mem_sz = sizeof(_field_group_t);
    327 
    328     /* Allocate and initialize memory for Field Group. */
    329     _FP_XGS3_ALLOC(fg, mem_sz, "field group");
    330     if (NULL == fg) {
    331         LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
    332             "FP(unit %d) Error:Allocation failure for "
    333              "_field_group_t\n"), unit));
    334         /* Memory allocation failure hence proceed to clean up. */
    335         fsm_ptr->rv = BCM_E_MEMORY;
    336         goto bcm_error;
    337     }
    338 
    339     /* Initialize group structure. */
    340     fg->gid            = fsm_ptr->group_id;
    341     fg->stage_id       = fsm_ptr->stage_fc->stage_id;
    342     fg->qset           = fsm_ptr->qset;
    343     fg->pbmp           = fsm_ptr->pbmp;
    344     fg->priority       = fsm_ptr->priority;
    345     fg->hintid         = fsm_ptr->hintid;
    346     fg->action_res_id  = fsm_ptr->action_res_id;
    347     sal_memcpy(&fg->aset, &fsm_ptr->aset, sizeof(bcm_field_aset_t));
    348 
    349     /* Initialize the action profile index's to -1 */
    350     for (idx=0; idx < MAX_ACT_PROF_ENTRIES_PER_GROUP; idx++) {
    351         fg->action_profile_idx[idx] =  -1;
    352     }
    353 
    354     for (idx = 0; idx < _FP_PAIR_MAX; idx++) {
    355         fg->vmap_group[idx] = BCM_FIELD_GROUP_ACTION_RES_ID_DEFAULT;
    356     }
    357 
    358     /* Clear the group's select codes and its slice Qsets. */
    359     for (idx = 0; idx < _FP_MAX_ENTRY_WIDTH; idx++) {
    360         _FIELD_SELCODE_CLEAR(fg->sel_codes[idx]);
    361     }
    362 
    363     /* Set the Field Group's instance information. */
    364     fsm_ptr->rv = _bcm_field_th_group_instance_set(unit, fg);
    365     if (BCM_FAILURE(fsm_ptr->rv)) {
    366         goto bcm_error;
    367     }
    368 
    369     fsm_ptr->rv = _bcm_field_hints_group_count_update(unit, fg->hintid, 1);
    370     if (BCM_FAILURE(fsm_ptr->rv)) {
    371         goto bcm_error;
    372     }
    373 
    374     /* Initialize group status. */
    375     fsm_ptr->rv = _bcm_field_group_status_init(unit, &fg->group_status);
    376     if (BCM_FAILURE(fsm_ptr->rv)) {
    377         goto bcm_error;
    378     }
    379 
    380     /* Hint Check. */
    381     fsm_ptr->rv = _bcm_field_hints_group_info_update(unit, fg);
    382     if (BCM_FAILURE(fsm_ptr->rv)) {
    383         goto bcm_error;
    384     }
    385 
    386     /* Set slice size selection group flags. */
    387     if (fsm_ptr->flags & _BCM_FP_GROUP_ADD_SMALL_SLICE) {
    388         fg->flags |= _FP_GROUP_SELECT_SMALL_SLICE;
    389     } else if (fsm_ptr->flags & _BCM_FP_GROUP_ADD_LARGE_SLICE) {
    390         fg->flags |= _FP_GROUP_SELECT_LARGE_SLICE;
    391     }
    392 
    393     /* Clear the group's slice extractor selectors value. */
    394     for (idx = 0; idx < _FP_MAX_ENTRY_WIDTH; idx++) {
    395         _FP_EXT_SELCODE_CLEAR(fg->ext_codes[idx]);
    396     }
    397 
    398     /* By default mark group as active. */
    399     fg->flags |= _FP_GROUP_LOOKUP_ENABLED;
    400 
    401     /* Update Preselector Support Flags */
    402     if (fsm_ptr->flags & BCM_FIELD_GROUP_CREATE_WITH_PRESELSET) {
    403        bcm_field_presel_t       presel;
    404 
    405        /* Preselector feature check */
    406        if (!soc_feature(unit, soc_feature_field_preselector_support)) {
    407           fsm_ptr->rv = BCM_E_UNAVAIL;
    408           goto bcm_error;
    409        }
    410 
    411        /* initialize the group preselector array */
    412        sal_memset(&fg->presel_ent_arr[0], 0x0,
    413             sizeof(_field_presel_entry_t *) * _FP_PRESEL_ENTRIES_MAX_PER_GROUP);
    414 
    415        for (presel = 0; presel < BCM_FIELD_PRESEL_SEL_MAX; presel++) {
    416           if (BCM_FIELD_PRESEL_TEST(fsm_ptr->preselset, presel)) {
    417              /* Assign the preselectors to the group presel array. */
    418              fsm_ptr->rv = _bcm_field_presel_group_add(unit, fg, presel);
    419              if (BCM_FAILURE(fsm_ptr->rv)) {
    420                  goto bcm_error;
    421              }
    422              fg->flags |= _FP_GROUP_PRESELECTOR_SUPPORT;
    423           }
    424        }
    425 
    426        if (!(fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT)) {
    427            LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
    428                "ERROR: Group (GID= %d) should have atleast"
    429                " one preselector assigned.\n\r"),fg->gid));
    430            fsm_ptr->rv = BCM_E_PARAM;
    431            goto bcm_error;
    432         }
    433 #if defined(BCM_FLOWTRACKER_SUPPORT)
    434     } else {
    435         if (fg->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER) {
    436            LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
    437                "ERROR: Group (GID= %d) should have atleast"
    438                " one preselector assigned.\n\r"),fg->gid));
    439             fsm_ptr->rv = BCM_E_PARAM;
    440             goto bcm_error;
    441         }
    442 #endif
    443     }
    444 
    445     /* Set allocated poniter to FSM structure. */
    446     fsm_ptr->fg = fg;
    447 
    448     /* Update group QSET with internal qualifiers. */
    449     fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_QSET_UPDATE;
    450 
    451     /* Execute the state machine for the new state. */
    452     return (BCM_E_NONE);
    453 
    454 bcm_error:
    455     if (fg != NULL) {
    456        sal_free(fg);
    457        fg = NULL;
    458     }
    459     fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
    460     return (BCM_E_NONE);
    461 }
    462 /*
    463  * Function:
    464  *     _field_calc_aset_size_all_actions
    465  * Purpose:
    466  *     For TD3 IFP
    467  *     Calculate the Aset size
    468  * Parameters:
    469  *     unit       - (IN)     BCM device number.
    470  *     fg         - (IN)     Field group structure.
    471  *     aset_size  - (IN/OUT) group's Aset size
    472  * Returns:
    473  *     BCM_E_XXX
    474  */
    475 static int
    476 _field_calc_aset_size_all_actions(int unit, _field_group_t *fg)
    477 {
    478     _field_stage_t *stage_fc = NULL;    /* Field Stage Control.         */
    479     _bcm_field_aset_t aset;             /* Action Set.           */
    480     uint16 aset_key_size = 0;           /* Action Set Size.      */
    481     uint8 aset_cnt[_FieldActionSetCount] = {0};
    482                                         /* Action Per Set Count. */
    483     int a_idx;                          /* Action Iterator.      */
    484     _bcm_field_action_set_t            *action_set_ptr;
    485                                         /* action set pointer */
    486     _bcm_field_action_conf_t           *action_conf_ptr;
    487                                         /* action configuration pointer */
    488     uint8 field_action_set;             /* to hold Aset enum */
    489 
    490 
    491     /* Input parameters check. */
    492     if (NULL == fg) {
    493         return BCM_E_INTERNAL;
    494     }
    495 
    496     /* Retreive Action Set */
    497     aset = fg->aset;
    498 
    499     /* Check whether it is a valid stage */
    500     /* this fucntion is valid for TD3 IFP */
    501     if (!(soc_feature(unit, soc_feature_ifp_action_profiling)
    502         && (fg->stage_id == _BCM_FIELD_STAGE_INGRESS)))
    503     {
    504         return BCM_E_NONE;
    505     }
    506 
    507     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fg->stage_id,
    508                            &stage_fc));
    509 
    510     action_set_ptr = stage_fc->action_set_ptr;
    511 
    512     /* Calculate Action Size. */
    513     for (a_idx = 0; a_idx < _bcmFieldActionCount; a_idx++) {
    514         if (BCM_FIELD_ASET_TEST(aset, a_idx)) {
    515             /* test whether the current action is supported in this stage */
    516             action_conf_ptr = stage_fc->f_action_arr[a_idx];
    517             if (NULL != action_conf_ptr) {
    518                 /* get the aset enum from action_conf_pointer */
    519                 field_action_set = action_conf_ptr->offset->aset;
    520             } else if (a_idx == bcmFieldActionPolicerGroup) {
    521                 /* Flag in ASETs to indicate group
    522                  * policer usage with the group */
    523                 field_action_set = _FieldActionMeterSet;
    524             } else if (a_idx == bcmFieldActionStatGroup) {
    525                 /* Flag in ASETs to indicate stat group
    526                  * usage with the group */
    527                  field_action_set = _FieldActionCounterSet;
    528             } else {
    529                 /* Ignore the unsupported actions */
    530                 continue;
    531             }
    532             /* if the aset for current action is 0, or
    533                action_set size is 0 for this stage/chip
    534                skip the hw field updation step */
    535             if ((0 == field_action_set) ||
    536                 (0 == action_set_ptr[field_action_set].size)) {
    537                 continue;
    538             } else {
    539                if (aset_cnt[field_action_set] ==0) {
    540                    aset_key_size +=
    541                               action_set_ptr[field_action_set].size;
    542                    aset_cnt[field_action_set]++;
    543                }
    544             }
    545         }
    546     }
    547     /* Check if L3SW/Redirect action is set.
    548      * If yes then reserve 1 bit for Green To Pid. */
    549     if (aset_cnt[_FieldActionL3SwChangeL2Set] ||
    550         aset_cnt[_FieldActionRedirectSet]) {
    551         aset_key_size +=
    552                    action_set_ptr[_FieldActionGreenToPidSet].size;
    553     }
    554     return aset_key_size;
    555 }
    556 
    557 
    558 /* Add internal actions associated with main Action */
    559 int
    560 _bcm_field_qset_update_with_internal_actions(int unit, _field_group_t *fg)
    561 {
    562 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT)
    563     if (BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionIntEncapEnable) ||
    564         BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionNshEncapEnable)) {
    565        BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionEditCtrlId);
    566        BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionExtractionCtrlId);
    567     }
    568 
    569     if (BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionIntTurnAround)) {
    570        BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionEditCtrlId);
    571     }
    572 
    573     if (BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionIntEncapUpdate)) {
    574        BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionExtractionCtrlId);
    575     }
    576 
    577     if (BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionAddIngOuterVlanToEgrOuterVlan) ||
    578         BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionErspan3HdrVlanCosPktCopy)) {
    579        BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionExtractionCtrlId);
    580     }
    581     
    582 #if 0
    583     if (BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionErspan3HdrGbpSrcIdAdd)) {
    584        BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionOpaque3);
    585     }
    586 
    587     if (BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionErspan3HdrUdf2Add)) {
    588        BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionOpaque4);
    589     }
    590 #endif /* 0 */
    591     if (BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionNshServiceIndex)) {
    592        BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionOpaque2);
    593     }
    594 
    595     if (BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionNshServicePathId)) {
    596        BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionOpaque1);
    597        BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionOpaque2);
    598     }
    599 
    600     if (BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionGbpSrcIdNew)
    601         || BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionAssignNatClassId)) {
    602         BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionOpaque1);
    603     }
    604 
    605     if (BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionGbpDstIdNew)) {
    606         BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionOpaque2);
    607     }
    608 
    609     if (BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionAssignChangeL2FieldsClassId)) {
    610         BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionOpaque3);
    611     }
    612 
    613     if ((BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionGbpSrcMacMcastBitSet))
    614         || (BCM_FIELD_ASET_TEST(fg->aset, bcmFieldActionGbpClassifierAdd))) {
    615        BCM_FIELD_ASET_ADD(fg->aset, _bcmFieldActionExtractionCtrlId);
    616     }
    617 
    618 #endif /* BCM_TRIDENT3_SUPPORT */
    619     return BCM_E_NONE;
    620 }
    621 
    622 /*
    623  * Function:
    624  *  _field_group_check_action_profile
    625  * Purpose:
    626  *  Check if same action profile is shared
    627  * Parameters:
    628  *  unit       - (IN)     BCM device number.
    629  *  fg         - (IN)     Field group structure.
    630  *  new_action_profile - (OUT) New Action Profile pointer.
    631  * Returns:
    632  *  BCM_E_XXX
    633  * Notes:
    634  *  This function will check if action profile indexes associated
    635  *  to provided group is shared by any other group in same stage.
    636  *  If found then it will update new_action_profile to 1.
    637  */
    638 int
    639 _field_group_check_action_profile(int unit, _field_group_t *fg,
    640                                      uint16 *new_action_profile)
    641 {
    642     _field_control_t *fc = NULL;
    643     uint16 ap_idx1 = 0, ap_idx2 = 0;
    644     _field_group_t *fgt = NULL;
    645 
    646     /* input parameter check */
    647     if (fg == NULL || new_action_profile == NULL) {
    648         return (BCM_E_INTERNAL);
    649     }
    650 
    651     /* get field control strucutre */
    652     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
    653 
    654     /* check if there is any other group with same action_profile index */
    655     for (fgt = fc->groups; fgt != NULL; fgt = fgt->next) {
    656         if ((fgt->gid == fg->gid) || (fgt->stage_id != fg->stage_id)) {
    657             continue;
    658         }
    659         for (ap_idx1 = 0; ap_idx1 < MAX_ACT_PROF_ENTRIES_PER_GROUP; ap_idx1++) {
    660             if (fgt->action_profile_idx[ap_idx1] != -1) {
    661                 for (ap_idx2 = 0; ap_idx2 < MAX_ACT_PROF_ENTRIES_PER_GROUP; ap_idx2++) {
    662                     if (fgt->action_profile_idx[ap_idx1] ==
    663                                     fg->action_profile_idx[ap_idx2]) {
    664                         *new_action_profile = 1;
    665                         break;
    666                     }
    667                 }
    668             }
    669         }
    670     }
    671 
    672     return (BCM_E_NONE);
    673 }
    674 
    675 /*
    676  * Function:
    677  *     _field_calc_group_aset_size
    678  * Purpose:
    679  *     For TD3 IFP
    680  *     Calculate the Aset size
    681  * Parameters:
    682  *     unit       - (IN)     BCM device number.
    683  *     fg         - (IN)     Field group structure.
    684  *     aset_size  - (IN/OUT) group's Aset size
    685  * Returns:
    686  *     BCM_E_XXX
    687  */
    688 int
    689 _field_calc_group_aset_size(int unit, _field_group_t *fg, uint16 *aset_size)
    690 {
    691     _field_stage_t *stage_fc = NULL;    /* Field Stage Control.         */
    692     _bcm_field_aset_t aset;             /* Action Set.           */
    693     uint16 aset_key_size = 0;           /* Action Set Size.      */
    694     uint8 aset_cnt[_FieldActionSetCount] = {0};
    695                                         /* Action Per Set Count. */
    696     int a_idx;                          /* Action Iterator.      */
    697     _bcm_field_action_set_t            *action_set_ptr;
    698                                         /* action set pointer */
    699     _bcm_field_action_conf_t           *action_conf_ptr;
    700                                         /* action configuration pointer */
    701     uint8 field_action_set;             /* to hold Aset enum */
    702     uint8 setChangeCosOrIntPriSet = 0;  /* For Actions which has 2 Asets */
    703     uint8 setMeterSet = 0;              /* For color dependent actions
    704                                            meter set should be enabled */
    705 
    706     /* Input parameters check. */
    707     if (NULL == fg) {
    708         return BCM_E_INTERNAL;
    709     }
    710 
    711     /* Retreive Action Set */
    712     aset = fg->aset;
    713 
    714     /* Check whether it is a valid stage */
    715     /* this fucntion is valid for TD3 IFP */
    716     if (!(soc_feature(unit, soc_feature_ifp_action_profiling)
    717         && (fg->stage_id == _BCM_FIELD_STAGE_INGRESS)))
    718     {
    719         return BCM_E_NONE;
    720     }
    721 
    722     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fg->stage_id,
    723                            &stage_fc));
    724 
    725     action_set_ptr = stage_fc->action_set_ptr;
    726     /* Calculate Action Size. */
    727     for (a_idx = 0; a_idx < _bcmFieldActionCount; a_idx++) {
    728         if (BCM_FIELD_ASET_TEST(aset, a_idx)) {
    729             /* test whether the current action is supported in this stage */
    730             action_conf_ptr = stage_fc->f_action_arr[a_idx];
    731             if (NULL != action_conf_ptr) {
    732                 /* get the aset enum from action_conf_pointer */
    733                 field_action_set = action_conf_ptr->offset->aset;
    734                 /* PrioPktAndInt* actions needs 2 action Sets:
    735                    1: _FieldActionChangePktPriSet
    736                    2: _FieldActionChangeCosOrIntPriSet
    737                    _FieldActionChangePktPriSet is set as part of
    738                    action initialization. 2nd Set to be taken care here
    739                 */
    740                 /* check whether the action is PrioPktAndInt* actions */
    741                 if (BCM_FIELD_ACTION_PRIO_PKT_AND_INT_TEST(a_idx)) {
    742                     setChangeCosOrIntPriSet = 1;
    743                 }
    744             } else if (a_idx == bcmFieldActionPolicerGroup) {
    745                 /* Flag in ASETs to indicate group
    746                  * policer usage with the group */
    747                 field_action_set = _FieldActionMeterSet;
    748             } else if (a_idx == bcmFieldActionStatGroup) {
    749                 /* Flag in ASETs to indicate stat group
    750                  * usage with the group */
    751                  field_action_set = _FieldActionCounterSet;
    752             } else {
    753                  /* action is not supported in this stage */
    754                  /* add log_error with stage, action, chip*/
    755                  LOG_ERROR(BSL_LS_BCM_FP,
    756                        (BSL_META_U(unit,
    757                         "FP(unit %d) Error: action=%s(%d) not supported\n"),
    758                          unit,
    759                          _field_action_name(a_idx),
    760                          a_idx
    761                          ));
    762                  return BCM_E_UNAVAIL;
    763             }
    764             /* if the aset for current action is 0, or
    765                action_set size is 0 for this stage/chip
    766                skip the hw field updation step */
    767             if ((0 == field_action_set) ||
    768                 (0 == action_set_ptr[field_action_set].size)) {
    769                 continue;
    770             } else {
    771                if (aset_cnt[field_action_set] ==0) {
    772                    aset_key_size +=
    773                               action_set_ptr[field_action_set].size;
    774                    aset_cnt[field_action_set]++;
    775                }
    776                if (1 == action_set_ptr[field_action_set].is_color_dependent) {
    777                    setMeterSet = 1;
    778                }
    779             }
    780         }
    781     }
    782     /* Set CosorIntPriSet in action profile mem and
    783        update key size if prioPktAndInt* actions are
    784        present in current group's Aset */
    785     if (1 == setChangeCosOrIntPriSet) {
    786         if (0 == aset_cnt[_FieldActionChangeCosOrIntPriSet]) {
    787            aset_key_size +=
    788                    action_set_ptr[_FieldActionChangeCosOrIntPriSet].size;
    789         }
    790     }
    791     /* Set MeterSet in action profile mem and
    792        update key size if any color dependent actions are
    793        present in current group's Aset */
    794     if (1 == setMeterSet) {
    795         if (0 == aset_cnt[_FieldActionMeterSet]) {
    796            aset_key_size +=
    797                    action_set_ptr[_FieldActionMeterSet].size;
    798            /* add meter Aset to fg's aset internally */
    799            BCM_FIELD_ASET_ADD(fg->aset, bcmFieldActionPolicerGroup);
    800         }
    801     }
    802     /* Check if L3SW/Redirect action is set.
    803      * If yes then reserve 1 bit for Green To Pid. */
    804     if (aset_cnt[_FieldActionL3SwChangeL2Set] ||
    805         aset_cnt[_FieldActionRedirectSet]) {
    806         aset_key_size +=
    807                    action_set_ptr[_FieldActionGreenToPidSet].size;
    808     }
    809     /* Update Aset size in group's structure */
    810     if (0 == aset_key_size) {
    811         LOG_VERBOSE(BSL_LS_BCM_FP,(BSL_META_U(unit,
    812             "VERB: Trying to create group with no actions\n"
    813              "Creating the group with all supporting actions\n")));
    814         /* Update the group's Aset with all supported actions */
    815         BCM_IF_ERROR_RETURN(_field_group_default_aset_set(unit, fg));
    816         BCM_FIELD_ASET_ADD(fg->aset, bcmFieldActionPolicerGroup);
    817         BCM_FIELD_ASET_ADD(fg->aset, bcmFieldActionStatGroup);
    818         (void)_bcm_field_qset_update_with_internal_actions(unit, fg);
    819         /* Set the group's Aset size to
    820         cummulative of all supporing Action sets size */
    821         aset_key_size = _field_calc_aset_size_all_actions(unit, fg);
    822     }
    823   *aset_size = aset_key_size;
    824   return BCM_E_NONE;
    825 }
    826 
    827 /*
    828  * Function:
    829  *     _field_th_group_add_aset_validate
    830  * Purpose:
    831  *     For TH EM and TD3 IFP, EM
    832  *     Calculate the Aset size and
    833  *     allocate the action profile pointer for group
    834  * Parameters:
    835  *     unit     - (IN)     BCM device number.
    836  *     fsm_ptr  - (IN/OUT) State machine tracking structure.
    837  * Returns:
    838  *     BCM_E_XXX
    839  */
    840 STATIC int
    841 _field_th_group_add_aset_validate(int unit, _field_group_add_fsm_t *fsm_ptr)
    842 {
    843     _field_group_t *fg;                 /* Field Group structure pointer. */
    844     _field_stage_t *stage_fc = NULL;    /* Field Stage Control.         */
    845     _bcm_field_aset_t aset;             /* Action Set.           */
    846     uint16 aset_key_size = 0, aset_size =0;          /* Action Set Size.      */
    847     uint8 aset_cnt[_FieldActionSetCount] = {0};
    848                                         /* Action Per Set Count. */
    849     int a_idx;                          /* Action Iterator.      */
    850     void *entries[1];                   /* Profile Entry.               */
    851     void *act_prof_entry[MAX_ACT_PROF_ENTRIES_PER_GROUP];
    852                                         /* Profile table buffer pointer */
    853     soc_mem_t mem;                      /* Memory Identifier.           */
    854     exact_match_action_profile_entry_t em_act_prof_entry;
    855                                         /* Action Profile Table Buffer. */
    856     ifp_policy_action_profile_entry_t
    857                         ifp_act_prof_entry[MAX_ACT_PROF_ENTRIES_PER_GROUP];
    858                                         /* Action Profile Table Buffer. */
    859     uint32 action_profile_idx[MAX_ACT_PROF_ENTRIES_PER_GROUP];
    860                                         /* Action profile index         */
    861     _bcm_field_action_set_t            *action_set_ptr;
    862                                         /* action set pointer */
    863     _bcm_field_action_conf_t           *action_conf_ptr;
    864                                         /* action configuration pointer */
    865     uint8 field_action_set;             /* to hold Aset enum */
    866     uint8 multi_mode = 0;
    867     uint8 setChangeCosOrIntPriSet = 0;  /* For Actions which has 2 Asets */
    868 
    869     /* Input parameters check. */
    870     if (NULL == fsm_ptr) {
    871         return (BCM_E_PARAM);
    872     }
    873 
    874     if (NULL == fsm_ptr->fg) {
    875         fsm_ptr->rv = (BCM_E_PARAM);
    876         fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
    877         return BCM_E_NONE;
    878     }
    879     /* Get field group structure. */
    880     fg = fsm_ptr->fg;
    881 
    882     /* Save current state as the previous state. */
    883     fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state;
    884     fsm_ptr->rv = (BCM_E_NONE);
    885 
    886     /* Retreive Action Set */
    887     aset = fg->aset;
    888 
    889 #if defined(BCM_FLOWTRACKER_SUPPORT)
    890     if ((soc_feature(unit, soc_feature_field_flowtracker_support)) &&
    891             (_BCM_FIELD_STAGE_FLOWTRACKER == fg->stage_id)) {
    892         /* Verify actions */
    893         for (a_idx = 0; a_idx < _bcmFieldActionCount; a_idx++) {
    894             if (BCM_FIELD_ASET_TEST(aset, a_idx)) {
    895                 switch(a_idx) {
    896                     case bcmFieldActionFlowtrackerGroupId:
    897                     case bcmFieldActionFlowtrackerEnable:
    898                     case bcmFieldActionFlowtrackerNewLearnEnable:
    899                         aset_size++;
    900                         break;
    901                     default:
    902                         fsm_ptr->rv = (BCM_E_UNAVAIL);
    903                         fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
    904                         return (BCM_E_NONE);
    905                 }
    906             }
    907         }
    908         if (aset_size == 0) {
    909             /* Update the group's Aset with all supported actions */
    910             BCM_IF_ERROR_RETURN(_field_group_default_aset_set(unit, fg));
    911         }
    912         goto clean_up;
    913     }
    914 #endif
    915 
    916     /* Check whether it is a valid stage */
    917     if (!(((SOC_IS_TOMAHAWKX(unit))
    918         && (fg->stage_id == _BCM_FIELD_STAGE_EXACTMATCH))
    919         || soc_feature(unit, soc_feature_ifp_action_profiling))) {
    920          goto clean_up;
    921     }
    922     /* Assign correct Action Profile Memory
    923      * and Action set's depending on stage */
    924     if (fg->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
    925         /* Assign Exact Match Action Profile Memory */
    926         mem = EXACT_MATCH_ACTION_PROFILEm;
    927         act_prof_entry[0] = &em_act_prof_entry;
    928         sal_memcpy(act_prof_entry[0], soc_mem_entry_null(unit, mem),
    929                 soc_mem_entry_words(unit, mem) * sizeof(uint32));
    930     } else {
    931         /* Assign ifp Action Profile Memory */
    932         mem = IFP_POLICY_ACTION_PROFILEm;
    933         for (a_idx =0;a_idx < MAX_ACT_PROF_ENTRIES_PER_GROUP; a_idx++) {
    934             act_prof_entry[a_idx] = &ifp_act_prof_entry[a_idx];
    935             sal_memcpy(act_prof_entry[a_idx], soc_mem_entry_null(unit, mem),
    936                 soc_mem_entry_words(unit, mem) * sizeof(uint32));
    937         }
    938     }
    939 
    940     /* Update internal pseudo actions for the given ASET */
    941     BCM_IF_ERROR_RETURN(_bcm_field_qset_update_with_internal_actions(unit, fg));
    942 
    943     /* calculate Aset size */
    944     fsm_ptr->rv = _field_calc_group_aset_size(unit, fg, &aset_size);
    945     if (BCM_FAILURE(fsm_ptr->rv)) {
    946         goto clean_up;
    947     }
    948 
    949     /* Retreive Action Set (it can be updated in above func */
    950     aset = fg->aset;
    951 
    952     if (soc_feature(unit, soc_feature_ifp_action_profiling) &&
    953        (fg->stage_id == _BCM_FIELD_STAGE_INGRESS)) {
    954        if (aset_size > _FP_ASET_DATA_SIZE_FOR_POLICY_WIDE) {
    955            /* we need to go for multi mode Policy tables */
    956            /* i.e., 2 IFP_POLICY_TABLE_WIDE entries will be
    957            used to save the policy data corresponding to each entry
    958            and correspondingly 2 action profiles will be used
    959            for saving group's actions bitmaps.
    960            The split will be based on color dependent Asets
    961            in one action profile and color independent actions in
    962            another Action profile entry */
    963            multi_mode = 1;
    964        }
    965     }
    966 
    967     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fg->stage_id,
    968                            &stage_fc));
    969     action_set_ptr = stage_fc->action_set_ptr;
    970 
    971     /* Calculate Action Size. */
    972     for (a_idx = 0; a_idx < _bcmFieldActionCount; a_idx++) {
    973         if (BCM_FIELD_ASET_TEST(aset, a_idx)) {
    974             /* test whether the current action is supported in this stage */
    975             action_conf_ptr = stage_fc->f_action_arr[a_idx];
    976             if (NULL != action_conf_ptr) {
    977                 /* get the aset enum from action_conf_pointer */
    978                 field_action_set = action_conf_ptr->offset->aset;
    979                 /* PrioPktAndInt* actions needs 2 action Sets:
    980                    1: _FieldActionChangePktPriSet
    981                    2: _FieldActionChangeCosOrIntPriSet
    982                    _FieldActionChangePktPriSet is set as part of
    983                    action initialization. 2nd Set to be taken care here
    984                 */
    985                 /* check whether the action is PrioPktAndInt* actions */
    986                 if (BCM_FIELD_ACTION_PRIO_PKT_AND_INT_TEST(a_idx)
    987                     && fg->stage_id == _BCM_FIELD_STAGE_INGRESS) {
    988                     setChangeCosOrIntPriSet = 1;
    989                 }
    990             } else if (a_idx == bcmFieldActionPolicerGroup) {
    991                 /* Flag in ASETs to indicate group
    992                  * policer usage with the group */
    993                 field_action_set = _FieldActionMeterSet;
    994             } else if (a_idx == bcmFieldActionStatGroup) {
    995                 /* Flag in ASETs to indicate stat group
    996                  * usage with the group */
    997                  field_action_set = _FieldActionCounterSet;
    998             } else {
    999                  /* action is not supported in this stage */
   1000                  /* add log_error with stage, action, chip*/
   1001                  LOG_ERROR(BSL_LS_BCM_FP,
   1002                        (BSL_META_U(unit,
   1003                         "FP(unit %d) Error: action=%s(%d) not supported\n"),
   1004                          unit,
   1005                          _field_action_name(a_idx),
   1006                          a_idx));
   1007                  fsm_ptr->rv = (BCM_E_UNAVAIL);
   1008                  goto clean_up;
   1009             }
   1010             /* if the aset for current action is 0, or
   1011                action_set size is 0 for this stage/chip
   1012                skip the hw field updation step */
   1013             if ((0 == field_action_set) ||
   1014                 (0 == action_set_ptr[field_action_set].size)) {
   1015                 continue;
   1016             } else {
   1017                if (aset_cnt[field_action_set] ==0) {
   1018                    if (1 == multi_mode) {
   1019                        /* check the color dependency of aset */
   1020                        /* always 1st action profile will hold color dependent asets */
   1021                        if (1 == action_set_ptr[field_action_set].is_color_dependent) {
   1022                            soc_mem_field32_set(unit, mem, act_prof_entry[0],
   1023                                  action_set_ptr[field_action_set].hw_field, 1);
   1024                        } else {
   1025                            soc_mem_field32_set(unit, mem, act_prof_entry[1],
   1026                                action_set_ptr[field_action_set].hw_field, 1);
   1027                        }
   1028                    } else {
   1029                        soc_mem_field32_set(unit, mem, act_prof_entry[0],
   1030                            action_set_ptr[field_action_set].hw_field, 1);
   1031                    }
   1032 
   1033                    aset_key_size +=
   1034                               action_set_ptr[field_action_set].size;
   1035                    aset_cnt[field_action_set]++;
   1036                }
   1037             }
   1038         }
   1039     }
   1040     /* Set CosorIntPriSet in action profile mem and
   1041        update key size if prioPktAndInt* actions are
   1042        present in current group's Aset */
   1043     if (1 == setChangeCosOrIntPriSet) {
   1044         if (0 == aset_cnt[_FieldActionChangeCosOrIntPriSet]) {
   1045            aset_key_size +=
   1046                    action_set_ptr[_FieldActionChangeCosOrIntPriSet].size;
   1047            soc_mem_field32_set(unit, mem, act_prof_entry[0],
   1048                 action_set_ptr[_FieldActionChangeCosOrIntPriSet].hw_field, 1);
   1049         }
   1050     }
   1051     /* Check if L3SW/Redirect action is set.
   1052      * If yes then reserve 1 bit for Green To Pid. */
   1053     if (aset_cnt[_FieldActionL3SwChangeL2Set] ||
   1054         aset_cnt[_FieldActionRedirectSet]) {
   1055         aset_key_size +=
   1056                    action_set_ptr[_FieldActionGreenToPidSet].size;
   1057         soc_mem_field32_set(unit, mem, act_prof_entry[0],
   1058              action_set_ptr[_FieldActionGreenToPidSet].hw_field , 1);
   1059     }
   1060 
   1061     /* Update Aset size in group's structure */
   1062     fsm_ptr->aset_size = aset_key_size;
   1063 
   1064     /* for single wide group, throw e-resource error
   1065      * if the aset size is more than 181b */
   1066     if ((fg->stage_id == _BCM_FIELD_STAGE_INGRESS) &&
   1067         (((fsm_ptr->aset_size > _FP_ASET_DATA_SIZE_FOR_POLICY_NARROW)
   1068         && (fsm_ptr->mode == bcmFieldGroupModeSingle))
   1069         || ((fsm_ptr->aset_size > _FP_ASET_DATA_SIZE_FOR_POLICY_WIDE) &&
   1070          (fsm_ptr->mode == bcmFieldGroupModeIntraSliceDouble)))) {
   1071         /* ADD error msg here */
   1072         LOG_ERROR(BSL_LS_BCM_FP,
   1073              (BSL_META_U(unit, "FP(unit %d) Error: Aset size =%d is not"
   1074              "supported in this group mode.\n"),
   1075              unit, fsm_ptr->aset_size));
   1076 
   1077         fsm_ptr->rv = (BCM_E_CONFIG);
   1078         goto clean_up;
   1079     }
   1080 
   1081     entries[0] = act_prof_entry[0];
   1082     /* Add Entries To Action Profile Table In Hardware. */
   1083     fsm_ptr->rv = soc_profile_mem_add(unit,
   1084                              &stage_fc->action_profile[fg->instance],
   1085                              entries, 1, &action_profile_idx[0]);
   1086     if (BCM_FAILURE(fsm_ptr->rv)) {
   1087         goto clean_up;
   1088     }
   1089 
   1090     fg->action_profile_idx[0] = action_profile_idx[0];
   1091 
   1092     if (1 == multi_mode) {
   1093         entries[0] = act_prof_entry[1];
   1094         /* Add Entries To Action Profile Table In Hardware. */
   1095         fsm_ptr->rv = soc_profile_mem_add(unit,
   1096                              &stage_fc->action_profile[fg->instance],
   1097                              entries, 1, &action_profile_idx[1]);
   1098         fg->action_profile_idx[1] = action_profile_idx[1];
   1099     }
   1100 
   1101     LOG_VERBOSE(BSL_LS_BCM_FP,(BSL_META_U(unit,
   1102             "VERB: groups aset size %d \n\r"),
   1103              fsm_ptr->aset_size));
   1104 
   1105     clean_up:
   1106     fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_SEL_CODES_GET;
   1107     return (BCM_E_NONE);
   1108 }
   1109 
   1110 /*
   1111  * Function:
   1112  *     _field_th_group_add_qset_update
   1113  * Purpose:
   1114  *     Update application requested qset with internal qualifiers.
   1115  * Parameters:
   1116  *     unit     - (IN)     BCM device number.
   1117  *     fsm_ptr  - (IN/OUT) State machine tracking structure.
   1118  * Returns:
   1119  *     BCM_E_XXX
   1120  */
   1121 STATIC int
   1122 _field_th_group_add_qset_update(int unit, _field_group_add_fsm_t *fsm_ptr)
   1123 {
   1124     _field_group_t *fg; /* Field Group structure pointer. */
   1125 
   1126     /* Input parameters check. */
   1127     if (NULL == fsm_ptr) {
   1128         return (BCM_E_PARAM);
   1129     }
   1130 
   1131     if (NULL == fsm_ptr->fg) {
   1132         fsm_ptr->rv = (BCM_E_PARAM);
   1133         fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   1134         return BCM_E_NONE;
   1135     }
   1136 
   1137     /* Get field group structure. */
   1138     fg = fsm_ptr->fg;
   1139 
   1140     /* Save current state as the previous state. */
   1141     fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state;
   1142 
   1143     /* InPorts Qualifier is not supported in TD3. */
   1144     if (soc_feature(unit, soc_feature_ifp_no_inports_support) &&
   1145         BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyInPorts)) {
   1146           LOG_WARN(BSL_LS_BCM_FP, (BSL_META_U(unit,
   1147               "InPorts Qualifier is not supported.\n\r")));
   1148           fsm_ptr->rv = (BCM_E_PARAM);
   1149           fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   1150           return BCM_E_NONE;
   1151     }
   1152 
   1153 #if defined(BCM_HELIX5_SUPPORT)
   1154     if (soc_feature(unit, soc_feature_flex_flowtracker_ver_1)) {
   1155         if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyFlowtrackerCheck) &&
   1156             (0 == BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyFlowtrackerGroupId))) {
   1157            LOG_ERROR(BSL_LS_BCM_FP,
   1158                       (BSL_META_U(unit,
   1159                       "(unit %d) Error: Qualifier FlowtrackerCheck needs "
   1160                       " to be used qualifier FlowtrackerGroupId"),
   1161                       unit));
   1162            fsm_ptr->rv = BCM_E_CONFIG;
   1163            fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   1164            return BCM_E_NONE;
   1165         }
   1166     }
   1167 #endif
   1168     /*
   1169      * In-case of Atomic update, InPorts qualifier is not supported
   1170      * in Global mode.
   1171      */
   1172     if ((_BCM_FIELD_STAGE_INGRESS == fg->stage_id) &&
   1173         (_BCM_FIELD_QSET_PBMP_TEST(fg->qset))) {
   1174        _field_stage_t *stage_fc;   /* Stage Field control structure. */
   1175 
   1176        BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fg->stage_id,
   1177                            &stage_fc));
   1178        if ((soc_property_get(unit, spn_FIELD_ATOMIC_UPDATE, FALSE) == TRUE) &&
   1179            (stage_fc->oper_mode == bcmFieldGroupOperModeGlobal)) {
   1180           LOG_WARN(BSL_LS_BCM_FP, (BSL_META_U(unit,
   1181               "InPorts Qualifier is not supported in Global mode"
   1182               " incase of atomic update.\n\r")));
   1183           fsm_ptr->rv = (BCM_E_PARAM);
   1184           fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   1185           return BCM_E_NONE;
   1186        }
   1187     }
   1188 
   1189     /*
   1190      * PBMP qualifiers conflict check.
   1191      * Group QSET should not contain more than one PBMP qualifier.
   1192      */
   1193     if (_BCM_FIELD_QSET_PBMP_TEST(fg->qset)) {
   1194        int pbm_qual;
   1195 
   1196        if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyInPorts)) {
   1197           pbm_qual = bcmFieldQualifyInPorts;
   1198           BCM_FIELD_QSET_REMOVE(fg->qset, pbm_qual);
   1199        } else if (BCM_FIELD_QSET_TEST(fg->qset,
   1200                                 bcmFieldQualifyDevicePortBitmap)) {
   1201           pbm_qual = bcmFieldQualifyDevicePortBitmap;
   1202           BCM_FIELD_QSET_REMOVE(fg->qset, pbm_qual);
   1203        } else if (BCM_FIELD_QSET_TEST(fg->qset,
   1204                                 bcmFieldQualifySystemPortBitmap)) {
   1205           pbm_qual = bcmFieldQualifySystemPortBitmap;
   1206           BCM_FIELD_QSET_REMOVE(fg->qset, pbm_qual);
   1207        } else {
   1208           pbm_qual = bcmFieldQualifySourceGportBitmap;
   1209           BCM_FIELD_QSET_REMOVE(fg->qset, pbm_qual);
   1210        }
   1211 
   1212        if (_BCM_FIELD_QSET_PBMP_TEST(fg->qset)) {
   1213           LOG_WARN(BSL_LS_BCM_FP, (BSL_META_U(unit,
   1214               "More than one Port Bitmap Qualifier is not supported in a"
   1215               " group.\n\r")));
   1216           fsm_ptr->rv = (BCM_E_PARAM);
   1217           fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   1218           BCM_FIELD_QSET_ADD(fg->qset, pbm_qual);
   1219           return BCM_E_NONE;
   1220        }
   1221 
   1222        BCM_FIELD_QSET_ADD(fg->qset, pbm_qual);
   1223 #if defined BCM_TRIDENT3_SUPPORT
   1224        if (soc_feature(unit, soc_feature_td3_style_fp) &&
   1225            (pbm_qual == bcmFieldQualifyInPorts)) {
   1226           BCM_FIELD_QSET_ADD(fg->qset, _bcmFieldQualifyInPorts_1);
   1227           BCM_FIELD_QSET_ADD(fg->qset, _bcmFieldQualifyInPorts_2);
   1228        }
   1229 #endif /* BCM_TRIDENT3_SUPPORT */
   1230     }
   1231 
   1232     /* All ingress devices implicitly have "bcmFieldQualifyStage" in QSETs. */
   1233     if ((_BCM_FIELD_STAGE_INGRESS == fg->stage_id) ||
   1234         (_BCM_FIELD_STAGE_EXACTMATCH == fg->stage_id) ||
   1235         (_BCM_FIELD_STAGE_FLOWTRACKER == fg->stage_id)) {
   1236         BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyStage);
   1237     }
   1238 
   1239     /* Automatically include "IpType" if QSET contains Ip4 or Ip6 qualifier. */
   1240     if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyIp4)
   1241         || BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyIp6)) {
   1242         BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyIpType);
   1243     }
   1244 
   1245     /* Include "LogicalTableId", if preselectors are associated to the group. */
   1246     if ((fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) &&
   1247         (fg->stage_id != _BCM_FIELD_STAGE_FLOWTRACKER)) {
   1248         BCM_FIELD_QSET_ADD(fg->qset, _bcmFieldQualifyPreLogicalTableId);
   1249     }
   1250 
   1251     if((fg->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER) &&
   1252         (soc_feature(unit, soc_feature_bscan_fae_port_flow_exclude))) {
   1253         BCM_FIELD_QSET_ADD(fg->qset, bcmFieldQualifyInPort);
   1254     }
   1255 
   1256     /* Update Exact Match Qset. */
   1257     if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyExactMatchHitStatus)) {
   1258         if ((!BCM_FIELD_QSET_TEST(fg->qset,
   1259                               _bcmFieldQualifyExactMatchHitStatusLookup0)) &&
   1260             (!BCM_FIELD_QSET_TEST(fg->qset,
   1261                               _bcmFieldQualifyExactMatchHitStatusLookup1))) {
   1262             BCM_FIELD_QSET_ADD(fg->qset,
   1263                               _bcmFieldQualifyExactMatchHitStatusLookup0);
   1264             if (!soc_feature(unit, soc_feature_th3_style_fp)) {
   1265                 BCM_FIELD_QSET_ADD(fg->qset,
   1266                                    _bcmFieldQualifyExactMatchHitStatusLookup1);
   1267             }
   1268         }
   1269     }
   1270 
   1271     if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyExactMatchGroupClassId)) {
   1272         if ((!BCM_FIELD_QSET_TEST(fg->qset,
   1273                         _bcmFieldQualifyExactMatchGroupClassIdLookup0)) &&
   1274             (!BCM_FIELD_QSET_TEST(fg->qset,
   1275                         _bcmFieldQualifyExactMatchGroupClassIdLookup1))) {
   1276             BCM_FIELD_QSET_ADD(fg->qset,
   1277                     _bcmFieldQualifyExactMatchGroupClassIdLookup0);
   1278             if (!soc_feature(unit, soc_feature_th3_style_fp)) {
   1279                 BCM_FIELD_QSET_ADD(fg->qset,
   1280                                    _bcmFieldQualifyExactMatchGroupClassIdLookup1);
   1281             }
   1282         }
   1283     }
   1284 
   1285     if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyExactMatchActionClassId)) {
   1286         if ((!BCM_FIELD_QSET_TEST(fg->qset,
   1287                        _bcmFieldQualifyExactMatchActionClassIdLookup0)) &&
   1288             (!BCM_FIELD_QSET_TEST(fg->qset,
   1289                        _bcmFieldQualifyExactMatchActionClassIdLookup1))) {
   1290             BCM_FIELD_QSET_ADD(fg->qset,
   1291                     _bcmFieldQualifyExactMatchActionClassIdLookup0);
   1292             if (!soc_feature(unit, soc_feature_th3_style_fp)) {
   1293                 BCM_FIELD_QSET_ADD(fg->qset,
   1294                                    _bcmFieldQualifyExactMatchActionClassIdLookup1);
   1295             }
   1296         }
   1297     }
   1298 
   1299 
   1300     /*
   1301      * NOTE:
   1302      * Since IPBM field is only optionally included in the IFP TCAM lookup key,
   1303      * InPorts qualifier is part of the QSET only when user explicitly adds it
   1304      * to the Group's QSET. SDK does not include it by default as its done
   1305      * in Pre-TH devices.
   1306      */
   1307 
   1308     /* Proceed to Extractor Mux selector selection. */
   1309     fsm_ptr->rv = (BCM_E_NONE);
   1310     fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_ASET_VALIDATE;
   1311 
   1312     return (BCM_E_NONE);
   1313 }
   1314 
   1315 /*
   1316  * Function:
   1317  *     _field_th_group_extractors_init
   1318  * Purpose:
   1319  *     Initialize field group extractor codes.
   1320  * Parameters:
   1321  *     unit      - (IN)     BCM unit number.
   1322  *     fg        - (IN/OUT) Field Group structure.
   1323  * Returns:
   1324  *     BCM_E_XXX
   1325  */
   1326 STATIC int
   1327 _field_th_group_extractors_init(int unit, _field_group_t *fg)
   1328 {
   1329     /* Input parameters check. */
   1330     if (NULL == fg) {
   1331         return (BCM_E_NONE);
   1332     }
   1333 
   1334     /*
   1335      * Initialize group extractor code flags based on group mode being
   1336      * created.
   1337      */
   1338     if (fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) {
   1339         fg->ext_codes[1].intraslice = _FP_EXT_SELCODE_DONT_USE;
   1340     } else if (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
   1341         fg->ext_codes[1].intraslice = _FP_EXT_SELCODE_DONT_USE;
   1342         fg->ext_codes[2].intraslice = _FP_EXT_SELCODE_DONT_USE;
   1343     }
   1344 
   1345     fg->ext_codes[0].secondary = _FP_EXT_SELCODE_DONT_USE;
   1346     if (fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) {
   1347         fg->ext_codes[1].secondary = _FP_EXT_SELCODE_DONT_USE;
   1348     } else if (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
   1349         fg->ext_codes[1].secondary = _FP_EXT_SELCODE_DONT_USE;
   1350         fg->ext_codes[2].secondary = _FP_EXT_SELCODE_DONT_USE;
   1351     }
   1352 
   1353     return (BCM_E_NONE);
   1354 }
   1355 
   1356 
   1357 int
   1358 _field_th_group_qual_info_get(int unit,
   1359                               _field_stage_t *stage_fc,
   1360                               _field_group_t *fg,
   1361                               bcm_field_qset_t *qset_req,
   1362                               bcmi_keygen_qual_info_t **qual_info_arr,
   1363                               uint16 *qual_info_count)
   1364 {
   1365     uint16 idx = 0;
   1366     uint16 qual_idx = 0;
   1367     _bcm_field_internal_qualify_t qual_id = _bcmFieldQualifyCount;
   1368     _field_hints_t *f_ht = NULL;
   1369     _field_hint_t *hint_node = NULL;
   1370 
   1371     /* Input parameters check. */
   1372     if (NULL == qual_info_arr || NULL == qset_req || NULL == fg ||
   1373         NULL == qual_info_count || NULL == stage_fc) {
   1374         return (BCM_E_PARAM);
   1375     }
   1376 
   1377     SHR_BIT_ITER(qset_req->w, BCM_FIELD_QUALIFY_MAX, idx) {
   1378         if (stage_fc->qual_cfg_info_db->qual_cfg_info[idx] == NULL) {
   1379             continue;
   1380         }
   1381         (*qual_info_count)++;
   1382     }
   1383 
   1384     /* If No valid qualifiers, return */
   1385     if ((*qual_info_count) == 0) {
   1386         *qual_info_arr = NULL;
   1387         return (BCM_E_NONE);
   1388     }
   1389 
   1390     _FP_XGS3_ALLOC((*qual_info_arr),
   1391                    sizeof(bcmi_keygen_qual_info_t) * (*qual_info_count),
   1392                    "Keygen Qualifier Information");
   1393     SHR_BIT_ITER(qset_req->w, BCM_FIELD_QUALIFY_MAX, idx) {
   1394         if (stage_fc->qual_cfg_info_db->qual_cfg_info[idx] == NULL) {
   1395             continue;
   1396         }
   1397         (*qual_info_arr)[qual_idx].qual_id = idx;
   1398         qual_idx++;
   1399     }
   1400 
   1401     if (!fg->hintid) {
   1402         return BCM_E_NONE;
   1403     }
   1404 
   1405     BCM_IF_ERROR_RETURN(_field_hints_control_get(unit, fg->hintid, &f_ht));
   1406 
   1407     for (qual_idx = 0; qual_idx < *qual_info_count; qual_idx++) {
   1408         qual_id = (*qual_info_arr)[qual_idx].qual_id;
   1409         if (NULL != f_ht) {
   1410             if (NULL != f_ht->hints) {
   1411                 /* Go through all hints in HintId and get the bit map of
   1412                  * qualifers with hints.
   1413                  */
   1414                 hint_node = f_ht->hints;
   1415                 while (NULL != hint_node) {
   1416                     if (bcmFieldQualifyUdf != hint_node->hint->qual) {
   1417 #if defined(BCM_HELIX5_SUPPORT)
   1418                         if ((bcmFieldHintTypeExtraction == hint_node->hint->hint_type) &&
   1419                                 (qual_id == (_bcm_field_internal_qualify_t) hint_node->hint->qual) &&
   1420                                 ((qual_id == (_bcm_field_internal_qualify_t) bcmFieldQualifyDosAttackEvents) ||
   1421                                  (qual_id == (_bcm_field_internal_qualify_t) bcmFieldQualifyInnerDosAttackEvents))) {
   1422                             BCM_IF_ERROR_RETURN(
   1423                                     _bcm_field_hx5_dosattack_event_qual_bitmap(unit,
   1424                                         hint_node, &(*qual_info_arr)[qual_idx]));
   1425                             hint_node = hint_node->next;
   1426                             continue;
   1427                         }
   1428 #endif
   1429                         if (bcmFieldHintTypeExtraction == hint_node->hint->hint_type &&
   1430                                 (qual_id == (_bcm_field_internal_qualify_t)hint_node->hint->qual)) {
   1431                             SHR_BITSET_RANGE((*qual_info_arr)[qual_idx].bitmap,
   1432                                     hint_node->hint->start_bit,
   1433                                     (hint_node->hint->end_bit -
   1434                                      hint_node->hint->start_bit + 1));
   1435                             (*qual_info_arr)[qual_idx].partial = TRUE;
   1436                         }
   1437                         hint_node = hint_node->next;
   1438                     } else {
   1439                         if ((bcmFieldHintTypeExtraction == hint_node->hint->hint_type) &&
   1440                                 (_FIELD_IS_INTERNAL_UDF_QUAL(qual_id))) {
   1441                             BCM_IF_ERROR_RETURN(_bcm_th_qual_hint_bmp_get(unit,
   1442                                         (int)qual_id, 0, hint_node,
   1443                                         (*qual_info_arr)[qual_idx].bitmap, 1,
   1444                                         qset_req, &(*qual_info_arr)[qual_idx]));
   1445                         }
   1446                         hint_node = hint_node->next;
   1447                     }
   1448                 }
   1449             }
   1450         }
   1451     }
   1452 
   1453     for (qual_idx = 0; qual_idx < *qual_info_count; qual_idx++) {
   1454         qual_id = (*qual_info_arr)[qual_idx].qual_id;
   1455         if (_FIELD_IS_INTERNAL_UDF_QUAL(qual_id)) {
   1456             if((TRUE == (*qual_info_arr)[qual_idx].partial)
   1457                     && (0 == (*qual_info_arr)[qual_idx].bitmap[0])) {
   1458                 SHR_BITCLR(qset_req->w, qual_id);
   1459             }
   1460         }
   1461     }
   1462     return BCM_E_NONE;
   1463 }
   1464 
   1465 STATIC int
   1466 _field_th_group_keygen_oper_insert(int unit,
   1467                                    _field_group_t *fg,
   1468                                    bcmi_keygen_oper_t *keygen_oper)
   1469 {
   1470     int rv = BCM_E_NONE;
   1471     uint8 part = 0;
   1472     uint8 gran = 0;
   1473     uint8 level = 0;
   1474     uint8 ctrl_sel_val = 0;
   1475     int parts_count = 0;
   1476     uint16 ext_num = 0;
   1477     uint16 ext_code_idx = 0;
   1478     uint16 qual_idx = 0;
   1479     uint16 offset = 0;
   1480     uint16 num_offsets = 0;
   1481     _field_ext_sel_t *grp_ext_code = NULL;
   1482     _bcm_field_group_qual_t *group_qual = NULL;
   1483     bcmi_keygen_qual_offset_info_t *qual_offset_info = NULL;
   1484     bcmi_keygen_ext_ctrl_sel_info_t *keygen_ext_code = NULL;
   1485 
   1486     /* Get number of entry parts based on the field group flags. */
   1487     BCM_IF_ERROR_RETURN(
   1488         _bcm_field_th_entry_tcam_parts_count(unit, fg->flags, &parts_count));
   1489 
   1490     for (part = 0; part < parts_count; part++) {
   1491         if (keygen_oper->qual_offset_info == NULL) {
   1492             break;
   1493         }
   1494         group_qual = &(fg->qual_arr[0][part]);
   1495         qual_offset_info = &(keygen_oper->qual_offset_info[part]);
   1496         group_qual->size = qual_offset_info->size;
   1497         /* Alloc larger mem since _bcmFieldInternalQualQid is wrongly set to 4.*/
   1498         _FP_XGS3_ALLOC(group_qual->qid_arr,
   1499                        qual_offset_info->size * sizeof(uint32),
   1500                        "Group Qualifer Information");
   1501         _FP_XGS3_ALLOC(group_qual->offset_arr,
   1502                        qual_offset_info->size * sizeof(_bcm_field_qual_offset_t),
   1503                        "Group Qualifer Offset Information");
   1504         for (qual_idx = 0; qual_idx < qual_offset_info->size; qual_idx++) {
   1505             group_qual->qid_arr[qual_idx] =
   1506                 qual_offset_info->qid_arr[qual_idx];
   1507             group_qual->offset_arr[qual_idx].field = KEYf;
   1508             num_offsets = 0;
   1509             for (offset = 0; offset < BCMI_KEYGEN_QUAL_OFFSETS_MAX; offset++) {
   1510                  if (!qual_offset_info->offset_arr[qual_idx].width[offset]) {
   1511                      continue;
   1512                  }
   1513                  group_qual->offset_arr[qual_idx].offset[offset] =
   1514                      qual_offset_info->offset_arr[qual_idx].offset[offset];
   1515                  group_qual->offset_arr[qual_idx].width[offset] =
   1516                      qual_offset_info->offset_arr[qual_idx].width[offset];
   1517                  num_offsets++;
   1518                  if (num_offsets ==
   1519                      qual_offset_info->offset_arr[qual_idx].num_offsets) {
   1520                      break;
   1521                  }
   1522             }
   1523             group_qual->offset_arr[qual_idx].num_offsets = (offset + 1);
   1524         }
   1525     }
   1526 
   1527     for (ext_code_idx = 0;
   1528         ext_code_idx < keygen_oper->ext_ctrl_sel_info_count;
   1529         ext_code_idx++) {
   1530         keygen_ext_code = &(keygen_oper->ext_ctrl_sel_info[ext_code_idx]);
   1531         part = keygen_ext_code->part;
   1532         gran = keygen_ext_code->gran;
   1533         level = keygen_ext_code->level;
   1534         ext_num = keygen_ext_code->ext_num;
   1535         ctrl_sel_val = keygen_ext_code->ctrl_sel_val;
   1536         grp_ext_code = &(fg->ext_codes[part]);
   1537         if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER) {
   1538             if (level == 1) {
   1539                 if (gran == 32) {
   1540                     grp_ext_code->l1_e32_sel[ext_num] = ctrl_sel_val;
   1541                 } else if (gran == 16) {
   1542                     grp_ext_code->l1_e16_sel[ext_num] = ctrl_sel_val;
   1543                 } else if (gran == 8) {
   1544                     grp_ext_code->l1_e8_sel[ext_num] = ctrl_sel_val;
   1545                 } else if (gran == 4) {
   1546                     grp_ext_code->l1_e4_sel[ext_num] = ctrl_sel_val;
   1547                 } else if (gran == 2) {
   1548                     grp_ext_code->l1_e2_sel[ext_num] = ctrl_sel_val;
   1549                 } else {
   1550                     rv = BCM_E_INTERNAL;
   1551                     goto cleanup;
   1552                 }
   1553             } else if (level == 2) {
   1554                 if (gran == 16) {
   1555                     grp_ext_code->l2_e16_sel[ext_num] = ctrl_sel_val;
   1556                 }
   1557 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1558                 else if (gran == 4) {
   1559                     if (SOC_IS_TOMAHAWK3(unit)) {
   1560                         grp_ext_code->l2_e4_sel[ext_num] = ctrl_sel_val;
   1561                     } else {
   1562                         rv = BCM_E_INTERNAL;
   1563                         goto cleanup;
   1564                     }
   1565                 } else if (gran == 2) {
   1566                     if (SOC_IS_TOMAHAWK3(unit)) {
   1567                         grp_ext_code->l2_e2_sel[ext_num] = ctrl_sel_val;
   1568                     } else {
   1569                         rv = BCM_E_INTERNAL;
   1570                         goto cleanup;
   1571                     }
   1572                 } else if (gran == 1) {
   1573                     if (SOC_IS_TOMAHAWK3(unit)) {
   1574                         grp_ext_code->l2_e1_sel[ext_num] = ctrl_sel_val;
   1575                     } else {
   1576                         rv = BCM_E_INTERNAL;
   1577                         goto cleanup;
   1578                     }
   1579                 }
   1580 #endif
   1581                 else {
   1582                     rv = BCM_E_INTERNAL;
   1583                     goto cleanup;
   1584                 }
   1585             } else if (level == 3) {
   1586                 if (gran == 4) {
   1587                     grp_ext_code->l3_e4_sel[ext_num] = ctrl_sel_val;
   1588                 } else if (gran == 2) {
   1589                     grp_ext_code->l3_e2_sel[ext_num] = ctrl_sel_val;
   1590                 } else if (gran == 1) {
   1591                     grp_ext_code->l3_e1_sel[ext_num] = ctrl_sel_val;
   1592                 } else {
   1593                     rv = BCM_E_INTERNAL;
   1594                     goto cleanup;
   1595                 }
   1596             } else {
   1597                 rv = BCM_E_INTERNAL;
   1598                 goto cleanup;
   1599             }
   1600         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_AUX_TAG_A) {
   1601             grp_ext_code->aux_tag_a_sel = keygen_ext_code->ctrl_sel_val;
   1602         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_AUX_TAG_B) {
   1603             grp_ext_code->aux_tag_b_sel = keygen_ext_code->ctrl_sel_val;
   1604         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_AUX_TAG_C) {
   1605             grp_ext_code->aux_tag_c_sel = keygen_ext_code->ctrl_sel_val;
   1606         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_AUX_TAG_D) {
   1607             grp_ext_code->aux_tag_d_sel = keygen_ext_code->ctrl_sel_val;
   1608         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_TCP_FN) {
   1609             grp_ext_code->tcp_fn_sel = keygen_ext_code->ctrl_sel_val;
   1610         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_TOS_FN) {
   1611             grp_ext_code->tos_fn_sel = keygen_ext_code->ctrl_sel_val;
   1612         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_TTL_FN) {
   1613             grp_ext_code->ttl_fn_sel = keygen_ext_code->ctrl_sel_val;
   1614         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_CLASSID_A) {
   1615             grp_ext_code->class_id_cont_a_sel = keygen_ext_code->ctrl_sel_val;
   1616         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_CLASSID_B) {
   1617             grp_ext_code->class_id_cont_b_sel = keygen_ext_code->ctrl_sel_val;
   1618         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_CLASSID_C) {
   1619             grp_ext_code->class_id_cont_c_sel = keygen_ext_code->ctrl_sel_val;
   1620         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_CLASSID_D) {
   1621             grp_ext_code->class_id_cont_d_sel = keygen_ext_code->ctrl_sel_val;
   1622         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_SRC_A) {
   1623             grp_ext_code->src_cont_a_sel = keygen_ext_code->ctrl_sel_val;
   1624         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_SRC_B) {
   1625             grp_ext_code->src_cont_b_sel = keygen_ext_code->ctrl_sel_val;
   1626         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_DST_A) {
   1627             grp_ext_code->dst_cont_a_sel = keygen_ext_code->ctrl_sel_val;
   1628         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_DST_B) {
   1629             grp_ext_code->dst_cont_b_sel = keygen_ext_code->ctrl_sel_val;
   1630         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_SRC_DST_0) {
   1631             grp_ext_code->src_dest_cont_0_sel = keygen_ext_code->ctrl_sel_val;
   1632         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_SRC_DST_1) {
   1633             grp_ext_code->src_dest_cont_1_sel = keygen_ext_code->ctrl_sel_val;
   1634         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_IPBM_PRESENT) {
   1635             grp_ext_code->ipbm_present = 1;
   1636             grp_ext_code->ipbm_source = keygen_ext_code->ctrl_sel_val;
   1637         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_L3_L4_NORM) {
   1638             grp_ext_code->normalize_l3_l4_sel = keygen_ext_code->ctrl_sel_val;
   1639         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_MAC_NORM) {
   1640             grp_ext_code->normalize_mac_sel = keygen_ext_code->ctrl_sel_val;
   1641         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_UDF) {
   1642             grp_ext_code->udf_sel = keygen_ext_code->ctrl_sel_val;
   1643         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_PMUX) {
   1644             grp_ext_code->pmux_sel[ctrl_sel_val] = 1;
   1645         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_ALT_TTL_FN) {
   1646             grp_ext_code->alt_ttl_fn_sel = keygen_ext_code->ctrl_sel_val;
   1647         } else if (keygen_ext_code->ctrl_sel == BCMI_KEYGEN_EXT_CTRL_SEL_LTID) {
   1648             continue;
   1649         } else {
   1650             rv = BCM_E_INTERNAL;
   1651             goto cleanup;
   1652         }
   1653     }
   1654 
   1655     for (part = 0; part < parts_count; part++) {
   1656         fg->ext_codes[part].normalize_l3_l4_sel =
   1657             BCM_FIELD_QSET_TEST(fg->qset,
   1658                 bcmFieldQualifyNormalizeIpAddrs) ? 1 : 0;
   1659         fg->ext_codes[part].normalize_mac_sel =
   1660             BCM_FIELD_QSET_TEST(fg->qset,
   1661                 bcmFieldQualifyNormalizeMacAddrs) ? 1 : 0;
   1662     }
   1663 
   1664 
   1665     if ((BCM_FIELD_QSET_TEST(fg->qset,
   1666         _bcmFieldQualifyPreLogicalTableId)) &&
   1667         ((fg->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) ||
   1668          (fg->stage_id == _BCM_FIELD_STAGE_INGRESS))) {
   1669         if (SOC_IS_TOMAHAWK(unit)
   1670         #if defined(BCM_TOMAHAWK2_SUPPORT)
   1671              || SOC_IS_TOMAHAWK2(unit)
   1672         #endif
   1673         #if defined(BCM_TRIDENT3_SUPPORT)
   1674             || (soc_feature(unit, soc_feature_td3_style_fp))
   1675         #endif
   1676             ) {
   1677             fg->ext_codes[0].l1_e8_sel[6]=5;
   1678             fg->ext_codes[0].l3_e4_sel[20]=36;
   1679             fg->ext_codes[0].l3_e2_sel[1]=74;
   1680         }
   1681 #if defined(BCM_TOMAHAWK3_SUPPORT)
   1682         else if (SOC_IS_TOMAHAWK3(unit)) {
   1683             fg->ext_codes[0].l1_e8_sel[5]=12;
   1684             fg->ext_codes[0].l2_e4_sel[11]=46;
   1685         }
   1686 #endif
   1687     }
   1688 
   1689     return rv;
   1690 
   1691 cleanup:
   1692     for (part = 0; part < parts_count; part++) {
   1693         group_qual = &(fg->qual_arr[0][part]);
   1694         if (group_qual->qid_arr != NULL) {
   1695             sal_free(group_qual->qid_arr);
   1696         }
   1697         if (group_qual->offset_arr != NULL) {
   1698             sal_free(group_qual->offset_arr);
   1699         }
   1700     }
   1701     return rv;
   1702 }
   1703 
   1704 STATIC int
   1705 _field_th_keygen_ext_ctrl_info_count_get(int unit,
   1706                                   _field_group_t *fg,
   1707                                   uint16 *ext_ctrl_info_count)
   1708 {
   1709     uint8 part = 0;
   1710     int parts_count = 0;
   1711     uint8 idx = 0;
   1712 
   1713     /* Input parameters check. */
   1714     if (NULL == fg || NULL == ext_ctrl_info_count) {
   1715         return (BCM_E_PARAM);
   1716     }
   1717 
   1718     /* Get number of entry parts based on the field group flags. */
   1719     BCM_IF_ERROR_RETURN(
   1720         _bcm_field_th_entry_tcam_parts_count(unit, fg->flags, &parts_count));
   1721     *ext_ctrl_info_count = 0;
   1722     for (part = 0; part < parts_count; part++) {
   1723         if (fg->ext_codes[part].aux_tag_a_sel != -1) {
   1724             (*ext_ctrl_info_count)++;
   1725         }
   1726         if (fg->ext_codes[part].aux_tag_b_sel != -1) {
   1727             (*ext_ctrl_info_count)++;
   1728         }
   1729         if (fg->ext_codes[part].aux_tag_c_sel != -1) {
   1730             (*ext_ctrl_info_count)++;
   1731         }
   1732         if (fg->ext_codes[part].aux_tag_d_sel != -1) {
   1733             (*ext_ctrl_info_count)++;
   1734         }
   1735         if (fg->ext_codes[part].tcp_fn_sel != -1) {
   1736             (*ext_ctrl_info_count)++;
   1737         }
   1738         if (fg->ext_codes[part].ttl_fn_sel != -1) {
   1739             (*ext_ctrl_info_count)++;
   1740         }
   1741         if (fg->ext_codes[part].tos_fn_sel != -1) {
   1742             (*ext_ctrl_info_count)++;
   1743         }
   1744         if (fg->ext_codes[part].class_id_cont_a_sel != -1) {
   1745             (*ext_ctrl_info_count)++;
   1746         }
   1747         if (fg->ext_codes[part].class_id_cont_b_sel != -1) {
   1748             (*ext_ctrl_info_count)++;
   1749         }
   1750         if (fg->ext_codes[part].class_id_cont_c_sel != -1) {
   1751             (*ext_ctrl_info_count)++;
   1752         }
   1753         if (fg->ext_codes[part].class_id_cont_d_sel != -1) {
   1754             (*ext_ctrl_info_count)++;
   1755         }
   1756         if (fg->ext_codes[part].src_cont_a_sel != -1) {
   1757             (*ext_ctrl_info_count)++;
   1758         }
   1759         if (fg->ext_codes[part].src_cont_b_sel != -1) {
   1760             (*ext_ctrl_info_count)++;
   1761         }
   1762         if (fg->ext_codes[part].src_dest_cont_0_sel != -1) {
   1763             (*ext_ctrl_info_count)++;
   1764         }
   1765         if (fg->ext_codes[part].src_dest_cont_1_sel != -1) {
   1766             (*ext_ctrl_info_count)++;
   1767         }
   1768         if (fg->ext_codes[part].ipbm_present != -1) {
   1769             (*ext_ctrl_info_count)++;
   1770         }
   1771         if (fg->ext_codes[part].normalize_l3_l4_sel != -1) {
   1772             (*ext_ctrl_info_count)++;
   1773         }
   1774         if (fg->ext_codes[part].normalize_mac_sel != -1) {
   1775             (*ext_ctrl_info_count)++;
   1776         }
   1777         for (idx = 0; idx < 15; idx++) {
   1778             if (fg->ext_codes[part].pmux_sel[idx] != -1) {
   1779                 (*ext_ctrl_info_count)++;
   1780             }
   1781         }
   1782         for (idx = 0; idx < 4; idx++) {
   1783             if (fg->ext_codes[part].l1_e32_sel[idx] != -1) {
   1784                 (*ext_ctrl_info_count)++;
   1785             }
   1786         }
   1787         for (idx = 0; idx < 7; idx++) {
   1788             if (fg->ext_codes[part].l1_e16_sel[idx] != -1) {
   1789                 (*ext_ctrl_info_count)++;
   1790             }
   1791         }
   1792         for (idx = 0; idx < 7; idx++) {
   1793             if (fg->ext_codes[part].l1_e8_sel[idx] != -1) {
   1794                 (*ext_ctrl_info_count)++;
   1795             }
   1796         }
   1797         for (idx = 0; idx < 8; idx++) {
   1798             if (fg->ext_codes[part].l1_e4_sel[idx] != -1) {
   1799                 (*ext_ctrl_info_count)++;
   1800             }
   1801         }
   1802         for (idx = 0; idx < 8; idx++) {
   1803             if (fg->ext_codes[part].l1_e2_sel[idx] != -1) {
   1804                 (*ext_ctrl_info_count)++;
   1805             }
   1806         }
   1807         for (idx = 0; idx < 10; idx++) {
   1808             if (fg->ext_codes[part].l2_e16_sel[idx] != -1) {
   1809                 (*ext_ctrl_info_count)++;
   1810             }
   1811         }
   1812         for (idx = 0; idx < 16; idx++) {
   1813             if (fg->ext_codes[part].l2_e4_sel[idx] != -1) {
   1814                 (*ext_ctrl_info_count)++;
   1815             }
   1816         }
   1817         for (idx = 0; idx < 7; idx++) {
   1818             if (fg->ext_codes[part].l2_e2_sel[idx] != -1) {
   1819                 (*ext_ctrl_info_count)++;
   1820             }
   1821         }
   1822         for (idx = 0; idx < 2; idx++) {
   1823             if (fg->ext_codes[part].l2_e1_sel[idx] != -1) {
   1824                 (*ext_ctrl_info_count)++;
   1825             }
   1826         }
   1827         for (idx = 0; idx < 21; idx++) {
   1828             if (fg->ext_codes[part].l3_e4_sel[idx] != -1) {
   1829                 (*ext_ctrl_info_count)++;
   1830             }
   1831         }
   1832         for (idx = 0; idx < 5; idx++) {
   1833             if (fg->ext_codes[part].l3_e2_sel[idx] != -1) {
   1834                 (*ext_ctrl_info_count)++;
   1835             }
   1836         }
   1837         for (idx = 0; idx < 2; idx++) {
   1838             if (fg->ext_codes[part].l3_e1_sel[idx] != -1) {
   1839                 (*ext_ctrl_info_count)++;
   1840             }
   1841         }
   1842         if (fg->ext_codes[part].alt_ttl_fn_sel != -1) {
   1843             (*ext_ctrl_info_count)++;
   1844         }
   1845     }
   1846 
   1847     return BCM_E_NONE;
   1848 }
   1849 
   1850 STATIC int
   1851 _field_th_keygen_ext_ctrl_info_get(int unit,
   1852                                _field_group_t *fg,
   1853                                bcmi_keygen_cfg_t *keygen_cfg)
   1854 {
   1855     uint8 part = 0;
   1856     int parts_count = 0;
   1857     uint16 idx = 0;
   1858     uint16 ext_idx = 0;
   1859     uint16 ext_ctrl_info_count = 0;
   1860     bcmi_keygen_ext_ctrl_sel_info_t *ext_ctrl_info = NULL;
   1861 
   1862     /* Input parameters check. */
   1863     if (NULL == fg || NULL == keygen_cfg) {
   1864         return (BCM_E_PARAM);
   1865     }
   1866 
   1867     /* Get number of entry parts based on the field group flags. */
   1868     BCM_IF_ERROR_RETURN(
   1869         _bcm_field_th_entry_tcam_parts_count(unit, fg->flags, &parts_count));
   1870     BCM_IF_ERROR_RETURN(
   1871         _field_th_keygen_ext_ctrl_info_count_get(unit, fg, &ext_ctrl_info_count));
   1872     if (ext_ctrl_info_count == 0) {
   1873         return BCM_E_NONE;
   1874     }
   1875     _FP_XGS3_ALLOC(ext_ctrl_info,
   1876              ext_ctrl_info_count * sizeof(bcmi_keygen_ext_ctrl_sel_info_t),
   1877              "Keygen Extractor control information");
   1878     if (ext_ctrl_info == NULL) {
   1879         return BCM_E_MEMORY;
   1880     }
   1881     sal_memset(ext_ctrl_info, 0,
   1882         ext_ctrl_info_count * sizeof(bcmi_keygen_ext_ctrl_sel_info_t));
   1883     keygen_cfg->ext_ctrl_sel_info_count = ext_ctrl_info_count;
   1884     keygen_cfg->ext_ctrl_sel_info = ext_ctrl_info;
   1885     for (part = 0; part < parts_count; part++) {
   1886         if (fg->ext_codes[part].aux_tag_a_sel != -1) {
   1887             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_AUX_TAG_A;
   1888             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].aux_tag_a_sel;
   1889             ext_ctrl_info[idx].part = part;
   1890             idx++;
   1891         }
   1892         if (fg->ext_codes[part].aux_tag_b_sel != -1) {
   1893             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_AUX_TAG_B;
   1894             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].aux_tag_b_sel;
   1895             ext_ctrl_info[idx].part = part;
   1896             idx++;
   1897         }
   1898         if (fg->ext_codes[part].aux_tag_c_sel != -1) {
   1899             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_AUX_TAG_C;
   1900             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].aux_tag_c_sel;
   1901             ext_ctrl_info[idx].part = part;
   1902             idx++;
   1903         }
   1904         if (fg->ext_codes[part].aux_tag_d_sel != -1) {
   1905             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_AUX_TAG_D;
   1906             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].aux_tag_d_sel;
   1907             ext_ctrl_info[idx].part = part;
   1908             idx++;
   1909         }
   1910         if (fg->ext_codes[part].tcp_fn_sel != -1) {
   1911             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_TCP_FN;
   1912             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].tcp_fn_sel;
   1913             ext_ctrl_info[idx].part = part;
   1914             idx++;
   1915         }
   1916         if (fg->ext_codes[part].ttl_fn_sel != -1) {
   1917             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_TTL_FN;
   1918             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].ttl_fn_sel;
   1919             ext_ctrl_info[idx].part = part;
   1920             idx++;
   1921         }
   1922         if (fg->ext_codes[part].tos_fn_sel != -1) {
   1923             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_TOS_FN;
   1924             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].tos_fn_sel;
   1925             ext_ctrl_info[idx].part = part;
   1926             idx++;
   1927         }
   1928         if (fg->ext_codes[part].class_id_cont_a_sel != -1) {
   1929             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_CLASSID_A;
   1930             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].class_id_cont_a_sel;
   1931             ext_ctrl_info[idx].part = part;
   1932             idx++;
   1933         }
   1934         if (fg->ext_codes[part].class_id_cont_b_sel != -1) {
   1935             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_CLASSID_B;
   1936             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].class_id_cont_b_sel;
   1937             ext_ctrl_info[idx].part = part;
   1938             idx++;
   1939         }
   1940         if (fg->ext_codes[part].class_id_cont_c_sel != -1) {
   1941             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_CLASSID_C;
   1942             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].class_id_cont_c_sel;
   1943             ext_ctrl_info[idx].part = part;
   1944             idx++;
   1945         }
   1946         if (fg->ext_codes[part].class_id_cont_d_sel != -1) {
   1947             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_CLASSID_D;
   1948             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].class_id_cont_d_sel;
   1949             ext_ctrl_info[idx].part = part;
   1950             idx++;
   1951         }
   1952         if (fg->ext_codes[part].src_cont_a_sel != -1) {
   1953             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_SRC_A;
   1954             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].src_cont_a_sel;
   1955             ext_ctrl_info[idx].part = part;
   1956             idx++;
   1957         }
   1958         if (fg->ext_codes[part].src_cont_b_sel != -1) {
   1959             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_SRC_B;
   1960             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].src_cont_b_sel;
   1961             ext_ctrl_info[idx].part = part;
   1962             idx++;
   1963         }
   1964         if (fg->ext_codes[part].src_dest_cont_0_sel != -1) {
   1965             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_SRC_DST_0;
   1966             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].src_dest_cont_0_sel;
   1967             ext_ctrl_info[idx].part = part;
   1968             idx++;
   1969         }
   1970         if (fg->ext_codes[part].src_dest_cont_1_sel != -1) {
   1971             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_SRC_DST_1;
   1972             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].src_dest_cont_1_sel;
   1973             ext_ctrl_info[idx].part = part;
   1974             idx++;
   1975         }
   1976         if (fg->ext_codes[part].ipbm_present == 1) {
   1977             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_IPBM_PRESENT;
   1978             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].ipbm_source;
   1979             ext_ctrl_info[idx].part = part;
   1980             idx++;
   1981         }
   1982         if (fg->ext_codes[part].normalize_l3_l4_sel == 1) {
   1983             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_L3_L4_NORM;
   1984             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].normalize_l3_l4_sel;
   1985             ext_ctrl_info[idx].part = part;
   1986             idx++;
   1987         }
   1988         if (fg->ext_codes[part].normalize_mac_sel == 1) {
   1989             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_MAC_NORM;
   1990             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].normalize_mac_sel;
   1991             ext_ctrl_info[idx].part = part;
   1992             idx++;
   1993         }
   1994         for (ext_idx = 0; ext_idx < 15; ext_idx++) {
   1995             if (fg->ext_codes[part].pmux_sel[ext_idx] != -1) {
   1996                 ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_PMUX;
   1997                 ext_ctrl_info[idx].ctrl_sel_val = ext_idx;
   1998                 ext_ctrl_info[idx].part = part;
   1999                 idx++;
   2000             }
   2001         }
   2002         for (ext_idx = 0; ext_idx < 4; ext_idx++) {
   2003             if (fg->ext_codes[part].l1_e32_sel[ext_idx] != -1) {
   2004                 ext_ctrl_info[idx].ctrl_sel =
   2005                                           BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER;
   2006                 ext_ctrl_info[idx].ctrl_sel_val =
   2007                                           fg->ext_codes[part].l1_e32_sel[ext_idx];
   2008                 ext_ctrl_info[idx].part = part;
   2009                 ext_ctrl_info[idx].level = 1;
   2010                 ext_ctrl_info[idx].gran = 32;
   2011                 ext_ctrl_info[idx].ext_num = ext_idx;
   2012                 idx++;
   2013             }
   2014         }
   2015         for (ext_idx = 0; ext_idx < 7; ext_idx++) {
   2016             if (fg->ext_codes[part].l1_e16_sel[ext_idx] != -1) {
   2017                 ext_ctrl_info[idx].ctrl_sel =
   2018                                           BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER;
   2019                 ext_ctrl_info[idx].ctrl_sel_val =
   2020                                           fg->ext_codes[part].l1_e16_sel[ext_idx];
   2021                 ext_ctrl_info[idx].part = part;
   2022                 ext_ctrl_info[idx].level = 1;
   2023                 ext_ctrl_info[idx].gran = 16;
   2024                 ext_ctrl_info[idx].ext_num = ext_idx;
   2025                 idx++;
   2026             }
   2027         }
   2028         for (ext_idx = 0; ext_idx < 7; ext_idx++) {
   2029             if (fg->ext_codes[part].l1_e8_sel[ext_idx] != -1) {
   2030                 ext_ctrl_info[idx].ctrl_sel =
   2031                                           BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER;
   2032                 ext_ctrl_info[idx].ctrl_sel_val =
   2033                                           fg->ext_codes[part].l1_e8_sel[ext_idx];
   2034                 ext_ctrl_info[idx].part = part;
   2035                 ext_ctrl_info[idx].level = 1;
   2036                 ext_ctrl_info[idx].gran = 8;
   2037                 ext_ctrl_info[idx].ext_num = ext_idx;
   2038                 idx++;
   2039             }
   2040         }
   2041         for (ext_idx = 0; ext_idx < 8; ext_idx++) {
   2042             if (fg->ext_codes[part].l1_e4_sel[ext_idx] != -1) {
   2043                 ext_ctrl_info[idx].ctrl_sel =
   2044                                           BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER;
   2045                 ext_ctrl_info[idx].ctrl_sel_val =
   2046                                           fg->ext_codes[part].l1_e4_sel[ext_idx];
   2047                 ext_ctrl_info[idx].part = part;
   2048                 ext_ctrl_info[idx].level = 1;
   2049                 ext_ctrl_info[idx].gran = 4;
   2050                 ext_ctrl_info[idx].ext_num = ext_idx;
   2051                 idx++;
   2052             }
   2053         }
   2054         for (ext_idx = 0; ext_idx < 8; ext_idx++) {
   2055             if (fg->ext_codes[part].l1_e2_sel[ext_idx] != -1) {
   2056                 ext_ctrl_info[idx].ctrl_sel =
   2057                                           BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER;
   2058                 ext_ctrl_info[idx].ctrl_sel_val =
   2059                                           fg->ext_codes[part].l1_e2_sel[ext_idx];
   2060                 ext_ctrl_info[idx].part = part;
   2061                 ext_ctrl_info[idx].level = 1;
   2062                 ext_ctrl_info[idx].gran = 2;
   2063                 ext_ctrl_info[idx].ext_num = ext_idx;
   2064                 idx++;
   2065             }
   2066         }
   2067         for (ext_idx = 0; ext_idx < 10; ext_idx++) {
   2068             if (fg->ext_codes[part].l2_e16_sel[ext_idx] != -1) {
   2069                 ext_ctrl_info[idx].ctrl_sel =
   2070                                           BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER;
   2071                 ext_ctrl_info[idx].ctrl_sel_val =
   2072                                           fg->ext_codes[part].l2_e16_sel[ext_idx];
   2073                 ext_ctrl_info[idx].part = part;
   2074                 ext_ctrl_info[idx].level = 2;
   2075                 ext_ctrl_info[idx].gran = 16;
   2076                 ext_ctrl_info[idx].ext_num = ext_idx;
   2077                 idx++;
   2078             }
   2079         }
   2080         for (ext_idx = 0; ext_idx < 16; ext_idx++) {
   2081             if (fg->ext_codes[part].l2_e4_sel[ext_idx] != -1) {
   2082                 ext_ctrl_info[idx].ctrl_sel =
   2083                                           BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER;
   2084                 ext_ctrl_info[idx].ctrl_sel_val =
   2085                                           fg->ext_codes[part].l2_e4_sel[ext_idx];
   2086                 ext_ctrl_info[idx].part = part;
   2087                 ext_ctrl_info[idx].level = 2;
   2088                 ext_ctrl_info[idx].gran = 4;
   2089                 ext_ctrl_info[idx].ext_num = ext_idx;
   2090                 idx++;
   2091             }
   2092         }
   2093         for (ext_idx = 0; ext_idx < 7; ext_idx++) {
   2094             if (fg->ext_codes[part].l2_e2_sel[ext_idx] != -1) {
   2095                 ext_ctrl_info[idx].ctrl_sel =
   2096                                           BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER;
   2097                 ext_ctrl_info[idx].ctrl_sel_val =
   2098                                           fg->ext_codes[part].l2_e2_sel[ext_idx];
   2099                 ext_ctrl_info[idx].part = part;
   2100                 ext_ctrl_info[idx].level = 2;
   2101                 ext_ctrl_info[idx].gran = 2;
   2102                 ext_ctrl_info[idx].ext_num = ext_idx;
   2103                 idx++;
   2104             }
   2105         }
   2106         for (ext_idx = 0; ext_idx < 2; ext_idx++) {
   2107             if (fg->ext_codes[part].l2_e1_sel[ext_idx] != -1) {
   2108                 ext_ctrl_info[idx].ctrl_sel =
   2109                                           BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER;
   2110                 ext_ctrl_info[idx].ctrl_sel_val =
   2111                                           fg->ext_codes[part].l2_e1_sel[ext_idx];
   2112                 ext_ctrl_info[idx].part = part;
   2113                 ext_ctrl_info[idx].level = 2;
   2114                 ext_ctrl_info[idx].gran = 1;
   2115                 ext_ctrl_info[idx].ext_num = ext_idx;
   2116                 idx++;
   2117             }
   2118         }
   2119         for (ext_idx = 0; ext_idx < 21; ext_idx++) {
   2120             if (fg->ext_codes[part].l3_e4_sel[ext_idx] != -1) {
   2121                 ext_ctrl_info[idx].ctrl_sel =
   2122                                           BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER;
   2123                 ext_ctrl_info[idx].ctrl_sel_val =
   2124                                           fg->ext_codes[part].l3_e4_sel[ext_idx];
   2125                 ext_ctrl_info[idx].part = part;
   2126                 ext_ctrl_info[idx].level = 3;
   2127                 ext_ctrl_info[idx].gran = 4;
   2128                 ext_ctrl_info[idx].ext_num = ext_idx;
   2129                 idx++;
   2130             }
   2131         }
   2132         for (ext_idx = 0; ext_idx < 5; ext_idx++) {
   2133             if (fg->ext_codes[part].l3_e2_sel[ext_idx] != -1) {
   2134                 ext_ctrl_info[idx].ctrl_sel =
   2135                                           BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER;
   2136                 ext_ctrl_info[idx].ctrl_sel_val =
   2137                                           fg->ext_codes[part].l3_e2_sel[ext_idx];
   2138                 ext_ctrl_info[idx].part = part;
   2139                 ext_ctrl_info[idx].level = 3;
   2140                 ext_ctrl_info[idx].gran = 2;
   2141                 ext_ctrl_info[idx].ext_num = ext_idx;
   2142                 idx++;
   2143             }
   2144         }
   2145         for (ext_idx = 0; ext_idx < 2; ext_idx++) {
   2146             if (fg->ext_codes[part].l3_e1_sel[ext_idx] != -1) {
   2147                 ext_ctrl_info[idx].ctrl_sel =
   2148                                           BCMI_KEYGEN_EXT_CTRL_SEL_MULTIPLEXER;
   2149                 ext_ctrl_info[idx].ctrl_sel_val =
   2150                                         fg->ext_codes[part].l3_e1_sel[ext_idx];
   2151                 ext_ctrl_info[idx].part = part;
   2152                 ext_ctrl_info[idx].level = 3;
   2153                 ext_ctrl_info[idx].gran = 1;
   2154                 ext_ctrl_info[idx].ext_num = ext_idx;
   2155                 idx++;
   2156             }
   2157         }
   2158         if (fg->ext_codes[part].alt_ttl_fn_sel != -1) {
   2159             ext_ctrl_info[idx].ctrl_sel = BCMI_KEYGEN_EXT_CTRL_SEL_ALT_TTL_FN;
   2160             ext_ctrl_info[idx].ctrl_sel_val = fg->ext_codes[part].alt_ttl_fn_sel;
   2161             ext_ctrl_info[idx].part = part;
   2162             idx++;
   2163         }
   2164     }
   2165     return BCM_E_NONE;
   2166 }
   2167 
   2168 #define IS_IBUS_CONT_QSET(_qset_) \
   2169             (BCM_FIELD_QSET_TEST(_qset_, bcmFieldQualifyIncomingOuterVlanId)) \
   2170 
   2171 /*
   2172  * Function:
   2173  *     _field_th_ingress_ext_code_get
   2174  * Purpose:
   2175  *     Finds extractor select encodings that will satisfy the
   2176  *     requested qualifier set (Qset).
   2177  * Parameters:
   2178  *     unit      - (IN)     BCM unit number.
   2179  *     stage_fc  - (IN)     Stage Field control structure.
   2180  *     qset_req  - (IN)     Client qualifier set.
   2181  *     fg        - (IN/OUT) Field group structure.
   2182  * Returns:
   2183  *     BCM_E_XXX
   2184  */
   2185 STATIC int
   2186 _field_th_ingress_ext_code_get(int unit, _field_group_add_fsm_t *fsm_ptr)
   2187 {
   2188     int rv = BCM_E_NONE;
   2189     int parts_count = 0;
   2190     uint16 rkey_size = 0;
   2191     uint16 qual_info_count = 0;
   2192     bcmi_keygen_mode_t keygen_mode;
   2193     bcmi_keygen_mode_t keygen_ext_mode;
   2194     bcmi_keygen_cfg_t keygen_cfg;
   2195     bcmi_keygen_oper_t keygen_oper;
   2196     bcmi_keygen_qual_info_t *qual_info_arr = NULL;
   2197     _field_group_t *fg;
   2198     _field_stage_t *stage_fc;
   2199     bcm_field_qset_t *qset_req;
   2200 #if defined (BCM_TRIDENT3_SUPPORT)
   2201     int ct = 0;
   2202     uint8 bkup_ct = 0;
   2203     uint8 num_qual_cfg_bkup[2] = {0};
   2204     bcm_field_qualify_t qual_bkup[2];
   2205     bcmi_keygen_qual_cfg_t *qual_cfg_arr_bkup[2] = {NULL};
   2206 #endif /* BCM_TRIDENT3_SUPPORT */
   2207 
   2208     /* Input parameters check. */
   2209     if (NULL == fsm_ptr) {
   2210         return (BCM_E_PARAM);
   2211     }
   2212 
   2213     fg = fsm_ptr->fg;
   2214     stage_fc = fsm_ptr->stage_fc;
   2215     qset_req = &(fg->qset);
   2216     /* Initialize group extractor codes based on group flags. */
   2217     rv = _field_th_group_extractors_init(unit, fg);
   2218     BCM_IF_ERROR_RETURN(rv);
   2219 
   2220     sal_memset(&keygen_cfg, 0, sizeof(bcmi_keygen_cfg_t));
   2221     sal_memset(&keygen_oper, 0, sizeof(bcmi_keygen_oper_t));
   2222 
   2223     /* Get number of entry parts based on the field group flags. */
   2224     BCM_IF_ERROR_RETURN(
   2225         _bcm_field_th_entry_tcam_parts_count(unit, fg->flags, &parts_count));
   2226 
   2227     if (soc_feature(unit, soc_feature_fp_ltid_match_all_parts) &&
   2228         (fg->stage_id == _BCM_FIELD_STAGE_INGRESS)) {
   2229        if (parts_count > 1) {
   2230            BCM_FIELD_QSET_ADD(fg->qset, _bcmFieldQualifyPreLogicalTableId1);
   2231            if (parts_count == 3) {
   2232                BCM_FIELD_QSET_ADD(fg->qset, _bcmFieldQualifyPreLogicalTableId2);
   2233            }
   2234        }
   2235     }
   2236 
   2237     rv = _field_th_group_qual_info_get(unit, stage_fc, fg, qset_req,
   2238                              &qual_info_arr, &qual_info_count);
   2239     BCM_IF_ERROR_RETURN(rv);
   2240 
   2241     if (fg->flags & _FP_GROUP_SPAN_SINGLE_SLICE &&
   2242         !(fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE)) {
   2243         keygen_mode = BCMI_KEYGEN_MODE_SINGLE;
   2244         keygen_ext_mode = BCMI_KEYGEN_MODE_DBLINTRA;
   2245     } else if (fg->flags & _FP_GROUP_SPAN_SINGLE_SLICE &&
   2246                fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) {
   2247         if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   2248             if (fg->em_mode == _FieldExactMatchMode160) {
   2249                 keygen_mode = BCMI_KEYGEN_MODE_SINGLE_ASET_NARROW;
   2250             } else if (fg->em_mode == _FieldExactMatchMode128) {
   2251                 keygen_mode = BCMI_KEYGEN_MODE_SINGLE_ASET_WIDE;
   2252             } else {
   2253                 rv = BCM_E_INTERNAL;
   2254                 goto cleanup;
   2255             }
   2256         } else {
   2257             keygen_mode = BCMI_KEYGEN_MODE_DBLINTRA;
   2258         }
   2259         keygen_ext_mode = BCMI_KEYGEN_MODE_DBLINTRA;
   2260     } else if (fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) {
   2261         keygen_mode = BCMI_KEYGEN_MODE_DBLINTER;
   2262         keygen_ext_mode = BCMI_KEYGEN_MODE_DBLINTER;
   2263     } else if (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
   2264         keygen_mode = BCMI_KEYGEN_MODE_TRIPLE;
   2265         keygen_ext_mode = BCMI_KEYGEN_MODE_TRIPLE;
   2266     } else {
   2267         rv = BCM_E_INTERNAL;
   2268         goto cleanup;
   2269     }
   2270 
   2271 #if defined (BCM_TRIDENT3_SUPPORT)
   2272     if (soc_feature(unit, soc_feature_td3_style_fp)) {
   2273        if (IS_IBUS_CONT_QSET(fsm_ptr->qset)) {
   2274           if (BCM_FIELD_QSET_TEST(fsm_ptr->qset, bcmFieldQualifyIncomingOuterVlanId)) {
   2275              qual_bkup[bkup_ct++] = bcmFieldQualifyIncomingOuterVlanId;
   2276           }
   2277 
   2278           for (ct = 0; ct < bkup_ct; ct++) {
   2279               num_qual_cfg_bkup[ct] =
   2280                 stage_fc->qual_cfg_info_db->qual_cfg_info[qual_bkup[ct]]->num_qual_cfg;
   2281               qual_cfg_arr_bkup[ct] =
   2282                 stage_fc->qual_cfg_info_db->qual_cfg_info[qual_bkup[ct]]->qual_cfg_arr;
   2283 
   2284               rv = _bcm_field_qual_cfg_info_db_update(unit, fsm_ptr->fg->instance,
   2285                                                       qual_bkup[ct], stage_fc);
   2286               if (BCM_FAILURE(rv)) {
   2287                  goto cleanup;
   2288               }
   2289           }
   2290        }
   2291     }
   2292 #endif /* BCM_TRIDENT3_SUPPORT */
   2293 
   2294     keygen_cfg.qual_info_arr = qual_info_arr;
   2295     keygen_cfg.qual_info_count = qual_info_count;
   2296     keygen_cfg.qual_cfg_info_db = stage_fc->qual_cfg_info_db;
   2297     keygen_cfg.ext_cfg_db = stage_fc->ext_cfg_db_arr[keygen_ext_mode];
   2298     keygen_cfg.mode = keygen_mode;
   2299     keygen_cfg.num_parts = parts_count;
   2300     if (fsm_ptr->flags & _FP_GROUP_CONFIG_VALIDATE) {
   2301         keygen_cfg.flags = BCMI_KEYGEN_CFG_FLAGS_VALIDATE_ONLY;
   2302     }
   2303     if (fsm_ptr->flags & _FP_GROUP_QSET_UPDATE) {
   2304         keygen_cfg.flags |= BCMI_KEYGEN_CFG_FLAGS_QSET_UPDATE;
   2305         rv = _field_th_keygen_ext_ctrl_info_get(unit, fg, &keygen_cfg);
   2306         if (BCM_FAILURE(rv)) {
   2307             goto cleanup;
   2308         }
   2309     }
   2310     if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS &&
   2311         !(fsm_ptr->flags & _FP_GROUP_QSET_UPDATE)) {
   2312         rv = bcmi_keygen_keysize_get(unit, &keygen_cfg, &rkey_size);
   2313         if (BCM_FAILURE(rv)) {
   2314             goto cleanup;
   2315         }
   2316         if (((keygen_mode == BCMI_KEYGEN_MODE_SINGLE) && (rkey_size > 80))
   2317             || ((keygen_mode == BCMI_KEYGEN_MODE_DBLINTRA) && (rkey_size > 160))
   2318             || ((keygen_mode == BCMI_KEYGEN_MODE_DBLINTER) && (rkey_size > 320))
   2319             || ((keygen_mode == BCMI_KEYGEN_MODE_TRIPLE) && (rkey_size > 480))) {
   2320             rv = BCM_E_CONFIG;
   2321             goto cleanup;
   2322         }
   2323     }
   2324     rv = bcmi_keygen_cfg_process(unit, &keygen_cfg, &keygen_oper);
   2325     if (BCM_FAILURE(rv)) {
   2326         goto cleanup;
   2327     }
   2328 
   2329     if ((fsm_ptr->flags & _FP_GROUP_CONFIG_VALIDATE) == 0) {
   2330         rv = _field_th_group_keygen_oper_insert(unit, fg, &keygen_oper);
   2331         if (BCM_FAILURE(rv)) {
   2332             goto cleanup;
   2333         }
   2334     }
   2335 
   2336 cleanup:
   2337     if (qual_info_arr != NULL) {
   2338         sal_free(qual_info_arr);
   2339     }
   2340     if (fsm_ptr->flags & _FP_GROUP_QSET_UPDATE) {
   2341         if (keygen_cfg.ext_ctrl_sel_info != NULL) {
   2342             sal_free(keygen_cfg.ext_ctrl_sel_info);
   2343         }
   2344     }
   2345 
   2346 #if defined (BCM_TRIDENT3_SUPPORT)
   2347     if (soc_feature(unit, soc_feature_td3_style_fp)) {
   2348        if (bkup_ct != 0) {
   2349           uint8 ct;
   2350           for (ct = 0; ct < bkup_ct; ct++) {
   2351              if (BCM_FAILURE(rv)) {
   2352                 stage_fc->qual_cfg_info_db->qual_cfg_info[qual_bkup[ct]]->qual_cfg_arr
   2353                                    = qual_cfg_arr_bkup[ct];
   2354                 stage_fc->qual_cfg_info_db->qual_cfg_info[qual_bkup[ct]]->num_qual_cfg
   2355                                    = num_qual_cfg_bkup[ct];
   2356                 BCM_IF_ERROR_RETURN
   2357                     (_bcm_field_td3_field_bus_cont_sel_remove(unit,
   2358                                               fsm_ptr->fg->instance,
   2359                                               stage_fc, fg,
   2360                                               qual_bkup[ct]));
   2361              } else {
   2362                 sal_free(qual_cfg_arr_bkup[ct]);
   2363              }
   2364           }
   2365        }
   2366     }
   2367 #endif /* BCM_TRIDENT3_SUPPORT */ 
   2368     (void)bcmi_keygen_oper_free(unit, parts_count, &keygen_oper);
   2369     return rv;
   2370 }
   2371 
   2372 /*
   2373  * Function:
   2374  *     _field_th_ext_code_assign
   2375  *
   2376  * Purpose:
   2377  *     Calculate the extractor select codes from a qualifier set and group mode.
   2378  *
   2379  * Parameters:
   2380  *     unit           - (IN) BCM device number.
   2381  *     qset           - (IN) Client qualifier set.
   2382  *     selcode_clear  - (IN) Clear the selcodes
   2383  *     fsm_ptr        - (IN/OUT) fsm pointer which has pointer to
   2384  *                           group structure ans aset size
   2385  *
   2386  * Returns:
   2387  *     BCM_E_PARAM    - mode unknown
   2388  *     BCM_E_RESOURCE - No select code will satisfy qualifier set
   2389  *     BCM_E_NONE     - Success
   2390  *
   2391  * Notes:
   2392  *     Calling function is responsible for ensuring appropriate slices
   2393  *     are available.
   2394  *     selcode_clear will be 0 (don't clear) when this function is called
   2395  *         from bcm_field_group_set
   2396  */
   2397 int
   2398 _field_th_ext_code_assign(int unit,
   2399                           int selcode_clear,
   2400                           _field_group_add_fsm_t *fsm_ptr)
   2401 {
   2402     int idx;                    /* slice index iterator.            */
   2403     _field_group_t *fg;         /* Field Group structure            */
   2404 
   2405     /*retrieve the group structure */
   2406     fg = fsm_ptr->fg;
   2407 
   2408     /* Input parameters check. */
   2409     if (NULL == fg) {
   2410         return (BCM_E_PARAM);
   2411     }
   2412 
   2413     /*
   2414      * Clear group extractor selector codes.
   2415      */
   2416     for (idx = 0; idx < _FP_MAX_ENTRY_WIDTH; idx++) {
   2417         if (selcode_clear) {
   2418             _FP_EXT_SELCODE_CLEAR(fg->ext_codes[idx]);
   2419         }
   2420     }
   2421 
   2422     /* Get keygen extractor codes for group qset. */
   2423     BCM_IF_ERROR_RETURN(_field_th_ingress_ext_code_get(unit, fsm_ptr));
   2424     return (BCM_E_NONE);
   2425 }
   2426 
   2427 /*
   2428  * Function:
   2429  *     _field_th_group_add_extractor_codes_get
   2430  * Purpose:
   2431  *     Calculate the extractor select codes from a qualifier set and group mode.
   2432  * Parameters:
   2433  *     unit     - (IN)     BCM device number.
   2434  *     fsm_ptr  - (IN/OUT) State machine tracking structure.
   2435  * Returns:
   2436  *     BCM_E_XXX
   2437  */
   2438 STATIC int
   2439 _field_th_group_add_extractor_codes_get(int unit,
   2440                                         _field_group_add_fsm_t *fsm_ptr)
   2441 {
   2442     _field_group_t *fg;     /* Field Group pointer.     */
   2443     int orig_group_flags;   /* Original Group flags.    */
   2444 
   2445     /* Input parameters check. */
   2446     if (NULL == fsm_ptr || NULL == fsm_ptr->fg) {
   2447         return (BCM_E_PARAM);
   2448     }
   2449 
   2450     /* Check if requested mode is supported by device. */
   2451     switch (fsm_ptr->mode) {
   2452         case bcmFieldGroupModeQuad:
   2453         case bcmFieldGroupModeDirect:
   2454         case bcmFieldGroupModeDirectExtraction:
   2455         case bcmFieldGroupModeHashing:
   2456         case bcmFieldGroupModeExactMatch:
   2457             /* Mode not supported by device. */
   2458             fsm_ptr->rv = (BCM_E_CONFIG);
   2459             break;
   2460         case bcmFieldGroupModeTriple: /* 480 bit mode. */
   2461             /* Check Triple wide mode group support in device feature list. */
   2462             if (0 == soc_feature(unit, soc_feature_field_ingress_triple_wide)) {
   2463                 fsm_ptr->rv = (BCM_E_CONFIG);
   2464             } else {
   2465                 if (fsm_ptr->stage_fc->stage_id
   2466                                             == _BCM_FIELD_STAGE_EXACTMATCH) {
   2467                     fsm_ptr->rv = (BCM_E_CONFIG);
   2468                 }
   2469             }
   2470             break;
   2471         case bcmFieldGroupModeDouble: /* 320 bit mode. */
   2472             /* Check if device supports Double wide mode. */
   2473             if (0 == soc_feature(unit, soc_feature_field_wide)) {
   2474                 fsm_ptr->rv = (BCM_E_CONFIG);
   2475             }
   2476             break;
   2477         case bcmFieldGroupModeIntraSliceDouble: /*160 bit mode */
   2478             if (!(soc_feature(unit, soc_feature_ifp_no_narrow_mode_support) ||
   2479                   soc_feature(unit, soc_feature_hx5_style_ifp_no_narrow_mode_support))) {
   2480                 /* Check if device supports intraslice Double wide mode. */
   2481                 if (0 == soc_feature(unit, soc_feature_field_intraslice_double_wide)) {
   2482                       fsm_ptr->rv = (BCM_E_CONFIG);
   2483                 }
   2484             } else {
   2485                 fsm_ptr->rv = (BCM_E_UNAVAIL);
   2486             }
   2487             break;
   2488         case bcmFieldGroupModeSingle: /* 80 bit mode. */
   2489             if (!soc_feature(unit, soc_feature_ifp_no_narrow_mode_support) &&
   2490                 !soc_feature(unit, soc_feature_hx5_style_ifp_no_narrow_mode_support)) {
   2491                 if (_BCM_FIELD_QSET_PBMP_TEST(fsm_ptr->qset)) {
   2492                     fsm_ptr->rv = (BCM_E_CONFIG);
   2493                 }
   2494             } else {
   2495                 /* Single mode is 160 bit mode */
   2496                 fsm_ptr->mode = bcmFieldGroupModeIntraSliceDouble;
   2497             }
   2498             break;
   2499         default:
   2500             break;
   2501     }
   2502 
   2503     /* If mode check returned failure, proceed to cleanup state. */
   2504     if (BCM_FAILURE(fsm_ptr->rv)) {
   2505         fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state;
   2506         fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   2507         return (BCM_E_NONE);
   2508     }
   2509 
   2510     /* Group pointer initialization. */
   2511     fg = fsm_ptr->fg;
   2512 
   2513     fsm_ptr->rv = BCM_E_RESOURCE;
   2514     orig_group_flags = fg->flags;
   2515 
   2516     if (fsm_ptr->stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   2517 
   2518         if (bcmFieldGroupModeAuto == fsm_ptr->mode) {
   2519             LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit, "Group mode auto.\n")));
   2520 
   2521             /* For Auto mode, try Single -> Double -> Triple modes. */
   2522             /* Single wide Non-Intra slice selection. */
   2523             if (!soc_feature(unit, soc_feature_ifp_no_narrow_mode_support) &&
   2524                  !soc_feature(unit, soc_feature_hx5_style_ifp_no_narrow_mode_support)) {
   2525                 if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY) &&
   2526                         !_BCM_FIELD_QSET_PBMP_TEST(fsm_ptr->qset)) {
   2527                     LOG_VERBOSE(BSL_LS_BCM_FP,
   2528                             (BSL_META_U(unit, "Trying single...\n")));
   2529                     if (soc_feature(unit, soc_feature_ifp_action_profiling) &&
   2530                         (fsm_ptr->aset_size > _FP_ASET_DATA_SIZE_FOR_POLICY_NARROW))
   2531                     {
   2532                         LOG_VERBOSE(BSL_LS_BCM_FP,
   2533                             (BSL_META_U(unit, "When Aset size is %d, Single wide group is not possible\n"),
   2534                             fsm_ptr->aset_size));
   2535                         fsm_ptr->rv = BCM_E_RESOURCE;
   2536                     } else {
   2537                        /* 80bit mode. */
   2538                        fg->flags = (orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE);
   2539                        fsm_ptr->rv = _field_th_ext_code_assign(unit, 1, fsm_ptr);
   2540                     }
   2541                 }
   2542             }
   2543 
   2544             /* Single wide intra slice selection. */
   2545             if ((BCM_FAILURE(fsm_ptr->rv)
   2546                         && (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE))) {
   2547                 if (soc_feature(unit, soc_feature_field_intraslice_double_wide)) {
   2548                     LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2549                                     "Trying intra...\n")));
   2550                     if (soc_feature(unit, soc_feature_ifp_action_profiling) &&
   2551                         (fsm_ptr->aset_size > _FP_ASET_DATA_SIZE_FOR_POLICY_WIDE))
   2552                     {
   2553                         LOG_VERBOSE(BSL_LS_BCM_FP,
   2554                             (BSL_META_U(unit, "When Aset size is %d, Intra Slice Double wide"
   2555                                 " group is not possible\n"), fsm_ptr->aset_size));
   2556                         fsm_ptr->rv = BCM_E_RESOURCE;
   2557                     } else {
   2558                         /* 160bit mode. */
   2559                         fg->flags = (orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE
   2560                                 | _FP_GROUP_INTRASLICE_DOUBLEWIDE);
   2561                         fsm_ptr->rv = _field_th_ext_code_assign(unit, 1, fsm_ptr);
   2562             }
   2563                 }
   2564             }
   2565 
   2566             /* Double wide inter slice selection. */
   2567             if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
   2568                 if (BCM_FAILURE(fsm_ptr->rv)) {
   2569                     LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2570                                     "Trying double...\n")));
   2571                     /* 320bit mode. */
   2572                     fg->flags = (orig_group_flags | _FP_GROUP_SPAN_DOUBLE_SLICE);
   2573                     fsm_ptr->rv = _field_th_ext_code_assign(unit, 1, fsm_ptr);
   2574                 }
   2575             }
   2576 
   2577             /* Triple wide inter slice selection. */
   2578             if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
   2579                 if (BCM_FAILURE(fsm_ptr->rv)) {
   2580                     LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2581                                     "Trying triple...\n")));
   2582                     /* 480bit mode. */
   2583                     fg->flags = (orig_group_flags | _FP_GROUP_SPAN_TRIPLE_SLICE);
   2584                     fsm_ptr->rv = _field_th_ext_code_assign(unit, 1, fsm_ptr);
   2585                 }
   2586             }
   2587         } else {
   2588             switch (fsm_ptr->mode) {
   2589                 case bcmFieldGroupModeSingle:
   2590                     /* Single wide non intra slice selection. */
   2591                     if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
   2592                         LOG_VERBOSE(BSL_LS_BCM_FP,
   2593                                 (BSL_META_U(unit, "Trying single...\n")));
   2594                         if (soc_feature(unit, soc_feature_ifp_action_profiling) &&
   2595                             (fsm_ptr->aset_size > _FP_ASET_DATA_SIZE_FOR_POLICY_NARROW))
   2596                         {
   2597                             LOG_VERBOSE(BSL_LS_BCM_FP,(BSL_META_U(unit,
   2598                                        "When Aset size is %d,Single wide group is not possible\n"),
   2599                                         fsm_ptr->aset_size));
   2600                             fsm_ptr->rv = BCM_E_RESOURCE;
   2601                         }
   2602                         else {
   2603                             fg->flags = (orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE);
   2604                             fsm_ptr->rv = _field_th_ext_code_assign(unit, 1,
   2605                                 fsm_ptr);
   2606                         }
   2607                     }
   2608                     break;
   2609                 case bcmFieldGroupModeIntraSliceDouble:
   2610                     /* Double wide intra slice selection. */
   2611                     if ((soc_feature(unit, soc_feature_field_intraslice_double_wide)
   2612                                 && (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE))) {
   2613                         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2614                                         "Trying intra...\n")));
   2615                         if (soc_feature(unit, soc_feature_ifp_action_profiling) &&
   2616                             (fsm_ptr->aset_size > _FP_ASET_DATA_SIZE_FOR_POLICY_WIDE))
   2617                         {
   2618                             LOG_VERBOSE(BSL_LS_BCM_FP,
   2619                                 (BSL_META_U(unit, "When Aset size is %d, Intra Slice Double wide"
   2620                                         " group is not possible\n"), fsm_ptr->aset_size));
   2621                             fsm_ptr->rv = BCM_E_RESOURCE;
   2622                         }
   2623                         else {
   2624                             fg->flags = (orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE
   2625                                 | _FP_GROUP_INTRASLICE_DOUBLEWIDE);
   2626                             fsm_ptr->rv = _field_th_ext_code_assign(unit, 1,
   2627                                 fsm_ptr);
   2628                        }
   2629                     }
   2630                 break;
   2631                 case bcmFieldGroupModeDouble:
   2632                     /* Double wide intra slice selection. */
   2633                 if (!soc_feature(unit, soc_feature_ifp_no_narrow_mode_support) &&
   2634                         !soc_feature(unit, soc_feature_hx5_style_ifp_no_narrow_mode_support)) {
   2635                         if ((soc_feature(unit, soc_feature_field_intraslice_double_wide)
   2636                                     && (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE))) {
   2637                             if (soc_feature(unit, soc_feature_ifp_action_profiling) &&
   2638                                 (fsm_ptr->aset_size > _FP_ASET_DATA_SIZE_FOR_POLICY_WIDE))
   2639                             {
   2640                                 LOG_VERBOSE(BSL_LS_BCM_FP,
   2641                                     (BSL_META_U(unit, "When Aset size is %d, Intra Slice Double wide"
   2642                                         " group is not possible\n"), fsm_ptr->aset_size));
   2643                                 fsm_ptr->rv = BCM_E_RESOURCE;
   2644                             } else {
   2645                                         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2646                                                     "Trying intra...\n")));
   2647                                     fg->flags = (orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE
   2648                                             | _FP_GROUP_INTRASLICE_DOUBLEWIDE);
   2649                                     fsm_ptr->rv = _field_th_ext_code_assign(unit, 1,
   2650                                             fsm_ptr);
   2651                             }
   2652                         }
   2653                     }
   2654                     /* Double wide inter slice selection. */
   2655                     if ((BCM_FAILURE(fsm_ptr->rv))
   2656                             && (0 == (fsm_ptr->flags
   2657                                     & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY))) {
   2658                         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2659                                         "Trying double...\n")));
   2660                         fg->flags = (orig_group_flags |
   2661                                 _FP_GROUP_SPAN_DOUBLE_SLICE);
   2662                         fsm_ptr->rv = _field_th_ext_code_assign(unit, 1,
   2663                                 fsm_ptr);
   2664                     }
   2665                     break;
   2666                 case bcmFieldGroupModeTriple:
   2667                     /* Triple wide inter slice selection. */
   2668                     if (0 == (fsm_ptr->flags
   2669                                 & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
   2670                         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2671                                         "Trying triple...\n")));
   2672                         fg->flags = (orig_group_flags |
   2673                                 _FP_GROUP_SPAN_TRIPLE_SLICE);
   2674                         fsm_ptr->rv = _field_th_ext_code_assign(unit, 1,
   2675                                 fsm_ptr);
   2676                     }
   2677                     break;
   2678                 default:
   2679                     fsm_ptr->rv = (BCM_E_CONFIG);
   2680             }
   2681         }
   2682     } else if (fsm_ptr->stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   2683 
   2684         if (bcmFieldGroupModeAuto == fsm_ptr->mode) {
   2685 
   2686             LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit, "Group mode auto.\n")));
   2687 
   2688             /* Single wide intra slice selection. */
   2689             if ((0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY))) {
   2690                 LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2691                                 "Trying single ...\n")));
   2692                 if (fsm_ptr->aset_size <= EM_MODE160_ACTION_DATA_SIZE) {
   2693                     fg->em_mode = _FieldExactMatchMode160;
   2694                     fg->flags = orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE
   2695                                                  | _FP_GROUP_INTRASLICE_DOUBLEWIDE;
   2696                     fsm_ptr->rv = _field_th_ext_code_assign(unit, 1, fsm_ptr);
   2697                     fg->flags = orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE;
   2698                 } else if ((EM_MODE160_ACTION_DATA_SIZE < fsm_ptr->aset_size)
   2699                     && (fsm_ptr->aset_size <= EM_MODE128_ACTION_DATA_SIZE)) {
   2700                     fg->em_mode = _FieldExactMatchMode128;
   2701                     fg->flags = orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE
   2702                                                  | _FP_GROUP_INTRASLICE_DOUBLEWIDE;
   2703                     fsm_ptr->rv = _field_th_ext_code_assign(unit, 1, fsm_ptr);
   2704                     fg->flags = orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE;
   2705                 }
   2706             }
   2707 
   2708             /* Double wide inter slice selection. */
   2709             if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
   2710                 if (BCM_FAILURE(fsm_ptr->rv)) {
   2711                     LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2712                                     "Trying double...\n")));
   2713                     if (fsm_ptr->aset_size <= EM_MODE320_ACTION_DATA_SIZE) {
   2714                         /* 320bit mode. */
   2715                         fg->em_mode = _FieldExactMatchMode320;
   2716                         fg->flags = (orig_group_flags |
   2717                                           _FP_GROUP_SPAN_DOUBLE_SLICE);
   2718                         fsm_ptr->rv = _field_th_ext_code_assign(unit,
   2719                                           1, fsm_ptr);
   2720                     }
   2721                 }
   2722             }
   2723         } else {
   2724             switch (fsm_ptr->mode) {
   2725                 case bcmFieldGroupModeSingle:
   2726                     /* Single Wide selection. */
   2727                     if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
   2728                         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2729                                         "Trying intra...\n")));
   2730                         fg->flags = orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE
   2731                                                      | _FP_GROUP_INTRASLICE_DOUBLEWIDE;
   2732                         fsm_ptr->rv = _field_th_ext_code_assign(unit, 1,
   2733                                                                                 fsm_ptr);
   2734                         fg->flags = orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE;
   2735                     }
   2736                     break;
   2737                 case bcmFieldGroupModeDouble:
   2738                     /* Double wide inter slice selection. */
   2739                     if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
   2740                         if (fsm_ptr->aset_size <= EM_MODE320_ACTION_DATA_SIZE) {
   2741                             LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2742                                         "Trying double ..\n")));
   2743                             fg->em_mode = _FieldExactMatchMode320;
   2744                             fg->flags = (orig_group_flags |
   2745                                           _FP_GROUP_SPAN_DOUBLE_SLICE);
   2746                             fsm_ptr->rv = _field_th_ext_code_assign(unit, 1,
   2747                                           fsm_ptr);
   2748                         } else {
   2749                             fsm_ptr->rv = (BCM_E_CONFIG);
   2750                         }
   2751                     }
   2752                     break;
   2753                 default:
   2754                     fsm_ptr->rv = (BCM_E_CONFIG);
   2755             }
   2756         }
   2757 #if defined(BCM_FLOWTRACKER_SUPPORT)
   2758     } else if (fsm_ptr->stage_fc->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER) {
   2759         if (bcmFieldGroupModeAuto == fsm_ptr->mode) {
   2760 
   2761             LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit, "Group mode auto.\n")));
   2762 
   2763             /* Single wide intra slice selection. */
   2764             if ((0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY))) {
   2765                 LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2766                                 "Trying single ...\n")));
   2767                 /* 180Bit mode. */
   2768                 fg->flags = orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE;
   2769                 fsm_ptr->rv = _field_hx5_ft_ext_code_assign(unit, 1, fsm_ptr);
   2770             }
   2771 
   2772             /* Double wide inter slice selection. */
   2773             if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
   2774                 if (BCM_FAILURE(fsm_ptr->rv)) {
   2775                     LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2776                                     "Trying double...\n")));
   2777                     /* 360bit mode. */
   2778                     fg->flags = (orig_group_flags |
   2779                                  _FP_GROUP_SPAN_SINGLE_SLICE |
   2780                                  _FP_GROUP_DW_DEPTH_EXPANDED);
   2781                     fsm_ptr->rv = _field_hx5_ft_ext_code_assign(unit, 1, fsm_ptr);
   2782                 }
   2783             }
   2784         } else {
   2785             switch (fsm_ptr->mode) {
   2786                 case bcmFieldGroupModeSingle:
   2787                     /* Single Wide selection. */
   2788                     if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
   2789                         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2790                                         "Trying Single...\n")));
   2791                         fg->flags = orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE;
   2792                         fsm_ptr->rv = _field_hx5_ft_ext_code_assign(unit, 1,
   2793                                         fsm_ptr);
   2794                         fg->flags = orig_group_flags | _FP_GROUP_SPAN_SINGLE_SLICE;
   2795                     }
   2796                     break;
   2797                 case bcmFieldGroupModeDouble:
   2798                     /* Double wide selection. */
   2799                     if (0 == (fsm_ptr->flags & _BCM_FP_GROUP_ADD_INTRA_SLICE_ONLY)) {
   2800                         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2801                                         "Trying double ..\n")));
   2802                         fg->flags = (orig_group_flags |
   2803                                     _FP_GROUP_SPAN_SINGLE_SLICE |
   2804                                     _FP_GROUP_DW_DEPTH_EXPANDED);
   2805                         fsm_ptr->rv = _field_hx5_ft_ext_code_assign(unit, 1,
   2806                                         fsm_ptr);
   2807                     }
   2808                     break;
   2809                 default:
   2810                     fsm_ptr->rv = (BCM_E_CONFIG);
   2811             }
   2812         }
   2813 #endif
   2814     } else {
   2815         return (BCM_E_INTERNAL);
   2816     }
   2817 
   2818     if (BCM_FAILURE(fsm_ptr->rv)) {
   2819         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit, "No success so far.\n")));
   2820 
   2821         /* No luck so far - try different alternative qset if possible. */
   2822         if ((BCM_E_RESOURCE == fsm_ptr->rv)
   2823              && (_BCM_FP_GROUP_ADD_STATE_QSET_UPDATE
   2824                  == fsm_ptr->fsm_state_prev)) {
   2825             fsm_ptr->rv = (BCM_E_NONE);
   2826             fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_QSET_ALTERNATE;
   2827         }
   2828     } else {
   2829 
   2830         /* Insert group into units group list. */
   2831         if (BCM_SUCCESS(fsm_ptr->rv)) {
   2832             LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2833                 "Configuration found...\n")));
   2834             fsm_ptr->rv = _bcm_field_group_linked_list_insert(unit, fsm_ptr);
   2835         }
   2836 
   2837         if (BCM_SUCCESS(fsm_ptr->rv)) {
   2838             /* Success proceed to slice allocation. */
   2839             if ((fsm_ptr->flags & _FP_GROUP_CONFIG_VALIDATE)) {
   2840                 fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   2841             } else {
   2842                 fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_SLICE_ALLOCATE;
   2843             }
   2844         } else {
   2845             /* Failure proceed to cleanup. */
   2846             fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   2847         }
   2848     }
   2849 
   2850     /* Set current state to be previous state. */
   2851     fsm_ptr->fsm_state_prev = _BCM_FP_GROUP_ADD_STATE_SEL_CODES_GET;
   2852 
   2853     return (BCM_E_NONE);
   2854 }
   2855 
   2856 /*
   2857  * Function:
   2858  *     _field_th_group_add_qset_alternate
   2859  * Purpose:
   2860  *     Currently no alternate QSET identified for TH IFP qualifiers.
   2861  *     Proceed to the next state in the state machine.
   2862  * Parameters:
   2863  *     unit     - (IN)     BCM device number.
   2864  *     fsm_ptr  - (IN/OUT) State machine tracking structure.
   2865  * Returns:
   2866  *     BCM_E_XXX
   2867  */
   2868 STATIC int
   2869 _field_th_group_add_qset_alternate(int unit, _field_group_add_fsm_t *fsm_ptr)
   2870 {
   2871     /* Input parameters check. */
   2872     if (NULL == fsm_ptr) {
   2873         return (BCM_E_PARAM);
   2874     }
   2875 
   2876     /* Set current state to be previous state. */
   2877     fsm_ptr->fsm_state_prev =  fsm_ptr->fsm_state;
   2878 
   2879     /* Alternate QSET is not available, proceed to end. */
   2880     fsm_ptr->rv = (BCM_E_RESOURCE);
   2881     fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   2882 
   2883     return (BCM_E_NONE);
   2884 }
   2885 
   2886 /*
   2887  * Function:
   2888  *     _field_th_group_lt_slice_validate
   2889  * Purpose:
   2890  *     Validate if the slice has enought free entries.
   2891  * Parameters:
   2892  *     unit          - (IN) BCM device number.
   2893  *     stage_fc      - (IN) Stage field control structure pointer.
   2894  *     fg            - (IN) Field group structure pointer.
   2895  *     slice_id      - (IN) Physical slice number.
   2896  *     lt_fs         - (IN) Reference to LT Slice structure.
   2897  * Returns:
   2898  *     BCM_E_XXX
   2899  */
   2900 int
   2901 _field_th_group_lt_slice_validate(int unit,
   2902                                   _field_stage_t *stage_fc,
   2903                                   _field_group_t *fg,
   2904                                   int slice_id,
   2905                                   _field_lt_slice_t *lt_fs)
   2906 {
   2907     /* Input parameters check. */
   2908     if ((NULL == stage_fc) || (NULL == fg)) {
   2909         return (BCM_E_PARAM);
   2910     }
   2911 
   2912     if (fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) {
   2913        int            id;                  /* iterator.           */
   2914        uint8          presel_ent_ct = 0;   /* Presel Entry count. */
   2915        uint8          first_entry_flg = 0;
   2916        uint8          atomicity_entry = 0;
   2917 
   2918        /* calculated the presel entries to be created */
   2919        for (id = 0; id < _FP_PRESEL_ENTRIES_MAX_PER_GROUP; id++) {
   2920            if (fg->presel_ent_arr[id] != NULL) {
   2921               presel_ent_ct++;
   2922            }
   2923        }
   2924 
   2925        if (lt_fs == NULL) {
   2926           lt_fs = stage_fc->lt_slices[fg->instance] + slice_id;
   2927           first_entry_flg = 1;
   2928        }
   2929 
   2930        /*
   2931         * To provide SW atomicity, an entry in the slice has to be kept
   2932         * free to move other entries in the slice during priority configuration.
   2933         * Hence, free entries has to be reduced to 1 during validation.
   2934         */
   2935        if (lt_fs->slice_flags & _BCM_FIELD_SLICE_SW_ATOMICITY_SUPPORT) {
   2936           if (lt_fs->free_count == 0) {
   2937              return BCM_E_INTERNAL;
   2938           }
   2939           atomicity_entry = 1;
   2940        }
   2941 
   2942        if ((lt_fs->free_count - atomicity_entry) < presel_ent_ct) {
   2943           if (first_entry_flg == 1) {
   2944              LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2945                 "No free entries left in the LT slice[%d] to create [%d]"
   2946                 " Preselector entries.\n\r"),
   2947                 slice_id, presel_ent_ct));
   2948              return (BCM_E_CONFIG);
   2949           } else {
   2950              LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2951                 "ERROR: Can not create the requested %d Presel entries"
   2952                 " for the given group's priority[%d].\n\r"
   2953                 "Only %d free entries left in the LT slice[%d]\n\r"),
   2954                 presel_ent_ct, fg->priority,
   2955                (lt_fs->free_count - atomicity_entry), slice_id));
   2956              return (BCM_E_RESOURCE);
   2957           }
   2958        }
   2959     } else {
   2960        int             part;            /* Part iterator */
   2961        int             parts_count = 0; /* Entry Parts */
   2962        _field_slice_t  *fs;             /* Field slice structure pointer.*/
   2963 
   2964        /* Get number of entry parts based on the field group flags. */
   2965        BCM_IF_ERROR_RETURN(_bcm_field_th_entry_tcam_parts_count(unit, fg->flags,
   2966                           &parts_count));
   2967 
   2968        /* Validate slice LT_MAP status. */
   2969        for (part = 0; part < parts_count; part++) {
   2970           fs = stage_fc->slices[fg->instance] + slice_id + part;
   2971           if (0 != fs->lt_map) {
   2972               if (!((soc_feature(unit, soc_feature_sw_mmu_flush_rqe_operation)) &&
   2973                   (fs->lt_map == 1))) {
   2974                    LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   2975                        "FP(unit %d) Verb: Slice=%d in-use.\n"),
   2976                         unit, (slice_id + part)));
   2977                    return (BCM_E_CONFIG);
   2978               }
   2979           }
   2980        }
   2981     }
   2982 
   2983     return (BCM_E_NONE);
   2984 }
   2985 
   2986 /*
   2987  * Function:
   2988  *  _bcm_field_th_priority_group_get_next
   2989  * Purpose:
   2990  *  Retrieve the next valid group pointer associated with the given priority.
   2991  * Parameters:
   2992  *  unit       - (IN   BCM device number.
   2993  *  instance   - (IN)  Pipe to which group belongs to.
   2994  *  stage_id   - (IN)  Stage (IFP/VFP/EFP) to which group belongs to.
   2995  *  priority   - (IN)  Field Group Priority.
   2996  *  curr_group - (IN)  Reference to current group index associated to group
   2997  *                     priority.
   2998  *  next_group - (OUT) Reference to next available group index associated to
   2999  *                     the given priority.
   3000  * Returns:
   3001  *  BCM_E_XXX
   3002  * Note:
   3003  *  "*curr_group == NULL" to retrieve the first group associated with the
   3004  *   given slice.
   3005  */
   3006 int
   3007 _bcm_field_th_priority_group_get_next(int unit,
   3008                                       int instance,
   3009                                       _field_stage_id_t stage_id,
   3010                                       int priority,
   3011                                       _field_group_t **curr_group,
   3012                                       _field_group_t **next_group)
   3013 {
   3014     _field_group_t *fg = NULL;
   3015 
   3016     if (curr_group == NULL || next_group == NULL) {
   3017         return BCM_E_PARAM;
   3018     }
   3019 
   3020     if (*curr_group == NULL) {
   3021         _field_control_t  *fc;     /* Field Control Structure */
   3022 
   3023         /* Get device Field control structure. */
   3024         BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   3025         fg = fc->groups;
   3026     } else {
   3027         fg = (*curr_group)->next;
   3028     }
   3029 
   3030     *next_group = NULL;
   3031     for (; fg != NULL; fg = fg->next) {
   3032         if ((instance != fg->instance) || (stage_id != fg->stage_id)) {
   3033             continue;
   3034         }
   3035 
   3036         if (fg->priority == priority) {
   3037             *next_group = fg;
   3038             return BCM_E_NONE;
   3039         }
   3040     }
   3041 
   3042     return BCM_E_NOT_FOUND;
   3043 }
   3044 
   3045 /*
   3046  * Function:
   3047  *     _bcm_field_th_group_add_slice_validate
   3048  * Purpose:
   3049  *     Validate a candidate slice if it fits for a group.
   3050  * Parameters:
   3051  *     unit          - (IN  BCM device number.
   3052  *     stage_fc      - (IN) State machine tracking structure.
   3053  *     fg            - (IN) Field group structure.
   3054  *     slice_id      - (IN) Candidate slice id.
   3055  * Returns:
   3056  *     BCM_E_XXX
   3057  */
   3058 int
   3059 _bcm_field_th_group_add_slice_validate(int unit,
   3060                                        _field_stage_t *stage_fc,
   3061                                        _field_group_t *fg,
   3062                                        int slice_id)
   3063 {
   3064     int                rv;                                /* Return status. */
   3065     _field_slice_t     *fs_part[_FP_MAX_ENTRY_WIDTH] = {NULL}; /* Field slice
   3066                                                                   structure
   3067                                                                   pointer. */
   3068     _field_group_t     *fg_ptr = NULL;
   3069     _field_lt_slice_t  *lt_slice = NULL;
   3070 
   3071     /* Input parameters check. */
   3072     if (NULL == stage_fc || NULL == fg) {
   3073         return (BCM_E_PARAM);
   3074     }
   3075 
   3076     /* Validate slice for exact match group. */
   3077     if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   3078         return _field_th_exactmatch_slice_validate(unit, stage_fc,
   3079                                                      fg, slice_id);
   3080     }
   3081 
   3082 #if defined(BCM_FLOWTRACKER_SUPPORT)
   3083     if (stage_fc->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER) {
   3084         return _field_hx5_ft_slice_validate(unit, stage_fc, fg, slice_id);
   3085     }
   3086 #endif
   3087 
   3088     /*
   3089      * If the slice belongs to an auto-expanded group and it is not the first
   3090      * slice of that group, cannot use it.
   3091      */
   3092     if (stage_fc->slices[fg->instance][slice_id].prev != NULL) {
   3093         return (BCM_E_CONFIG);
   3094     }
   3095 
   3096     /*
   3097      *  Skip the slice if group slice size is small  and
   3098      *  slice is not of smaller size.
   3099      */
   3100     if ((fg->flags & _FP_GROUP_SELECT_SMALL_SLICE) &&
   3101         (0 == (stage_fc->slices[fg->instance][slice_id].slice_flags &
   3102                _BCM_FIELD_SLICE_SIZE_SMALL))) {
   3103         return (BCM_E_CONFIG);
   3104     }
   3105 
   3106     /*
   3107      *  Skip the slice if group slice size is large  and
   3108      *  slice is not of large size.
   3109      */
   3110     if ((fg->flags & _FP_GROUP_SELECT_LARGE_SLICE) &&
   3111         (0 == (stage_fc->slices[fg->instance][slice_id].slice_flags &
   3112                _BCM_FIELD_SLICE_SIZE_LARGE))) {
   3113         return (BCM_E_CONFIG);
   3114     }
   3115 
   3116     /*
   3117      * Skip the slice if group is Intraslice and slice is not Intraslice
   3118      * capable.
   3119      */
   3120     if ((fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE)
   3121         && !(stage_fc->slices[fg->instance][slice_id].slice_flags
   3122             & _BCM_FIELD_SLICE_INTRASLICE_CAPABLE)) {
   3123         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3124             "FP(unit %d) Verb: bad slice=%d for IntraSliceDouble wide-mode.\n"),
   3125              unit, slice_id));
   3126         return (BCM_E_CONFIG);
   3127     }
   3128 
   3129     /*
   3130      * Requested 80bit single wide group mode. Check if slice is already
   3131      * operating in 160bit mode and return error if that's true
   3132      */
   3133     fs_part[0] = stage_fc->slices[fg->instance] + slice_id;
   3134     if (((fg->flags & _FP_GROUP_SPAN_SINGLE_SLICE)
   3135             && !(fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE))
   3136          && (fs_part[0]->group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE)) {
   3137         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3138             "FP(unit %d) Verb: bad slice=%d for Single wide-mode.\n"), unit,
   3139              slice_id));
   3140         return (BCM_E_CONFIG);
   3141     }
   3142 
   3143     /*
   3144      * Three TCAMs are grouped to give a memory macro of size "160b * 256 * 3".
   3145      * Triple wide group is created using slices within the same memory macro.
   3146      */
   3147     if ((fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE) && (slice_id % 3 != 0)) {
   3148         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3149             "FP(unit %d) Verb: bad slice=%d for Triple wide-mode.\n"), unit,
   3150              slice_id));
   3151         return (BCM_E_CONFIG);
   3152     }
   3153 
   3154     /*
   3155      * Double wide group is created using consecutive slices within a memory
   3156      * macro. But consecutive slices across a memory macro boundary cannot be
   3157      * paried to create a double wide group. Skip slices 2, 5, 8 and 11 from
   3158      * allocating for Double Wide Group base slice.
   3159      */
   3160     if ((fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) && (2 == (slice_id % 3))) {
   3161         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3162             "FP(unit %d) Verb: bad slice=%d for Double wide-mode.\n"), unit,
   3163              slice_id));
   3164         return (BCM_E_CONFIG);
   3165     }
   3166 
   3167     /*
   3168      * For slices 1, 4, 7 and 10 check if previous slice is configured for Double
   3169      * wide mode. If TRUE, then skip current slice for Double wide groups.
   3170      */
   3171     if ((fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) && (1 == (slice_id % 3))) {
   3172         fs_part[0] = stage_fc->slices[fg->instance] + (slice_id - 1);
   3173         if (fs_part[0]->group_flags & _FP_GROUP_SPAN_DOUBLE_SLICE) {
   3174             LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3175                 "FP(unit %d) Verb: slice=%d is secondary slice of DoubleWide"
   3176                 " group.\n"), unit, slice_id));
   3177             return (BCM_E_CONFIG);
   3178         }
   3179 
   3180         /*
   3181          * If previous slice is unused, then current slice will be used as
   3182          * secondary slice for the double wide group, hence skip it.
   3183          */
   3184         if (0 == (fs_part[0]->group_flags & _FP_GROUP_SPAN_MASK)) {
   3185             LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3186                 "FP(unit %d) Verb: slice=%d accounted for DoubleWide"
   3187                 " group.\n"), unit, slice_id));
   3188             return (BCM_E_CONFIG);
   3189         }
   3190     }
   3191 
   3192     /*
   3193      * Validate slice current mode for double wide group's allocation
   3194      * eligibility.
   3195      */
   3196     if (fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) {
   3197         fs_part[0] = stage_fc->slices[fg->instance] + slice_id;
   3198         fs_part[1] = stage_fc->slices[fg->instance] + (slice_id + 1);
   3199         if (((fs_part[0]->group_flags & _FP_GROUP_SPAN_SINGLE_SLICE)
   3200                 && !(fs_part[0]->group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE))
   3201             || ((fs_part[1]->group_flags & _FP_GROUP_SPAN_SINGLE_SLICE)
   3202                 && !(fs_part[1]->group_flags
   3203                      & _FP_GROUP_INTRASLICE_DOUBLEWIDE))) {
   3204             /*
   3205              * HW Limitation: Single wide mode slices (80-bit wide) in use
   3206              * cannot be paired with another slice.
   3207              */
   3208             LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3209                 "FP(unit %d) Verb: bad slice=%d for Double wide-mode.\n"),
   3210                  unit, slice_id));
   3211             return (BCM_E_CONFIG);
   3212         }
   3213     }
   3214 
   3215     /* Validate slice for triple wide mode use. */
   3216     if (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
   3217         fs_part[0] = stage_fc->slices[fg->instance] + slice_id;
   3218         fs_part[1] = stage_fc->slices[fg->instance] + slice_id + 1;
   3219         fs_part[2] = stage_fc->slices[fg->instance] + slice_id + 2;
   3220         if (((fs_part[0]->group_flags & _FP_GROUP_SPAN_SINGLE_SLICE)
   3221                 && !(fs_part[0]->group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE))
   3222             || ((fs_part[1]->group_flags & _FP_GROUP_SPAN_SINGLE_SLICE)
   3223                  && !(fs_part[1]->group_flags
   3224                       & _FP_GROUP_INTRASLICE_DOUBLEWIDE))
   3225             || ((fs_part[2]->group_flags & _FP_GROUP_SPAN_SINGLE_SLICE)
   3226                  && !(fs_part[2]->group_flags
   3227                       & _FP_GROUP_INTRASLICE_DOUBLEWIDE))) {
   3228             /*
   3229              * HW Limitation: Single wide mode slices (80-bit wide) in use
   3230              * cannot be paired with another slice.
   3231              */
   3232             LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3233                 "FP(unit %d) Verb: bad slice=%d for Triple-mode.\n"), unit,
   3234                  slice_id));
   3235             return (BCM_E_CONFIG);
   3236         }
   3237     }
   3238 
   3239     /* Initialize group auto expansion support status. */
   3240     if (soc_feature(unit, soc_feature_field_virtual_slice_group)) {
   3241         if (stage_fc->flags & _FP_STAGE_AUTO_EXPANSION) {
   3242             fg->flags |= _FP_GROUP_SELECT_AUTO_EXPANSION;
   3243             LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3244                 "FP(unit %d) Verb: Group Auto Expansion status=%d.\n"),
   3245                  unit, (fg->flags & _FP_GROUP_SELECT_AUTO_EXPANSION) ? 1: 0));
   3246         }
   3247     }
   3248 
   3249     /* Retrieve the existing groups associated with the Slice */
   3250     rv = _bcm_field_slice_group_get_next(unit, fg->instance,
   3251                                             fg->stage_id, slice_id,
   3252                                             &fg_ptr, &fg_ptr);
   3253 
   3254     if (BCM_SUCCESS(rv)) {
   3255 
   3256         int mode;
   3257 
   3258         /* In case of auto-expansion, go for a next slice for the same group. */
   3259         if (fg == fg_ptr) {
   3260            return (BCM_E_CONFIG);
   3261         }
   3262 
   3263         /* Compare the group priority with the existing group in the slice. */
   3264         if (fg->priority != fg_ptr->priority) {
   3265            LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3266              "Slice[%d] contains other groups with different priority.\n\r"),
   3267               slice_id));
   3268            return (BCM_E_CONFIG);
   3269         }
   3270 
   3271         /* Allow two groups without preselectors and with same prioirty for
   3272          *  backward comaptability. If two groups have same prioirty, that
   3273          *  means prioirty b/w these two groups doesnot matter to the user.
   3274          */
   3275         if ((fg_ptr->flags & _FP_GROUP_PRESELECTOR_SUPPORT) == 0 &&
   3276             (fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) == 0) {
   3277             return BCM_E_CONFIG;
   3278         }
   3279 
   3280        /*
   3281         * Groups can't share the slice, if the existing group
   3282         * doesn't support preselector
   3283         */
   3284         if ((fg_ptr->flags & _FP_GROUP_PRESELECTOR_SUPPORT) == 0) {
   3285            LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3286              "Group creation failed, Already default group exists"
   3287              " with the same priority[%d].\n\r"),
   3288               fg_ptr->priority));
   3289            return (BCM_E_PARAM);
   3290         }
   3291 
   3292         if ((fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) == 0) {
   3293            LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3294             "Group creation failed, can't create a group with the priority"
   3295             " same as existing preselector group priority[%d]\n\r"),
   3296               fg_ptr->priority));
   3297            return (BCM_E_PARAM);
   3298         }
   3299 
   3300         /* Compare the group modes */
   3301         mode = _FP_GROUP_SPAN_SINGLE_SLICE | _FP_GROUP_SPAN_DOUBLE_SLICE |
   3302                _FP_GROUP_SPAN_TRIPLE_SLICE | _FP_GROUP_INTRASLICE_DOUBLEWIDE;
   3303 
   3304         if ((fg->flags & mode) != (fg_ptr->flags & mode)) {
   3305            LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   3306              "Group creation failed, already existing group with the same"
   3307              " priority[%d] is in different mode. Can't create same priority"
   3308              " groups with different modes.\n\r"),
   3309               slice_id));
   3310            return (BCM_E_PARAM);
   3311         }
   3312 
   3313         /* Update the LT Slice to which the group's
   3314          * preselector entries are to be created. */
   3315         lt_slice = fg_ptr->lt_slices;
   3316     } else if (rv == BCM_E_NOT_FOUND) {
   3317         fs_part[0] = stage_fc->slices[fg->instance] + slice_id;
   3318         if (fs_part[0]->group_flags != 0x0) {
   3319             /*
   3320              *  If group_flags is not NULL, the slice must belongs to some
   3321              *  other group and should be a part of double-wide or Triple-wide
   3322              *  for the previous slice.
   3323              */
   3324             return BCM_E_CONFIG;
   3325         }
   3326     } else {
   3327         return rv;
   3328     }
   3329 
   3330     /*
   3331      * To share slices with more than one field group, mutually exclusive
   3332      * pre-selection rules must be setup in LT select TCAM. In legacy mode,
   3333      * only a default pre-selection rule is installed per-slice. Hence slices
   3334      * cannot be shared by multiple field groups. Validate slice LT mapping to
   3335      * confirm it's available for new group. For wide mode group, all slices
   3336      * should be available for group create to succeed.
   3337      */
   3338     BCM_IF_ERROR_RETURN(_field_th_group_lt_slice_validate(unit, stage_fc, fg,
   3339                                                           slice_id, lt_slice));
   3340 
   3341     return (BCM_E_NONE);
   3342 }
   3343 
   3344 /*
   3345  * Function:
   3346  *     _field_th_ingress_slice_mode_set
   3347  * Purpose:
   3348  *     Program group's slice mode in hardware.
   3349  * Parameters:
   3350  *     unit         - (IN) BCM device number.
   3351  *     stage_fc     - (IN) Stage field control structure.
   3352  *     slice_num    - (IN) Slice for which mode is to be set in HW.
   3353  *     fg           - (IN) Field group structure pointer.
   3354  *     clear        - (IN) Reset to hardware default value.
   3355  * Returns:
   3356  *     BCM_E_XXX
   3357  */
   3358 STATIC int
   3359 _field_th_ingress_slice_mode_set(int unit, _field_stage_t *stage_fc,
   3360                                  uint8 slice_num, _field_group_t *fg,
   3361                                  int clear)
   3362 {
   3363     uint8 mode;                          /* Slice mode: 0-Narrow, 1-Wide.  */
   3364     uint32 ifp_config;                   /* Register SW entry buffer.      */
   3365     soc_reg_t ifp_config_reg = INVALIDr; /* Per-Pipe IFP config registers. */
   3366 
   3367     /* Input Parameter Check */
   3368     if (NULL == stage_fc || NULL == fg) {
   3369         return (BCM_E_PARAM);
   3370     }
   3371 
   3372     /* Do nothing for exact match stage. */
   3373     if ((stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) ||
   3374         (stage_fc->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER)) {
   3375         return (BCM_E_NONE);
   3376     }
   3377 
   3378     if (0 == clear) {
   3379         /* Determine the slice mode based on group flags. */
   3380         mode = (fg->flags & _FP_GROUP_SPAN_SINGLE_SLICE)
   3381                     && !(fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE) ? 0 : 1;
   3382     } else {
   3383         /* HW reset default is "1 - Wide" mode. */
   3384         mode = 1;
   3385     }
   3386 
   3387 
   3388     switch (stage_fc->oper_mode) {
   3389         case bcmFieldGroupOperModeGlobal:
   3390             /* Get slice configuration from hardware. */
   3391             BCM_IF_ERROR_RETURN(READ_IFP_CONFIGr(unit, slice_num, &ifp_config));
   3392 
   3393             /* Set slice mode value in register buffer. */
   3394             if (!soc_feature(unit,
   3395                              soc_feature_ifp_no_narrow_mode_support)) {
   3396                 soc_reg_field_set(unit, IFP_CONFIGr, &ifp_config,
   3397                                   IFP_SLICE_MODEf,
   3398                                   mode);
   3399             }
   3400 
   3401             /* Write register value to hardware. */
   3402             BCM_IF_ERROR_RETURN(WRITE_IFP_CONFIGr(unit, slice_num, ifp_config));
   3403             break;
   3404 
   3405         case bcmFieldGroupOperModePipeLocal:
   3406             BCM_IF_ERROR_RETURN(_bcm_field_reg_instance_get(unit,
   3407                                                            IFP_CONFIGr,
   3408                                                            fg->instance,
   3409                                                            &ifp_config_reg));
   3410             BCM_IF_ERROR_RETURN(soc_reg32_get(unit,
   3411                 ifp_config_reg, REG_PORT_ANY, slice_num,
   3412                 &ifp_config));
   3413 
   3414             /* Set slice mode value in register buffer. */
   3415             if (!soc_feature(unit,
   3416                              soc_feature_ifp_no_narrow_mode_support)) {
   3417                 soc_reg_field_set(unit, ifp_config_reg, &ifp_config,
   3418                     IFP_SLICE_MODEf, mode);
   3419             }
   3420 
   3421             BCM_IF_ERROR_RETURN(soc_reg32_set(unit,
   3422                 ifp_config_reg, REG_PORT_ANY, slice_num,
   3423                 ifp_config));
   3424             break;
   3425         default:
   3426             return (BCM_E_INTERNAL);
   3427     }
   3428 
   3429     return (BCM_E_NONE);
   3430 }
   3431 
   3432 /*
   3433  * Function:
   3434  *     _field_th_lt_entry_dirty
   3435  * Purpose:
   3436  *     Check if logical table entry was modified after last installation
   3437  * Parameters:
   3438  *     unit     - (IN)  BCM device number.
   3439  *     lt_f_ent - (IN)  Primary entry pointer.
   3440  *     dirty    - (OUT) Entry dirty flag status.
   3441  * Returns:
   3442  *     BCM_E_XXX
   3443  */
   3444 STATIC int
   3445 _field_th_lt_entry_dirty(int unit, _field_lt_entry_t *lt_f_ent, int *dirty)
   3446 {
   3447     int parts_count = 0;    /* Entry TCAM parts count.  */
   3448     int idx;                /* Entry parts iterator.    */
   3449 
   3450     /* Input parameters check. */
   3451     if (NULL == lt_f_ent || NULL == dirty) {
   3452         return (BCM_E_PARAM);
   3453     }
   3454 
   3455     /* Get number of TCAM parts based on group flags. */
   3456     BCM_IF_ERROR_RETURN(_bcm_field_th_entry_tcam_parts_count(unit,
   3457         lt_f_ent->group->flags, &parts_count));
   3458 
   3459     for (idx = 0; idx < parts_count; idx++) {
   3460         if (lt_f_ent[idx].flags & _FP_ENTRY_DIRTY) {
   3461             break;
   3462         }
   3463     }
   3464 
   3465     /* Update dirty flags status based on part index value. */
   3466     *dirty = (idx < parts_count) ? TRUE : FALSE;
   3467 
   3468     return (BCM_E_NONE);
   3469 }
   3470 
   3471 /*
   3472  * Function:
   3473  *      _field_lt_entry_t_compare
   3474  * Purpose:
   3475  *      Compare logical table entry id in _field_lt_entry_t structure.
   3476  * Parameters:
   3477  *      a - (IN) first entry to compare.
   3478  *      b - (IN) second entry to compare with.
   3479  * Returns:
   3480  *      a<=>b
   3481  */
   3482 STATIC int
   3483 _field_lt_entry_t_compare(void *a, void *b)
   3484 {
   3485     _field_lt_entry_t **first; /* First compared entry. */
   3486     _field_lt_entry_t **second; /* Second compared entry. */
   3487 
   3488     first = (_field_lt_entry_t **)a;
   3489     second = (_field_lt_entry_t **)b;
   3490 
   3491     if ((*first)->eid < (*second)->eid) {
   3492         return (-1);
   3493     } else if ((*first)->eid > (*second)->eid) {
   3494         return (1);
   3495     }
   3496     return (0);
   3497 }
   3498 
   3499 /*
   3500  * Function:
   3501  *     _field_th_entry_flags_to_tcam_part
   3502  * Purpose:
   3503  *     Each logical table field entry contains up to 3 TCAM entries. This
   3504  *     routine maps sw entry flags to tcam entry (0-2).
   3505  *     Note this is not a physical address in tcam.
   3506  *     Single: 0
   3507  *     Single & Intraslice Double: 0
   3508  *     Paired: 0, 1
   3509  *     Triple: 0, 1, 2
   3510  * Parameters:
   3511  *     unit        - (IN)  BCM device number.
   3512  *     entry_flags - (IN)  Entry flags.
   3513  *     group_flags - (IN)  Entry group flags.
   3514  *     entry_part  - (OUT) Entry part (0-2)
   3515  * Returns:
   3516  *     BCM_E_NONE       - Success
   3517  *     BCM_E_INTERNAL   - Error
   3518  */
   3519 int
   3520 _bcm_field_th_entry_flags_to_tcam_part(int unit, uint32 entry_flags,
   3521                                        uint32 group_flags,
   3522                                        uint8 *entry_part)
   3523 {
   3524     /* Input parameter check. */
   3525     if (NULL == entry_part) {
   3526         return (BCM_E_PARAM);
   3527     }
   3528 
   3529     if (entry_flags & _FP_ENTRY_PRIMARY) {
   3530         *entry_part = 0;
   3531     } else if (entry_flags & _FP_ENTRY_SECONDARY) {
   3532         *entry_part = 1;
   3533     } else if (entry_flags & _FP_ENTRY_TERTIARY) {
   3534         *entry_part = 2;
   3535     } else {
   3536         return (BCM_E_INTERNAL);
   3537     }
   3538     return (BCM_E_NONE);
   3539 }
   3540 
   3541 /*
   3542  * Function:
   3543  *     _field_th_lt_entry_get
   3544  * Purpose:
   3545  *     Lookup a LT entry in Group's LT entries array for a given unit ID,
   3546  *     Entry ID and entry flags.
   3547  * Parmeters:
   3548  *     unit     - (IN)  BCM device number.
   3549  *     lt_eid   - (IN)  Logical table Entry ID.
   3550  *     flags    - (IN)  Entry flags to match.
   3551  *     lt_ent_p - (OUT) Entry lookup result.
   3552  * Returns:
   3553  *     BCM_E_XXX
   3554  */
   3555 STATIC int
   3556 _field_th_lt_entry_get(int unit, bcm_field_entry_t lt_eid, uint32 flags,
   3557                        _field_lt_entry_t **lt_ent_p)
   3558 {
   3559     _field_lt_entry_t target; /* LT entry lookup variable. */
   3560     _field_lt_entry_t *lt_f_ent; /* LT entry lookup pointer. */
   3561     _field_control_t *fc; /* Device Field control structure. */
   3562     _field_group_t *fg; /* Field group structure. */
   3563     uint8 entry_part = 0; /* Wide entry part number. */
   3564     int idx; /* LT entry index. */
   3565 
   3566     /* Input parameters check. */
   3567     if (NULL == lt_ent_p) {
   3568         return (BCM_E_PARAM);
   3569     }
   3570 
   3571     /* Initialize target logical table entry. */
   3572     target.eid = lt_eid;
   3573     lt_f_ent = &target;
   3574 
   3575     /* Get device Field control structure. */
   3576     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   3577 
   3578     /* Get field groups handle. */
   3579     fg = fc->groups;
   3580 
   3581     while (NULL != fg) {
   3582         /* Skip empty groups. */
   3583         if (NULL == fg->lt_entry_arr) {
   3584             fg = fg->next;
   3585             continue;
   3586         }
   3587 
   3588         /* Search in group entry array list.*/
   3589         idx = _shr_bsearch(fg->lt_entry_arr, fg->lt_grp_status.entry_count,
   3590                     sizeof(_field_lt_entry_t *), (void *)&lt_f_ent,
   3591                     _field_lt_entry_t_compare);
   3592         if (idx >= 0) {
   3593             (void) _bcm_field_th_entry_flags_to_tcam_part(unit, flags,
   3594                                    fg->flags, &entry_part);
   3595             *lt_ent_p = fg->lt_entry_arr[idx] + entry_part;
   3596             return (BCM_E_NONE);
   3597         }
   3598         fg = fg->next;
   3599     }
   3600 
   3601     /* LT entry with lt_eid not found. */
   3602     return (BCM_E_NOT_FOUND);
   3603 }
   3604 
   3605 /*
   3606  * Function:
   3607  *     _field_th_lt_entry_get_by_id
   3608  * Purpose:
   3609  *     Lookup a complete Logical table FP rule(entry) from a unit & rule id
   3610  *     choice.
   3611  * Parmeters:
   3612  *     unit         - (IN) BCM device number.
   3613  *     lt_eid       - (IN) LT Entry id.
   3614  *     lt_ent_arr   - (OUT) Entry lookup result array.
   3615  *                          (Array of pointers to primary/secondary/teriary ...
   3616  *                           parts of entry).
   3617  * Returns:
   3618  *     BCM_E_XXX
   3619  */
   3620 STATIC int
   3621 _field_th_lt_entry_get_by_id(int unit, bcm_field_entry_t lt_eid,
   3622                              _field_lt_entry_t **lt_ent_arr)
   3623 {
   3624     int rv; /* Operation return status. */
   3625 
   3626     /* Input parameter check. */
   3627     if (NULL == lt_ent_arr) {
   3628         return (BCM_E_PARAM);
   3629     }
   3630 
   3631     /* Initialize entry pointer array*/
   3632     *lt_ent_arr = NULL;
   3633 
   3634     rv = _field_th_lt_entry_get(unit, lt_eid, _FP_ENTRY_PRIMARY, lt_ent_arr);
   3635     return (rv);
   3636 }
   3637 
   3638 /*
   3639  * Function:
   3640  *     _field_th_lt_entry_tcam_idx_get
   3641  * Purpose:
   3642  *     Get the TCAM index of an entry ID.
   3643  * Parameters:
   3644  *     unit         - (IN) BCM device number.
   3645  *     lt_f_ent     - (IN) Pointer to field logical table entry structure.
   3646  *     lt_fs        - (IN) Pointer to field logical table slice structure.
   3647  *     tcam_idx     - (OUT) Entry tcam index.
   3648  *
   3649  * Returns:
   3650  *     BCM_E_XXX
   3651  */
   3652 STATIC int
   3653 _field_th_lt_entry_tcam_idx_get(int unit, _field_lt_entry_t *lt_f_ent,
   3654                                 _field_lt_slice_t *lt_fs, int *tcam_idx)
   3655 {
   3656     /* Input parameters check. */
   3657     if ((NULL == lt_f_ent) || (NULL == tcam_idx || (NULL == lt_fs))) {
   3658         return (BCM_E_PARAM);
   3659     }
   3660 
   3661     /* Requested entry structure sanity check. */
   3662     if ((NULL == lt_f_ent->group) || (NULL == lt_f_ent->lt_fs)) {
   3663         return (BCM_E_PARAM);
   3664     }
   3665 
   3666     /* Calculate the TCAM index. */
   3667     *tcam_idx = lt_fs->start_tcam_idx + lt_f_ent->index;
   3668 
   3669     return (BCM_E_NONE);
   3670 }
   3671 
   3672 /*
   3673  * Function:
   3674  *     _field_th_lt_tcam_mem_get
   3675  * Purpose:
   3676  *     Get logica table memory identifier based on stage group operational mode.
   3677  * Parameters:
   3678  *     unit         - (IN)     BCM device number.
   3679  *     stage_fc     - (IN)     Stage field control structure.
   3680  *     lt_f_ent     - (IN)     Pointer to field logical table entry structure.
   3681  *     lt_tcam_mem  - (IN/OUT) LT memory identifer pointer.
   3682  *
   3683  * Returns:
   3684  *     BCM_E_XXX
   3685  */
   3686 STATIC int
   3687 _field_th_lt_tcam_mem_get(int unit, _field_stage_t *stage_fc,
   3688                           _field_lt_entry_t *lt_f_ent,
   3689                           soc_mem_t *lt_tcam_mem)
   3690 {
   3691     /* Input parameters check. */
   3692     if ((NULL == stage_fc) || (NULL == lt_f_ent) || (NULL == lt_tcam_mem)) {
   3693         return (BCM_E_PARAM);
   3694     }
   3695 
   3696     /* Set LT selection memory identifier based on stage group oper mode. */
   3697     switch (stage_fc->oper_mode) {
   3698         case bcmFieldGroupOperModeGlobal:
   3699             if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   3700                 *lt_tcam_mem = IFP_LOGICAL_TABLE_SELECTm;
   3701             } else if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   3702                 *lt_tcam_mem = EXACT_MATCH_LOGICAL_TABLE_SELECTm;
   3703             } else {
   3704                 return (BCM_E_INTERNAL);
   3705             }
   3706             break;
   3707         case bcmFieldGroupOperModePipeLocal:
   3708             if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   3709                 BCM_IF_ERROR_RETURN(_bcm_field_mem_instance_get(unit,
   3710                                                        IFP_LOGICAL_TABLE_SELECTm,
   3711                                                        lt_f_ent->group->instance,
   3712                                                        lt_tcam_mem));
   3713             } else if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   3714                 BCM_IF_ERROR_RETURN(_bcm_field_mem_instance_get(unit,
   3715                                                        EXACT_MATCH_LOGICAL_TABLE_SELECTm,
   3716                                                        lt_f_ent->group->instance,
   3717                                                        lt_tcam_mem));
   3718             } else {
   3719                 return (BCM_E_INTERNAL);
   3720             }
   3721             break;
   3722         default:
   3723             return (BCM_E_INTERNAL);
   3724     }
   3725     return (BCM_E_NONE);
   3726 }
   3727 
   3728 /*
   3729  * Function:
   3730  *     _bcm_field_th_lt_tcam_entry_get
   3731  * Purpose:
   3732  *     Read an entry installed in hardware into SW entry buffer.
   3733  * Parameters:
   3734  *     unit     - (IN)  BCM device number.
   3735  *     fg       - (IN)  Pointer to field group structure.
   3736  *     lt_f_ent - (OUT) Pointer to field logical table entry structure.
   3737  * Returns:
   3738  *     BCM_E_XXX
   3739  */
   3740 int
   3741 _bcm_field_th_lt_tcam_entry_get(int unit, _field_group_t *fg,
   3742                             _field_lt_entry_t *lt_f_ent)
   3743 {
   3744     uint32 tcam_entry[SOC_MAX_MEM_FIELD_WORDS]; /* Entry buffer.    */
   3745     _field_stage_t *stage_fc;     /* Stage field control structure. */
   3746     int tcam_idx;                 /* TCAM index.                    */
   3747     static soc_mem_t lt_tcam_mem; /* LT selection TCAM memory ID.   */
   3748     int rv;                       /* Operation return status.       */
   3749 
   3750     /* Input parameters check. */
   3751     if ((NULL == lt_f_ent) || (NULL == fg)) {
   3752         return (BCM_E_PARAM);
   3753     }
   3754 
   3755     /* Check if LT TCAM entry is already present in SW. */
   3756     if (NULL != lt_f_ent->tcam.key) {
   3757         return (BCM_E_NONE);
   3758     }
   3759 
   3760     /* Get stage field control structure. */
   3761     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fg->stage_id,
   3762         &stage_fc));
   3763 
   3764     /* Get key and data field based on stage */
   3765     if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   3766         /* Get key field size in logical table entry. */
   3767         lt_f_ent->tcam.key_size = WORDS2BYTES(soc_mem_field_length(unit,
   3768                     IFP_LOGICAL_TABLE_SELECTm, KEYf));
   3769 
   3770         /* Get data field size in logical table entry. */
   3771         lt_f_ent->tcam.data_size = WORDS2BYTES(soc_mem_field_length(unit,
   3772                     IFP_LOGICAL_TABLE_SELECTm, DATAf));
   3773     } else if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   3774         /* Get key field size in logical table entry. */
   3775         lt_f_ent->tcam.key_size = WORDS2BYTES(soc_mem_field_length(unit,
   3776                     EXACT_MATCH_LOGICAL_TABLE_SELECTm, KEYf));
   3777 
   3778         /* Get data field size in logical table entry. */
   3779         lt_f_ent->tcam.data_size = WORDS2BYTES(soc_mem_field_length(unit,
   3780                     EXACT_MATCH_LOGICAL_TABLE_SELECTm, DATAf));
   3781     } else {
   3782         return (BCM_E_PARAM);
   3783     }
   3784 
   3785     /* Allocate memory to store entry Key info. */
   3786     _FP_XGS3_ALLOC(lt_f_ent->tcam.key, lt_f_ent->tcam.key_size,
   3787                     "LT Key Alloc.");
   3788     if (NULL == lt_f_ent->tcam.key) {
   3789         rv = BCM_E_MEMORY;
   3790         goto error;
   3791     }
   3792 
   3793     /* Allocate memory to store entry Mask info. */
   3794     _FP_XGS3_ALLOC(lt_f_ent->tcam.mask, lt_f_ent->tcam.key_size,
   3795                     "LT Mask Alloc.");
   3796     if (NULL == lt_f_ent->tcam.mask) {
   3797         rv = BCM_E_MEMORY;
   3798         goto error;
   3799     }
   3800 
   3801     /* Allocate memory to store entry Data info. */
   3802     _FP_XGS3_ALLOC(lt_f_ent->tcam.data, lt_f_ent->tcam.data_size,
   3803                     "LT Data Alloc.");
   3804     if (NULL == lt_f_ent->tcam.data) {
   3805         rv = BCM_E_MEMORY;
   3806         goto error;
   3807     }
   3808 
   3809     /* Get entry TCAM index. */
   3810     rv = _field_th_lt_entry_tcam_idx_get(unit, lt_f_ent, lt_f_ent->lt_fs,
   3811                                          &tcam_idx);
   3812     if (BCM_FAILURE(rv)) {
   3813         goto error;
   3814     }
   3815 
   3816     /* Get logical table memory name based on the group operational mode. */
   3817     BCM_IF_ERROR_RETURN(_field_th_lt_tcam_mem_get(unit, stage_fc, lt_f_ent,
   3818         &lt_tcam_mem));
   3819 
   3820     /* Read entry part from hardware. */
   3821     rv = soc_th_ifp_mem_read(unit, lt_tcam_mem, MEM_BLOCK_ANY, tcam_idx,
   3822             tcam_entry);
   3823     if (BCM_FAILURE(rv)) {
   3824         goto error;
   3825     }
   3826 
   3827     /* Get entry Key value. */
   3828     soc_mem_field_get(unit, lt_tcam_mem, tcam_entry, KEYf,
   3829         lt_f_ent->tcam.key);
   3830 
   3831     /* Get entry Mask value. */
   3832     soc_mem_field_get(unit, lt_tcam_mem, tcam_entry, MASKf,
   3833         lt_f_ent->tcam.mask);
   3834 
   3835     /* Get entry Data value. */
   3836     soc_mem_field_get(unit, lt_tcam_mem, tcam_entry, DATAf,
   3837         lt_f_ent->tcam.data);
   3838 
   3839     return (BCM_E_NONE);
   3840 
   3841 error:
   3842     if (lt_f_ent->tcam.key) {
   3843         sal_free(lt_f_ent->tcam.key);
   3844         lt_f_ent->tcam.key = NULL;
   3845     }
   3846 
   3847     if (lt_f_ent->tcam.mask) {
   3848         sal_free(lt_f_ent->tcam.mask);
   3849         lt_f_ent->tcam.mask = NULL;
   3850     }
   3851 
   3852     if (lt_f_ent->tcam.data) {
   3853         sal_free(lt_f_ent->tcam.data);
   3854         lt_f_ent->tcam.data = NULL;
   3855     }
   3856 
   3857     return (rv);
   3858 }
   3859 
   3860 /*
   3861  * Function:
   3862  *     _field_th_lt_default_entry_install
   3863  * Purpose:
   3864  *     Install a logical table entry in hardware.
   3865  * Parameters:
   3866  *     unit     - (IN) BCM device number.
   3867  *     lt_entry - (IN) Field logical table entry.
   3868  * Returns:
   3869  *     BCM_E_XXX
   3870  */
   3871 STATIC int
   3872 _field_th_lt_default_entry_install(int unit, bcm_field_entry_t lt_entry)
   3873 {
   3874     _field_control_t *fc;           /* Field control structure. */
   3875     _field_lt_entry_t *lt_f_ent;    /* LT field entry.          */
   3876     int rv;                         /* Operation return status. */
   3877     int dirty;                      /* Field entry dirty flag.  */
   3878 
   3879     /* Get device field control structure. */
   3880     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   3881 
   3882     /* Lookup using entry ID and get the SW entry copy. */
   3883     BCM_IF_ERROR_RETURN(_field_th_lt_entry_get(unit, lt_entry,
   3884         _FP_ENTRY_PRIMARY, &lt_f_ent));
   3885 
   3886     /* Check if entry has been modified since last install in hardware. */
   3887     BCM_IF_ERROR_RETURN(_field_th_lt_entry_dirty(unit, lt_f_ent, &dirty));
   3888 
   3889     if (dirty) {
   3890         /* Entry has changed, install in hardware. */
   3891         rv = _field_th_lt_default_tcam_entry_install(unit, lt_entry, 0, 0, NULL);
   3892     } else {
   3893         /* No change and nothing to do, return success. */
   3894         rv = BCM_E_NONE;
   3895     }
   3896     return rv;
   3897 }
   3898 
   3899 /*
   3900  * Function:
   3901  *     _field_th_group_lt_entry_add
   3902  * Purpose:
   3903  *     Given stage, group instance, slice and entry offset in slice, calculate
   3904  *     TCAM index.
   3905  * Parameters:
   3906  *     unit     - (IN)  BCM device number.
   3907  *     fg       - (IN)  Field group structure.
   3908  *     lt_f_ent - (OUT) Field logical table entry structure.
   3909  * Returns:
   3910  *     BCM_E_XXX
   3911  */
   3912 STATIC int
   3913 _field_th_group_lt_entry_add(int unit, _field_group_t *fg,
   3914                              _field_lt_entry_t *lt_f_ent)
   3915 {
   3916     _field_lt_entry_t **lt_f_ent_arr;   /* Field group LT entry array. */
   3917     int mem_sz;                         /* Allocation memory size. */
   3918     int idx;                            /* Entry insertion index. */
   3919     int tmp;                            /* Temporary iterator. */
   3920 
   3921     /* Input parameters check. */
   3922     if (NULL == fg || NULL == lt_f_ent) {
   3923         return (BCM_E_PARAM);
   3924     }
   3925 
   3926     /* Verify if entry is already present in the group. */
   3927     if (NULL != fg->lt_entry_arr) {
   3928         idx = _shr_bsearch(fg->lt_entry_arr, fg->lt_grp_status.entry_count,
   3929                     sizeof(_field_lt_entry_t *), &lt_f_ent,
   3930                     _field_lt_entry_t_compare);
   3931         if (idx >= 0) {
   3932             return (BCM_E_NONE);
   3933         }
   3934     } else {
   3935         idx = -1; /* Insert into 0th location. */
   3936     }
   3937 
   3938     /* Check if group has enough room for new entry. */
   3939     if ((fg->lt_grp_status.entry_count + 1)
   3940         > (fg->lt_ent_blk_cnt * _FP_GROUP_ENTRY_ARR_BLOCK)) {
   3941         mem_sz = _FP_GROUP_ENTRY_ARR_BLOCK * (fg->lt_ent_blk_cnt + 1)
   3942                     * sizeof(_field_lt_entry_t *);
   3943         lt_f_ent_arr = NULL;
   3944         _FP_XGS3_ALLOC(lt_f_ent_arr, mem_sz, "field group LT entries array");
   3945         if (NULL == lt_f_ent_arr) {
   3946             return (BCM_E_MEMORY);
   3947         }
   3948 
   3949         /* Copy original array to newly allocated one. */
   3950         if (NULL != fg->lt_entry_arr) {
   3951             mem_sz = _FP_GROUP_ENTRY_ARR_BLOCK * (fg->lt_ent_blk_cnt)
   3952                         * sizeof(_field_lt_entry_t *);
   3953             sal_memcpy(lt_f_ent_arr, fg->lt_entry_arr, mem_sz);
   3954             sal_free(fg->lt_entry_arr);
   3955         }
   3956 
   3957         fg->lt_entry_arr = lt_f_ent_arr;
   3958         fg->lt_ent_blk_cnt++;
   3959     }
   3960 
   3961     /* Check entry block exists to add the entry. */
   3962     if (NULL != fg->lt_entry_arr) {
   3963         /*
   3964          * Make room for entry insertion.
   3965          */
   3966         idx = (((-1) * idx) - 1);
   3967         tmp = fg->lt_grp_status.entry_count - 1;
   3968         while (tmp >= idx) {
   3969             fg->lt_entry_arr[tmp + 1] = fg->lt_entry_arr[tmp];
   3970             tmp--;
   3971         }
   3972         fg->lt_entry_arr[idx] = lt_f_ent;
   3973         fg->lt_grp_status.entry_count++;
   3974     }
   3975     return (BCM_E_NONE);
   3976 }
   3977 
   3978 /*
   3979  * Function:
   3980  *     _bcm_field_th_lt_slice_offset_to_tcam_index
   3981  * Purpose:
   3982  *     Given stage, group instance, slice and entry offset in slice, calculate
   3983  *     TCAM index.
   3984  * Parameters:
   3985  *     unit     - (IN) BCM device number.
   3986  *     stage_fc - (IN) Pointer to field entry structure.
   3987  *     slice    - (IN) Entry slice number.
   3988  *     slice_idx -(IN) Entry offset in the slice.
   3989  *     tcam_idx - (OUT) Entry tcam index.
   3990  * Returns:
   3991  *     BCM_E_XXX
   3992  */
   3993 int
   3994 _bcm_field_th_lt_slice_offset_to_tcam_index(int unit, _field_stage_t *stage_fc,
   3995                                             int instance, int slice,
   3996                                             int slice_idx, int *tcam_idx)
   3997 {
   3998     _field_lt_slice_t *lt_fs; /* Logical table slice number. */
   3999 
   4000     /* Input parameters check. */
   4001     if ((NULL == stage_fc) || (NULL == tcam_idx)) {
   4002         return (BCM_E_PARAM);
   4003     }
   4004 
   4005     /* Input parameters check. */
   4006     if (instance < 0 || instance >= stage_fc->num_instances) {
   4007         return (BCM_E_PARAM);
   4008     }
   4009 
   4010     /* Get logical table slice structure. */
   4011     lt_fs = stage_fc->lt_slices[instance] + slice;
   4012 
   4013     /*
   4014      * Compute TCAM index using the slice start TCAM index and supplied
   4015      * slice offset index.
   4016      */
   4017     *tcam_idx = lt_fs->start_tcam_idx + slice_idx;
   4018 
   4019     return (BCM_E_NONE);
   4020 }
   4021 
   4022 /*
   4023  * Function:
   4024  *     _bcm_field_th_lt_tcam_idx_to_slice_offset
   4025  * Purpose:
   4026  *     Given stage, group instance and tcam_index, calculate slice and entry
   4027  *     offset in the slice.
   4028  * Parameters:
   4029  *     unit         - (IN) BCM device number.
   4030  *     stage_fc     - (IN) Stage field control structure.
   4031  *     instance     - (IN) Field Group instance.
   4032  *     tcam_idx     - (IN) Entry tcam index.
   4033  *     slice        - (OUT) Entry slice number.
   4034  *     slice_idx    - (OUT) Entry offset in the slice.
   4035  * Returns:
   4036  *     BCM_E_XXX
   4037  */
   4038 int
   4039 _bcm_field_th_lt_tcam_idx_to_slice_offset(int unit, _field_stage_t *stage_fc,
   4040                                           int instance, int tcam_idx,
   4041                                           int *slice, int *slice_idx)
   4042 {
   4043     _field_lt_slice_t *lt_fs;   /* Field Slice number.  */
   4044     int idx;                    /* Slice iterator.      */
   4045 
   4046     /* Input parameters check. */
   4047     if ((NULL == stage_fc) || (NULL == slice_idx) || (NULL == slice)
   4048         || (instance < 0 || instance > stage_fc->num_instances)) {
   4049         return (BCM_E_PARAM);
   4050     }
   4051 
   4052     for (idx = 0; idx < stage_fc->tcam_slices; idx++) {
   4053         lt_fs = stage_fc->lt_slices[instance] + idx;
   4054         if (tcam_idx < (lt_fs->start_tcam_idx + lt_fs->entry_count)) {
   4055             *slice = idx;
   4056             *slice_idx = tcam_idx - lt_fs->start_tcam_idx;
   4057             break;
   4058         }
   4059     }
   4060 
   4061     /* TCAM index sanity check. */
   4062     if (idx == stage_fc->tcam_slices) {
   4063         return (BCM_E_PARAM);
   4064     }
   4065 
   4066     return (BCM_E_NONE);
   4067 }
   4068 
   4069 /*
   4070  * Function:
   4071  *     _bcm_field_th_lt_entry_part_tcam_idx_get
   4072  *
   4073  * Purpose:
   4074  *     Given primary entry slice/idx calculate
   4075  *     secondary/tertiary slice/index.
   4076  *
   4077  * Parameters:
   4078  *     unit    - (IN) BCM device number.
   4079  *     f_ent   - (IN) Field entry pointer.
   4080  *     idx_pri - (IN) Primary entry tcam index.
   4081  *     ent_part    - (IN) Entry part id.
   4082  *     idx_out - (OUT) Entry part tcam index.
   4083  * Returns
   4084  *     BCM_E_XXX
   4085  */
   4086 int
   4087 _bcm_field_th_lt_entry_part_tcam_idx_get(int unit, _field_group_t *fg,
   4088                                          uint32 idx_pri, uint8 ent_part,
   4089                                          int *idx_out)
   4090 {
   4091     uint8 slice_num;            /* Primary entry slice number.      */
   4092     int pri_slice = -1;          /* Prmary entry slice number.       */
   4093     int pri_index = -1;          /* Primary entry slice index.       */
   4094     _field_stage_t *stage_fc;   /* Stage field control structure.   */
   4095     _field_lt_slice_t *lt_fs;   /* Logical table slice structure.   */
   4096     int rv;                     /* Operation return status.         */
   4097 
   4098 
   4099     /* Input parameters check. */
   4100     if (NULL == fg || NULL == idx_out) {
   4101         return (BCM_E_PARAM);
   4102     }
   4103 
   4104     /* Primary entry index. */
   4105     if (0 == ent_part) {
   4106         *idx_out = idx_pri;
   4107         return (BCM_E_NONE);
   4108     }
   4109 
   4110     /* Get Stage Field Control Structure. */
   4111     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fg->stage_id,
   4112         &stage_fc));
   4113 
   4114     /*
   4115      * Get primary part entry slice number and slice offset given entry TCAM
   4116      * index.
   4117      */
   4118     BCM_IF_ERROR_RETURN(_bcm_field_th_lt_tcam_idx_to_slice_offset(unit,
   4119         stage_fc, fg->instance, idx_pri, &pri_slice, &pri_index));
   4120 
   4121     /* Get entry part to slice number 0, 1, 2 */
   4122     BCM_IF_ERROR_RETURN(_bcm_field_th_tcam_part_to_slice_number(ent_part,
   4123         fg->flags, &slice_num));
   4124 
   4125     /* Get slice descriptor structure. */
   4126     lt_fs = stage_fc->lt_slices[fg->instance] + (pri_slice + slice_num);
   4127 
   4128     /* Get the TCAM index given slice number and slice entry offset. */
   4129     rv = _bcm_field_th_lt_slice_offset_to_tcam_index(unit, stage_fc,
   4130             fg->instance, lt_fs->slice_number, pri_index, idx_out);
   4131 
   4132     return (rv);
   4133 }
   4134 
   4135 /*
   4136  * Function:
   4137  *    _field_th_lt_default_entry_phys_create
   4138  * Purpose:
   4139  *    Create a physical entry in a logical table slice.
   4140  * Parameters:
   4141  *    unit      - (IN) BCM device number.
   4142  *    stage_fc  - (IN) Stage field control structure.
   4143  *    lt_ent    - (IN) Logical table entry identifier.
   4144  *    prio      - (IN) Logical table entry priority.
   4145  *    lt_fs     - (IN) Logical table slice structure.
   4146  *    fg        - (IN) Field group structure.
   4147  *    ent_p     - (OUT) Allocated & initialized entry.
   4148  * Returns:
   4149  *    BCM_E_XXX
   4150  */
   4151 STATIC int
   4152 _field_th_lt_default_entry_phys_create(int unit, _field_stage_t *stage_fc,
   4153                                    bcm_field_entry_t lt_ent, int prio,
   4154                                    _field_lt_slice_t *lt_fs, _field_group_t *fg,
   4155                                    _field_lt_entry_t **ent_p)
   4156 {
   4157     _field_control_t *fc;   /* Field control structure.              */
   4158     int idx;                /* Slice entries iteration index.        */
   4159     int parts_count = -1;   /* Number of entry parts.                */
   4160     int part_index;         /* Entry parts iterator.                 */
   4161     int mem_sz;             /* Memory allocation size.               */
   4162     _field_lt_entry_t *lt_f_ent = NULL; /* LT field entry structure. */
   4163     int rv;                 /* Operation return status.              */
   4164     int pri_tcam_idx = -1;  /* Primary entry TCAM index.             */
   4165     int slice_num = -1;     /* Slice number.                         */
   4166 
   4167     /* Input parameters check. */
   4168     if ((NULL == stage_fc) || (NULL == lt_fs) || (NULL == fg)
   4169          || (NULL == ent_p)) {
   4170         return (BCM_E_PARAM);
   4171     }
   4172 
   4173     /* Check if free entries are available in the slice. */
   4174     if (0 == lt_fs->free_count) {
   4175         return (BCM_E_RESOURCE);
   4176     }
   4177 
   4178     /* Get device field control structure. */
   4179     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   4180 
   4181     /* Get number of entry parts based on group flags. */
   4182     BCM_IF_ERROR_RETURN(_bcm_field_th_entry_tcam_parts_count(unit, fg->flags,
   4183         &parts_count));
   4184 
   4185     /* Calcuate buffer size required for SW entry. */
   4186     mem_sz = sizeof(_field_lt_entry_t) * parts_count;
   4187 
   4188     /* Allocate and zero memory for LT selection entry. */
   4189     _FP_XGS3_ALLOC(lt_f_ent, mem_sz, "LT field entry");
   4190     if (NULL == lt_f_ent) {
   4191         LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   4192             "FP(unit %d) Error: allocation failure for LT entry\n"), unit));
   4193         return (BCM_E_MEMORY);
   4194     }
   4195 
   4196     /* Get index for primary entry. */
   4197     for (idx = 0; idx < lt_fs->entry_count; idx++) {
   4198         if (NULL == lt_fs->entries[idx]) {
   4199 #if defined (BCM_TOMAHAWK3_SUPPORT)
   4200             if ((soc_feature(unit, soc_feature_sw_mmu_flush_rqe_operation)) &&
   4201                 (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH)) {
   4202                  if (NULL == lt_fs->p_entries[idx]) {
   4203                      lt_f_ent->index = idx;
   4204                      break;
   4205                  }
   4206             } else
   4207 #endif
   4208             {
   4209                  lt_f_ent->index = idx;
   4210                  break;
   4211             }
   4212         }
   4213     }
   4214 
   4215     /* Get entry TCAM index given slice number and entry offset in slice. */
   4216     rv = _bcm_field_th_lt_slice_offset_to_tcam_index(unit, stage_fc,
   4217             fg->instance, lt_fs->slice_number, lt_f_ent->index, &pri_tcam_idx);
   4218     if (BCM_FAILURE(rv)) {
   4219         sal_free(lt_f_ent);
   4220         return (rv);
   4221     }
   4222 
   4223     /* Fill entry primitives. */
   4224     for (idx = 0; idx < parts_count; idx++) {
   4225         lt_f_ent[idx].eid = lt_ent;
   4226         lt_f_ent[idx].prio = prio;
   4227         lt_f_ent[idx].group = fg;
   4228 
   4229         /* Get entry part flags. */
   4230         rv = _bcm_field_th_tcam_part_to_entry_flags(unit, idx, fg->flags,
   4231                 &lt_f_ent[idx].flags);
   4232         if (BCM_FAILURE(rv)) {
   4233             sal_free(lt_f_ent);
   4234             return rv;
   4235         }
   4236 
   4237         /* Given primary entry TCAM index calculate entry part tcam index. */
   4238         if (0 != idx) {
   4239             rv = _bcm_field_th_lt_entry_part_tcam_idx_get(unit, lt_f_ent->group,
   4240                                                 pri_tcam_idx, idx, &part_index);
   4241             if (BCM_FAILURE(rv)) {
   4242                 sal_free(lt_f_ent);
   4243                 return (rv);
   4244             }
   4245 
   4246             /*
   4247              * Given entry part TCAM index, determine the slice number and slice
   4248              * offset index.
   4249              */
   4250             rv = _bcm_field_th_lt_tcam_idx_to_slice_offset(unit, stage_fc,
   4251                     fg->instance, part_index, &slice_num,
   4252                     (int *)&lt_f_ent[idx].index);
   4253             if (BCM_FAILURE(rv)) {
   4254                 sal_free(lt_f_ent);
   4255                 return (rv);
   4256             }
   4257             lt_f_ent[idx].lt_fs = stage_fc->lt_slices[fg->instance] + slice_num;
   4258         } else {
   4259             /* Set entry slice. */
   4260             lt_f_ent[idx].lt_fs = lt_fs;
   4261         }
   4262 
   4263         /* Mark entry dirty. */
   4264         lt_f_ent[idx].flags |= _FP_ENTRY_DIRTY;
   4265     }
   4266 
   4267     /* Insert the entry into group entry array. */
   4268     rv = _field_th_group_lt_entry_add(unit, fg, lt_f_ent);
   4269     if (BCM_FAILURE(rv)) {
   4270         sal_free(lt_f_ent);
   4271         return (rv);
   4272     }
   4273 
   4274     /* Update slice related parameters after succesful update */
   4275     for (idx = 0; idx < parts_count; idx++) {
   4276         /* Decrement slice free entry count for primary entries. */
   4277         lt_f_ent[idx].lt_fs->free_count--;
   4278 
   4279         /* Assign entry to a slice. */
   4280         lt_f_ent[idx].lt_fs->entries[lt_f_ent[idx].index] = lt_f_ent + idx;
   4281     }
   4282 
   4283     /* Return allocated/filled entry structure to the caller. */
   4284     *ent_p = lt_f_ent;
   4285     return (rv);
   4286 }
   4287 
   4288 /*
   4289  * Function:
   4290  *    _field_th_group_lt_entry_delete
   4291  * Purpose:
   4292  *    Delete an entry from group LT entries array.
   4293  * Parameters:
   4294  *    unit     - (IN) BCM device number.
   4295  *    fg       - (IN) Field group structure.
   4296  *    lt_f_ent - (IN) Logical table entry structure.
   4297  * Returns:
   4298  *    BCM_E_XXX
   4299  */
   4300 STATIC int
   4301 _field_th_group_lt_entry_delete(int unit, _field_group_t *fg,
   4302                                 _field_lt_entry_t *lt_f_ent)
   4303 {
   4304     int idx; /* Entry deletion index.   */
   4305     int tmp; /* Temporary iterator.     */
   4306 
   4307     /* Input parameters check. */
   4308     if ((NULL == fg) || (NULL == lt_f_ent)) {
   4309         return (BCM_E_PARAM);
   4310     }
   4311 
   4312     /* Ensure group entry array is valid. */
   4313     if (NULL == fg->lt_entry_arr) {
   4314         return (BCM_E_INTERNAL);
   4315     }
   4316 
   4317     /* Confirm entry is present in the group. */
   4318     idx = _shr_bsearch(fg->lt_entry_arr, fg->lt_grp_status.entry_count,
   4319                 sizeof(_field_lt_entry_t *), &lt_f_ent,
   4320                 _field_lt_entry_t_compare);
   4321     if (idx < 0) {
   4322         return (BCM_E_NOT_FOUND);
   4323     }
   4324 
   4325     /* Store array index where the entry was found. */
   4326     tmp = idx;
   4327     /*
   4328      * Re-Pack the entries array to clear the last pointer due to entry deletion.
   4329      */
   4330     while (tmp < fg->lt_grp_status.entry_count - 1) {
   4331         fg->lt_entry_arr[tmp] = fg->lt_entry_arr[tmp + 1];
   4332         tmp++;
   4333     }
   4334 
   4335     /* Decrement total valid entry count. */
   4336     fg->lt_grp_status.entry_count--;
   4337 
   4338     /* Clear entry address stored in the last array index. */
   4339     fg->lt_entry_arr[fg->lt_grp_status.entry_count] = NULL;
   4340 
   4341     return (BCM_E_NONE);
   4342 }
   4343 
   4344 /*
   4345  * Function:
   4346  *    _field_th_lt_default_entry_phys_destroy
   4347  * Purpose:
   4348  *    Destroy a physical entry from a logical table slice.
   4349  * Parameters:
   4350  *    unit     - (IN) BCM device number.
   4351  *    lt_f_ent - (IN) Logical table entry structure.
   4352  * Returns:
   4353  *    BCM_E_XXX
   4354  */
   4355 STATIC int
   4356 _field_th_lt_default_entry_phys_destroy(int unit, _field_lt_entry_t *lt_f_ent)
   4357 {
   4358     _field_control_t *fc;       /* Device field control structure. */
   4359     _field_lt_slice_t *lt_fs;   /* Logical table slice structure.  */
   4360     _field_group_t *fg;         /* Field group structure.          */
   4361     int parts_count = -1;       /* Entry parts count.              */
   4362     int idx;                    /* Entry iterator index.           */
   4363     uint8 slice_number;         /* Slice number.                   */
   4364     int rv;                     /* Operation return status.        */
   4365 
   4366     /* Input parameters check. */
   4367     if ((NULL == lt_f_ent) || (NULL == lt_f_ent->lt_fs)) {
   4368         return (BCM_E_PARAM);
   4369     }
   4370 
   4371     /* Get field control structure. */
   4372     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   4373 
   4374     /* Get entry slice information. */
   4375     lt_fs = lt_f_ent->lt_fs;
   4376 
   4377     /* Get the group to which the entry belongs. */
   4378     fg = lt_f_ent->group;
   4379 
   4380     /* Get entry parts count. */
   4381     BCM_IF_ERROR_RETURN(_bcm_field_th_entry_tcam_parts_count(unit, fg->flags,
   4382         &parts_count));
   4383 
   4384     for (idx = 0; idx < parts_count; idx++) {
   4385 
   4386         /* Free entry TCAM key buffer if valid. */
   4387         if (NULL != lt_f_ent[idx].tcam.key) {
   4388             sal_free(lt_f_ent[idx].tcam.key);
   4389         }
   4390 
   4391         /* Free entry TCAM mask buffer if valid. */
   4392         if (NULL != lt_f_ent[idx].tcam.mask) {
   4393             sal_free(lt_f_ent[idx].tcam.mask);
   4394         }
   4395 
   4396         /* Free entry Data mask buffer if valid. */
   4397         if (NULL != lt_f_ent[idx].tcam.data) {
   4398             sal_free(lt_f_ent[idx].tcam.data);
   4399         }
   4400 
   4401         /* Get entry part slice number. */
   4402         BCM_IF_ERROR_RETURN(_bcm_field_th_tcam_part_to_slice_number(idx,
   4403             fg->flags, &slice_number));
   4404 
   4405         /* Remove entry pointer from the slice. */
   4406         lt_fs[slice_number].entries[lt_f_ent[idx].index] = NULL;
   4407 
   4408         /* Increment slice unused entry count. */
   4409         if (0 == (lt_f_ent[idx].flags & _FP_ENTRY_SECOND_HALF)) {
   4410             lt_fs[slice_number].free_count++;
   4411         }
   4412     }
   4413 
   4414     /* Remove the entry from group entry array. */
   4415     rv = _field_th_group_lt_entry_delete(unit, fg, lt_f_ent);
   4416     if (BCM_FAILURE(rv)) {
   4417         LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   4418             "FP(unit %d) Error: Group entry delete Eid=%d.\n"),
   4419              unit, lt_f_ent->eid));
   4420     }
   4421 
   4422     /* Free entry memory. */
   4423     sal_free(lt_f_ent);
   4424     return (rv);
   4425 }
   4426 
   4427 /*
   4428  * Function:
   4429  *    _field_th_lt_tcam_data_mem_get
   4430  * Purpose:
   4431  *    Get logical table data memory identifier based on stage group operational
   4432  *    mode.
   4433  * Parameters:
   4434  *    unit          - (IN) BCM device number.
   4435  *    stage_fc      - (IN) Stage field control structure.
   4436  *    fg            - (IN) Field group control structure.
   4437  *    lt_tcam_mem   - (IN) Logical table data view identifier.
   4438  * Returns:
   4439  *     BCM_E_XXX
   4440  */
   4441 STATIC int
   4442 _field_th_lt_tcam_data_mem_get(int unit, _field_stage_t *stage_fc,
   4443                                 _field_group_t *fg,
   4444                                 soc_mem_t *lt_tcam_mem)
   4445 {
   4446     /* Input parameters check. */
   4447     if (NULL == lt_tcam_mem) {
   4448         return (BCM_E_PARAM);
   4449     }
   4450 
   4451     /*
   4452      * Assign LT selection TCAM memory identifier based on
   4453      * stage's group operational mode.
   4454      */
   4455     switch (stage_fc->oper_mode) {
   4456         case bcmFieldGroupOperModeGlobal:
   4457             if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   4458                 *lt_tcam_mem = IFP_LOGICAL_TABLE_SELECT_DATA_ONLYm;
   4459             } else if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   4460                 *lt_tcam_mem = EXACT_MATCH_LOGICAL_TABLE_SELECT_DATA_ONLYm;
   4461             } else {
   4462                 return (BCM_E_INTERNAL);
   4463             }
   4464             break;
   4465         case bcmFieldGroupOperModePipeLocal:
   4466             if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   4467                 BCM_IF_ERROR_RETURN(_bcm_field_mem_instance_get(unit,
   4468                                         IFP_LOGICAL_TABLE_SELECT_DATA_ONLYm,
   4469                                         fg->instance,
   4470                                         lt_tcam_mem));
   4471             } else if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   4472                 BCM_IF_ERROR_RETURN(_bcm_field_mem_instance_get(unit,
   4473                                     EXACT_MATCH_LOGICAL_TABLE_SELECT_DATA_ONLYm,
   4474                                     fg->instance,
   4475                                     lt_tcam_mem));
   4476             } else {
   4477                 return (BCM_E_INTERNAL);
   4478             }
   4479             break;
   4480         default:
   4481             return (BCM_E_INTERNAL);
   4482     }
   4483     return (BCM_E_NONE);
   4484 }
   4485 
   4486 /*
   4487  * Function:
   4488  *     _bcm_field_th_lt_entry_data_value_set
   4489  * Purpose:
   4490  *     Set LT entry DATA portion of an entry.
   4491  * Parameters:
   4492  *     unit        - (IN) BCM device number.
   4493  *     stage_fc    - (IN) Stage field control structure.
   4494  *     fg          - (IN) Field group structure.
   4495  *     index       - (IN) Entry part index.
   4496  *     lt_data_mem - (IN) LT Data Memory.
   4497  *     data        - (IN/OUT) Reference to LT Data to be configured.
   4498  * Returns:
   4499  *     BCM_E_XXX
   4500  */
   4501 int
   4502 _bcm_field_th_lt_entry_data_value_set(int unit, _field_stage_t *stage_fc,
   4503                                       _field_group_t *fg, int index,
   4504                                       soc_mem_t lt_data_mem, uint32 *data)
   4505 {
   4506     /* Input parameters check. */
   4507     if ((NULL == stage_fc) || (NULL == fg) || (NULL == data)) {
   4508         return (BCM_E_PARAM);
   4509     }
   4510 
   4511     /* Presel entry in Flowtracker stage is handled differently */
   4512 #if defined(BCM_FLOWTRACKER_SUPPORT)
   4513     if ((soc_feature(unit, soc_feature_field_flowtracker_support)) &&
   4514         (stage_fc->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER)) {
   4515         return _bcm_field_hx5_ft_lt_entry_data_value_set(unit, stage_fc,
   4516                 fg, index, lt_data_mem, data);
   4517     }
   4518 #endif
   4519 
   4520     /* Group must have a valid KeyGen index, else return error. */
   4521     if (_FP_EXT_SELCODE_DONT_CARE == fg->ext_codes[index].keygen_index) {
   4522         return (BCM_E_INTERNAL);
   4523     }
   4524 
   4525     /* Check and set keygen index value. */
   4526     soc_mem_field32_set(unit, lt_data_mem, data,
   4527         KEY_GEN_PROGRAM_PROFILE_INDEXf, fg->ext_codes[index].keygen_index);
   4528 
   4529     /* Check and set IP Normalize control. */
   4530     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].normalize_l3_l4_sel) {
   4531         soc_mem_field32_set(unit, lt_data_mem, data,
   4532             NORMALIZE_L3_L4f, fg->ext_codes[index].normalize_l3_l4_sel);
   4533     }
   4534 
   4535     /* Check and set MAC Normalize control. */
   4536     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].normalize_mac_sel) {
   4537         soc_mem_field32_set(unit, lt_data_mem, data,
   4538             NORMALIZE_L2f, fg->ext_codes[index].normalize_mac_sel);
   4539     }
   4540 
   4541     /* Check and set AUX TAG A selector value. */
   4542     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].aux_tag_a_sel) {
   4543         soc_mem_field32_set(unit, lt_data_mem, data,
   4544             AUX_TAG_A_SELf, fg->ext_codes[index].aux_tag_a_sel);
   4545     }
   4546 
   4547     /* Check and set AUX TAG B selector value. */
   4548     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].aux_tag_b_sel) {
   4549         soc_mem_field32_set(unit, lt_data_mem, data,
   4550             AUX_TAG_B_SELf, fg->ext_codes[index].aux_tag_b_sel);
   4551     }
   4552 
   4553     /* Check and set AUX TAG C selector value. */
   4554     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].aux_tag_c_sel) {
   4555         soc_mem_field32_set(unit, lt_data_mem, data,
   4556             AUX_TAG_C_SELf, fg->ext_codes[index].aux_tag_c_sel);
   4557     }
   4558 
   4559     /* Check and set AUX TAG D selector value. */
   4560     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].aux_tag_d_sel) {
   4561         soc_mem_field32_set(unit, lt_data_mem, data,
   4562             AUX_TAG_D_SELf, fg->ext_codes[index].aux_tag_d_sel);
   4563     }
   4564 
   4565     /* Check and set TCP function selector. */
   4566     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].tcp_fn_sel) {
   4567         soc_mem_field32_set(unit, lt_data_mem, data,
   4568             TCP_FN_SELf, fg->ext_codes[index].tcp_fn_sel);
   4569     }
   4570 
   4571     /* Check and set TOS function selector. */
   4572     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].tos_fn_sel) {
   4573         soc_mem_field32_set(unit, lt_data_mem, data,
   4574             TOS_FN_SELf, fg->ext_codes[index].tos_fn_sel);
   4575     }
   4576 
   4577     /* Check and set TTL function selector. */
   4578     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].ttl_fn_sel) {
   4579         soc_mem_field32_set(unit, lt_data_mem, data,
   4580             TTL_FN_SELf, fg->ext_codes[index].ttl_fn_sel);
   4581     }
   4582 
   4583     /* Check and set Class ID container A selector. */
   4584     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].class_id_cont_a_sel) {
   4585         soc_mem_field32_set(unit, lt_data_mem, data,
   4586             CLASS_ID_CONTAINER_A_SELf,
   4587             fg->ext_codes[index].class_id_cont_a_sel);
   4588     }
   4589 
   4590     /* Check and set Class ID container B selector. */
   4591     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].class_id_cont_b_sel) {
   4592         soc_mem_field32_set(unit, lt_data_mem, data,
   4593             CLASS_ID_CONTAINER_B_SELf,
   4594             fg->ext_codes[index].class_id_cont_b_sel);
   4595     }
   4596 
   4597     /* Check and set Class ID container C selector. */
   4598     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].class_id_cont_c_sel) {
   4599         soc_mem_field32_set(unit, lt_data_mem, data,
   4600             CLASS_ID_CONTAINER_C_SELf,
   4601             fg->ext_codes[index].class_id_cont_c_sel);
   4602     }
   4603 
   4604     /* Check and set Class ID container D selector. */
   4605     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].class_id_cont_d_sel) {
   4606         soc_mem_field32_set(unit, lt_data_mem, data,
   4607             CLASS_ID_CONTAINER_D_SELf,
   4608             fg->ext_codes[index].class_id_cont_d_sel);
   4609     }
   4610 
   4611     /* Check and set Source Container A selector. */
   4612     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].src_cont_a_sel) {
   4613         soc_mem_field32_set(unit, lt_data_mem, data,
   4614             SRC_CONTAINER_A_SELf, fg->ext_codes[index].src_cont_a_sel);
   4615     }
   4616 
   4617     /* Check and set Source Container B selector. */
   4618     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].src_cont_b_sel) {
   4619         soc_mem_field32_set(unit, lt_data_mem, data,
   4620             SRC_CONTAINER_B_SELf, fg->ext_codes[index].src_cont_b_sel);
   4621     }
   4622 
   4623     /* Check and set Src Dest Container 0 selector. */
   4624     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].src_dest_cont_0_sel) {
   4625         soc_mem_field32_set(unit, lt_data_mem, data,
   4626             SRC_DST_CONTAINER_0_SELf, fg->ext_codes[index].src_dest_cont_0_sel);
   4627     }
   4628 
   4629     /* Check and set Src Dest Container 1 selector. */
   4630     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].src_dest_cont_1_sel) {
   4631         soc_mem_field32_set(unit, lt_data_mem, data,
   4632             SRC_DST_CONTAINER_1_SELf, fg->ext_codes[index].src_dest_cont_1_sel);
   4633     }
   4634 
   4635     /* Check and set IPBM selector. */
   4636     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].ipbm_present) {
   4637         soc_mem_field32_set(unit, lt_data_mem, data,
   4638             IPBM_PRESENTf, fg->ext_codes[index].ipbm_present);
   4639     }
   4640 
   4641     /* Check and set IPBM Source. */
   4642     if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].ipbm_source) {
   4643         soc_mem_field32_set(unit, lt_data_mem, data,
   4644             IPBM_SOURCEf, fg->ext_codes[index].ipbm_source);
   4645     }
   4646 
   4647 #if defined(BCM_TOMAHAWK3_SUPPORT)
   4648     if (SOC_IS_TOMAHAWK3(unit)) {
   4649             if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].udf_sel) {
   4650             soc_mem_field32_set(unit, lt_data_mem, data,
   4651                 UDF_SELf, fg->ext_codes[index].udf_sel);
   4652         }
   4653         /* Check and set Destination Container A selector. */
   4654         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].dst_cont_a_sel) {
   4655             soc_mem_field32_set(unit, lt_data_mem, data,
   4656                 DST_CONTAINER_0_SELf, fg->ext_codes[index].dst_cont_a_sel);
   4657         }
   4658 
   4659         /* Check and set Destination Container B selector. */
   4660         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].dst_cont_b_sel) {
   4661             soc_mem_field32_set(unit, lt_data_mem, data,
   4662                 DST_CONTAINER_1_SELf, fg->ext_codes[index].dst_cont_b_sel);
   4663         }
   4664 
   4665         /* Check and set ALT TTL function selector. */
   4666         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[index].alt_ttl_fn_sel) {
   4667             soc_mem_field32_set(unit, lt_data_mem, data,
   4668                 ALT_TTL_FN_SELf, fg->ext_codes[index].alt_ttl_fn_sel);
   4669         }
   4670     }
   4671 #endif
   4672 
   4673     /* Set Logical Table ID value. */
   4674     if (-1 != fg->lt_id) {
   4675         soc_mem_field32_set(unit, lt_data_mem, data,
   4676             LOGICAL_TABLE_IDf, (fg->lt_id));
   4677     }
   4678 
   4679     /* Enable lookup for this logical table in the slice. */
   4680     soc_mem_field32_set(unit, lt_data_mem, data, ENABLEf,
   4681         (fg->flags & _FP_GROUP_LOOKUP_ENABLED) ? 1 : 0);
   4682 
   4683     if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   4684         /* Switch on entry part. */
   4685         switch (index) {
   4686             case 0:
   4687                 if ((fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE)
   4688                         || (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE)) {
   4689                     /* Multiwide mode first slice. */
   4690                     soc_mem_field32_set(unit, lt_data_mem, data,
   4691                             MULTIWIDE_MODEf, 1);
   4692                 } else {
   4693                     /* Independent slice. */
   4694                     soc_mem_field32_set(unit, lt_data_mem, data,
   4695                             MULTIWIDE_MODEf, 0);
   4696                 }
   4697                 break;
   4698             case 1:
   4699                 if (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
   4700                     /* Multiwide mode second slice of THREE. */
   4701                     soc_mem_field32_set(unit, lt_data_mem, data,
   4702                             MULTIWIDE_MODEf, 3);
   4703                 } else {
   4704                     /* Multiwide mode second slice of TWO. */
   4705                     soc_mem_field32_set(unit, lt_data_mem, data,
   4706                             MULTIWIDE_MODEf, 2);
   4707                 }
   4708                 break;
   4709             case 2:
   4710                 /* Multiwide mode third slice. */
   4711                 soc_mem_field32_set(unit, lt_data_mem, data,
   4712                         MULTIWIDE_MODEf, 4);
   4713                 break;
   4714             default:
   4715                 return (BCM_E_INTERNAL);
   4716         }
   4717     } else if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   4718         soc_mem_field32_set(unit, lt_data_mem, data,
   4719                                          KEY_TYPEf, fg->em_mode);
   4720     } else {
   4721         /* Invalid Stage Id */
   4722         return (BCM_E_INTERNAL);
   4723     }
   4724 
   4725     return (BCM_E_NONE);
   4726 }
   4727 
   4728 /*
   4729  * Function:
   4730  *     _field_th_lt_entry_default_data_value_set
   4731  * Purpose:
   4732  *     Set LT entry DATA portion of an entry.
   4733  * Parameters:
   4734  *     unit     - (IN)     BCM device number.
   4735  *     stage_fc - (IN)     Stage field control structure.
   4736  *     fg       - (IN)     Field group structure.
   4737  *     index    - (IN)     Entry part index.
   4738  *     lt_f_ent - (IN/OUT) Logical table entry structure.
   4739  * Returns:
   4740  *     BCM_E_XXX
   4741  */
   4742 STATIC int
   4743 _field_th_lt_entry_default_data_value_set(int unit, _field_stage_t *stage_fc,
   4744                                           _field_group_t *fg, int index,
   4745                                           _field_lt_entry_t *lt_f_ent)
   4746 {
   4747     soc_mem_t lt_tcam_mem; /* LT selection TCAM data view memory name. */
   4748 
   4749     /* Input parameters check. */
   4750     if ((NULL == stage_fc) || (NULL == fg) || (NULL == lt_f_ent)) {
   4751         return (BCM_E_PARAM);
   4752     }
   4753 
   4754     /* Group must have a valid KeyGen index, else return error. */
   4755     if (_FP_EXT_SELCODE_DONT_CARE == fg->ext_codes[index].keygen_index) {
   4756         return (BCM_E_INTERNAL);
   4757     }
   4758 
   4759     /* Get LT select TCAM memory identifier. */
   4760     BCM_IF_ERROR_RETURN(_field_th_lt_tcam_data_mem_get(unit, stage_fc, fg,
   4761         &lt_tcam_mem));
   4762 
   4763     /* Allocate entry part key, mask & data buffer. */
   4764     BCM_IF_ERROR_RETURN(_bcm_field_th_lt_tcam_entry_get(unit, fg, lt_f_ent));
   4765 
   4766     /* Configure TCAM data values */
   4767     BCM_IF_ERROR_RETURN(_bcm_field_th_lt_entry_data_value_set(unit, stage_fc,
   4768                                   fg, index, lt_tcam_mem, lt_f_ent->tcam.data));
   4769 
   4770     return (BCM_E_NONE);
   4771 }
   4772 
   4773 /*
   4774  * Function:
   4775  *     _field_th_keygen_profiles_mem_get
   4776  * Purpose:
   4777  *     Get LT keygen program profile memory names.
   4778  * Parameters:
   4779  *     unit     - (IN)     BCM device number.
   4780  *     stage_fc - (IN)     Stage field control structure.
   4781  *     fg       - (IN)     Field group structure.
   4782  *     mem_arr  - (IN/OUT) Pointer to memory name array.
   4783  *     arr_len  - (IN)     Memory name array length.
   4784  * Returns:
   4785  *     BCM_E_XXX
   4786  */
   4787 STATIC int
   4788 _field_th_keygen_profiles_mem_get(int unit, _field_stage_t *stage_fc,
   4789                                   _field_group_t *fg, soc_mem_t *mem_arr,
   4790                                   int arr_len)
   4791 {
   4792     int idx; /* Array index iterator. */
   4793     static const soc_mem_t ifp_global_mem[2] =
   4794     {
   4795         IFP_KEY_GEN_PROGRAM_PROFILEm,
   4796         IFP_KEY_GEN_PROGRAM_PROFILE2m
   4797     };
   4798     static const soc_mem_t em_global_mem[2] =
   4799     {
   4800         EXACT_MATCH_KEY_GEN_PROGRAM_PROFILEm,
   4801         EXACT_MATCH_KEY_GEN_MASKm
   4802     };
   4803 
   4804 
   4805     /* Input parameters check. */
   4806     if ((NULL == stage_fc) || (NULL == fg) || (NULL == mem_arr)) {
   4807         return (BCM_E_PARAM);
   4808     }
   4809 
   4810     /*
   4811      * Assign keygen memory identifier name based on stage group oper mode.
   4812      */
   4813     switch (stage_fc->oper_mode) {
   4814         case bcmFieldGroupOperModeGlobal:
   4815             if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   4816                 for (idx = 0; idx < arr_len; idx++) {
   4817                     mem_arr[idx] = ifp_global_mem[idx];
   4818                 }
   4819             } else if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   4820                 for (idx = 0; idx < arr_len; idx++) {
   4821                     mem_arr[idx] = em_global_mem[idx];
   4822                 }
   4823             } else {
   4824                 return (BCM_E_PARAM);
   4825             }
   4826             break;
   4827         case bcmFieldGroupOperModePipeLocal:
   4828             if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   4829                 for (idx = 0; idx < arr_len; idx++) {
   4830                     BCM_IF_ERROR_RETURN(_bcm_field_mem_instance_get(unit,
   4831                                              ifp_global_mem[idx],
   4832                                              fg->instance,
   4833                                              &mem_arr[idx]));
   4834                 }
   4835             } else if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   4836                 for (idx = 0; idx < arr_len; idx++) {
   4837                     BCM_IF_ERROR_RETURN(_bcm_field_mem_instance_get(unit,
   4838                                              em_global_mem[idx],
   4839                                              fg->instance,
   4840                                              &mem_arr[idx]));
   4841                 }
   4842             } else {
   4843                 return (BCM_E_PARAM);
   4844             }
   4845             break;
   4846         default:
   4847             return (BCM_E_INTERNAL);
   4848     }
   4849     return (BCM_E_NONE);
   4850 }
   4851 
   4852 /*
   4853  * Function:
   4854  *     _field_th_keygen_profile2_entry_pack
   4855  * Purpose:
   4856  *     Build a LT keygen program profile2 table entry.
   4857  * Parameters:
   4858  *     unit         - (IN)     BCM device number.
   4859  *     stage_fc     - (IN)     Stage field control structure.
   4860  *     fg           - (IN)     Field group structure.
   4861  *     part         - (IN)     Entry part number.
   4862  *     mem          - (IN)     Memory name identifier.
   4863  *     prof2_entry  - (IN/OUT) Entry buffer pointer.
   4864  * Returns:
   4865  *     BCM_E_XXX
   4866  */
   4867 STATIC int
   4868 _field_th_keygen_profile2_entry_pack(int unit, _field_stage_t *stage_fc,
   4869                             _field_group_t *fg, int part, soc_mem_t mem,
   4870                             ifp_key_gen_program_profile2_entry_t *prof2_entry)
   4871 {
   4872     int idx; /* Iterator index. */
   4873     static const soc_field_t pmux_sel[] = /* Post mux selectors. */
   4874         {
   4875             POST_EXTRACTOR_MUX_0_SELf,
   4876             POST_EXTRACTOR_MUX_1_SELf,
   4877             POST_EXTRACTOR_MUX_2_SELf,
   4878             POST_EXTRACTOR_MUX_3_SELf,
   4879             POST_EXTRACTOR_MUX_4_SELf,
   4880             POST_EXTRACTOR_MUX_5_SELf,
   4881             POST_EXTRACTOR_MUX_6_SELf,
   4882             POST_EXTRACTOR_MUX_7_SELf,
   4883             POST_EXTRACTOR_MUX_8_SELf,
   4884             POST_EXTRACTOR_MUX_9_SELf,
   4885             POST_EXTRACTOR_MUX_10_SELf,
   4886             POST_EXTRACTOR_MUX_11_SELf,
   4887             POST_EXTRACTOR_MUX_12_SELf,
   4888             POST_EXTRACTOR_MUX_13_SELf,
   4889             POST_EXTRACTOR_MUX_14_SELf
   4890         };
   4891 
   4892     /* Input parameters check. */
   4893     if ((NULL == stage_fc) || (NULL == fg) || (NULL == prof2_entry)) {
   4894         return (BCM_E_PARAM);
   4895     }
   4896 
   4897     /* Set Post MUX extractor selcode values. */
   4898     for (idx = 0; idx < 15; idx++) {
   4899         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[part].pmux_sel[idx]) {
   4900             soc_mem_field32_set(unit, mem, prof2_entry, pmux_sel[idx],
   4901                 fg->ext_codes[part].pmux_sel[idx]);
   4902         }
   4903     }
   4904     return (BCM_E_NONE);
   4905 }
   4906 
   4907 /*
   4908  * Function:
   4909  *     _field_th_keygen_profile1_entry_pack
   4910  * Purpose:
   4911  *     Build a LT keygen program profile1 table entry.
   4912  * Parameters:
   4913  *     unit         - (IN)     BCM device number.
   4914  *     stage_fc     - (IN)     Stage field control structure.
   4915  *     fg           - (IN)     Field group structure.
   4916  *     part         - (IN)     Entry part number.
   4917  *     mem          - (IN)     Memory name identifier.
   4918  *     prof1_entry  - (IN/OUT) Entry buffer pointer.
   4919  * Returns:
   4920  *     BCM_E_XXX
   4921  */
   4922 STATIC int
   4923 _field_th_keygen_profile1_entry_pack(int unit, _field_stage_t *stage_fc,
   4924                                _field_group_t *fg, int part, soc_mem_t mem,
   4925                                ifp_key_gen_program_profile_entry_t *prof1_entry)
   4926 {
   4927     int idx; /* Iterator index. */
   4928     static const soc_field_t l1_32_sel[] = /* 32 bit extractors. */
   4929         {
   4930             L1_E32_SEL_0f,
   4931             L1_E32_SEL_1f,
   4932             L1_E32_SEL_2f,
   4933             L1_E32_SEL_3f
   4934         };
   4935     static const soc_field_t l1_16_sel[] = /* 16 bit extractors. */
   4936         {
   4937             L1_E16_SEL_0f,
   4938             L1_E16_SEL_1f,
   4939             L1_E16_SEL_2f,
   4940             L1_E16_SEL_3f,
   4941             L1_E16_SEL_4f,
   4942             L1_E16_SEL_5f,
   4943             L1_E16_SEL_6f
   4944         };
   4945     static const soc_field_t l1_8_sel[] = /* 8 bit extractors. */
   4946         {
   4947             L1_E8_SEL_0f,
   4948             L1_E8_SEL_1f,
   4949             L1_E8_SEL_2f,
   4950             L1_E8_SEL_3f,
   4951             L1_E8_SEL_4f,
   4952             L1_E8_SEL_5f,
   4953             L1_E8_SEL_6f
   4954         };
   4955     static const soc_field_t l1_4_sel[] = /* 4 bit extractors. */
   4956         {
   4957             L1_E4_SEL_0f,
   4958             L1_E4_SEL_1f,
   4959             L1_E4_SEL_2f,
   4960             L1_E4_SEL_3f,
   4961             L1_E4_SEL_4f,
   4962             L1_E4_SEL_5f,
   4963             L1_E4_SEL_6f,
   4964             L1_E4_SEL_7f
   4965         };
   4966     static const soc_field_t l1_2_sel[] = /* 2 bit extractors. */
   4967         {
   4968             L1_E2_SEL_0f,
   4969             L1_E2_SEL_1f,
   4970             L1_E2_SEL_2f,
   4971             L1_E2_SEL_3f,
   4972             L1_E2_SEL_4f,
   4973             L1_E2_SEL_5f,
   4974             L1_E2_SEL_6f,
   4975             L1_E2_SEL_7f
   4976         };
   4977     static const soc_field_t l2_16_sel[] = /* 16 bit extractors. */
   4978         {
   4979             L2_E16_SEL_0f,
   4980             L2_E16_SEL_1f,
   4981             L2_E16_SEL_2f,
   4982             L2_E16_SEL_3f,
   4983             L2_E16_SEL_4f,
   4984             L2_E16_SEL_5f,
   4985             L2_E16_SEL_6f,
   4986             L2_E16_SEL_7f,
   4987             L2_E16_SEL_8f,
   4988             L2_E16_SEL_9f
   4989         };
   4990     static const soc_field_t l3_4_sel[] = /* 4 bit extractors. */
   4991         {
   4992             L3_E4_SEL_0f,
   4993             L3_E4_SEL_1f,
   4994             L3_E4_SEL_2f,
   4995             L3_E4_SEL_3f,
   4996             L3_E4_SEL_4f,
   4997             L3_E4_SEL_5f,
   4998             L3_E4_SEL_6f,
   4999             L3_E4_SEL_7f,
   5000             L3_E4_SEL_8f,
   5001             L3_E4_SEL_9f,
   5002             L3_E4_SEL_10f,
   5003             L3_E4_SEL_11f,
   5004             L3_E4_SEL_12f,
   5005             L3_E4_SEL_13f,
   5006             L3_E4_SEL_14f,
   5007             L3_E4_SEL_15f,
   5008             L3_E4_SEL_16f,
   5009             L3_E4_SEL_17f,
   5010             L3_E4_SEL_18f,
   5011             L3_E4_SEL_19f,
   5012             L3_E4_SEL_20f
   5013         };
   5014     static const soc_field_t l3_2_sel[] = /* 2 bit extractors. */
   5015         {
   5016             L3_E2_SEL_0f,
   5017             L3_E2_SEL_1f,
   5018             L3_E2_SEL_2f,
   5019             L3_E2_SEL_3f,
   5020             L3_E2_SEL_4f
   5021         };
   5022     static const soc_field_t l3_1_sel[] = /* 1 bit extractors. */
   5023         {
   5024             L3_E1_SEL_0f,
   5025             L3_E1_SEL_1f
   5026         };
   5027 
   5028     /* Input parameters check. */
   5029     if ((NULL == stage_fc) || (NULL == fg) || (NULL == prof1_entry)) {
   5030         return (BCM_E_PARAM);
   5031     }
   5032 
   5033     /* Set 32bit extractor selcode values. */
   5034     for (idx = 0; idx < 4; idx++) {
   5035         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[part].l1_e32_sel[idx]) {
   5036             soc_mem_field32_set(unit, mem, prof1_entry, l1_32_sel[idx],
   5037                 fg->ext_codes[part].l1_e32_sel[idx]);
   5038         }
   5039     }
   5040 
   5041     /* Set 16bit extractor selcode values. */
   5042     for (idx = 0; idx < 7; idx++) {
   5043         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[part].l1_e16_sel[idx]) {
   5044             soc_mem_field32_set(unit, mem, prof1_entry, l1_16_sel[idx],
   5045                 fg->ext_codes[part].l1_e16_sel[idx]);
   5046         }
   5047     }
   5048 
   5049     /* Set 8bit extractor selcode values. */
   5050     for (idx = 0; idx < 7; idx++) {
   5051         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[part].l1_e8_sel[idx]) {
   5052             soc_mem_field32_set(unit, mem, prof1_entry, l1_8_sel[idx],
   5053                 fg->ext_codes[part].l1_e8_sel[idx]);
   5054         }
   5055     }
   5056 
   5057     /* Set 4bit extractor selcode values. */
   5058     for (idx = 0; idx < 8; idx++) {
   5059         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[part].l1_e4_sel[idx]) {
   5060             soc_mem_field32_set(unit, mem, prof1_entry, l1_4_sel[idx],
   5061                 fg->ext_codes[part].l1_e4_sel[idx]);
   5062         }
   5063     }
   5064 
   5065     /* Set 2bit extractor selcode values. */
   5066     for (idx = 0; idx < 8; idx++) {
   5067         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[part].l1_e2_sel[idx]) {
   5068             soc_mem_field32_set(unit, mem, prof1_entry, l1_2_sel[idx],
   5069                 fg->ext_codes[part].l1_e2_sel[idx]);
   5070         }
   5071     }
   5072 
   5073     /* Set 16bit extractor selcode values. */
   5074     for (idx = 0; idx < 10; idx++) {
   5075         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[part].l2_e16_sel[idx]) {
   5076             soc_mem_field32_set(unit, mem, prof1_entry, l2_16_sel[idx],
   5077                 fg->ext_codes[part].l2_e16_sel[idx]);
   5078         }
   5079     }
   5080 
   5081     /* Set 4bit extractor selcode values. */
   5082     for (idx = 0; idx < 21; idx++) {
   5083         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[part].l3_e4_sel[idx]) {
   5084             soc_mem_field32_set(unit, mem, prof1_entry, l3_4_sel[idx],
   5085                 fg->ext_codes[part].l3_e4_sel[idx]);
   5086         }
   5087     }
   5088 
   5089     /* Set 2bit extractor selcode values. */
   5090     for (idx = 0; idx < 5; idx++) {
   5091         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[part].l3_e2_sel[idx]) {
   5092             soc_mem_field32_set(unit, mem, prof1_entry, l3_2_sel[idx],
   5093                 fg->ext_codes[part].l3_e2_sel[idx]);
   5094         }
   5095     }
   5096 
   5097     /* Set 1bit extractor selcode values. */
   5098     for (idx = 0; idx < 2; idx++) {
   5099         if (_FP_EXT_SELCODE_DONT_CARE != fg->ext_codes[part].l3_e1_sel[idx]) {
   5100             soc_mem_field32_set(unit, mem, prof1_entry, l3_1_sel[idx],
   5101                 fg->ext_codes[part].l3_e1_sel[idx]);
   5102         }
   5103     }
   5104 
   5105     return (BCM_E_NONE);
   5106 }
   5107 
   5108 /*
   5109  * Function:
   5110  *     _bcm_field_th_group_keygen_profiles_index_alloc
   5111  * Purpose:
   5112  *     Install LT keygen program profile table entries in hardware.
   5113  * Parameters:
   5114  *     unit         - (IN)     BCM device number.
   5115  *     stage_fc     - (IN)     Stage field control structure.
   5116  *     fg           - (IN)     Field group structure.
   5117  *     part_index   - (IN)     Entry part number.
   5118  * Returns:
   5119  *     BCM_E_XXX
   5120  */
   5121 int
   5122 _bcm_field_th_group_keygen_profiles_index_alloc(int unit,
   5123                                                 _field_stage_t *stage_fc,
   5124                                                 _field_group_t *fg,
   5125                                                 int part_index)
   5126 {
   5127     ifp_key_gen_program_profile_entry_t ifp_prof1_entry;
   5128                                      /* IFP Keygen profile1. */
   5129     ifp_key_gen_program_profile2_entry_t ifp_prof2_entry;
   5130                                      /* IFP Keygen profile2. */
   5131     exact_match_key_gen_program_profile_entry_t em_prof_entry;
   5132                                      /* Exact Match Profile. */
   5133     exact_match_key_gen_mask_entry_t em_prof_mask_entry;
   5134                                      /* Exact Match Mask Profile. */
   5135     void *entries[2];                /* Entries array.   */
   5136     soc_mem_t mem[2];                /* Keygen profile memory identifier. */
   5137     int rv;                          /* Operation return status.          */
   5138 
   5139     /* Input parameters check. */
   5140     if ((NULL == stage_fc) || (NULL == fg)) {
   5141         return (BCM_E_PARAM);
   5142     }
   5143 
   5144     if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   5145         /* Get keygen program profiles memory name identifer. */
   5146         BCM_IF_ERROR_RETURN(_field_th_keygen_profiles_mem_get(unit, stage_fc, fg,
   5147                     mem, COUNTOF(mem)));
   5148 
   5149         /* Clear keygen profile entry. */
   5150         sal_memcpy(&ifp_prof1_entry, soc_mem_entry_null(unit, mem[0]),
   5151                 soc_mem_entry_words(unit, mem[0]) * sizeof(uint32));
   5152 
   5153         /* Clear keygen profile2 entry. */
   5154         sal_memcpy(&ifp_prof2_entry, soc_mem_entry_null(unit, mem[1]),
   5155                 soc_mem_entry_words(unit, mem[1]) * sizeof(uint32));
   5156 
   5157 #if defined(BCM_TOMAHAWK3_SUPPORT)
   5158         if (SOC_IS_TOMAHAWK3(unit)) {
   5159             /* Construct keygen profile1 table entry. */
   5160             BCM_IF_ERROR_RETURN(
   5161                 _bcm_field_th3_keygen_profile1_entry_pack(unit, stage_fc, fg,
   5162                                        part_index, mem[0], &ifp_prof1_entry));
   5163         } else
   5164 #endif
   5165         {
   5166             /* Construct keygen profile1 table entry. */
   5167             BCM_IF_ERROR_RETURN(
   5168                 _field_th_keygen_profile1_entry_pack(unit, stage_fc, fg,
   5169                                        part_index, mem[0], &ifp_prof1_entry));
   5170         }
   5171 
   5172         /* Construct keygen profile2 table entry. */
   5173         BCM_IF_ERROR_RETURN(_field_th_keygen_profile2_entry_pack(unit, stage_fc, fg,
   5174                     part_index, mem[1], &ifp_prof2_entry));
   5175 
   5176         /* Initialize entries array pointers. */
   5177         entries[0] = &ifp_prof1_entry;
   5178         entries[1] = &ifp_prof2_entry;
   5179 
   5180         /* Add entries to profile tables in hardware. */
   5181         rv = soc_profile_mem_add(unit,
   5182                             &stage_fc->keygen_profile[fg->instance].profile,
   5183                             entries, 1, &fg->ext_codes[part_index].keygen_index);
   5184     } else if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   5185 
   5186         BCM_IF_ERROR_RETURN(_field_th_keygen_profiles_mem_get(unit, stage_fc, fg,
   5187                     mem, COUNTOF(mem)));
   5188 
   5189         /* Clear keygen profile entry. */
   5190         sal_memcpy(&em_prof_entry, soc_mem_entry_null(unit, mem[0]),
   5191                 soc_mem_entry_words(unit, mem[0]) * sizeof(uint32));
   5192 
   5193         sal_memcpy(&em_prof_mask_entry, soc_mem_entry_null(unit, mem[1]),
   5194                 soc_mem_entry_words(unit, mem[1]) * sizeof(uint32));
   5195 
   5196         /* Construct keygen profile table entry. */
   5197 #if defined(BCM_TOMAHAWK3_SUPPORT)
   5198         if (soc_feature(unit, soc_feature_th3_style_fp)) {
   5199             BCM_IF_ERROR_RETURN(
   5200                     _bcm_field_th3_keygen_em_profile_entry_pack(unit, stage_fc, fg,
   5201                                                                 part_index, mem[0], 
   5202                                                                 &em_prof_entry));
   5203         } else
   5204 #endif
   5205         {
   5206             BCM_IF_ERROR_RETURN(_field_th_keygen_em_profile_entry_pack(unit, stage_fc, fg,
   5207                         part_index, mem[0], &em_prof_entry));
   5208         }
   5209 
   5210         /* Construct keygen mask entry */
   5211         BCM_IF_ERROR_RETURN(_field_th_keygen_em_profile_mask_entry_pack(unit, stage_fc, fg,
   5212                     part_index, mem[1], &em_prof_mask_entry));
   5213 
   5214         /* Initialize entries array pointers. */
   5215         entries[0] = &em_prof_entry;
   5216         entries[1] = &em_prof_mask_entry;
   5217 
   5218         /* Add entries to profile tables in hardware. */
   5219         rv = soc_profile_mem_add(unit,
   5220                          &stage_fc->keygen_profile[fg->instance].profile,
   5221                          entries, 1, &fg->ext_codes[part_index].keygen_index);
   5222 #if defined(BCM_FLOWTRACKER_SUPPORT)
   5223     } else if (stage_fc->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER) {
   5224         /* KeyGen is set along with lts install */
   5225         rv = BCM_E_NONE;
   5226 #endif
   5227     } else {
   5228         /* Invalid Stage */
   5229         rv = BCM_E_PARAM;
   5230     }
   5231 
   5232     return (rv);
   5233 }
   5234 
   5235 /*
   5236  * Function:
   5237  *    _field_th_lt_entry_default_rule_init
   5238  * Purpose:
   5239  *    Create a default rule for the group in logical table selection TCAM with
   5240  *    appropriate key, mask and data values.
   5241  * Parameters:
   5242  *     unit     - (IN)      BCM device number.
   5243  *     stage_fc - (IN)      Stage field control structure.
   5244  *     lt_f_ent - (IN/OUT)  Logical table entry structure.
   5245  * Returns:
   5246  *     BCM_E_XXX
   5247  */
   5248 STATIC int
   5249 _field_th_lt_entry_default_rule_init(int unit, _field_stage_t *stage_fc,
   5250                                      _field_lt_entry_t *lt_f_ent)
   5251 {
   5252     _field_group_t *fg;   /* Field group structure.       */
   5253     int parts_count = -1; /* Number of field entry parts. */
   5254     int idx;              /* Entry parts iterator.        */
   5255 
   5256     /* Input parameters check. */
   5257     if ((NULL == stage_fc) || (NULL == lt_f_ent)) {
   5258         return (BCM_E_PARAM);
   5259     }
   5260 
   5261     /* Get entry's group structure. */
   5262     fg = lt_f_ent->group;
   5263 
   5264     /* Get number of entry parts using group flags. */
   5265     BCM_IF_ERROR_RETURN(_bcm_field_th_entry_tcam_parts_count(unit, fg->flags,
   5266         &parts_count));
   5267 
   5268     /* Install entry parts in hardware. */
   5269     for (idx = 0; idx < parts_count; idx++) {
   5270         /*
   5271          * Install keygen program profile table entries for the group in
   5272          * hardware.
   5273          */
   5274         BCM_IF_ERROR_RETURN(_bcm_field_th_group_keygen_profiles_index_alloc(
   5275                                                    unit, stage_fc, fg, idx));
   5276         /*
   5277          * Build LT selection TCAM default entry.
   5278          */
   5279         BCM_IF_ERROR_RETURN(_field_th_lt_entry_default_data_value_set(unit,
   5280                             stage_fc, fg, idx, lt_f_ent + idx));
   5281     }
   5282     return (BCM_E_NONE);
   5283 }
   5284 
   5285 /*
   5286  * Function:
   5287  *     _field_th_lt_default_tcam_entry_install
   5288  * Purpose:
   5289  *     Install a logical table entry in hardware.
   5290  * Parameters:
   5291  *     unit     - (IN) BCM device number.
   5292  *     lt_entry - (IN) Field logical table entry.
   5293  *     group_expand - (IN) Indicates whether the LT tcam install
   5294  *                         is for auto-expanded slices.
   5295  *     part_idx - (IN) Slice part, valid only if group_expand is 1.
   5296  *     lt_fs    - (IN) Reference to LT slice, valid only if group_expand is 1.
   5297  * Returns:
   5298  *     BCM_E_XXX
   5299  */
   5300 STATIC int
   5301 _field_th_lt_default_tcam_entry_install(int unit, bcm_field_entry_t lt_entry,
   5302                                         int group_expand, int part_idx,
   5303                                         _field_lt_slice_t *lt_fs)
   5304 {
   5305     _field_stage_t *stage_fc;           /* Stage Field Control structure.  */
   5306     int tcam_idx[_FP_MAX_ENTRY_WIDTH];  /* Entry TCAM index.               */
   5307     int parts_count = 0;                /* Field entry parts count.        */
   5308     _field_lt_entry_t *lt_f_ent;        /* Field LT entry pointer.         */
   5309     _field_lt_slice_t *lt_part_fs = NULL; /* Field LT entry pointer.       */
   5310     _field_control_t *fc;               /* Field control pointer.          */
   5311     int idx;                            /* Index iterator.                 */
   5312     int rv = BCM_E_NONE;                /* Operation return status.        */
   5313     soc_mem_t lt_tcam_mem;              /* TCAM memory ID.                 */
   5314     uint8          valid;               /* Entry Valid bit.                */
   5315 
   5316     /* Get device field control structure. */
   5317     BCM_IF_ERROR_RETURN(_field_control_get(unit , &fc));
   5318 
   5319     /* Get all part of the entry. */
   5320     BCM_IF_ERROR_RETURN
   5321          (_field_th_lt_entry_get_by_id(unit, lt_entry, &lt_f_ent));
   5322 
   5323     /* Get device stage control structure. */
   5324     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit,
   5325         lt_f_ent->group->stage_id, &stage_fc));
   5326 
   5327     /* Get number of entry parts. */
   5328     BCM_IF_ERROR_RETURN(_bcm_field_th_entry_tcam_parts_count(unit,
   5329         lt_f_ent->group->flags, &parts_count));
   5330 
   5331     for (idx = 0; idx < parts_count; idx++) {
   5332         if (group_expand == 1) {
   5333             if (part_idx != idx) {
   5334                 continue;
   5335             }
   5336             lt_part_fs = lt_fs;
   5337         } else {
   5338             lt_part_fs = (lt_f_ent + idx)->lt_fs;
   5339         }
   5340 
   5341         BCM_IF_ERROR_RETURN(_field_th_lt_entry_tcam_idx_get(unit,
   5342                         lt_f_ent + idx, lt_part_fs, tcam_idx + idx));
   5343     }
   5344 
   5345     if (lt_part_fs == NULL) {
   5346         return BCM_E_INTERNAL;
   5347     }
   5348 
   5349     /*
   5350      * Get TCAM view to be used for programming the hardware based on the group
   5351      * operational mode.
   5352      */
   5353     BCM_IF_ERROR_RETURN(_field_th_lt_tcam_mem_get(unit, stage_fc, lt_f_ent,
   5354         &lt_tcam_mem));
   5355 
   5356 #if defined(BCM_TOMAHAWK2_SUPPORT)
   5357     if (soc_feature(unit, soc_feature_field_multi_pipe_enhanced) &&
   5358         _BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) {
   5359         valid = (lt_f_ent->group->flags & _FP_GROUP_LOOKUP_ENABLED) ? 3 : 0;
   5360     } else
   5361 #endif /* BCM_TOMAHAWK2_SUPPORT */
   5362     {
   5363         valid = (lt_f_ent->group->flags & _FP_GROUP_LOOKUP_ENABLED) ?
   5364                 (soc_feature(unit, soc_feature_td3_style_fp) ? 3 : 1) : 0;
   5365     }
   5366 
   5367     /* Install all parts of the entry in hardware. */
   5368     for (idx = 0; idx < parts_count; idx++) {
   5369         /* In case of group expand, iterate for the given part. */
   5370         if ((group_expand == 1) && (part_idx != idx)) {
   5371             continue;
   5372         }
   5373        /*
   5374         * Maximum index value for entry in this TCAM is limited to
   5375         * No. of slices * No. of LT_IDs/slice (12 * 32 == 384).
   5376         */
   5377         if ((tcam_idx[idx] < soc_mem_index_min(unit, lt_tcam_mem)) ||
   5378             (tcam_idx[idx] > (stage_fc->lt_tcam_sz - 1) )) {
   5379            LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   5380            "Error: tcam_idx[%d]:%d is out of range.\n\r"), idx, tcam_idx[idx]));
   5381            return (BCM_E_INTERNAL);
   5382         }
   5383 
   5384 
   5385         rv = _bcm_field_th_lt_entry_hw_install(unit, lt_tcam_mem, tcam_idx[idx],
   5386                                                (lt_f_ent + idx)->tcam.key,
   5387                                                (lt_f_ent + idx)->tcam.mask,
   5388                                                (lt_f_ent + idx)->tcam.data,
   5389                                                valid);
   5390         if (BCM_FAILURE(rv)) {
   5391            LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   5392            "Error: LT entry HW Install failed[%d] tcam_idx[%d]:%d.\n\r"),
   5393                rv, idx, tcam_idx[idx]));
   5394            return (BCM_E_INTERNAL);
   5395         }
   5396         lt_f_ent[idx].flags &= ~_FP_ENTRY_DIRTY;
   5397         lt_f_ent[idx].flags |= _FP_ENTRY_INSTALLED;
   5398         lt_f_ent[idx].flags |= _FP_ENTRY_ENABLED;
   5399     }
   5400 
   5401     return (rv);
   5402 }
   5403 
   5404 /*
   5405  * Function:
   5406  *    _field_th_lt_default_entry_create
   5407  * Purpose:
   5408  *    Create an entry in the slice/s reserved in logical table selection TCAM
   5409  *    for the field group.
   5410  * Parameters:
   5411  *     unit         - (IN)  BCM device number.
   5412  *     stage_fc     - (IN)  Stage field control structure.
   5413  *     fg           - (IN)  Field group structure.
   5414  *     lt_fs        - (IN)  Field logical table slice structure.
   5415  *     lt_entry     - (OUT) Logical Table field entry identifier.
   5416  * Returns:
   5417  *     BCM_E_XXX
   5418  */
   5419 STATIC int
   5420 _field_th_lt_default_entry_create(int unit, _field_stage_t *stage_fc,
   5421                                   _field_group_t *fg, _field_lt_slice_t *lt_fs,
   5422                                   bcm_field_entry_t *lt_entry)
   5423 {
   5424     _field_control_t *fc;        /* Field control structure.    */
   5425     _field_lt_entry_t *lt_f_ent; /* LT field entry pointer.     */
   5426     int rv;                      /* Operation return status.    */
   5427 
   5428     /* Input parameter check. */
   5429     if ((NULL == lt_entry) || (NULL == stage_fc) || (NULL == fg)
   5430          || (NULL == lt_fs)) {
   5431         return (BCM_E_PARAM);
   5432     }
   5433 
   5434     /* Get device field control handle. */
   5435     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   5436 
   5437     /* Generate an LT entry ID. */
   5438     fc->last_allocated_lt_eid++;
   5439     while (BCM_SUCCESS(_field_th_lt_entry_get(unit, fc->last_allocated_lt_eid,
   5440                 _FP_ENTRY_PRIMARY, &lt_f_ent))) {
   5441         fc->last_allocated_lt_eid++;
   5442         if (_FP_ID_MAX == fc->last_allocated_lt_eid) {
   5443             /* Initialize base LT Entry ID*/
   5444             fc->last_allocated_lt_eid = _FP_ID_BASE;
   5445         }
   5446     }
   5447 
   5448     /* Update allocated entry ID to the caller. */
   5449     *lt_entry = fc->last_allocated_lt_eid;
   5450 
   5451     /* Create entry in primary slice. */
   5452     rv = _field_th_lt_default_entry_phys_create(unit, stage_fc, *lt_entry,
   5453             BCM_FIELD_ENTRY_PRIO_LOWEST, lt_fs, fg, &lt_f_ent);
   5454     if (BCM_FAILURE(rv)) {
   5455         return (rv);
   5456     }
   5457 
   5458     /* Set up default LT selection rule based on group's keygen codes. */
   5459     rv = _field_th_lt_entry_default_rule_init(unit, stage_fc, lt_f_ent);
   5460     if (BCM_FAILURE(rv)) {
   5461         /* Destroy resources allocated for the entry. */
   5462         _field_th_lt_default_entry_phys_destroy(unit, lt_f_ent);
   5463         return (rv);
   5464     }
   5465     return (rv);
   5466 }
   5467 
   5468 /*
   5469  * Function:
   5470  *    _field_th_ingress_selcodes_install
   5471  * Purpose:
   5472  *    Install Logical table selection rule and TCAM key generation rules in
   5473  *    hardware.
   5474  * Parameters:
   5475  *     unit         - (IN)  BCM device number.
   5476  *     stage_fc     - (IN)  Stage field control structure.
   5477  *     fg           - (IN)  Field group structure.
   5478  *     lt_fs        - (IN)  Field logical table slice structure.
   5479  * Returns:
   5480  *     BCM_E_XXX
   5481  */
   5482 STATIC int
   5483 _field_th_ingress_selcodes_install(int unit,
   5484                                    _field_stage_t *stage_fc,
   5485                                    _field_group_t *fg,
   5486                                    _field_lt_slice_t *lt_fs,
   5487                                    int lt_pri_part_prio)
   5488 {
   5489     int   rv;            /* Operation return status.    */
   5490     int   idx;           /* iteration index.            */
   5491     _field_control_t *fc; /* Field Control Structure.   */
   5492     int   lt_part_prio = 0;
   5493 
   5494     /* Input parameters check. */
   5495     if ((NULL == fg) || (NULL == stage_fc) || (NULL == lt_fs)) {
   5496         return (BCM_E_PARAM);
   5497     }
   5498 
   5499     /* Field control get. */
   5500     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   5501 
   5502     if (fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) {
   5503        _field_presel_entry_t  *f_presel;
   5504 
   5505        /*
   5506         * Create Presel Entries in the LT slice associated with the group
   5507         */
   5508        for (idx = 0; idx < _FP_PRESEL_ENTRIES_MAX_PER_GROUP; idx++) {
   5509            if (fg->presel_ent_arr[idx] != NULL) {
   5510               f_presel = fg->presel_ent_arr[idx];
   5511            } else {
   5512               continue;
   5513            }
   5514 
   5515            /* Allocate the presel entries in the LT slice for this group. */
   5516            rv = _bcm_field_th_lt_entry_config_set(unit, stage_fc, fg, lt_fs,
   5517                                                   f_presel);
   5518            BCM_IF_ERROR_RETURN(rv);
   5519 
   5520            /* Install the LT Entry in HW. */
   5521            rv = _bcm_field_th_lt_entry_parts_install(unit, f_presel);
   5522            BCM_IF_ERROR_RETURN(rv);
   5523 
   5524            /* Check if the group is expanded across slices. */
   5525            if (f_presel->lt_fs->next != NULL) {
   5526               _field_lt_slice_t     *lt_part_fs;
   5527               _field_presel_entry_t *f_presel_p;
   5528               int                   p, parts_count = -1;
   5529 
   5530               /* Get number of entry parts. */
   5531               rv = _bcm_field_th_entry_tcam_parts_count(unit, fg->flags,
   5532                                                         &parts_count);
   5533               BCM_IF_ERROR_RETURN(rv);
   5534 
   5535               f_presel_p = f_presel;
   5536               for (p = 0; (p < parts_count && f_presel_p != NULL); p++) {
   5537                   lt_part_fs = f_presel_p->lt_fs->next;
   5538                   lt_part_prio = lt_pri_part_prio;
   5539                   for (;lt_part_fs != NULL; lt_part_fs = lt_part_fs->next) {
   5540                      /* LT part prio update */
   5541                      lt_part_prio -= 1; 
   5542                      rv = _field_th_ingress_group_expand_slice_install(unit, stage_fc,
   5543                                            fg, lt_part_fs->slice_number, p, lt_part_prio);
   5544                      BCM_IF_ERROR_RETURN(rv);
   5545                   }
   5546               }
   5547            }
   5548        }
   5549     } else {
   5550        bcm_field_entry_t lt_entry; /* LT entry ID. */
   5551 
   5552        /* Create a default LT entry for this group. */
   5553        BCM_IF_ERROR_RETURN(_field_th_lt_default_entry_create(unit, stage_fc, fg,
   5554                                                              lt_fs, &lt_entry));
   5555        /* Store LT Entry ID in group LT information structure. */
   5556        fc->lt_info[fg->instance][fg->lt_id]->lt_entry = lt_entry;
   5557 
   5558        /* Install the LT entry in hardware. */
   5559        BCM_IF_ERROR_RETURN(_field_th_lt_default_entry_install(unit, lt_entry));
   5560     }
   5561 
   5562     return (BCM_E_NONE);
   5563 }
   5564 
   5565 /*
   5566  * Function:
   5567  *     _field_ltmap_unused_resource_get
   5568  * Purpose:
   5569  *     Get unused LT IDs and LT action priorities information.
   5570  * Parameters:
   5571  *     unit                 - (IN) BCM device number.
   5572  *     stage_fc             - (IN) Field stage control structure.
   5573  *     ltmap                - (IN) Logical table configuration structure.
   5574  *     unused_ltids         - (OUT) Unused Logical Table IDs.
   5575  * Returns:
   5576  *     BCM_E_XXX
   5577  */
   5578 STATIC int
   5579 _field_ltmap_unused_resource_get(int unit,
   5580                                  _field_stage_t *stage_fc,
   5581                                  _field_group_t *fg,
   5582                                  uint32 *unused_ltids)
   5583 {
   5584     int lt_idx;                 /* Logical table iterator. */
   5585     uint32 used_ltids = 0;      /* Used Logical Table IDs. */
   5586     _field_control_t   *fc;     /* Field Control Strucutre.*/
   5587     uint32 supported_ltids = 0; /* Supported Logical Table IDs. */
   5588 
   5589     /* Input parameters check. */
   5590     if ((NULL == fg) || (NULL == stage_fc) || (NULL == unused_ltids)) {
   5591         return (BCM_E_PARAM);
   5592     }
   5593 
   5594 #if defined(BCM_FLOWTRACKER_SUPPORT)
   5595     if (_BCM_FIELD_STAGE_FLOWTRACKER == stage_fc->stage_id) {
   5596         return BCM_E_NONE;
   5597     }
   5598 #endif
   5599 
   5600     /* Get field control information. */
   5601     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   5602 
   5603     /* Based on stage oper mode, derive used ltid */
   5604 
   5605      /* Iterate over all supported LT IDs. */
   5606     for (lt_idx = 0; lt_idx < stage_fc->num_logical_tables; lt_idx++) {
   5607         /* Skip unused LT IDs. */
   5608         if (FALSE == fc->lt_info[fg->instance][lt_idx]->valid) {
   5609             continue;
   5610         }
   5611         /* Update bit value in the used bitmaps. */
   5612         used_ltids |= (1 << lt_idx);
   5613     }
   5614 
   5615     /* Unused caller requested information. */
   5616     *unused_ltids = ~(used_ltids);
   5617 
   5618     /* Validate with supported LTIDs */
   5619     SHR_BITSET_RANGE(&supported_ltids, 0, stage_fc->num_logical_tables);
   5620     *unused_ltids = ((*unused_ltids) & (supported_ltids));
   5621 
   5622 
   5623     return (BCM_E_NONE);
   5624 }
   5625 
   5626 /*
   5627  * Function:
   5628  *    _field_th_ltid_alloc
   5629  * Purpose:
   5630  *    Allocate a logical table identifier from unused logical table ID pool.
   5631  * Parameters:
   5632  *    unit              - (IN) BCM device number.
   5633  *    max_ltid          - (IN) Logical Table ID maximum value possible.
   5634  *    lt_unused_bmap    - (IN) Unused Logical Table IDs.
   5635  *    lt_id             - (OUT) Logical Table Identifier.
   5636  * Returns:
   5637  *    BCM_E_XXX
   5638  */
   5639 STATIC int
   5640 _field_th_ltid_alloc(int unit, int max_ltid, uint32 *lt_unused_bmap, int *lt_id)
   5641 {
   5642     int lt_idx; /* Logical table iterator. */
   5643 
   5644     /* Input parameters check. */
   5645     if (NULL == lt_unused_bmap || NULL == lt_id) {
   5646         return (BCM_E_PARAM);
   5647     }
   5648 
   5649     /* If all LT_IDs have been assigned, return resource error. */
   5650     if (0 == *lt_unused_bmap) {
   5651         return (BCM_E_RESOURCE);
   5652     }
   5653 
   5654     /* Iterate over unused LT_IDs bit array. */
   5655     for (lt_idx = 0; lt_idx < max_ltid; lt_idx++) {
   5656         if (*lt_unused_bmap & (1 << lt_idx)) {
   5657             break;
   5658         }
   5659     }
   5660 
   5661     /* Mark selected LT_ID as used. */
   5662     *lt_unused_bmap &= ~(1 << lt_idx);
   5663 
   5664     /* Update LT_ID value in caller argument. */
   5665     *lt_id = lt_idx;
   5666     return (BCM_E_NONE);
   5667 }
   5668 
   5669 /*
   5670  * Function:
   5671  *     _field_th_lt_prio_cmp
   5672  * Purpose:
   5673  *     Compare two group priorities linked to logical tables.
   5674  * Parameters:
   5675  *     a - (IN) First logical table group priority.
   5676  *     b - (IN) Second logical table group priority.
   5677  * Returns:
   5678  *     -1 if prio_first <  prio_second
   5679  *     0 if prio_first == prio_second
   5680  *     1 if prio_first >  prio_second
   5681  */
   5682 STATIC int
   5683 _field_th_lt_prio_cmp(void *a, void *b)
   5684 {
   5685     _field_lt_config_t *first;  /* First Logical table configuration.   */
   5686     _field_lt_config_t *second; /* Second Logical table configuration.  */
   5687 
   5688     first = (_field_lt_config_t *)a;
   5689     second = (_field_lt_config_t *)b;
   5690 
   5691     if (first->priority < second->priority) {
   5692         return (-1);
   5693     } else if (first->priority > second->priority) {
   5694         return (1);
   5695     }
   5696 
   5697     return (0);
   5698 }
   5699 
   5700 /*
   5701  * Function:
   5702  *    _field_th_lt_priority_alloc
   5703  * Purpose:
   5704  *    Allocate logical table action priority for the group.
   5705  * Parameters:
   5706  *    unit      - (IN) BCM device number.
   5707  *    stage_fc  - (IN/OUT) Stage field control structure.
   5708  *    fg        - (IN) State machine tracking structure.
   5709  *    lt_id     - (IN) Logical Table Identifier.
   5710  * Returns:
   5711  *    BCM_E_XXX
   5712  */
   5713 STATIC int
   5714 _field_th_lt_priority_alloc(int unit, _field_stage_t *stage_fc,
   5715                             _field_group_t *fg, int lt_id)
   5716 {
   5717     int lt_idx;                                 /* Logical table iterator.   */
   5718     _field_lt_config_t *lt_info = NULL; /* LT information.           */
   5719     int action_prio;                    /* LT action priority value. */
   5720     int idx;                                    /* Iterator.                 */
   5721     _field_control_t *fc;                       /* Field Control Strucutre.  */
   5722 
   5723     /* Input parameters check. */
   5724     if (NULL == stage_fc || NULL == fg) {
   5725         return (BCM_E_PARAM);
   5726     }
   5727 
   5728     action_prio = stage_fc->num_logical_tables - 1;
   5729     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   5730 
   5731     _FP_XGS3_ALLOC(lt_info, 
   5732         (stage_fc->num_logical_tables * sizeof(_field_lt_config_t)),
   5733         "lt info for all lt ids");
   5734     if (lt_info == NULL) {
   5735        return (BCM_E_MEMORY);
   5736     }
   5737     /* Get LT information for the group. */
   5738     for (idx = 0; idx < stage_fc->num_logical_tables; idx++) {
   5739         sal_memcpy(&lt_info[idx], fc->lt_info[fg->instance][idx],
   5740                 sizeof(_field_lt_config_t));
   5741     }
   5742 
   5743     /*
   5744      * Initialize LT information for the new logical table ID, for it to be
   5745      * in the correct location after the sort.
   5746      */
   5747     lt_info[lt_id].priority = fg->priority;
   5748     lt_info[lt_id].lt_action_pri = 0;
   5749     lt_info[lt_id].valid = TRUE;
   5750 
   5751     for (lt_idx = 0; lt_idx < stage_fc->num_logical_tables; lt_idx++) {
   5752         LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   5753            "FP(unit %d): Verb-B4-Sort: lt_id(%d): lt_grp_prio(%d): "
   5754            "lt_actn_prio(%d): valid:(%d) flags(0x%x)\n"),
   5755             unit, lt_info[lt_idx].lt_id,
   5756             lt_info[lt_idx].priority, lt_info[lt_idx].lt_action_pri,
   5757             lt_info[lt_idx].valid, lt_info[lt_idx].flags));
   5758     }
   5759 
   5760     /* Sort the logical tables array based on group priority value. */
   5761     _shr_sort(lt_info, stage_fc->num_logical_tables,
   5762               sizeof(_field_lt_config_t),
   5763               _field_th_lt_prio_cmp);
   5764 
   5765     for (lt_idx = 0; lt_idx < stage_fc->num_logical_tables; lt_idx++) {
   5766         LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   5767             "FP(unit %d): Verb-Aft-Sort: lt_id(%d): lt_grp_prio(%d): "
   5768             "lt_actn_prio(%d): valid:(%d) flags(0x%x)\n"),
   5769             unit, lt_info[lt_idx].lt_id, lt_info[lt_idx].priority,
   5770             lt_info[lt_idx].lt_action_pri, lt_info[lt_idx].valid,
   5771             lt_info[lt_idx].flags));
   5772     }
   5773 
   5774     /*
   5775      * Assign LT action priority based on the position of LT ID in the sorted
   5776      * array.
   5777      */
   5778     for (idx = (stage_fc->num_logical_tables - 1); idx >= 0; idx--) {
   5779         if (FALSE == lt_info[idx].valid) {
   5780             continue;
   5781         }
   5782         lt_info[idx].lt_action_pri = action_prio--;
   5783     }
   5784 
   5785     for (lt_idx = 0; lt_idx < stage_fc->num_logical_tables; lt_idx++) {
   5786        LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   5787            "FP(unit %d): Verb-Aft-PrioAssign: lt_id(%d): lt_grp_prio(%d): "
   5788            "lt_actn_prio(%d): valid:(%d) flags(0x%x)\n"),
   5789             unit, lt_info[lt_idx].lt_id, lt_info[lt_idx].priority,
   5790             lt_info[lt_idx].lt_action_pri, lt_info[lt_idx].valid,
   5791            lt_info[lt_idx].flags));
   5792     }
   5793 
   5794     for (idx = 0; idx < stage_fc->num_logical_tables; idx++) {
   5795         if (FALSE == lt_info[idx].valid) {
   5796             continue;
   5797         }
   5798         lt_idx = lt_info[idx].lt_id;
   5799         fc->lt_info[fg->instance][lt_idx]->lt_action_pri =
   5800             lt_info[idx].lt_action_pri;
   5801     }
   5802 
   5803     sal_free(lt_info);
   5804     return (BCM_E_NONE);
   5805 }
   5806 
   5807 /*
   5808  * Function:
   5809  *    _field_th_group_ltmap_alloc
   5810  * Purpose:
   5811  *    Allocate a Logitcal Table ID for the field group.
   5812  * Parameters:
   5813  *    unit      - (IN) BCM device number.
   5814  *    stage_fc  - (IN/OUT) Stage field control structure.
   5815  *    fg        - (IN/OUT) Field group structure pointer.
   5816  * Returns:
   5817  *    BCM_E_XXX
   5818  */
   5819 STATIC int
   5820 _field_th_group_ltmap_alloc(int unit, _field_stage_t *stage_fc,
   5821                             _field_group_t *fg)
   5822 {
   5823     uint32 unused_ltids = 0;                    /* Unused LT IDs.             */
   5824     int lt_id;                                  /* Logical Table Identifier.  */
   5825     _field_control_t *fc;                       /* Field Control Strucutre.   */
   5826 
   5827     /* Input parameters check. */
   5828     if (NULL == stage_fc || NULL == fg) {
   5829         return (BCM_E_PARAM);
   5830     }
   5831 
   5832 #if defined(BCM_FLOWTRACKER_SUPPORT)
   5833     if (_BCM_FIELD_STAGE_FLOWTRACKER == stage_fc->stage_id) {
   5834         return BCM_E_NONE;
   5835     }
   5836 #endif
   5837 
   5838     /* Get field control information. */
   5839     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   5840 
   5841     /* Get unused LT IDs and LT action priorites. */
   5842     BCM_IF_ERROR_RETURN(_field_ltmap_unused_resource_get(unit, stage_fc,
   5843                                                          fg, &unused_ltids));
   5844     /* Allocate a LT ID from unused LT ID pool. */
   5845     BCM_IF_ERROR_RETURN(_field_th_ltid_alloc(unit, stage_fc->num_logical_tables,
   5846                                              &unused_ltids, &lt_id));
   5847 
   5848     /* Allocate LT action priority. */
   5849     BCM_IF_ERROR_RETURN(_field_th_lt_priority_alloc(unit, stage_fc, fg, lt_id));
   5850 
   5851     /* Set LT ID info in database. */
   5852     fc->lt_info[fg->instance][lt_id]->valid = TRUE;
   5853     fc->lt_info[fg->instance][lt_id]->priority = fg->priority;
   5854     fc->lt_info[fg->instance][lt_id]->flags = fg->flags;
   5855 
   5856     /* Get group's LT info structure pointer. */
   5857     fg->lt_id = lt_id;
   5858 
   5859     return (BCM_E_NONE);
   5860 }
   5861 
   5862 /*
   5863  * Function:
   5864  *    _field_th_ingress_group_install
   5865  * Purpose:
   5866  *    Auxiliary routine used to install field group in hardware.
   5867  * Parameters:
   5868  *     unit         - (IN)      BCM device number.
   5869  *     stage_fc     - (IN)      Installed group structure.
   5870  *     fg           - (IN/OUT)  Field group structure.
   5871  * Returns:
   5872  *     BCM_E_XXX
   5873  */
   5874 STATIC int
   5875 _field_th_ingress_group_install(int unit, _field_stage_t *stage_fc,
   5876                                 _field_group_t *fg)
   5877 {
   5878     _field_lt_slice_t *lt_fs;   /* LT Slice pointer.                */
   5879     _field_slice_t *fs;         /* Field slice structure pointer.   */
   5880     int parts_count = -1;       /* Number of entry parts.           */
   5881     int part;                   /* Entry parts iterator.            */
   5882     uint8 slice_number;         /* LT Slice number.                 */
   5883     _field_control_t *fc;       /* Field control structure.         */
   5884     int lt_part_prio = _FP_MAX_LT_PART_PRIO(unit);
   5885                                 /* LT part priority value.          */
   5886 
   5887     /* Input parameters check. */
   5888     if ((NULL == stage_fc) || (NULL == fg) || (NULL == fg->lt_slices)) {
   5889         return (BCM_E_PARAM);
   5890     }
   5891 
   5892     /* Get field control structure. */
   5893     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   5894 
   5895     /* Allocate a Logical Table ID for the group. */
   5896     BCM_IF_ERROR_RETURN(_field_th_group_ltmap_alloc(unit, stage_fc, fg));
   5897 
   5898 #if defined(BCM_FLOWTRACKER_SUPPORT)
   5899     /* Assign Group Key Type for the group */
   5900     BCM_IF_ERROR_RETURN(_field_hx5_ft_group_keytype_assign(unit, stage_fc, fg));
   5901 #endif
   5902 
   5903     /* Get number of entry parts. */
   5904     BCM_IF_ERROR_RETURN(_bcm_field_th_lt_entry_tcam_parts_count(unit,
   5905         stage_fc->stage_id, fg->flags, &parts_count));
   5906 
   5907     /* Iterate over entry parts and program hardware for each slice. */
   5908     for (part = 0; part < parts_count; part++) {
   5909         /* Get slice number to which the entry part belongs to. */
   5910         BCM_IF_ERROR_RETURN(_bcm_field_th_tcam_part_to_slice_number(part,
   5911             fg->flags, &slice_number));
   5912 
   5913         /* Get LT entry part slice control structure. */
   5914         lt_fs = stage_fc->lt_slices[fg->instance] +
   5915                 fg->slices->slice_number + slice_number;
   5916 
   5917         if (stage_fc->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER) {
   5918             break;
   5919         }
   5920 
   5921         /* Set slice mode in hardware based on Group mode/flags. */
   5922         BCM_IF_ERROR_RETURN(_field_th_ingress_slice_mode_set(unit, stage_fc,
   5923             lt_fs->slice_number, fg, 0));
   5924         /*
   5925          * Initialize slice free entries count value to number of
   5926          * entries in the slice.
   5927          */
   5928         if (0 == fg->slices[0].lt_map) {
   5929             lt_fs->free_count = lt_fs->entry_count;
   5930         }
   5931 
   5932         /* Get IFP TCAM slice information. */
   5933         fs = fg->slices + part;
   5934 
   5935         /* Update slice LT_ID mapping in group's slice. */
   5936         fs->lt_map |= (1 << fg->lt_id);
   5937 
   5938         fc->lt_info[fg->instance][fg->lt_id]->lt_part_map |= (1 << fs->slice_number);
   5939         fc->lt_info[fg->instance][fg->lt_id]->lt_part_pri[fs->slice_number] = lt_part_prio;
   5940     }
   5941 
   5942     /* Install TCAM keygen program configuration in hardware for each slice. */
   5943     BCM_IF_ERROR_RETURN(_field_th_ingress_selcodes_install(unit, stage_fc, fg,
   5944                                                            fg->lt_slices, lt_part_prio));
   5945 
   5946     return (BCM_E_NONE);
   5947 }
   5948 
   5949 /*
   5950  * Function:
   5951  *     _field_th_group_add_group_install
   5952  * Purpose:
   5953  *     Install group slice mode in hardware and update slice parameters based on
   5954  *     the group mode.
   5955  * Parameters:
   5956  *     unit     - (IN)     BCM device number.
   5957  *     fsm_ptr  - (IN/OUT) State machine tracking structure.
   5958  * Returns:
   5959  *     BCM_E_XXX
   5960  */
   5961 STATIC int
   5962 _field_th_group_add_group_install(int unit,
   5963                                   _field_group_add_fsm_t *fsm_ptr)
   5964 {
   5965     _field_slice_t *fs;     /* Slice pointer.           */
   5966     _field_group_t *fg;     /* Field Group Pointer.     */
   5967     int parts_count = -1;   /* Number of entry parts.   */
   5968     int idx;                /* Slice iterator.          */
   5969     uint32 entry_flags;     /* Entry flags.             */
   5970     uint8 slice_number;     /* Slice number.            */
   5971     int slice_init;         /* Slice SW init needed.    */
   5972 
   5973     /* Input parameters check. */
   5974     if (NULL == fsm_ptr) {
   5975         return (BCM_E_PARAM);
   5976     }
   5977 
   5978     /* Get field group pointer. */
   5979     fg = fsm_ptr->fg;
   5980 
   5981     /* Check if this is the first group installed in slice. */
   5982     slice_init = (0 == fg->slices[0].lt_map) ? TRUE : FALSE;
   5983 
   5984     /* Write group parameters to hardware. */
   5985     BCM_IF_ERROR_RETURN(_field_th_ingress_group_install(unit,
   5986                                      fsm_ptr->stage_fc, fg));
   5987 
   5988     /* Get number of entry parts. */
   5989     BCM_IF_ERROR_RETURN(_bcm_field_th_lt_entry_tcam_parts_count(unit,
   5990         fsm_ptr->stage_fc->stage_id, fg->flags, &parts_count));
   5991 
   5992     for (idx = parts_count - 1; idx >=0; idx--) {
   5993         /* Get entry flags. */
   5994         BCM_IF_ERROR_RETURN(_bcm_field_th_tcam_part_to_entry_flags(unit, idx,
   5995             fg->flags, &entry_flags));
   5996 
   5997         /* Get slice number for given entry part. */
   5998         BCM_IF_ERROR_RETURN(_bcm_field_th_tcam_part_to_slice_number(idx,
   5999             fg->flags, &slice_number));
   6000 
   6001         /* Get slice pointer. */
   6002         fs = fg->slices + slice_number;
   6003 
   6004         if (!(entry_flags & _FP_ENTRY_SECOND_HALF)) {
   6005             if (fg->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   6006                 if (slice_init) {
   6007                     /*
   6008                      * Initialize slice free entries count value based on group
   6009                      * flags.
   6010                      */
   6011 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6012                     if (SOC_IS_TOMAHAWK3(unit) &&
   6013                         (fg->stage_id == _BCM_FIELD_STAGE_INGRESS)) {
   6014                         fs->free_count = fs->entry_count;
   6015                     } else
   6016 #endif
   6017                     {
   6018 
   6019                         if ((fg->flags & _FP_GROUP_SPAN_SINGLE_SLICE)
   6020                             && !(fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE)) {
   6021                             fs->free_count = fs->entry_count;
   6022                         } else {
   6023                             fs->entry_count >>= 1;
   6024                             fs->free_count = fs->entry_count;
   6025                             fs->start_tcam_idx >>= 1;
   6026                         }
   6027                     }
   6028                     /* Initialize slice group flags. */
   6029                     fs->group_flags = fg->flags & _FP_GROUP_STATUS_MASK;
   6030                 }
   6031             } else {
   6032                 fs->group_flags |= fg->flags & _FP_GROUP_STATUS_MASK;
   6033             }
   6034         }
   6035     }
   6036 
   6037     return (BCM_E_NONE);
   6038 }
   6039 
   6040 /* Function:
   6041  * _bcm_field_th_group_add_mode_validate
   6042  *
   6043  * Purpose:
   6044  *    validate the group to make sure the group with same priority and mode
   6045  *    doesnot exist in other slices
   6046  *
   6047  * Paramaters:
   6048  * unit             - (IN) BCM device number
   6049  * fg               - (IN) Pointer to device field group structure
   6050  *
   6051  * Returns:
   6052  *     BCM_E_XXX
   6053  */
   6054 
   6055 int
   6056 _bcm_field_th_group_add_mode_validate(int unit,
   6057                                       _field_group_t *fg,
   6058                                       int *slice_number)
   6059 {
   6060     _field_control_t  *fc;
   6061     _field_group_t    *curr_group;
   6062 
   6063 	if (fg == NULL) {
   6064         return BCM_E_PARAM;
   6065     }
   6066      /* Get device Field control structure. */
   6067      BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   6068      curr_group = fc->groups;
   6069 
   6070     if (curr_group == NULL) {
   6071         return BCM_E_NONE;
   6072     }
   6073 
   6074     while (curr_group != NULL) {
   6075         if ((curr_group->stage_id == fg->stage_id) &&
   6076             (curr_group->gid != fg->gid) &&
   6077             (curr_group->stage_id != _BCM_FIELD_STAGE_EXACTMATCH) &&
   6078             (curr_group->stage_id != _BCM_FIELD_STAGE_FLOWTRACKER) &&
   6079             (curr_group->instance == fg->instance) &&
   6080             (curr_group->priority == fg->priority)) {
   6081             /*
   6082              * Default group and Presel group can't have same priority.
   6083              */
   6084             if ((fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) !=
   6085                 (curr_group->flags & _FP_GROUP_PRESELECTOR_SUPPORT)) {
   6086                  LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   6087                     "Error: Same priority is not possible between default group and"
   6088                     " presel group.\n\r")));
   6089                  return BCM_E_PARAM;
   6090             }
   6091 
   6092             if (fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) {
   6093                 /* Return Error if modes are different */
   6094                 if ((fg->flags & _FP_GROUP_SPAN_MASK) !=
   6095                     (curr_group->flags & _FP_GROUP_SPAN_MASK)) {
   6096                     return BCM_E_PARAM;
   6097                 }
   6098 
   6099                 /* update slice shared with same priority groups */
   6100                 *slice_number = curr_group->slices->slice_number;
   6101                 break;
   6102             }
   6103         }
   6104         curr_group = curr_group->next;
   6105     }
   6106     return BCM_E_NONE;
   6107 }
   6108 /*
   6109  * Function:
   6110  *    _field_th_group_add_slice_allocate
   6111  * Purpose:
   6112  *    Allocate slice for a new group.
   6113  * Parameters:
   6114  *    unit     - (IN)     BCM device number.
   6115  *    fsm_ptr  - (IN/OUT) State machine tracking structure.
   6116  * Returns:
   6117  *    BCM_E_XXX
   6118  */
   6119 STATIC int
   6120 _field_th_group_add_slice_allocate(int unit, _field_group_add_fsm_t *fsm_ptr)
   6121 {
   6122     _field_group_t     *fg;           /* Field Group structure pointer. */
   6123     _field_stage_t     *stage_fc;     /* Field Stage control pointer.   */
   6124     int                slice;         /* Slice iterator.                */
   6125     uint8              slice_found = 0; /* Slice found indicator.       */
   6126 
   6127     /* Input parameters check. */
   6128     if (NULL == fsm_ptr) {
   6129         return (BCM_E_PARAM);
   6130     }
   6131 
   6132     /* Initialize field group pointer. */
   6133     fg = fsm_ptr->fg;
   6134 
   6135     /* Initialize field stage pointer. */
   6136     stage_fc = fsm_ptr->stage_fc;
   6137 
   6138     /*
   6139      * If group priority is BCM_FIELD_GROUP_PRIO_ANY,
   6140      * generate a new unique priority.
   6141      */
   6142     if ((stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) &&
   6143         (fg->priority == BCM_FIELD_GROUP_PRIO_ANY)) {
   6144         stage_fc->group_running_prio += 1;
   6145         fg->priority = stage_fc->group_running_prio;
   6146     }
   6147 
   6148     slice = -1;
   6149     fsm_ptr->rv = _bcm_field_th_group_add_mode_validate(unit, fg, &slice);
   6150     if (BCM_FAILURE(fsm_ptr->rv)) {
   6151         fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   6152         return BCM_E_NONE;
   6153     }
   6154 
   6155     if (slice != -1) {
   6156         slice_found = 1;
   6157     } else {
   6158         slice = 0;
   6159     }
   6160 
   6161     /* Reserve a slice for this new Field Group. */
   6162     for (; slice < stage_fc->tcam_slices; slice++ ) {
   6163         fsm_ptr->rv = _bcm_field_th_group_add_slice_validate(unit, stage_fc, fg,
   6164                                                              slice);
   6165         if (BCM_SUCCESS(fsm_ptr->rv)) {
   6166             LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   6167             "==> %s(): SLICE[%d] allocated for group[%d].\n\r"),
   6168             __func__, slice, fg->gid));
   6169             break;
   6170         } else if (slice_found == 1) {
   6171             fsm_ptr->rv = (BCM_E_RESOURCE);
   6172             fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   6173             return BCM_E_NONE;
   6174         }
   6175 
   6176         if ((BCM_E_PARAM == fsm_ptr->rv) || (BCM_E_RESOURCE == fsm_ptr->rv)) {
   6177             break;
   6178         }
   6179     }
   6180 
   6181     /* Check if allocation was successful. */
   6182     if (slice == stage_fc->tcam_slices) {
   6183         fsm_ptr->rv = (BCM_E_RESOURCE);
   6184     }
   6185 
   6186     if (BCM_FAILURE(fsm_ptr->rv)) {
   6187         if (fsm_ptr->fsm_state_prev != _BCM_FP_GROUP_ADD_STATE_CAM_COMPRESS) {
   6188             fsm_ptr->rv = (BCM_E_NONE);
   6189             fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_CAM_COMPRESS;
   6190         } else {
   6191             fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   6192         }
   6193     } else {
   6194         /* Update Group slices pointer. */
   6195         fg->slices = stage_fc->slices[fg->instance] + slice;
   6196 
   6197         /* Update Group LT slices pointer. */
   6198         fg->lt_slices = stage_fc->lt_slices[fg->instance] + slice;
   6199 
   6200         /*
   6201          * Install key generation extractor codes and LT selection rule for the
   6202          * group in hardware.
   6203          */
   6204         fsm_ptr->rv = _field_th_group_add_group_install(unit, fsm_ptr);
   6205         if (BCM_SUCCESS(fsm_ptr->rv)) {
   6206             fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_ADJUST_VIRTUAL_MAP;
   6207         } else {
   6208             fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   6209         }
   6210     }
   6211 
   6212     /* Set current state as the previous state. */
   6213     fsm_ptr->fsm_state_prev = _BCM_FP_GROUP_ADD_STATE_SLICE_ALLOCATE;
   6214     return (BCM_E_NONE);
   6215 }
   6216 
   6217 /*
   6218  * Function:
   6219  *    _bcm_field_th_entry_tcam_parts_count
   6220  * Purpose:
   6221  *    Get number of tcam entries needed to accomodate a SW entry.
   6222  * Parameters:
   6223  *    unit        - (IN)  BCM device number.
   6224  *    group_flags - (IN)  Entry group flags.
   6225  *    part_count  - (OUT) Entry parts count.
   6226  * Returns:
   6227  *    BCM_E_XXX
   6228  */
   6229 int
   6230 _bcm_field_th_entry_tcam_parts_count(int unit, uint32 group_flags,
   6231                                      int *part_count)
   6232 {
   6233     /* Input parameters check. */
   6234     if (NULL == part_count) {
   6235         return (BCM_E_PARAM);
   6236     }
   6237 
   6238     /* Check group flags settings and determine number of TCAM entry parts. */
   6239     if (group_flags & _FP_GROUP_DW_DEPTH_EXPANDED) {
   6240         /* Double-wide in BSK_FTFP_TCAM */
   6241         *part_count = 2;
   6242     } else if (group_flags & _FP_GROUP_SPAN_SINGLE_SLICE) {
   6243         /*
   6244          * Part value is same for Narrow and Wide TCAMs
   6245          * (IFP_TCAM and IFP_TCAM_WIDE)
   6246          * (group_flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE)
   6247          */
   6248         *part_count = 1;
   6249     } else if (group_flags & _FP_GROUP_SPAN_DOUBLE_SLICE) {
   6250         /* IFP_TCAM_WIDE view only. */
   6251         *part_count = 2;
   6252     } else if (group_flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
   6253         /* IFP_TCAM_WIDE view only. */
   6254         *part_count = 3;
   6255     }
   6256     return (BCM_E_NONE);
   6257 }
   6258 
   6259 /*
   6260  * Function:
   6261  *    _bcm_field_th_lt_entry_tcam_parts_count
   6262  * Purpose:
   6263  *    Get number of lt tcam entries needed to accomodate a SW entry.
   6264  * Parameters:
   6265  *    unit        - (IN)  BCM device number.
   6266  *    stage_id    - (IN)  Stage Identifier.
   6267  *    group_flags - (IN)  Entry group flags.
   6268  *    part_count  - (OUT) Entry parts count.
   6269  * Returns:
   6270  *    BCM_E_XXX
   6271  */
   6272 int
   6273 _bcm_field_th_lt_entry_tcam_parts_count(int unit,
   6274                                         _field_stage_id_t stage_id,
   6275                                         uint32 group_flags,
   6276                                         int *part_count)
   6277 {
   6278     /* Input parameters check. */
   6279     if (NULL == part_count) {
   6280         return (BCM_E_PARAM);
   6281     }
   6282 
   6283     if (stage_id == _BCM_FIELD_STAGE_FLOWTRACKER) {
   6284         *part_count = 1;
   6285         return BCM_E_NONE;
   6286     }
   6287 
   6288     return _bcm_field_th_entry_tcam_parts_count(unit, group_flags, part_count);
   6289 
   6290 }
   6291 
   6292 /*
   6293  * Function:
   6294  *     _bcm_field_th_slice_offset_to_tcam_idx
   6295  * Purpose:
   6296  *     Given stage, slice number and entry index in the slice, calculate TCAM
   6297  *     index.
   6298  *
   6299  * Parameters:
   6300  *     unit     - (IN) BCM device number.
   6301  *     stage_fc - (IN) Pointer to field entry structure.
   6302  *     instance - (IN) Field processor pipe instance.
   6303  *     slice    - (IN) Entry slice number.
   6304  *     slice_idx -(IN) Entry offset in the slice.
   6305  *     tcam_idx - (OUT) Entry tcam index.
   6306  * Returns:
   6307  *     BCM_E_XXX
   6308  */
   6309 int
   6310 _bcm_field_th_slice_offset_to_tcam_idx(int unit, _field_stage_t *stage_fc,
   6311                                        int instance, int slice, int slice_idx,
   6312                                        int *tcam_idx)
   6313 {
   6314     _field_slice_t *fs; /* Field slice structure pointer. */
   6315 
   6316     /* Input parameters check. */
   6317     if (NULL == stage_fc || NULL == tcam_idx) {
   6318         return (BCM_E_PARAM);
   6319     }
   6320 
   6321     /* Input parameters check. */
   6322     if (instance < 0 || instance >= stage_fc->num_instances) {
   6323         return (BCM_E_PARAM);
   6324     }
   6325 
   6326     /* Get the slice pointer. */
   6327     fs = stage_fc->slices[instance] + slice;
   6328 
   6329     /* Given stage slice number and slice index, calcuate TCAM index. */
   6330     *tcam_idx = fs->start_tcam_idx + slice_idx;
   6331 
   6332     return (BCM_E_NONE);
   6333 }
   6334 
   6335 /*
   6336  * Function:
   6337  *     _bcm_field_th_tcam_idx_to_slice_offset
   6338  *
   6339  * Purpose:
   6340  *     Given stage and tcam_index,
   6341  *     calculate slice and entry offset in the
   6342  *
   6343  * Parameters:
   6344  *     unit     - (IN) BCM device number.
   6345  *     stage_fc - (IN) Pointer to field stage structure.
   6346  *     f_ent    - (IN) Reference to field entry structure.
   6347  *     tcam_idx - (IN) Entry tcam index.
   6348  *     slice    - (OUT) Entry slice number.
   6349  *     slice_idx -(OUT) Entry offset in the slice.
   6350  * Returns:
   6351  *     BCM_E_XXX
   6352  */
   6353 int
   6354 _bcm_field_th_tcam_idx_to_slice_offset(int unit, _field_stage_t *stage_fc,
   6355                                        _field_entry_t *f_ent, int tcam_idx,
   6356                                        int *slice, int *slice_idx)
   6357 {
   6358     _field_slice_t  *fs;                  /* Field Slice number.  */
   6359     int             idx;                  /* Slice iterator.      */
   6360     int             max_entries_in_slice; /* Max entries supported in a slice.*/
   6361 
   6362    /* Input parameters check. */
   6363     if ((NULL == stage_fc) || (NULL == slice_idx) || (NULL == slice)
   6364         || (NULL == f_ent)) {
   6365         return (BCM_E_PARAM);
   6366     }
   6367 
   6368 #if defined (BCM_TOMAHAWK3_SUPPORT)
   6369     if (SOC_IS_TOMAHAWK3(unit)) {
   6370         return (_bcm_field_th3_tcam_idx_to_slice_offset (unit, stage_fc,
   6371                                                          f_ent, tcam_idx,
   6372                                                          slice,
   6373                                                          slice_idx));
   6374     }
   6375 #endif
   6376 
   6377     max_entries_in_slice = stage_fc->tcam_sz / stage_fc->tcam_slices;
   6378 
   6379     if (!(f_ent->group->flags & _FP_GROUP_SPAN_SINGLE_SLICE) ||
   6380         (f_ent->group->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE)) {
   6381         max_entries_in_slice = max_entries_in_slice/2;
   6382     }
   6383 
   6384     for (idx = 0; idx < stage_fc->tcam_slices; idx++) {
   6385         fs = stage_fc->slices[f_ent->group->instance] + idx;
   6386 
   6387         if (tcam_idx < ((idx * max_entries_in_slice) + max_entries_in_slice)) {
   6388             *slice = idx;
   6389             *slice_idx = tcam_idx - fs->start_tcam_idx;
   6390             break;
   6391         }
   6392     }
   6393 
   6394     /* TCAM index sanity check. */
   6395     if (idx == stage_fc->tcam_slices) {
   6396         return (BCM_E_PARAM);
   6397     }
   6398 
   6399     return (BCM_E_NONE);
   6400 }
   6401 
   6402 /*
   6403  * Function:
   6404  *     _bcm_field_th_tcam_part_to_slice_number
   6405  * Purpose:
   6406  *     Each field entry contains up to 3 TCAM entries. This routine maps tcam
   6407  *     entry (0-2) to a slice number
   6408  * Parameters:
   6409  *     entry_part   - (IN)  Entry Part number.
   6410  *     group_flags  - (IN)  Field Group flags.
   6411  *     slice_number - (OUT) Slice number (0-2)
   6412  * Returns:
   6413  *     BCM_E_XXX
   6414  */
   6415 int
   6416 _bcm_field_th_tcam_part_to_slice_number(int entry_part, uint32 group_flags,
   6417                                         uint8 *slice_number)
   6418 {
   6419     /* Input parameters check. */
   6420     if (NULL == slice_number) {
   6421         return (BCM_E_PARAM);
   6422     }
   6423 
   6424     switch (entry_part) {
   6425         case 0:
   6426             *slice_number = 0;
   6427             break;
   6428         case 1:
   6429             *slice_number = 1;
   6430             break;
   6431         case 2:
   6432             *slice_number = 2;
   6433             break;
   6434         default:
   6435             return (BCM_E_INTERNAL);
   6436     }
   6437     return (BCM_E_NONE);
   6438 }
   6439 
   6440 /*
   6441  * Function:
   6442  *     _bcm_field_th_entry_part_tcam_idx_get
   6443  *
   6444  * Purpose:
   6445  *     Given primary entry slice/idx calculate secondary/tertiary slice/index.
   6446  *
   6447  * Parameters:
   6448  *     unit     - (IN) BCM device number.
   6449  *     f_ent    - (IN) Field entry pointer.
   6450  *     idx_pri  - (IN) Primary entry tcam index.
   6451  *     ent_part - (IN) Entry part id.
   6452  *     idx_out  - (OUT) Entry part tcam index.
   6453  * Returns
   6454  *     BCM_E_XXX
   6455  */
   6456 int
   6457 _bcm_field_th_entry_part_tcam_idx_get(int unit, _field_entry_t *f_ent,
   6458                                       uint32 idx_pri, uint8 entry_part,
   6459                                       int *idx_out)
   6460 {
   6461     uint8 slice_num = 0;        /* Primary entry slice number.              */
   6462     int pri_slice = 0;          /* Primary slice number.                    */
   6463     int pri_index = 0;          /* Primary entry.                           */
   6464     int part_index;             /* Entry part slice index.                  */
   6465     _field_stage_t *stage_fc;   /* Field stage control structure pointer.   */
   6466     _field_slice_t *fs;         /* Field slice structure pointer.           */
   6467     _field_group_t *fg;         /* Field Group structure.                   */
   6468     int rv;                     /* Operation return status.                 */
   6469 
   6470     /* Input parameters check. */
   6471     if (NULL == f_ent || NULL == idx_out) {
   6472         return (BCM_E_PARAM);
   6473     }
   6474 
   6475     /* Primary entry index. */
   6476     if (0 == entry_part) {
   6477         *idx_out = idx_pri;
   6478         return (BCM_E_NONE);
   6479     }
   6480 
   6481     fg = f_ent->group;
   6482 
   6483     /* Get stage control structure. */
   6484     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fg->stage_id,
   6485         &stage_fc));
   6486 
   6487     /* Get primary part slice and entry index. */
   6488     BCM_IF_ERROR_RETURN(_bcm_field_th_tcam_idx_to_slice_offset(unit, stage_fc,
   6489         f_ent, idx_pri, &pri_slice, &pri_index));
   6490 
   6491     /* Get entry part slice number 0, 1, 2. */
   6492     BCM_IF_ERROR_RETURN(_bcm_field_th_tcam_part_to_slice_number(entry_part,
   6493         fg->flags, &slice_num));
   6494 
   6495     fs = stage_fc->slices[fg->instance] + (pri_slice + slice_num);
   6496 
   6497     part_index = pri_index;
   6498 
   6499     /*
   6500      * Given slice number & entry's offset index in slice, calculcate TCAM
   6501      * index.
   6502      */
   6503     rv = _bcm_field_th_slice_offset_to_tcam_idx(unit, stage_fc, fg->instance,
   6504             fs->slice_number, part_index, idx_out);
   6505     return (rv);
   6506 }
   6507 
   6508 /*
   6509  * Function:
   6510  *     _field_th_entry_slice_idx_change
   6511  * Purpose:
   6512  *     Move the software entry to a new slice index.
   6513  * Parmeters:
   6514  *     unit         - (IN)      BCM device number.
   6515  *     f_ent        - (IN/OUT)  Field entry to be moved.
   6516  *     parts_count  - (IN)      Number of entry parts count.
   6517  *     tcam_idx_new - (IN)      Entry new TCAM index.
   6518  * Returns:
   6519  *     BCM_E_XXX
   6520  */
   6521 STATIC int
   6522 _field_th_entry_slice_idx_change(int unit, _field_entry_t *f_ent,
   6523                                  int parts_count, int *tcam_idx_new)
   6524 {
   6525     _field_slice_t *fs;         /* Field slice structure pointer.           */
   6526     _field_group_t *fg;         /* Field Group structure pointer.           */
   6527     _field_stage_t *stage_fc;   /* Stage Field control structure pointer.   */
   6528     int new_slice_num = 0;      /* Entry new slice number.                  */
   6529     int new_slice_idx = 0;      /* Entry's new offset in the slice.         */
   6530     int part;                   /* Entry parts iterator.                    */
   6531 
   6532     /* Input parameters check. */
   6533     if ((NULL == f_ent) || (NULL == f_ent->group) || (NULL == f_ent->fs)) {
   6534         return (BCM_E_PARAM);
   6535     }
   6536 
   6537     /* Get stage control structure. */
   6538     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, f_ent->group->stage_id,
   6539         &stage_fc));
   6540 
   6541     /* Get entry group information. */
   6542     fg = f_ent->group;
   6543     for (part = 0; part < parts_count; part++) {
   6544         /* Get slice control structure. */
   6545         fs = f_ent[part].fs;
   6546 
   6547         if (FALSE == th_prio_set_with_no_free_entries) {
   6548             fs->entries[f_ent[part].slice_idx] = NULL;
   6549         }
   6550 
   6551         /*
   6552          * Calculate entry new slice number and offset in slice from TCAM index
   6553          * value.
   6554          */
   6555         BCM_IF_ERROR_RETURN(_bcm_field_th_tcam_idx_to_slice_offset(unit, stage_fc,
   6556             f_ent, tcam_idx_new[part], &new_slice_num, &new_slice_idx));
   6557 
   6558         /* If entry moves across the slice, update free counter.*/
   6559         if (new_slice_num != f_ent[part].fs->slice_number
   6560             && (0 == (f_ent[part].flags & _FP_ENTRY_SECOND_HALF))) {
   6561             fs->free_count++;
   6562             stage_fc->slices[fg->instance][new_slice_num].free_count--;
   6563         }
   6564 
   6565         /* Update entry structure. */
   6566         stage_fc->slices[fg->instance][new_slice_num].entries[new_slice_idx] =
   6567             f_ent + part;
   6568         f_ent[part].fs = &stage_fc->slices[fg->instance][new_slice_num];
   6569         f_ent[part].slice_idx = new_slice_idx;
   6570     }
   6571 
   6572     return (BCM_E_NONE);
   6573 }
   6574 
   6575 /*
   6576  * Function:
   6577  *     _field_th_entry_move
   6578  * Purpose:
   6579  *     Move an entry within a slice by "amount" indexes
   6580  * Parameters:
   6581  *     unit     - BCM device number
   6582  *     f_ent    - entry to be moved
   6583  *     amount   - number of indexes to move + or -
   6584  * Returns:
   6585  *     BCM_E_NONE - Success
   6586  */
   6587 STATIC int
   6588 _field_th_entry_move(int unit, _field_entry_t *f_ent, int amount)
   6589 {
   6590     int tcam_idx_old[_FP_MAX_ENTRY_WIDTH] = {0}; /* Original entry TCAM
   6591                                                     index.          */
   6592     int tcam_idx_new[_FP_MAX_ENTRY_WIDTH] = {0}; /* New destination TCAM
   6593                                                     index.          */
   6594     _field_control_t *fc;       /* Field control structure pointer. */
   6595     _field_stage_t *stage_fc;   /* Field stage structure pointer.   */
   6596     _field_group_t *fg;         /* Field Group structure pointer.   */
   6597     /* _field_slice_t *fs; */   /* Field slice structure pointer.   */
   6598     int parts_count = 0;        /* Number of parts per-entry.       */
   6599     int idx;                    /* Entry parts iterator.            */
   6600     int new_offset;             /* New entry offset in slice.       */
   6601     int new_slice_num = -1;     /* New slice number.                */
   6602 
   6603     /* Input parameters check. */
   6604     if ((NULL == f_ent) || (NULL == f_ent->fs) || (NULL == f_ent->group)) {
   6605         return (BCM_E_PARAM);
   6606     }
   6607 
   6608     LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   6609         "FP(unit %d) vverb: BEGIN _field_th_entry_move(entry=%d, amount=%d)\n"),
   6610          unit, f_ent->eid, amount));
   6611 
   6612     fg = f_ent->group;
   6613 
   6614     if (0 == amount) {
   6615         LOG_WARN(BSL_LS_BCM_FP, (BSL_META_U(unit,
   6616             "FP(unit %d) warn:  moving entry=%d, same slice_idx=%d(%#x)\n"),
   6617              unit, f_ent->eid, f_ent->slice_idx, f_ent->slice_idx));
   6618         return (BCM_E_NONE);
   6619     }
   6620 
   6621     /* Get Field control structure. */
   6622     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   6623 
   6624     /* Get Stage control structure. */
   6625     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fg->stage_id,
   6626         &stage_fc));
   6627 
   6628     /* Get number of parts. */
   6629     BCM_IF_ERROR_RETURN(_bcm_field_th_entry_tcam_parts_count(unit, fg->flags,
   6630         &parts_count));
   6631 
   6632     for (idx = 0; idx < parts_count; idx++) {
   6633         /* Calculate entry parts OLD TCAM indices. */
   6634         BCM_IF_ERROR_RETURN(_bcm_field_entry_tcam_idx_get(unit, f_ent + idx,
   6635             &tcam_idx_old[idx]));
   6636 
   6637         /* Calculate entry part tcam offset. */
   6638         BCM_IF_ERROR_RETURN(_bcm_field_th_entry_part_tcam_idx_get(unit, f_ent,
   6639             tcam_idx_old[0] + amount, idx, &tcam_idx_new[idx]));
   6640     }
   6641 
   6642     BCM_IF_ERROR_RETURN(_bcm_field_th_tcam_idx_to_slice_offset(unit, stage_fc,
   6643         f_ent, tcam_idx_new[0], &new_slice_num, &new_offset));
   6644 
   6645     if (f_ent->flags & _FP_ENTRY_INSTALLED) {
   6646         /* fs = stage_fc->slices[fg->instance] + new_slice_num; */
   6647 
   6648         /* Move the entry in hardware if it's already installed in HW. */
   6649         if (f_ent->flags & _FP_ENTRY_INSTALLED) {
   6650             BCM_IF_ERROR_RETURN(fc->functions.fp_entry_move(unit, f_ent,
   6651                 parts_count, tcam_idx_old, tcam_idx_new));
   6652         }
   6653     }
   6654     /* Move the SW entry to the new slice index. */
   6655     BCM_IF_ERROR_RETURN(_field_th_entry_slice_idx_change(unit, f_ent,
   6656         parts_count, tcam_idx_new));
   6657 
   6658     return (BCM_E_NONE);
   6659 }
   6660 
   6661 /*
   6662  * Function:
   6663  *     _field_th_slice_is_empty
   6664  * Purpose:
   6665  *     Report if a slice has any entries.
   6666  * Parameters:
   6667  *     fc       - (IN)  Field control structure.
   6668  *     fs       - (IN)  Slice control structure.
   6669  *     empty    - (OUT) True - slice is empty/False otherwise.
   6670  * Returns:
   6671  *     BCM_E_XXX
   6672  */
   6673 STATIC int
   6674 _field_th_slice_is_empty(int unit, _field_slice_t *fs, uint8 *empty)
   6675 {
   6676     /* Input parameters check. */
   6677     if (NULL == fs || NULL == empty) {
   6678         return (BCM_E_PARAM);
   6679     }
   6680 
   6681     /* Check if total entries count is equal to the free count. */
   6682     if (fs->entry_count == fs->free_count) {
   6683         /* Slice has not valid group entries. */
   6684         *empty = TRUE;
   6685     } else {
   6686         /* Slice has atleast one valid entry. */
   6687         *empty = FALSE;
   6688     }
   6689 
   6690     return (BCM_E_NONE);
   6691 }
   6692 
   6693 /*
   6694  * Function:
   6695  *    _field_th_ingress_slice_clear
   6696  *
   6697  * Purpose:
   6698  *    Reset the fields in a slice. Note that the entries list must be
   6699  *    empty before calling this. Also, this does NOT deallocate the memory for
   6700  *    the slice itself. Normally, this is used when a group no longer needs
   6701  *    ownership of a slice so the slice gets returned to the pool of available
   6702  *    slices.
   6703  *
   6704  * Paramters:
   6705  *    unit  - (IN)     BCM device number
   6706  *    fg    - (IN)     Field group structure.
   6707  *    fs    - (IN/OUT) Link to physical slice structure to be cleared
   6708  *
   6709  * Returns:
   6710  *    BCM_E_NONE    - Success
   6711  *    BCM_E_BUSY    - Entries still in slice, can't clear slice
   6712  */
   6713 STATIC int
   6714 _field_th_ingress_slice_clear(int unit, _field_group_t *fg, _field_slice_t *fs)
   6715 {
   6716     _field_stage_t *stage_fc;   /* Stage field control structure.   */
   6717     _field_control_t *fc;       /* Field control structure.         */
   6718     uint32 entry_idx;           /* Slice entries iterator.          */
   6719     bcm_port_t port;            /* Port iterator.                   */
   6720     int slice;                  /* Slice iterator. */
   6721     int tcam_idx;               /* Slice first entry tcam index tracker. */
   6722     _field_slice_t *slice_ptr;  /* Slice Pointer for traversal */
   6723 
   6724     /* Input parameters check. */
   6725     if ((NULL == fg) || (NULL == fs)) {
   6726         return (BCM_E_PARAM);
   6727     }
   6728 
   6729     /* Skip for Flowtracker stage */
   6730     if (fg->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER) {
   6731         return (BCM_E_NONE);
   6732     }
   6733 
   6734     /* Get field control structure. */
   6735     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   6736 
   6737     /* Get stage field control structure. */
   6738     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fs->stage_id,
   6739         &stage_fc));
   6740 
   6741     for (entry_idx = 0; entry_idx < fs->entry_count; entry_idx++) {
   6742         if ((NULL != fs->entries[entry_idx])
   6743              && (fs->entries[entry_idx]->group->gid == fg->gid)) {
   6744              LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   6745                 "FP(unit %d) Error: Entries still in slice=%d.\n"),
   6746                  unit, fs->slice_number));
   6747             return (BCM_E_BUSY);
   6748         }
   6749     }
   6750 
   6751     /* Remove ports from slice's port bitmap. */
   6752     BCM_PBMP_ITER(fg->pbmp, port) {
   6753         BCM_PBMP_PORT_REMOVE(fs->pbmp, port);
   6754     }
   6755 
   6756     /* Clear Group's LT_ID bit in slice LT map. */
   6757     fs->lt_map &= ~(1 << fg->lt_id);
   6758 
   6759     /* Set entry count to invalid number */
   6760     fs->entry_count = -1;
   6761     /*  Initialize entries per-slice count. */
   6762     if ((soc_feature(unit, soc_feature_th3_style_fp) &&
   6763         (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS))) {
   6764 #if defined(BCM_TOMAHAWK3_SUPPORT)
   6765         if (fs->slice_number < _BCM_FIELD_TH3_INGRESS_MAX_SMALL_SLICES) {
   6766             fs->entry_count = _BCM_FIELD_TH3_INGRESS_SMALL_SLICE_SZ;
   6767         } else {
   6768             fs->entry_count = _BCM_FIELD_TH3_INGRESS_LARGE_SLICE_SZ;
   6769         }
   6770 #endif /* BCM_TOMAHAWK3_SUPPORT */
   6771 
   6772         for (slice = 0, tcam_idx = 0; slice < fs->slice_number; slice++) {
   6773             slice_ptr = stage_fc->slices[fg->instance] + slice;
   6774             tcam_idx += slice_ptr->entry_count;
   6775         }
   6776         fs->start_tcam_idx = tcam_idx;
   6777     } else {
   6778         fs->entry_count = stage_fc->tcam_sz / stage_fc->tcam_slices;
   6779         fs->start_tcam_idx = fs->slice_number * fs->entry_count;
   6780     }
   6781 
   6782     /* Initialize free entries count. */
   6783     fs->free_count = fs->entry_count;
   6784 
   6785     /* Initialize start TCAM index. */
   6786     slice_ptr = NULL;
   6787 
   6788     /* Clear group flags settings. */
   6789     fs->group_flags = 0;
   6790 
   6791     return (BCM_E_NONE);
   6792 }
   6793 /*
   6794  * Function:
   6795  *    _bcm_field_th_ingress_slice_clear
   6796  *
   6797  * Purpose:
   6798  *    Reset the fields in a slice. Note that the entries list must be
   6799  *    empty before calling this. Also, this does NOT deallocate the memory for
   6800  *    the slice itself. Normally, this is used when a group no longer needs
   6801  *    ownership of a slice so the slice gets returned to the pool of available
   6802  *    slices.
   6803  *
   6804  * Paramters:
   6805  *    unit  - (IN)     BCM device number
   6806  *    fg    - (IN)     Field group structure.
   6807  *    fs    - (IN/OUT) Link to physical slice structure to be cleared
   6808  *
   6809  * Returns:
   6810  *    BCM_E_NONE    - Success
   6811  *    BCM_E_BUSY    - Entries still in slice, can't clear slice
   6812  */
   6813 int
   6814 _bcm_field_th_ingress_slice_clear(int unit,
   6815                                   _field_group_t *fg,
   6816                                   _field_slice_t *fs)
   6817 {
   6818     return _field_th_ingress_slice_clear(unit, fg, fs);
   6819 }
   6820 
   6821 /*
   6822  * Function to delete the LT entry from Hardware.
   6823  */
   6824 STATIC int
   6825 _field_th_lt_hw_entry_delete(int unit,
   6826                              _field_stage_t *stage_fc,
   6827                              _field_group_t *fg,
   6828                              int tcam_idx)
   6829 {
   6830     int        rv;
   6831     soc_mem_t  lt_tcam_mem;
   6832     uint32     entry[SOC_MAX_MEM_FIELD_WORDS] = {0}; /*Entry buffer*/
   6833 
   6834     /* Get TCAM view to be used for programming the hardware */
   6835     if (stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   6836         rv = (_bcm_field_th_lt_tcam_policy_mem_get(unit, stage_fc,
   6837                                                      fg->instance,
   6838                                        _BCM_FIELD_MEM_TYPE_IFP_LT,
   6839                           _BCM_FIELD_MEM_VIEW_TYPE_TCAM_DATA_COMB,
   6840                                              &lt_tcam_mem, NULL));
   6841     } else if (stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   6842         rv = (_bcm_field_th_lt_tcam_policy_mem_get(unit, stage_fc,
   6843                                                      fg->instance,
   6844                                         _BCM_FIELD_MEM_TYPE_EM_LT,
   6845                                     _BCM_FIELD_MEM_VIEW_TYPE_TCAM,
   6846                                              &lt_tcam_mem, NULL));
   6847     } else {
   6848         return BCM_E_PARAM;
   6849     }
   6850     BCM_IF_ERROR_RETURN(rv);
   6851 
   6852     /* Clear the entry in hardware. */
   6853     return (soc_th_ifp_mem_write(unit, lt_tcam_mem, MEM_BLOCK_ALL,
   6854                                                 tcam_idx, entry));
   6855 }
   6856 
   6857 
   6858 /*
   6859  * Function:
   6860  *    _bcm_field_th_lt_slice_clear
   6861  *
   6862  * Purpose:
   6863  *    Reset the default LT entry or Preselector entries in a slice. 
   6864  *    Note that the entries list must be empty before calling this.
   6865  *    Also, this does NOT deallocate the memory for the slice itself.
   6866  *    Normally, this is used when a group no longer needs ownership
   6867  *    of a slice so the slice gets returned to the pool of available
   6868  *    slices.
   6869  *
   6870  * Paramters:
   6871  *    unit      - (IN) BCM device number
   6872  *    fg        - (IN) Field group structure.
   6873  *    slice_num - (IN) Slice to be reset.
   6874  *
   6875  * Returns:
   6876  *    BCM_E_xxx
   6877  */
   6878 STATIC int
   6879 _bcm_field_th_lt_slice_clear(int unit, _field_group_t *fg, int slice_num)
   6880 {
   6881     int                   rv, idx;
   6882     int                   tcam_idx;
   6883     int                   part, parts = -1;
   6884     _field_stage_t        *stage_fc;
   6885     _field_control_t      *fc;
   6886     _field_lt_slice_t     *lt_fs;
   6887     _field_lt_slice_t     *lt_part_fs = NULL;
   6888     bcm_field_entry_t      lt_entry;
   6889     _field_lt_entry_t     *lt_f_entry,
   6890                           *lt_f_entry_p = NULL;
   6891     _field_presel_entry_t *f_presel,
   6892                           *f_presel_p;
   6893 
   6894     /* Input parameters check. */
   6895     if (NULL == fg) {
   6896         return (BCM_E_PARAM);
   6897     }
   6898 
   6899     /* Field control get. */
   6900     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   6901 
   6902     /* Get stage control structure. */
   6903     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fg->stage_id,
   6904         &stage_fc));
   6905 
   6906     /* Find the LT Slice to be cleared. */
   6907     lt_fs = stage_fc->lt_slices[fg->instance] + slice_num;
   6908 
   6909     if (fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) {
   6910         for (idx = 0; idx < _FP_PRESEL_ENTRIES_MAX_PER_GROUP; idx++) {
   6911             if (fg->presel_ent_arr[idx] != NULL) {
   6912                f_presel = fg->presel_ent_arr[idx];
   6913             } else {
   6914                continue;
   6915             }
   6916 
   6917             f_presel_p = f_presel;
   6918 
   6919             tcam_idx = -1;
   6920             for (; f_presel_p != NULL; f_presel_p = f_presel_p->next) {
   6921                 lt_part_fs = f_presel_p->lt_fs;
   6922 
   6923                 for (; lt_part_fs != NULL; lt_part_fs=lt_part_fs->next) {
   6924                     if (lt_part_fs == lt_fs) {
   6925                        lt_part_fs->free_count++;
   6926                        lt_part_fs->p_entries[f_presel_p->hw_index] = NULL;
   6927         
   6928                        rv = _bcm_field_presel_entry_tcam_idx_get(unit,
   6929                                         f_presel_p, lt_fs, &tcam_idx);
   6930                        BCM_IF_ERROR_RETURN(rv);
   6931                        rv = _field_th_lt_hw_entry_delete(unit, stage_fc,
   6932                                                           fg, tcam_idx);
   6933                        BCM_IF_ERROR_RETURN(rv);
   6934 
   6935                        if (f_presel_p->lt_fs == lt_part_fs) {
   6936                            f_presel_p->lt_fs = lt_part_fs->next;
   6937                        }
   6938                        break;
   6939                     }
   6940                 }
   6941 
   6942                 if (tcam_idx != -1) {
   6943                    break;
   6944                 }
   6945             } 
   6946         }
   6947     } else {
   6948         /* Get entry parts count. */
   6949         BCM_IF_ERROR_RETURN(_bcm_field_th_entry_tcam_parts_count(unit,
   6950                                                   fg->flags, &parts));
   6951         lt_entry = fc->lt_info[fg->instance][fg->lt_id]->lt_entry;
   6952 
   6953         /* Get all part of the entry. */
   6954         BCM_IF_ERROR_RETURN(_field_th_lt_entry_get_by_id(unit,
   6955                             lt_entry, &lt_f_entry));
   6956         if (lt_f_entry->lt_fs == NULL) {
   6957             return BCM_E_INTERNAL;
   6958         }
   6959 
   6960         tcam_idx = -1;
   6961         for (part = 0; part < parts; part++) {
   6962             lt_f_entry_p = lt_f_entry + part;
   6963             lt_part_fs = lt_f_entry_p->lt_fs;
   6964             for (;lt_part_fs != NULL;lt_part_fs=lt_part_fs->next) {
   6965                 if (lt_part_fs == lt_fs) {
   6966                     lt_part_fs->free_count++;
   6967                     lt_part_fs->entries[lt_f_entry_p->index] = NULL;
   6968 
   6969                     rv = _field_th_lt_entry_tcam_idx_get(unit, lt_f_entry_p,
   6970                                                           lt_fs, &tcam_idx);
   6971                     BCM_IF_ERROR_RETURN(rv);
   6972                     rv = _field_th_lt_hw_entry_delete(unit, stage_fc,
   6973                                                        fg, tcam_idx);
   6974                     BCM_IF_ERROR_RETURN(rv);
   6975 
   6976                     if (lt_f_entry_p->lt_fs == lt_part_fs) {
   6977                         lt_f_entry_p->lt_fs = lt_part_fs->next;
   6978                     }
   6979                     break;
   6980                 }
   6981             }
   6982             if (tcam_idx != -1) {
   6983                 break;
   6984             }
   6985         }     
   6986     }
   6987 
   6988     /* Update group's primary lt slice */
   6989     if (fg->lt_slices == lt_fs) {
   6990         fg->lt_slices = lt_fs->next;
   6991     }
   6992 
   6993     if (lt_fs->free_count == lt_fs->entry_count) {
   6994         if (lt_fs->prev != NULL) {
   6995             lt_fs->prev->next = lt_fs->next;
   6996         }
   6997 
   6998         if (lt_fs->next != NULL) {
   6999             lt_fs->next->prev = lt_fs->prev;
   7000         }
   7001 
   7002         lt_fs->next = NULL;
   7003         lt_fs->prev = NULL;
   7004     }
   7005 
   7006     return BCM_E_NONE;
   7007 }
   7008 
   7009 /*
   7010  * Function:
   7011  *    _bcm_field_th_group_free_unused_slices
   7012  * Purpose:
   7013  *     Unallocate group unused slices.
   7014  * Parameters:
   7015  *     unit           - (IN) BCM device number.
   7016  *     stage_fc       - (IN) Stage field control structure.
   7017  *     fg             - (IN) Field group structure.
   7018  * Returns:
   7019  *     BCM_E_XXX
   7020  */
   7021 int
   7022 _bcm_field_th_group_free_unused_slices(int unit,
   7023                                        _field_stage_t *stage_fc,
   7024                                        _field_group_t *fg)
   7025 {
   7026     _field_slice_t *fs;         /* Field slice structure pointer.           */
   7027     _field_slice_t *fs_next;    /* Field slice structure pointer.           */
   7028     _field_slice_t *fs_ptr;     /* Field slice structure pointer.           */
   7029     uint8 empty;                /* Slice is empty flag.                     */
   7030     int slice;                  /* Group slices iterator.                   */
   7031     int count;                  /* Group slices span count.                 */
   7032     _field_control_t *fc;       /* field control                            */
   7033     _field_meter_pool_t *f_mp;  /* Meter pool descriptor.                   */
   7034     _field_group_t *fg_next = NULL;
   7035     int pri_slice = -1;
   7036     int pool_idx = 0;
   7037 
   7038     /* Input parameters check. */
   7039     if ((NULL == stage_fc) || (NULL == fg)) {
   7040         return (BCM_E_PARAM);
   7041     }
   7042 
   7043     if (NULL == fg->slices) {
   7044         return (BCM_E_INTERNAL);
   7045     }
   7046 
   7047     fs = fg->slices;
   7048     /* Don't free the slice if it is the last slice in the group */
   7049     if (fs->next == NULL) {
   7050        return BCM_E_NONE;
   7051     }
   7052 
   7053     while (NULL != fs) {
   7054        if (pri_slice == -1) {
   7055            pri_slice = fs->slice_number;
   7056        }
   7057        fs_next = fs->next;
   7058        BCM_IF_ERROR_RETURN(_field_th_slice_is_empty(unit, fs, &empty));
   7059 
   7060        if (empty) {
   7061            BCM_IF_ERROR_RETURN(_bcm_field_group_slice_count_get(fs->group_flags,
   7062                &count));
   7063 
   7064            do {
   7065                /* Retrieve the existing groups associated with the Slice */
   7066                (void)_bcm_field_slice_group_get_next(unit,
   7067                                                fg->instance, fg->stage_id,
   7068                                                fs->slice_number,
   7069                                                &fg_next, &fg_next);
   7070                if (fg_next != NULL) {
   7071                    for (slice = 0; slice < count; slice++) {
   7072                       /* Remove slice from Group's slices linked list. */
   7073                       fs_ptr = fs + slice;
   7074                       LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   7075                         "%s(): SLICE TO BE detached SLICE:%d fs_ptr:%p fg_slice:%p"
   7076                         " fg_slice_num:%d\n\r\n\r"), __func__,
   7077                         fs_ptr->slice_number, fs_ptr, fg->slices,
   7078                         (fg->slices!=NULL)?fg->slices->slice_number:-1));
   7079 
   7080                       /* Reset the partition priority for the slice. */
   7081                       BCM_IF_ERROR_RETURN(_bcm_field_th_lt_part_prio_reset(unit,
   7082                                                      stage_fc, fg_next, fs_ptr));
   7083                       /* Clear unused LT slice settings. */
   7084                       BCM_IF_ERROR_RETURN(_bcm_field_th_lt_slice_clear(unit,
   7085                                              fg_next, fs_ptr->slice_number));
   7086                       /* Clear unused slice settings. */
   7087                       BCM_IF_ERROR_RETURN(_field_th_ingress_slice_clear(unit,
   7088                                                             fg_next, fs_ptr));
   7089                    }
   7090                }
   7091 
   7092                if ((fg_next != NULL) && (fg_next->slices == fs)) {
   7093                    fg_next->slices = fs->next;
   7094 
   7095                    if (fg_next->presel_ent_arr[0]) {
   7096                       LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   7097                          "$$ GID:[%d] fg->presel_ent_arr[0]->lt_fs:%p slice:%d\n\r"),
   7098                          fg_next->gid, fg_next->presel_ent_arr[0]->lt_fs,
   7099                          (fg_next->presel_ent_arr[0]->lt_fs == NULL) ?
   7100                          -1 : fg_next->presel_ent_arr[0]->lt_fs->slice_number));
   7101 
   7102                       LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   7103                          "$$        fg->presel_ent_arr[0]->next->lt_fs:%p slice:%d\n\r"),
   7104                           fg_next->presel_ent_arr[0]->next->lt_fs,
   7105                           (fg_next->presel_ent_arr[0]->next->lt_fs == NULL) ?
   7106                           -1 : fg_next->presel_ent_arr[0]->next->lt_fs->slice_number));
   7107                    } 
   7108               } 
   7109            } while(fg_next != NULL);
   7110 
   7111            /* Get field control structure. */
   7112            BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   7113 
   7114            /* When the first slice (primary slice) of the group is released,
   7115             * the meter pool slice_id of the policers attached to
   7116             * the remaining entries are updated to the new primary slice id.
   7117             */
   7118 
   7119            if ((!(_FP_POLICER_GROUP_SHARE_ENABLE & fc->flags)) &&
   7120                (_BCM_FIELD_STAGE_INGRESS == stage_fc->stage_id) &&
   7121                (stage_fc->flags & _FP_STAGE_GLOBAL_METER_POOLS) &&
   7122                (fs->slice_number == pri_slice)) {
   7123                for (pool_idx = 0; pool_idx < stage_fc->num_meter_pools;
   7124                     pool_idx++) {
   7125                    f_mp = stage_fc->meter_pool[fg->instance][pool_idx];
   7126                    if ((f_mp->level == 0) &&
   7127                        (f_mp->slice_id == pri_slice)) {
   7128                        f_mp->slice_id = fs->next->slice_number;
   7129                    }
   7130                }
   7131            }
   7132 
   7133            /* Unlink the slice from the group's list */
   7134            for (slice = 0; slice < count; slice++) {
   7135                fs_ptr = fs + slice;
   7136                if (fs_ptr->next != NULL) {
   7137                   fs_ptr->next->prev = fs_ptr->prev;
   7138                }
   7139 
   7140                if (fs_ptr->prev != NULL) {
   7141                   fs_ptr->prev->next = fs_ptr->next;
   7142                }
   7143                fs_ptr->prev = NULL;
   7144                fs_ptr->next = NULL;
   7145            }
   7146        }
   7147        fs = fs_next;
   7148     }
   7149 
   7150     return (BCM_E_NONE);
   7151 }
   7152 
   7153 /*
   7154  * Function:
   7155  *     _bcm_field_th_group_compress
   7156  * Purpose:
   7157  *     Compress field group entries in order to free slices used by the group.
   7158  * Paramters:
   7159  *     unit     - (IN) BCM device number
   7160  *     fg       - (IN) Field group structure
   7161  *     stage_fc - (IN) Stage field control structure.
   7162  * Returns:
   7163  *     BCM_E_XXX
   7164  */
   7165 int
   7166 _bcm_field_th_group_compress(int unit, _field_group_t *fg, _field_stage_t *stage_fc)
   7167 {
   7168     _field_slice_t *fs;     /* Field slice structure pointer.   */
   7169     _field_slice_t *efs;    /* Slice that contains free slots.  */
   7170     int eidx;               /* Empty slot index.                */
   7171     int idx;                /* Slice entry iterator.            */
   7172     int tmp_idx1;           /* Slice entry index 1.             */
   7173     int tmp_idx2;           /* Slice entry index 2.             */
   7174     int slice_sz;           /* Number of entries in a slice.    */
   7175     int rv;                 /* Operation return status.         */
   7176 
   7177     /* Get group slice pointer. */
   7178     fs = fg->slices;
   7179 
   7180     efs = NULL;
   7181     eidx = -1;
   7182 
   7183     while (NULL != fs) {
   7184         _BCM_FIELD_ENTRIES_IN_SLICE(unit, fg, fs, slice_sz);
   7185         for (idx = 0; idx < slice_sz; idx++) {
   7186             /* Find an empty slot. */
   7187             if (NULL == fs->entries[idx]) {
   7188                 if (NULL == efs) {
   7189                     efs = fs;
   7190                     eidx = idx;
   7191                 }
   7192                 continue;
   7193             }
   7194 
   7195             if (NULL != efs) {
   7196                 /*
   7197                  * Given Stage, Slice number and Entry offset in the slice,
   7198                  * calculate the TCAM entry indices.
   7199                  */
   7200                 BCM_IF_ERROR_RETURN(_bcm_field_th_slice_offset_to_tcam_idx(unit,
   7201                     stage_fc, fg->instance, efs->slice_number, eidx, &tmp_idx1));
   7202 
   7203                 BCM_IF_ERROR_RETURN(_bcm_field_th_slice_offset_to_tcam_idx(unit,
   7204                     stage_fc, fg->instance, fs->slice_number, idx, &tmp_idx2));
   7205 
   7206                 /* Move the entry in hardware. */
   7207                 BCM_IF_ERROR_RETURN(_field_th_entry_move(unit, fs->entries[idx],
   7208                     (tmp_idx1 - tmp_idx2)));
   7209                 fs = efs;
   7210                 idx = eidx;
   7211                 efs = NULL;
   7212                 eidx = -1;
   7213                 _BCM_FIELD_ENTRIES_IN_SLICE(unit, fg, fs, slice_sz);
   7214             }
   7215         }
   7216         fs = fs->next;
   7217     }
   7218     rv = _bcm_field_th_group_free_unused_slices(unit, stage_fc, fg);
   7219     return (rv);
   7220 }
   7221 
   7222 /*
   7223  * Function:
   7224  *     _field_th_stage_group_compress
   7225  * Purpose:
   7226  *     Compress field group entries in order to free slices used by the group.
   7227  * Paramters:
   7228  *     unit     - (IN) BCM device number
   7229  *     fg       - (IN) Field group structure
   7230  *     stage_fc - (IN) Stage field control structure.
   7231  * Returns:
   7232  *     BCM_E_XXX
   7233  */
   7234 STATIC int
   7235 _field_th_stage_group_compress(int unit,
   7236                                _field_control_t *fc,
   7237                                _field_stage_t *stage_fc)
   7238 {
   7239     _field_group_t *fg;     /* Field Group structure pointer.   */
   7240     int rv = BCM_E_NONE;    /* Operation return status.         */
   7241 
   7242     for (fg = fc->groups; fg != NULL; fg = fg->next) {
   7243         /* Skit other stages. */
   7244         if (fg->stage_id != stage_fc->stage_id) {
   7245             continue;
   7246         }
   7247 
   7248         /* Skit new groups. */
   7249         if (NULL == fg->slices) {
   7250             continue;
   7251         }
   7252 
   7253         /* Ignore Non-Expanded Groups. */
   7254         if (NULL == fg->slices->next) {
   7255             continue;
   7256         }
   7257 
   7258         /*
   7259          * Best effort to compress groups that occupy more than one physical
   7260          * table.
   7261          */
   7262         rv = _bcm_field_th_group_compress(unit, fg, stage_fc);
   7263     }
   7264     return (rv);
   7265 }
   7266 
   7267 /*
   7268  * Function:
   7269  *     _field_th_group_add_cam_compress
   7270  * Purpose:
   7271  *     Compress other groups to free room for inserted group.
   7272  * Parameters:
   7273  *     unit     - (IN)     BCM device number.
   7274  *     fsm_ptr  - (IN/OUT) State machine tracking structure.
   7275  * Returns:
   7276  *     BCM_E_XXX
   7277  */
   7278 STATIC int
   7279 _field_th_group_add_cam_compress(int unit, _field_group_add_fsm_t *fsm_ptr)
   7280 {
   7281     /* Set current stage to be previous state. */
   7282     fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state;
   7283 
   7284     /* Compress expanded groups. */
   7285     fsm_ptr->rv = _field_th_stage_group_compress(unit, fsm_ptr->fc,
   7286                                                  fsm_ptr->stage_fc);
   7287 
   7288     if (BCM_SUCCESS(fsm_ptr->rv)) {
   7289        /* Retry allocating slice/s for the new field group. */
   7290        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_SLICE_ALLOCATE;
   7291     } else {
   7292        fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   7293     }
   7294 
   7295     return (BCM_E_NONE);
   7296 }
   7297 
   7298 /*
   7299  * Function:
   7300  *     _bcm_field_th_tcam_part_to_entry_flags
   7301  * Purpose:
   7302  *     Each field entry contains up to 3 TCAM
   7303  *     entries. This routine maps tcam entry (0-2)
   7304  *     to SW entry flags.
   7305  *     Single: 0 (IFP_TCAM view)
   7306  *     Single & Intraslice Double: 0 (IFP_TCAM_WIDE view)
   7307  *     Paired: 0, 1 (IFP_TCAM_WIDE view)
   7308  *     Triple: 0, 1, 2 (IFP_TCAM_WIDE view)
   7309  *     Retrieve the part of the group entry resides in.
   7310  * Parameters:
   7311  *     unit        - (IN)  BCM device number.
   7312  *     entry_flags - (IN)  Entry flags.
   7313  *     group_flags - (IN)  Entry group flags.
   7314  *     entry_part  - (OUT) Entry part (0-2)
   7315  * Returns:
   7316  *     BCM_E_NONE       - Success.
   7317  *     BCM_E_INTERNAL   - Invalid entry part.
   7318  */
   7319 int
   7320 _bcm_field_th_tcam_part_to_entry_flags(int unit, int entry_part,
   7321                                        uint32 group_flags,
   7322                                        uint32 *entry_flags)
   7323 {
   7324     /* Input parameters check. */
   7325     if (NULL == entry_flags) {
   7326         return (BCM_E_PARAM);
   7327     }
   7328 
   7329     /* Map entry part count to entry flags. */
   7330     switch (entry_part) {
   7331         case 0:
   7332             *entry_flags = _FP_ENTRY_PRIMARY;
   7333             break;
   7334         case 1:
   7335             *entry_flags = _FP_ENTRY_SECONDARY;
   7336             break;
   7337         case 2:
   7338             *entry_flags = _FP_ENTRY_TERTIARY;
   7339             break;
   7340         default:
   7341             return (BCM_E_INTERNAL);
   7342     }
   7343     return (BCM_E_NONE);
   7344 }
   7345 
   7346 /*
   7347  * Function:
   7348  *    _field_th_group_ltmap_delete
   7349  * Purpose:
   7350  *    Delete Logical Table's association with group.
   7351  * Parameters:
   7352  *    unit      - (IN) BCM device number.
   7353  *    fg        - (IN/OUT) Field group structure pointer.
   7354  * Returns:
   7355  *    BCM_E_XXX
   7356  */
   7357 STATIC int
   7358 _field_th_group_ltmap_delete(int unit, _field_group_t *fg)
   7359 {
   7360     _field_control_t *fc;       /* Field Control Strucutre.       */
   7361     _field_stage_t *stage_fc;   /* Field stage control structure. */
   7362 
   7363     /* Input parameters check. */
   7364     if (NULL == fg) {
   7365         return (BCM_E_PARAM);
   7366     }
   7367 
   7368     /* skip for Flowtracker stage */
   7369     if (fg->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER) {
   7370         return (BCM_E_NONE);
   7371     }
   7372 
   7373     /* Check if group has a valid logical table information pointer. */
   7374     if (fg->lt_id == -1) {
   7375         return (BCM_E_NONE);
   7376     }
   7377 
   7378     /* Get field control information. */
   7379     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   7380 
   7381     /* Get stage control information. */
   7382     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit,
   7383                                                  fg->stage_id, &stage_fc));
   7384 
   7385 
   7386     fc->lt_info[fg->instance][fg->lt_id]->valid = FALSE;
   7387     fc->lt_info[fg->instance][fg->lt_id]->priority = 0;
   7388     fc->lt_info[fg->instance][fg->lt_id]->flags = 0;
   7389     fc->lt_info[fg->instance][fg->lt_id]->lt_action_pri = 0;
   7390     fc->lt_info[fg->instance][fg->lt_id]->lt_entry = 0;
   7391 
   7392     /* Clear Group's LT_ID information. */
   7393     fg->lt_id = -1;
   7394 
   7395     return (BCM_E_NONE);
   7396 }
   7397 /*
   7398  * Function:
   7399  *     _field_lt_entry_tcam_remove
   7400  * Purpose:
   7401  *     Clears a LT selection TCAM entry for a given index from hardware.
   7402  * Parameters:
   7403  *     unit     - (IN) BCM device number.
   7404  *     lt_f_ent - (IN) Logical Table entry structure.
   7405  *     tcam_idx - (IN) Entry TCAM index.
   7406  * Returns:
   7407  *     BCM_E_XXX
   7408  */
   7409 STATIC int
   7410 _field_lt_entry_tcam_remove(int unit, _field_lt_entry_t *lt_f_ent,
   7411                             int tcam_idx)
   7412 {
   7413     _field_stage_t *stage_fc;   /* Stage field control structure.   */
   7414     soc_mem_t lt_tcam_mem;      /* LT TCAM memory name identifier.  */
   7415 
   7416     /* Input parameters check. */
   7417     if ((NULL == lt_f_ent) || (NULL == lt_f_ent->lt_fs)) {
   7418         return (BCM_E_PARAM);
   7419     }
   7420 
   7421     /* Get stage field control structure. */
   7422     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit,
   7423         lt_f_ent->lt_fs->stage_id, &stage_fc));
   7424 
   7425     /* Get LT TCAM memory name. */
   7426     BCM_IF_ERROR_RETURN(_field_th_lt_tcam_mem_get(unit, stage_fc, lt_f_ent,
   7427         &lt_tcam_mem));
   7428 
   7429     /* Validate supplied TCAM index. */
   7430     if (tcam_idx < soc_mem_index_min(unit, lt_tcam_mem)
   7431         || tcam_idx > soc_mem_index_max(unit, lt_tcam_mem)) {
   7432         return (BCM_E_PARAM);
   7433     }
   7434 
   7435     /* Clear TCAM entry in hardware at the supplied TCAM index. */
   7436     SOC_IF_ERROR_RETURN(soc_th_ifp_mem_write(unit, lt_tcam_mem, MEM_BLOCK_ALL,
   7437         tcam_idx, soc_mem_entry_null(unit, lt_tcam_mem)));
   7438 
   7439     return (BCM_E_NONE);
   7440 }
   7441 
   7442 /*
   7443  * Function:
   7444  *     _field_th_lt_default_entry_remove
   7445  * Purpose:
   7446  *     Remove a logical table entry from hardware.
   7447  * Parameters:
   7448  *     unit     - (IN) BCM device number.
   7449  *     lt_entry - (IN) Logical Table entry identifier.
   7450  * Returns:
   7451  *     BCM_E_XXX
   7452  */
   7453 STATIC int
   7454 _field_th_lt_default_entry_remove(int unit, bcm_field_entry_t lt_entry)
   7455 {
   7456     _field_lt_entry_t *lt_f_ent; /* LT entry structure pointer. */
   7457     int parts_count = -1;        /* Entry parts count.          */
   7458     int part;                    /* Entry part.                 */
   7459     int tcam_idx;                /* LT TCAM entry index.        */
   7460 
   7461     BCM_IF_ERROR_RETURN(_field_th_lt_entry_get(unit, lt_entry,
   7462         _FP_ENTRY_PRIMARY, &lt_f_ent));
   7463 
   7464     if (!(lt_f_ent->flags & _FP_ENTRY_INSTALLED)) {
   7465         /* Entry not installed in hardware to remove. */
   7466         return (BCM_E_NONE);
   7467     }
   7468 
   7469     /* Get number of entry parts using group flags. . */
   7470     BCM_IF_ERROR_RETURN(_bcm_field_th_entry_tcam_parts_count(unit,
   7471         lt_f_ent->group->flags, &parts_count));
   7472 
   7473     /* Iterate over entry parts and remove the entry from HW. */
   7474     for (part = 0; part < parts_count; part++) {
   7475         /* Get LT TCAM entry details from hardware. */
   7476         BCM_IF_ERROR_RETURN(_bcm_field_th_lt_tcam_entry_get(unit, lt_f_ent->group,
   7477             lt_f_ent + part));
   7478 
   7479         /* Given entry part number, get the entry TCAM index. */
   7480         BCM_IF_ERROR_RETURN(_field_th_lt_entry_tcam_idx_get(unit,
   7481             lt_f_ent + part, (lt_f_ent + part)->lt_fs, &tcam_idx));
   7482 
   7483         /* Clear the entry from hardware. */
   7484         BCM_IF_ERROR_RETURN(_field_lt_entry_tcam_remove(unit, lt_f_ent + part,
   7485             tcam_idx));
   7486 
   7487         lt_f_ent[part].flags |= _FP_ENTRY_DIRTY;
   7488         lt_f_ent[part].flags &= ~(_FP_ENTRY_INSTALLED);
   7489         lt_f_ent[part].flags &= ~(_FP_ENTRY_ENABLED);
   7490     }
   7491 
   7492     return (BCM_E_NONE);
   7493 }
   7494 
   7495 /*
   7496  * Function:
   7497  *     _field_th_lt_entry_default_rule_deinit
   7498  * Purpose:
   7499  *     Deinit logical table default rule from hardware.
   7500  * Parameters:
   7501  *     unit     - (IN) BCM device number.
   7502  *     stage_fc - (IN) Field stage control structure.
   7503  *     lt_f_ent - (IN) Logical table entry structure.
   7504  * Returns:
   7505  *     BCM_E_XXX
   7506  */
   7507 STATIC int
   7508 _field_th_lt_entry_default_rule_deinit(int unit, _field_stage_t *stage_fc,
   7509                                        _field_lt_entry_t *lt_f_ent)
   7510 {
   7511     int parts_count = 0; /* Entry parts count.               */
   7512     int part;            /* Entry part iterator.             */
   7513     _field_group_t *fg;  /* Field group structure pointer.   */
   7514 
   7515     /* Input parameters check. */
   7516     if ((NULL == stage_fc) || (NULL == lt_f_ent)) {
   7517         return (BCM_E_PARAM);
   7518     }
   7519 
   7520     /* Get field group structure pointer. */
   7521     fg = lt_f_ent->group;
   7522 
   7523     /* Get number of entry parts using group flags. */
   7524     BCM_IF_ERROR_RETURN(_bcm_field_th_entry_tcam_parts_count(unit, fg->flags,
   7525         &parts_count));
   7526 
   7527     /* Uninstall entry parts keygen program profile entries from hardware. */
   7528     for (part = 0; part < parts_count; part++) {
   7529         BCM_IF_ERROR_RETURN(soc_profile_mem_delete(unit,
   7530             &stage_fc->keygen_profile[fg->instance].profile,
   7531             fg->ext_codes[part].keygen_index));
   7532     }
   7533 
   7534     return (BCM_E_NONE);
   7535 }
   7536 
   7537 /*
   7538  * Function:
   7539  *     _field_th_ingress_selcodes_uninstall
   7540  * Purpose:
   7541  *     Uninstall group's key generation program from hardware.
   7542  * Parameters:
   7543  *     unit     - (IN) BCM device number.
   7544  *     stage_fc - (IN) Field stage control structure.
   7545  *     fg       - (IN) Field Group control structure.
   7546  * Returns:
   7547  *     BCM_E_XXX
   7548  */
   7549 STATIC int
   7550 _field_th_ingress_selcodes_uninstall(int unit, _field_stage_t *stage_fc,
   7551                                      _field_group_t *fg)
   7552 {
   7553     _field_control_t *fc;         /* Field Control Strucutre.  */
   7554 
   7555     /* Input parameters check. */
   7556     if ((NULL == fg) || (NULL == stage_fc)) {
   7557         return (BCM_E_PARAM);
   7558     }
   7559 
   7560     /* Field control get. */
   7561     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   7562 
   7563     if (fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) {
   7564        int                     part, parts_ct = 0;
   7565        int                     idx;
   7566        _field_presel_entry_t  *f_presel;
   7567 
   7568 
   7569        /* Get number of entry parts. */
   7570        BCM_IF_ERROR_RETURN(_bcm_field_th_lt_entry_tcam_parts_count(unit,
   7571                                     fg->stage_id, fg->flags, &parts_ct));
   7572 
   7573        /*
   7574         * Detach Presel Entries from the LT slice associated with the group
   7575         */
   7576        for (idx = 0; idx < _FP_PRESEL_ENTRIES_MAX_PER_GROUP; idx++) {
   7577            if (fg->presel_ent_arr[idx] != NULL) {
   7578               f_presel = fg->presel_ent_arr[idx];
   7579            } else {
   7580               continue;
   7581            }
   7582 
   7583            /* Uninstall entry parts keygen program profile
   7584             * entries from hardware. */
   7585            if (fg->stage_id != _BCM_FIELD_STAGE_FLOWTRACKER) {
   7586                for (part = 0; part < parts_ct; part++) {
   7587                    BCM_IF_ERROR_RETURN(soc_profile_mem_delete(unit,
   7588                                &stage_fc->keygen_profile[fg->instance].profile,
   7589                                fg->ext_codes[part].keygen_index));
   7590                }
   7591            }
   7592 
   7593            /* Remove Presel entries from hardware. */
   7594            BCM_IF_ERROR_RETURN(_bcm_field_th_presel_entry_hw_remove
   7595                                                    (unit, f_presel));
   7596 
   7597            /* Destroy resources allocated for the entry. */
   7598            BCM_IF_ERROR_RETURN(_bcm_field_th_lt_entry_phys_destroy
   7599                                                    (unit, f_presel));
   7600        }
   7601     } else {
   7602        _field_lt_entry_t *lt_f_ent; /* LT field entry structure pointer.  */
   7603        bcm_field_entry_t lt_entry;  /* LT selection Entry ID.             */
   7604 
   7605         /* Get Entry ID Group's LT information structure. */
   7606        if (stage_fc->oper_mode == bcmFieldGroupOperModeGlobal) {
   7607            lt_entry = fc->lt_info[0][fg->lt_id]->lt_entry;
   7608        } else {
   7609            lt_entry = fc->lt_info[fg->instance][fg->lt_id]->lt_entry;
   7610        }
   7611 
   7612        /* Get entry LT entry structure pointer. */
   7613        BCM_IF_ERROR_RETURN(_field_th_lt_entry_get(unit, lt_entry,
   7614                            _FP_ENTRY_PRIMARY, &lt_f_ent));
   7615 
   7616        /* Remove LT entry from hardware. */
   7617        BCM_IF_ERROR_RETURN(_field_th_lt_default_entry_remove(unit, lt_entry));
   7618 
   7619        /* Delete keygen profiles used by the group. */
   7620        BCM_IF_ERROR_RETURN(_field_th_lt_entry_default_rule_deinit(unit,
   7621                                                      stage_fc, lt_f_ent));
   7622 
   7623        /* Destroy resources allocated for the entry. */
   7624        BCM_IF_ERROR_RETURN(_field_th_lt_default_entry_phys_destroy(
   7625                                                      unit, lt_f_ent));
   7626     }
   7627     return (BCM_E_NONE);
   7628 }
   7629 
   7630 /*
   7631  * Function:
   7632  *    _field_th_ingress_group_uninstall
   7633  * Purpose:
   7634  *     Uninstall group from all slices.
   7635  *
   7636  * Parameters:
   7637  *     unit     - (IN) BCM device number.
   7638  *     stage_fc - (IN) Field stage control structure.
   7639  *     fg       - (IN) Field group.
   7640  *
   7641  * Returns:
   7642  *     BCM_E_XXX
   7643  */
   7644 STATIC int
   7645 _field_th_ingress_group_uninstall(int unit, _field_stage_t *stage_fc,
   7646                                   _field_group_t *fg)
   7647 {
   7648     _field_control_t *fc;       /* Field control structure.     */
   7649     _field_slice_t *fs;         /* Field slice structure.       */
   7650     _field_slice_t *temp_fs;    /* Expanded slices iterator.    */
   7651     int parts_count = 0;        /* Number of entry parts.       */
   7652     uint16 group_count = 0;     /* Number of groups.            */
   7653     uint8 slice_number;         /* Slice iterator.              */
   7654     uint8 slice_reset = 0;      /* Slice reset flg.             */
   7655     int idx;                    /* Slice iterator.              */
   7656 
   7657     /* Input parameters check. */
   7658     if (NULL == fg) {
   7659         return (BCM_E_PARAM);
   7660     }
   7661     /* Get Field Control structure pointer. */
   7662     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   7663 
   7664     /*
   7665      * Uninstall TCAM keygen program configuration from hardware for each
   7666      * slice.
   7667      */
   7668     BCM_IF_ERROR_RETURN(_field_th_ingress_selcodes_uninstall(unit, stage_fc,
   7669         fg));
   7670 
   7671 #if defined(BCM_FLOWTRACKER_SUPPORT)
   7672     /* clear keytype bit */
   7673     BCM_IF_ERROR_RETURN(_field_hx5_ft_group_keytype_clear(unit, stage_fc, fg));
   7674     if (stage_fc->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER) {
   7675         return (BCM_E_NONE);
   7676     }
   7677 #endif
   7678 
   7679     if (fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) {
   7680         (void)_bcm_field_group_count_get(unit, fg->instance,
   7681                                          stage_fc,
   7682                                          fg->priority,
   7683                                          _FP_GROUP_SPAN_MASK,
   7684                                          &group_count);
   7685         if (group_count <= 1) {
   7686             slice_reset = 1;
   7687         }
   7688     } else {
   7689         slice_reset = 1;
   7690     }
   7691 
   7692     LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   7693        "SLICE CLEAR: Gid:%d prio:%d count:%d slice_num:%d mode:0x%x slice_reset:%d \n\r"),
   7694        fg->gid, fg->priority, group_count, fg->slices->slice_number,
   7695        (fg->flags & _FP_GROUP_SPAN_MASK), slice_reset));
   7696 
   7697     /* Get number of entry parts. */
   7698     BCM_IF_ERROR_RETURN(_bcm_field_th_entry_tcam_parts_count(unit, fg->flags,
   7699         &parts_count));
   7700 
   7701     /*
   7702      * Parse through the Group parts to clear
   7703      * LT partition priority and slices.
   7704      */
   7705     for (idx = parts_count - 1; idx >= 0; idx--) {
   7706         /* Get Slice ID from TCAM entry part number. */
   7707         BCM_IF_ERROR_RETURN(_bcm_field_th_tcam_part_to_slice_number(idx,
   7708             fg->flags, &slice_number));
   7709 
   7710         fs = fg->slices + slice_number;
   7711 
   7712         if (slice_reset == 1) {
   7713            /* Clear slice mode in hardware and reset to HW default. */
   7714            BCM_IF_ERROR_RETURN(_field_th_ingress_slice_mode_set(unit, stage_fc,
   7715                                fs->slice_number, fg, 1));
   7716         }
   7717 
   7718         while (NULL != fs) {
   7719             temp_fs = fs->next;
   7720             /* Reset the LT partition priority for the slice. */
   7721             BCM_IF_ERROR_RETURN(_bcm_field_th_lt_part_prio_reset(unit,
   7722                                                    stage_fc, fg, fs));
   7723             if (slice_reset == 1) {
   7724                 /* Clear slice if in-use by the group alone. */
   7725                 BCM_IF_ERROR_RETURN(_field_th_ingress_slice_clear(unit, fg, fs));
   7726                 fs->prev = NULL;
   7727                 fs->next = NULL;
   7728             }
   7729 
   7730             fs = temp_fs;
   7731         }
   7732     }
   7733 
   7734     /*  Free LT_ID association with this group. */
   7735     BCM_IF_ERROR_RETURN(_field_th_group_ltmap_delete(unit, fg));
   7736 
   7737     /* Install LT Action Priority. */
   7738     BCM_IF_ERROR_RETURN(_bcm_field_th_ingress_lt_action_prio_install(unit,
   7739                                                            stage_fc, fg));
   7740     return (BCM_E_NONE);
   7741 }
   7742 
   7743 /*
   7744  * Function:
   7745  *    _bcm_field_th_group_lt_prio_update
   7746  * Purpose:
   7747  *    Update a group's logical table action priority value.
   7748  * Parameters:
   7749  *     unit     - (IN) BCM device number.
   7750  *     fg       - (IN) Field group.
   7751  *     priority - (IN) New field group priority value.
   7752  *
   7753  * Returns:
   7754  *     BCM_E_XXX
   7755  */
   7756 int
   7757 _bcm_field_th_group_lt_prio_update(int unit, _field_group_t *fg,
   7758                                    int priority)
   7759 {
   7760     _field_stage_t *stage_fc;   /* Field stage control.         */
   7761     int lt_id;                  /* Logical Table Identifier.    */
   7762     _field_group_t     *fg_ptr = NULL;
   7763     _field_control_t *fc;       /* Field control structure.     */
   7764 
   7765     /* Input parameters check. */
   7766     if (NULL == fg) {
   7767         return (BCM_E_PARAM);
   7768     }
   7769 
   7770     /* Return success if there is no change in group's priority value. */
   7771     if (fg->priority == priority) {
   7772         return (BCM_E_NONE);
   7773     }
   7774 
   7775     /* Get stage control structure. */
   7776     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fg->stage_id,
   7777         &stage_fc));
   7778 
   7779     /* Get field control structure. */
   7780     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   7781 
   7782     if (fg->slices == NULL) {
   7783         return BCM_E_INTERNAL;
   7784     }
   7785 
   7786     do {
   7787         /* Retrieve the existing groups associated with the Slice */
   7788         (void)_bcm_field_slice_group_get_next(unit, fg->instance,
   7789                                                  fg->stage_id,
   7790                                                  fg->slices->slice_number,
   7791                                                  &fg_ptr, &fg_ptr);
   7792         if ((fg_ptr != NULL) && (fg_ptr != fg)) {
   7793            if (!((soc_feature(unit,
   7794                soc_feature_sw_mmu_flush_rqe_operation))
   7795                && (fg_ptr->gid == _FP_INTERNAL_RESERVED_EM_ID))) {
   7796                LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   7797                     "Error: Can not set the priority, group's Slice has more"
   7798                     " than one group.\n\r")));
   7799                return BCM_E_CONFIG;
   7800            }
   7801         }
   7802     } while(fg_ptr != NULL);
   7803 
   7804     /* For exact match stage group priority cannot change
   7805      * even if group exist with same priority but in different
   7806      * slice.
   7807      */
   7808     if (fg->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   7809         do {
   7810             /* Retrieve the existing groups associated with the priority */
   7811             (void)_bcm_field_th_priority_group_get_next(unit, fg->instance,
   7812                                                         fg->stage_id,
   7813                                                         priority,
   7814                                                         &fg_ptr, &fg_ptr);
   7815             if ((fg_ptr != NULL) && (fg_ptr != fg)) {
   7816                 if (!((soc_feature(unit,
   7817                     soc_feature_sw_mmu_flush_rqe_operation))
   7818                     && (fg_ptr->gid == _FP_INTERNAL_RESERVED_EM_ID))) {
   7819                     LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   7820                               "Error: Can not set the priority, exact match"
   7821                               " group(%d) has same priority.\n\r"),
   7822                               fg_ptr->gid));
   7823                     return BCM_E_CONFIG;
   7824                 }
   7825             }
   7826         } while(fg_ptr != NULL);
   7827     }
   7828 
   7829     /* Get current Logical Table ID value assigned to the Group. */
   7830     lt_id = fg->lt_id;
   7831 
   7832     /* Update group's priority value. */
   7833     fg->priority = priority;
   7834 
   7835     /* Allocate LT action priority. */
   7836     BCM_IF_ERROR_RETURN(_field_th_lt_priority_alloc(unit, stage_fc, fg,
   7837         lt_id));
   7838 
   7839     /* Update priority value in Group's logical table information structure. */
   7840     fc->lt_info[fg->instance][lt_id]->priority = fg->priority;
   7841 
   7842     /* Install LT part mapping to hardware. */
   7843     BCM_IF_ERROR_RETURN(_bcm_field_th_ingress_logical_table_map_write(unit,
   7844                                                              stage_fc, fg));
   7845 
   7846     return (BCM_E_NONE);
   7847 }
   7848 
   7849 /*
   7850  * Function:
   7851  *    _bcm_field_th_group_deinit
   7852  * Purpose:
   7853  *    Destroy field group structure.
   7854  * Parameters:
   7855  *     unit   - (IN) BCM device number.
   7856  *     fg     - (IN) Allocated group structure.
   7857  *
   7858  * Returns:
   7859  *     BCM_E_NONE      - Success
   7860  */
   7861 int
   7862 _bcm_field_th_group_deinit(int unit, _field_group_t *fg)
   7863 {
   7864     int rv = BCM_E_NONE;        /* OPerational status. */
   7865     _field_control_t *fc;       /* Field control structure.       */
   7866     int idx;                    /* Qualifiers iteration index.    */
   7867     _field_stage_t *stage_fc;   /* Stage field control structure. */
   7868 
   7869     /* Nothing to do as group is already uninstalled. */
   7870     if (NULL == fg) {
   7871         return (BCM_E_NONE);
   7872     }
   7873 
   7874     /* Get Field Control structure. */
   7875     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   7876 
   7877     /* Get device stage control structure. */
   7878     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, fg->stage_id,
   7879         &stage_fc));
   7880 
   7881     /* Uninstall group from every slice. */
   7882     if (NULL != fg->slices) {
   7883         _field_th_ingress_group_uninstall(unit, stage_fc, fg);
   7884     }
   7885 
   7886     /* Deallocate group qualifiers list. */
   7887     for (idx = 0; idx < _FP_MAX_ENTRY_WIDTH; idx++) {
   7888         /* If qualifier set was updated, free original qualifiers arrary. */
   7889         BCM_IF_ERROR_RETURN(_bcm_field_group_qualifiers_free(fg, idx));
   7890     }
   7891 
   7892     /* Decrement the use counts for any UDFs used by the group */
   7893     for (idx = 0; idx < BCM_FIELD_USER_NUM_UDFS; idx++) {
   7894         if (SHR_BITGET(fg->qset.udf_map, idx))  {
   7895             if (fc->udf[idx].use_count > 0) {
   7896                 fc->udf[idx].use_count--;
   7897             }
   7898         }
   7899     }
   7900 
   7901     /* Deallocate group entry array if any. */
   7902     if (NULL != fg->entry_arr) {
   7903         sal_free(fg->entry_arr);
   7904     }
   7905 
   7906     /* Deallocate group LT entry array if any. */
   7907     if (NULL != fg->lt_entry_arr) {
   7908         sal_free(fg->lt_entry_arr);
   7909     }
   7910     /* Free Flowtracker stage extractor codes. */
   7911 #if defined(BCM_FLOWTRACKER_SUPPORT)
   7912     if (NULL != fg->ft_ext_codes) {
   7913         sal_free(fg->ft_ext_codes);
   7914     }
   7915 #endif
   7916     /* Deallocte the action profile index allocated for group */
   7917     if (_BCM_FIELD_STAGE_INGRESS == fg->stage_id ||
   7918         _BCM_FIELD_STAGE_EXACTMATCH ==  fg->stage_id) {
   7919         for (idx =0; idx < MAX_ACT_PROF_ENTRIES_PER_GROUP;idx++) {
   7920             if (-1 != fg->action_profile_idx[idx]) {
   7921                 rv = soc_profile_mem_delete(unit,
   7922                                  &stage_fc->action_profile[fg->instance],
   7923                                  fg->action_profile_idx[idx]);
   7924                 BCM_IF_ERROR_RETURN(rv);
   7925             }
   7926         }
   7927     }
   7928 
   7929     rv = _bcm_field_group_stat_destroy(unit, fg->gid);
   7930     BCM_IF_ERROR_RETURN(rv);
   7931 
   7932     /* Remove group from unit's group list. */
   7933     BCM_IF_ERROR_RETURN(_bcm_field_group_linked_list_remove(unit, fg));
   7934 
   7935     /* Decrement Hint count if any. */
   7936     BCM_IF_ERROR_RETURN(
   7937             _bcm_field_hints_group_count_update (unit, fg->hintid, 0));
   7938 
   7939 
   7940 #if defined (BCM_TRIDENT3_SUPPORT)
   7941     if (soc_feature(unit, soc_feature_td3_style_fp)) {
   7942         if (BCM_FIELD_QSET_TEST(fg->qset, bcmFieldQualifyIncomingOuterVlanId)) {
   7943             bcm_field_qualify_t qual = bcmFieldQualifyIncomingOuterVlanId;
   7944 
   7945             rv = _bcm_field_td3_field_bus_cont_sel_remove(unit, fg->instance,
   7946                                                           stage_fc, fg, qual);
   7947             BCM_IF_ERROR_RETURN(rv);
   7948         }
   7949     }
   7950 #endif /* BCM_TRIDENT3_SUPPORT */
   7951 
   7952     /* Deallocate group memory. */
   7953     sal_free(fg);
   7954 
   7955     return (BCM_E_NONE);
   7956 }
   7957 
   7958 /*
   7959  * Function:
   7960  *     _field_th_group_add_end
   7961  * Purpose:
   7962  *     Group add state machine last/clean up state.
   7963  * Parameters:
   7964  *     unit     - (IN)     BCM device number.
   7965  *     fsm_ptr  - (IN/OUT) State machine tracking structure.
   7966  * Returns:
   7967  *     BCM_E_XXX
   7968  */
   7969 STATIC int
   7970 _field_th_group_add_end(int unit, _field_group_add_fsm_t *fsm_ptr)
   7971 {
   7972     /* Input parameters check. */
   7973     if (NULL == fsm_ptr) {
   7974         return (BCM_E_PARAM);
   7975     }
   7976 
   7977     /*
   7978      * Clear slice size selection group flags.
   7979      * These internal flags are valid only at the time of group creation.
   7980      * These flags are need not be intersted post group creation.
   7981      * Anyways for Autoexpansion, Autoexpansion hint has to be used
   7982      * for respective group sizes.
   7983      */
   7984     if (fsm_ptr->flags & _BCM_FP_GROUP_ADD_SMALL_SLICE) {
   7985         fsm_ptr->fg->flags &= ~_FP_GROUP_SELECT_SMALL_SLICE;
   7986     } else if (fsm_ptr->flags & _BCM_FP_GROUP_ADD_LARGE_SLICE) {
   7987         fsm_ptr->fg->flags &= ~_FP_GROUP_SELECT_LARGE_SLICE;
   7988     }
   7989 
   7990     /* Deallocate Field Group memory on failure. */
   7991     if (fsm_ptr->stage_fc != NULL) {
   7992         if (fsm_ptr->stage_fc->stage_id == _BCM_FIELD_STAGE_INGRESS) {
   7993 
   7994             if (BCM_FAILURE(fsm_ptr->rv)) {
   7995                 _bcm_field_th_group_deinit(unit, fsm_ptr->fg);
   7996             }
   7997             else if (!soc_feature(unit, soc_feature_ifp_action_profiling)) {
   7998                 if (BCM_FAILURE(fsm_ptr->rv =
   7999                     _field_group_default_aset_set(unit, fsm_ptr->fg))) {
   8000                     _bcm_field_th_group_deinit(unit, fsm_ptr->fg);
   8001                 }
   8002             }
   8003         } else if ((fsm_ptr->stage_fc->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) ||
   8004                 (fsm_ptr->stage_fc->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER)) {
   8005             if (BCM_FAILURE(fsm_ptr->rv)) {
   8006                 _bcm_field_th_group_deinit(unit, fsm_ptr->fg);
   8007             }
   8008         } else {
   8009             return (BCM_E_PARAM);
   8010         }
   8011     } else {
   8012         if (BCM_FAILURE(fsm_ptr->rv)) {
   8013             _bcm_field_th_group_deinit(unit, fsm_ptr->fg);
   8014         }
   8015     }
   8016 
   8017     return (fsm_ptr->rv);
   8018 }
   8019 
   8020 /*
   8021  * Function:
   8022  *    _field_th_group_add_adjust_lt_map
   8023  * Purpose:
   8024  *    Update slices logical table mapping and priority in hardware.
   8025  * Parameters:
   8026  *    unit     - (IN)     BCM device number.
   8027  *    fsm_ptr  - (IN/OUT) State machine tracking structure.
   8028  * Returns:
   8029  *    BCM_E_XXX
   8030  */
   8031 STATIC int
   8032 _field_th_group_add_adjust_lt_map(int unit, _field_group_add_fsm_t *fsm_ptr)
   8033 {
   8034     /* Input parameter check. */
   8035     if (NULL == fsm_ptr) {
   8036         return (BCM_E_PARAM);
   8037     }
   8038 
   8039     /* Set current state to be the previous state. */
   8040     fsm_ptr->fsm_state_prev = fsm_ptr->fsm_state;
   8041 
   8042     /* Install LT part mapping to hardware. */
   8043     fsm_ptr->rv = _bcm_field_th_ingress_logical_table_map_write(unit,
   8044                                       fsm_ptr->stage_fc, fsm_ptr->fg);
   8045 
   8046     fsm_ptr->fsm_state = _BCM_FP_GROUP_ADD_STATE_END;
   8047 
   8048     return (BCM_E_NONE);
   8049 }
   8050 
   8051 /*
   8052  * Function:
   8053  *    _field_th_group_add
   8054  * Purpose:
   8055  *    Create a field processor group
   8056  * Parameters:
   8057  *    unit      - (IN)     BCM device number.
   8058  *    fsm_ptr   - (IN/OUT) State machine tracking structure.
   8059  * Returns:
   8060  *    BCM_E_PARAM       - Null state machine structure pointer.
   8061  *    BCM_E_UNAVAIL     - Unsupported group create option specified.
   8062  *    BCM_E_RESOURCE    - Requested HW resources unavailable
   8063  *                        or Specified QSET cannot be accomodated with available
   8064  *                        hardware resources.
   8065  *    BCM_E_MEMORY      - Memory allocation failure.
   8066  *    BCM_E_NONE        - Success.
   8067  */
   8068 STATIC int
   8069 _field_th_group_add(int unit, _field_group_add_fsm_t *fsm_ptr)
   8070 {
   8071     int rv = BCM_E_INTERNAL; /* Operation return status. */
   8072 
   8073     /* Input parameters check. */
   8074     if (NULL == fsm_ptr) {
   8075         return (BCM_E_PARAM);
   8076     }
   8077 
   8078     do
   8079     {
   8080         switch (fsm_ptr->fsm_state) {
   8081             case _BCM_FP_GROUP_ADD_STATE_START:
   8082                 rv = _field_th_group_add_initialize(unit, fsm_ptr);
   8083                 LOG_DEBUG(BSL_LS_BCM_FP,
   8084                           (BSL_META_U(unit,
   8085                           "Completed state->"
   8086                           "_BCM_FP_GROUP_ADD_STATE_START\r\n")));
   8087                 break;
   8088             case _BCM_FP_GROUP_ADD_STATE_ALLOC:
   8089                 rv = _field_th_group_add_alloc(unit, fsm_ptr);
   8090                 LOG_DEBUG(BSL_LS_BCM_FP,
   8091                           (BSL_META_U(unit,
   8092                           "Completed state->"
   8093                           "_BCM_FP_GROUP_ADD_STATE_ALLOC\r\n")));
   8094                 break;
   8095             case _BCM_FP_GROUP_ADD_STATE_QSET_UPDATE:
   8096                 rv = _field_th_group_add_qset_update(unit, fsm_ptr);
   8097                 LOG_DEBUG(BSL_LS_BCM_FP,
   8098                           (BSL_META_U(unit,
   8099                           "Completed state->"
   8100                           "_BCM_FP_GROUP_ADD_STATE_QSET_UPDATE\r\n")));
   8101                 break;
   8102             case _BCM_FP_GROUP_ADD_STATE_ASET_VALIDATE:
   8103                 rv = _field_th_group_add_aset_validate(unit, fsm_ptr);
   8104                     break;
   8105                 LOG_DEBUG(BSL_LS_BCM_FP,
   8106                           (BSL_META_U(unit,
   8107                           "Completed state->"
   8108                           "_BCM_FP_GROUP_ADD_STATE_ASET_VALIDATE\r\n")));
   8109                 break;
   8110 
   8111             case _BCM_FP_GROUP_ADD_STATE_SEL_CODES_GET:
   8112                 rv = _field_th_group_add_extractor_codes_get(unit, fsm_ptr);
   8113                 LOG_DEBUG(BSL_LS_BCM_FP,
   8114                           (BSL_META_U(unit,
   8115                           "Completed state->"
   8116                           "_BCM_FP_GROUP_ADD_STATE_SEL_CODES_GET\r\n")));
   8117                 break;
   8118             case _BCM_FP_GROUP_ADD_STATE_QSET_ALTERNATE:
   8119                 rv = _field_th_group_add_qset_alternate(unit, fsm_ptr);
   8120                 LOG_DEBUG(BSL_LS_BCM_FP,
   8121                           (BSL_META_U(unit,
   8122                           "Completed state->"
   8123                           "_BCM_FP_GROUP_ADD_STATE_QSET_ALTERNATE\r\n")));
   8124                 break;
   8125             case _BCM_FP_GROUP_ADD_STATE_SLICE_ALLOCATE:
   8126                 rv = _field_th_group_add_slice_allocate(unit, fsm_ptr);
   8127                 LOG_DEBUG(BSL_LS_BCM_FP,
   8128                           (BSL_META_U(unit,
   8129                           "Completed state->"
   8130                           "_BCM_FP_GROUP_ADD_STATE_SLICE_ALLOCATE\r\n")));
   8131                 break;
   8132             case _BCM_FP_GROUP_ADD_STATE_CAM_COMPRESS:
   8133                 rv = _field_th_group_add_cam_compress(unit, fsm_ptr);
   8134                 LOG_DEBUG(BSL_LS_BCM_FP,
   8135                           (BSL_META_U(unit,
   8136                           "Completed state->"
   8137                           "_BCM_FP_GROUP_ADD_STATE_CAM_COMPRESS\r\n")));
   8138                 break;
   8139             case _BCM_FP_GROUP_ADD_STATE_ADJUST_VIRTUAL_MAP:
   8140                 rv = _field_th_group_add_adjust_lt_map(unit, fsm_ptr);
   8141                 LOG_DEBUG(BSL_LS_BCM_FP,
   8142                           (BSL_META_U(unit,
   8143                           "Completed state->"
   8144                           "_BCM_FP_GROUP_ADD_STATE_ADJUST_VIRTUAL_MAP\r\n")));
   8145                 break;
   8146             case _BCM_FP_GROUP_ADD_STATE_END:
   8147                 rv = _field_th_group_add_end(unit, fsm_ptr);
   8148                 LOG_DEBUG(BSL_LS_BCM_FP,
   8149                           (BSL_META_U(unit,
   8150                           "Completed state->"
   8151                           "_BCM_FP_GROUP_ADD_STATE_END\r\n")));
   8152                 return rv;
   8153                 break;
   8154             default:
   8155                 /* Not a valid switch-case option. */
   8156                 return rv;
   8157         }
   8158     } while(1);
   8159 
   8160     return (rv);
   8161 }
   8162 
   8163 /*
   8164  * Function:
   8165  *    _bcm_field_th_group_add
   8166  * Purpose:
   8167  *    Create a field processor group
   8168  * Parameters:
   8169  *    unit  - (IN)     BCM device number.
   8170  *    flags - (IN)     Input flags.
   8171  *    gc    - (IN/OUT) Group configuration structure pointer.
   8172  * Returns:
   8173  *    BCM_E_PARAM - Null group configuration structure pointer.
   8174  *    BCM_E_UNAVAIL - Unsupported group create option specified.
   8175  *    BCM_E_RESOURCE - Requested HW resources unavailable
   8176  *                     or Specified QSET cannot be accomodated with available
   8177  *                     hardware resources.
   8178  *    BCM_E_MEMORY - Memory allocation failure.
   8179  *    BCM_E_NONE - Success.
   8180  */
   8181 int
   8182 _bcm_field_th_group_add(int unit, uint32 flags,
   8183                         bcm_field_group_config_t *gc)
   8184 {
   8185     int                    rv = BCM_E_INTERNAL; /* Operation return status. */
   8186     _field_stage_id_t      stage;    /* FP stage information. */
   8187     _field_group_add_fsm_t fsm;      /* Group creation state machine.    */
   8188     _field_control_t       *fc;
   8189     _field_hints_t         *f_ht = NULL;
   8190                                      /* Field hints Structure. */
   8191     _field_hint_t          *hint_list = NULL;
   8192                                      /* Field Hints Structure. */
   8193     bcm_field_hint_t       *hint_entry;
   8194                                      /* Hint Entry.            */
   8195     bcm_pbmp_t             all_pbmp;   /* Group port bitmap.           */
   8196 
   8197     /* Input parameter check. */
   8198     if (NULL == gc) {
   8199         return (BCM_E_PARAM);
   8200     }
   8201 
   8202     /* Get unit FP control structure. */
   8203     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   8204 
   8205     /*
   8206      * Check and return error when SMALL or LARGE slice request flag is set
   8207      * for TH device.
   8208      */
   8209     if ((0 == soc_feature(unit, soc_feature_field_ingress_two_slice_types))
   8210         && (gc->flags & BCM_FIELD_GROUP_CREATE_SMALL
   8211             || gc->flags & BCM_FIELD_GROUP_CREATE_LARGE)) {
   8212         return (BCM_E_UNAVAIL);
   8213     }
   8214 
   8215 
   8216     /* Get the FP stage in which new group must be created. */
   8217     BCM_IF_ERROR_RETURN(_bcm_field_group_stage_get(unit, &gc->qset, &stage));
   8218     BCM_IF_ERROR_RETURN(_bcm_field_group_stage_validate(unit, stage));
   8219 
   8220     if (!(gc->flags & BCM_FIELD_GROUP_CREATE_WITH_ID)) {
   8221         /* qset and pri are validated in bcm_field_group_create_mode_id(). */
   8222         BCM_IF_ERROR_RETURN(_bcm_field_group_id_generate(unit, &gc->group));
   8223     }
   8224 
   8225     if (soc_property_get(unit, spn_FLOWTRACKER_ENABLE, 0) == 1) {
   8226     /*
   8227      * Return BCM_E_UNAVAIL if soc property FLOWTRACKER_ENABLE is enabled and
   8228      * As flow tracker creates ExactMatch group during
   8229      * their initialization and User doesn't have provision to create groups under ExactMatch stage.
   8230      */
   8231         if ((_BCM_FIELD_STAGE_EXACTMATCH == stage) &&
   8232             (0 == (flags & _FP_GROUP_CONFIG_FLOWTRACKER_SPECIFIC))) {
   8233             LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   8234                             "Error: ExactMatch Field stage is dedicated to Flowtracker module.\n\r")));
   8235             return BCM_E_UNAVAIL;
   8236         }
   8237 
   8238         if ((flags & _FP_GROUP_CONFIG_FLOWTRACKER_SPECIFIC) &&
   8239              (_BCM_FIELD_STAGE_EXACTMATCH != stage)){
   8240             /* FLOWTRACKER SPECIFIC flag should be used for EXACTMATCH Stage only */
   8241             return BCM_E_PARAM;
   8242         }
   8243 
   8244         /* Check to Restrict EM for internal use */
   8245         if (((_FP_FLOWTRACKER_RESERVED_EM_GID_AFTER_SHIFT) ==
   8246              ((uint32)gc->group >> (_FP_FLOWTRACKER_RESERVED_EM_GID_SHIFT_VAL))) &&
   8247              (0 == (flags & _FP_GROUP_CONFIG_FLOWTRACKER_SPECIFIC))) {
   8248             LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   8249                             "Error: Field Group Id : %d is internally reserved for Flowtracker module.\n\r"),
   8250                             gc->group));
   8251             return BCM_E_UNAVAIL;
   8252         }
   8253 
   8254         /* Validation check for flowtracker module to use only reserved _FP_FLOWTRACKER_RESERVED_EM_GID_* GIDs  */
   8255         if (((_FP_FLOWTRACKER_RESERVED_EM_GID_AFTER_SHIFT) !=
   8256              ((uint32)gc->group >> (_FP_FLOWTRACKER_RESERVED_EM_GID_SHIFT_VAL))) &&
   8257              (flags & _FP_GROUP_CONFIG_FLOWTRACKER_SPECIFIC)) {
   8258             LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   8259                             "Error: Field Group Id : %d is not reserved for Flowtracker module. \n\r"),
   8260                             gc->group));
   8261             return BCM_E_CONFIG;
   8262         }
   8263     } else {
   8264         if (flags & _FP_GROUP_CONFIG_FLOWTRACKER_SPECIFIC) {
   8265             /* FLOWTRACKER SPECIFIC flag should be used only if soc property FLOWTRACKER_ENABLE is enabled */
   8266             return BCM_E_PARAM;
   8267         }
   8268     }
   8269 
   8270     /* Read device port configuration. */ 
   8271     BCM_PBMP_CLEAR(all_pbmp);
   8272     BCM_IF_ERROR_RETURN(_bcm_field_valid_pbmp_get(unit, &all_pbmp));
   8273 
   8274     /* Initialize group creation tracking structure. */
   8275     sal_memset(&fsm, 0, sizeof(_field_group_add_fsm_t));
   8276 
   8277     /* Initialize group creation tracking structure. */
   8278     fsm.fsm_state = _BCM_FP_GROUP_ADD_STATE_START;
   8279     fsm.priority = gc->priority;
   8280     fsm.group_id = gc->group;
   8281     fsm.qset = gc->qset;
   8282     fsm.aset = gc->aset;
   8283     fsm.rv = BCM_E_NONE;
   8284     fsm.action_res_id = gc->action_res_id;
   8285     fsm.hintid = gc->hintid;
   8286 
   8287     /* Apply slice selection configuration */
   8288     if (gc->flags & BCM_FIELD_GROUP_CREATE_SMALL) {
   8289         fsm.flags |= _BCM_FP_GROUP_ADD_SMALL_SLICE;
   8290     } else if (gc->flags & BCM_FIELD_GROUP_CREATE_LARGE) {
   8291         fsm.flags |= _BCM_FP_GROUP_ADD_LARGE_SLICE;
   8292     }
   8293 
   8294     if (fsm.hintid != 0) {
   8295         if (fsm.hintid >= _FP_HINT_ID_MAX) {
   8296             LOG_DEBUG(BSL_LS_BCM_FP,
   8297                     (BSL_META_U(unit, "HintId is out of allowed range\r\n")));
   8298             rv = BCM_E_PARAM;
   8299             return (rv);
   8300         }
   8301         if (_FP_HINTID_BMP_TEST(fc->hintid_bmp, fsm.hintid) == 0) {
   8302             LOG_DEBUG(BSL_LS_BCM_FP,
   8303                     (BSL_META_U(unit, "Trying to attach hintid which is"
   8304                                 " not created.\r\n")));
   8305             rv = BCM_E_NOT_FOUND;
   8306             return (rv);
   8307         }
   8308         if ((BCM_FIELD_QSET_TEST(fsm.qset, bcmFieldQualifyStageExternal)) ||
   8309             (BCM_FIELD_QSET_TEST(fsm.qset, bcmFieldQualifyStageClass)) ||
   8310             (BCM_FIELD_QSET_TEST(fsm.qset, bcmFieldQualifyStageClassExactMatch))) {
   8311 
   8312             LOG_DEBUG(BSL_LS_BCM_FP,
   8313                (BSL_META_U(unit,"Unsupported hint type attached"
   8314                                      "to hintid(%d).\r\n"),
   8315                                       gc->hintid));
   8316              rv = BCM_E_PARAM;
   8317              return (rv);
   8318         }
   8319 
   8320         BCM_IF_ERROR_RETURN(_field_hints_control_get (unit, gc->hintid, &f_ht));
   8321         if (f_ht == NULL) {
   8322             LOG_DEBUG(BSL_LS_BCM_FP,
   8323                     (BSL_META_U(unit,"Hints are not attached to hintid(%d)."
   8324                                 "\r\n"),
   8325                                 gc->hintid));
   8326             rv = BCM_E_NOT_FOUND;
   8327             return (rv);
   8328         }
   8329 
   8330         hint_list = f_ht->hints;
   8331         while (hint_list != NULL) {
   8332             hint_entry = hint_list->hint;
   8333             if (hint_entry != NULL) {
   8334                 /* hint type _field_hints_control_get is not supported for any stage */
   8335                 if (hint_entry->hint_type ==
   8336                                  bcmFieldHintTypeCompression) {
   8337                     LOG_DEBUG(BSL_LS_BCM_FP,
   8338                        (BSL_META_U(unit,"Unsupported hint type attached"
   8339                                              "to hintid(%d).\r\n"),
   8340                                               gc->hintid));
   8341                     rv = BCM_E_PARAM;
   8342                     return (rv);
   8343                 }
   8344 
   8345                 if (!soc_feature(unit, soc_feature_field_ingress_two_slice_types)) {
   8346                     /*
   8347                      * For Ingress state, hint type auto expansion is
   8348                      * supported only for flags BCM_FIELD_GROUP_MAX_SIZE_HARD_LIMIT
   8349                      */
   8350                     if((BCM_FIELD_QSET_TEST(fsm.qset,
   8351                                     bcmFieldQualifyStageIngress)) &&
   8352                             (hint_entry->hint_type ==
   8353                              bcmFieldHintTypeGroupAutoExpansion)) {
   8354 
   8355                         if(hint_entry->flags != BCM_FIELD_GROUP_MAX_SIZE_HARD_LIMIT) {
   8356                             LOG_DEBUG(BSL_LS_BCM_FP,
   8357                                     (BSL_META_U(unit,"Unsupported hint type attached"
   8358                                                 "to hintid(%d).\r\n"),
   8359                                      gc->hintid));
   8360                             rv = BCM_E_PARAM;
   8361                             return (rv);
   8362                         }
   8363                     }
   8364                 }
   8365                 /* for egress and lookup stages, only the hint type
   8366                  * bcmFieldHintTypeGroupAutoExpansion along with flag
   8367                  * BCM_FIELD_GROUP_MAX_SIZE_HARD_LIMIT is supported
   8368                  */
   8369 
   8370                 if ((BCM_FIELD_QSET_TEST(fsm.qset, bcmFieldQualifyStageEgress)) ||
   8371                     (BCM_FIELD_QSET_TEST(fsm.qset, bcmFieldQualifyStageLookup))) {
   8372 
   8373                     if(!( (hint_entry->hint_type ==
   8374                               bcmFieldHintTypeGroupAutoExpansion) &&
   8375                           (hint_entry->flags == BCM_FIELD_GROUP_MAX_SIZE_HARD_LIMIT) ) ) {
   8376                         LOG_DEBUG(BSL_LS_BCM_FP,
   8377                        (BSL_META_U(unit,"Unsupported hint type attached"
   8378                                              "to hintid(%d).\r\n"),
   8379                                               gc->hintid));
   8380                         rv = BCM_E_PARAM;
   8381                         return (rv);
   8382                     }
   8383                 }
   8384             }
   8385             hint_list = hint_list->next;
   8386         }
   8387     }
   8388 
   8389 
   8390     /* Apply group member port configuration. */
   8391     if (gc->flags & BCM_FIELD_GROUP_CREATE_WITH_PORT) {
   8392         BCM_PBMP_ASSIGN(fsm.pbmp, gc->ports);
   8393     } else {
   8394         BCM_PBMP_ASSIGN(fsm.pbmp, all_pbmp);
   8395     }
   8396 
   8397     /* Apply group mode configuration */
   8398     if (gc->flags & BCM_FIELD_GROUP_CREATE_WITH_MODE) {
   8399         fsm.mode = gc->mode;
   8400     } else {
   8401         fsm.mode = bcmFieldGroupModeDefault;
   8402     }
   8403 
   8404     /* Apply Validate flag if the group needs to be created partially */
   8405     if (flags & _FP_GROUP_CONFIG_VALIDATE) {
   8406        fsm.flags |= _FP_GROUP_CONFIG_VALIDATE;
   8407     }
   8408 
   8409     /* Validate and Apply group Preselset configuration */
   8410     if (gc->flags & BCM_FIELD_GROUP_CREATE_WITH_PRESELSET) {
   8411        fsm.preselset = gc->preselset;
   8412        fsm.flags |= BCM_FIELD_GROUP_CREATE_WITH_PRESELSET;
   8413     }
   8414 
   8415     switch (stage) {
   8416         case _BCM_FIELD_STAGE_LOOKUP:
   8417         case _BCM_FIELD_STAGE_EGRESS:
   8418             /*  Add FP group. */
   8419             rv = _bcm_field_group_add(unit, &fsm);
   8420             break;
   8421         case _BCM_FIELD_STAGE_EXACTMATCH:
   8422             /*  Add FP group under EM Stage. */
   8423             rv = _field_th_group_add(unit, &fsm);
   8424             if (BCM_SUCCESS(rv) &&
   8425                 (soc_property_get(unit, spn_FLOWTRACKER_ENABLE, 0) == 1) &&
   8426                 (flags & _FP_GROUP_CONFIG_FLOWTRACKER_SPECIFIC)) {
   8427                 /*
   8428                  * _field_detach shoud not destroy Exact Match groups created by Flow Tracker.
   8429                  * So Setting _FP_EXACTMATCH_STAGE_SKIP_DETACH flag to retain Exact Match Stage.
   8430                  */
   8431                 fc->flags |= _FP_EXACTMATCH_STAGE_SKIP_DETACH;
   8432             }
   8433             break;
   8434         case _BCM_FIELD_STAGE_INGRESS:
   8435             rv = _field_th_group_add(unit, &fsm);
   8436             break;
   8437         case _BCM_FIELD_STAGE_CLASS:
   8438             rv = _bcm_field_th_class_group_add(unit, &fsm, gc->aset);
   8439             break;
   8440 #if defined(BCM_FLOWTRACKER_SUPPORT)
   8441         case _BCM_FIELD_STAGE_FLOWTRACKER:
   8442             if ((!soc_feature(unit, soc_feature_field_flowtracker_support)) ||
   8443                  (soc_property_get(unit, spn_FLOWTRACKER_ENABLE, 1) != 1)) {
   8444                 return (BCM_E_UNAVAIL);
   8445             }
   8446             rv = _field_th_group_add(unit, &fsm);
   8447             break;
   8448 #endif
   8449         default:
   8450             /* Invalid FP stage. */
   8451             return (BCM_E_PARAM);
   8452     }
   8453 
   8454 #ifdef BCM_WARM_BOOT_SUPPORT
   8455     SOC_CONTROL_LOCK(unit);
   8456     SOC_CONTROL(unit)->scache_dirty = 1;
   8457     SOC_CONTROL_UNLOCK(unit);
   8458 #endif
   8459 
   8460     return (rv);
   8461 }
   8462 
   8463 /*
   8464  * Function:
   8465  *    _field_th_ingress_selcodes_update
   8466  * Purpose:
   8467  *    Install Logical table selection rule and TCAM key generation rules in
   8468  *    hardware.
   8469  * Parameters:
   8470  *     unit         - (IN)  BCM device number.
   8471  *     stage_fc     - (IN)  Stage field control structure.
   8472  *     fg           - (IN)  Field group structure.
   8473  *     lt_fs        - (IN)  Field logical table slice structure.
   8474  * Returns:
   8475  *     BCM_E_XXX
   8476  */
   8477 STATIC int
   8478 _field_th_ingress_selcodes_update(int unit, _field_stage_t *stage_fc,
   8479                                    _field_group_t *fg, _field_lt_slice_t *lt_fs)
   8480 {
   8481     int   rv;            /* Operation return status.    */
   8482     int   idx;           /* iteration index.            */
   8483     _field_control_t *fc; /* Field Control Structure.   */
   8484     bcm_field_entry_t lt_entry; /* LT entry ID. */
   8485     _field_lt_entry_t *lt_f_ent; /* LT field entry structure pointer.  */
   8486     uint8 part;
   8487     int parts_count = 0; /* number of slices allocated for the group. */
   8488 
   8489     /* Input parameters check. */
   8490     if ((NULL == fg) || (NULL == stage_fc) || (NULL == lt_fs)) {
   8491         return (BCM_E_PARAM);
   8492     }
   8493 
   8494     /* Field control get. */
   8495     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   8496 
   8497     if (fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) {
   8498        _field_presel_entry_t  *f_presel;
   8499 
   8500        /*
   8501         * Create Presel Entries in the LT slice associated with the group
   8502         */
   8503        for (idx = 0; idx < _FP_PRESEL_ENTRIES_MAX_PER_GROUP; idx++) {
   8504            if (fg->presel_ent_arr[idx] != NULL) {
   8505               f_presel = fg->presel_ent_arr[idx];
   8506            } else {
   8507               continue;
   8508            }
   8509 
   8510            rv = _field_th_lt_entry_data_config_set(unit, stage_fc, f_presel);
   8511            if (BCM_FAILURE(rv)) {
   8512               return (rv);
   8513            }
   8514 
   8515            /* Install the LT Entry in HW. */
   8516            rv = _bcm_field_th_lt_entry_parts_install(unit, f_presel);
   8517            BCM_IF_ERROR_RETURN(rv);
   8518 
   8519            /* Check if the group is expanded across slices. */
   8520            if (f_presel->lt_fs->next != NULL) {
   8521               _field_lt_slice_t     *lt_part_fs;
   8522               _field_presel_entry_t *f_presel_p;
   8523               int                   p, parts_count = -1;
   8524 
   8525               /* Get number of entry parts. */
   8526               rv = _bcm_field_th_entry_tcam_parts_count(unit, fg->flags,
   8527                                                         &parts_count);
   8528               BCM_IF_ERROR_RETURN(rv);
   8529 
   8530               f_presel_p = f_presel;
   8531               for (p = 0; (p < parts_count && f_presel_p != NULL); p++) {
   8532                   lt_part_fs = f_presel_p->lt_fs->next;
   8533                   for (;lt_part_fs != NULL; lt_part_fs = lt_part_fs->next) {
   8534                      rv = _field_th_ingress_group_expand_install(unit, stage_fc,
   8535                                                              fg, p, lt_part_fs);
   8536                      BCM_IF_ERROR_RETURN(rv);
   8537                   }
   8538               }
   8539            }
   8540        }
   8541     } else {
   8542        rv = _bcm_field_th_entry_tcam_parts_count(unit,fg->flags,&parts_count);
   8543        if (BCM_FAILURE(rv)) {
   8544             return rv;
   8545        }
   8546        if (stage_fc->oper_mode == bcmFieldGroupOperModeGlobal) {
   8547            lt_entry = fc->lt_info[0][fg->lt_id]->lt_entry;
   8548        } else {
   8549            lt_entry = fc->lt_info[fg->instance][fg->lt_id]->lt_entry;
   8550        }
   8551        BCM_IF_ERROR_RETURN(_field_th_lt_entry_get(unit, lt_entry,
   8552            _FP_ENTRY_PRIMARY, &lt_f_ent));
   8553 
   8554       for (part = 0; part < parts_count; part++) {
   8555           BCM_IF_ERROR_RETURN(_bcm_field_th_group_keygen_profiles_index_alloc(
   8556               unit, stage_fc, fg, part));
   8557 
   8558           BCM_IF_ERROR_RETURN(_field_th_lt_entry_default_data_value_set(unit,
   8559               stage_fc, fg, part, lt_f_ent + part));
   8560           lt_f_ent[part].flags |= _FP_ENTRY_DIRTY;
   8561       }
   8562       BCM_IF_ERROR_RETURN(_field_th_lt_default_entry_install(unit, lt_entry));
   8563    }
   8564 
   8565     return (BCM_E_NONE);
   8566 }
   8567 
   8568 int
   8569 _bcm_field_th_group_update(int unit, bcm_field_group_t group, bcm_field_qset_t *qset)
   8570 {
   8571     int rv = BCM_E_NONE; /* Return status.  */
   8572     int idx = 0;         /* Index Variable. */
   8573     int qid_index = 0;   /* Index Variable. */
   8574     int qid;             /* Qualifier ID.   */
   8575     int parts_count = 0; /* number of slices allocated for the group. */
   8576     uint8 part;          /* Group Partition. */
   8577     uint16 *qid_array[_FP_MAX_ENTRY_WIDTH] = { NULL };
   8578                                             /* Array of qualifiers.    */
   8579     uint16 size = 0;                        /* Total number of qualifiers in
   8580                                                each partition of the group. */
   8581     _field_group_t *fg = NULL;           /* Field group operational Structure. */
   8582     _field_group_t *temp_fg = NULL;      /* Temp field group operational structure. */
   8583     _field_stage_t *stage_fc = NULL;     /* Field Stage operational structure. */
   8584     bcm_field_qset_t temp_qset;          /* Temporary qset information. */
   8585     _bcm_field_qual_offset_t  *offset_array[_FP_MAX_ENTRY_WIDTH] = { NULL };
   8586                                          /* Array of qualifiers offset information. */
   8587     _field_group_add_fsm_t fsm_ptr;
   8588     _field_presel_entry_t  *f_presel;
   8589 
   8590     if(qset == NULL) {
   8591         return BCM_E_PARAM;
   8592     }
   8593     BCM_IF_ERROR_RETURN(_field_group_get(unit, group, &fg));
   8594     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_fc));
   8595 
   8596     sal_memcpy(&temp_qset, qset, sizeof(bcm_field_qset_t));
   8597 
   8598     for (qid = 0; qid < _bcmFieldQualifyCount; qid++) {
   8599 
   8600         if (BCM_FIELD_QSET_TEST(temp_qset, qid) &&
   8601             !BCM_FIELD_QSET_TEST(fg->qset, qid) &&
   8602             IS_POST_MUX_QUALIFIER(qid)) {
   8603             LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   8604                         "FP(unit %d) Verb: Adding new post mux"
   8605                         "qualifiers to QSET is not supported.\n"), unit));
   8606             return BCM_E_PARAM;
   8607         }
   8608 
   8609         if (BCM_FIELD_QSET_TEST(fg->qset, qid)) {
   8610             BCM_FIELD_QSET_REMOVE(temp_qset, qid);
   8611         }
   8612     }
   8613 
   8614     _FP_XGS3_ALLOC(temp_fg, sizeof(_field_group_t), "Temp group for update");
   8615     if (NULL == temp_fg) {
   8616         return BCM_E_MEMORY;
   8617     }
   8618 
   8619     temp_fg->gid = fg->gid;
   8620     temp_fg->flags = fg->flags;
   8621     sal_memcpy(&temp_fg->qset, &temp_qset, sizeof(bcm_field_qset_t));
   8622     sal_memcpy(temp_fg->ext_codes, fg->ext_codes,
   8623                       (sizeof(_field_ext_sel_t) * _FP_MAX_ENTRY_WIDTH));
   8624     sal_memset(&fsm_ptr, 0, sizeof(_field_group_add_fsm_t));
   8625     fsm_ptr.fg = temp_fg;
   8626     fsm_ptr.stage_fc = stage_fc;
   8627     fsm_ptr.flags = _FP_GROUP_QSET_UPDATE;
   8628     rv = _field_th_ext_code_assign(unit, 0, &fsm_ptr);
   8629 
   8630     if (BCM_FAILURE(rv)) {
   8631         LOG_VERBOSE(BSL_LS_BCM_FP, (BSL_META_U(unit,
   8632             "FP(unit %d) Verb: Processing group QSET.\n"), unit));
   8633         goto cleanup;
   8634     }
   8635 
   8636     for (part = 0; part < _FP_MAX_ENTRY_WIDTH; part++)  {
   8637         size = 0;
   8638 
   8639         size = temp_fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].size +
   8640                 fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].size;
   8641 
   8642         if (size != 0) {
   8643 
   8644              _FP_XGS3_ALLOC(qid_array[part], size * sizeof(uint16), "Qid Array");
   8645              if (NULL == qid_array[part]) {
   8646                 rv = BCM_E_MEMORY;
   8647                 goto cleanup;
   8648              }
   8649 
   8650              _FP_XGS3_ALLOC(offset_array[part], size * sizeof(_bcm_field_qual_offset_t),
   8651                                                         "Qualifier Offset Array");
   8652              if (NULL == offset_array[part]) {
   8653                 rv = BCM_E_MEMORY;
   8654                 goto cleanup;
   8655              }
   8656 
   8657 
   8658              qid_index = 0;
   8659              for (idx = 0; idx < fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].size; idx++) {
   8660 
   8661                  sal_memcpy(&qid_array[part][qid_index],
   8662                         &(fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].qid_arr[idx]),
   8663                         sizeof(uint16));
   8664 
   8665                  sal_memcpy(&offset_array[part][qid_index],
   8666                             &(fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].offset_arr[idx]),
   8667                             sizeof(_bcm_field_qual_offset_t));
   8668 
   8669                  qid_index++;
   8670 
   8671              }
   8672 
   8673              fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].size = size;
   8674 
   8675              /* Copy qualifier array and offset array of new
   8676               * qualifiers in this partition.
   8677               */
   8678              size = temp_fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].size;
   8679              sal_memcpy(&qid_array[part][qid_index],
   8680                         temp_fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].qid_arr,
   8681                         size * sizeof(uint16));
   8682 
   8683              sal_memcpy(&offset_array[part][qid_index],
   8684                         temp_fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].offset_arr,
   8685                         size * sizeof(_bcm_field_qual_offset_t));
   8686 
   8687              if (NULL != fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].qid_arr) {
   8688                  sal_free(fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].qid_arr);
   8689              }
   8690 
   8691              if (NULL != fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].offset_arr) {
   8692                  sal_free(fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].offset_arr);
   8693              }
   8694 
   8695              if (NULL != temp_fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].qid_arr) {
   8696                  sal_free(temp_fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].qid_arr);
   8697              }
   8698 
   8699              if (NULL != temp_fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].offset_arr) {
   8700                  sal_free(temp_fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].offset_arr);
   8701              }
   8702 
   8703              fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].qid_arr = qid_array[part];
   8704              fg->qual_arr[_FP_ENTRY_TYPE_DEFAULT][part].offset_arr = offset_array[part];
   8705         }
   8706     }
   8707     if (fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) {
   8708         for (idx = 0; idx < _FP_PRESEL_ENTRIES_MAX_PER_GROUP; idx++) {
   8709             if (fg->presel_ent_arr[idx] != NULL) {
   8710                f_presel = fg->presel_ent_arr[idx];
   8711             } else {
   8712                continue;
   8713             }
   8714             parts_count = 0;
   8715             rv = _bcm_field_th_lt_entry_tcam_parts_count(unit,
   8716                                 f_presel->group->stage_id,
   8717                                 f_presel->group->flags, &parts_count);
   8718             if (BCM_FAILURE(rv)) {
   8719                 goto cleanup;
   8720             }
   8721             /* Uninstall entry parts keygen program profile entries from hardware. */
   8722            for (part = 0; part < parts_count; part++) {
   8723                BCM_IF_ERROR_RETURN(soc_profile_mem_delete(unit,
   8724                    &stage_fc->keygen_profile[fg->instance].profile,
   8725                    fg->ext_codes[part].keygen_index));
   8726            }
   8727 
   8728         }
   8729     } else {
   8730         rv = _bcm_field_th_entry_tcam_parts_count(unit, fg->flags, &parts_count);
   8731         if (BCM_FAILURE(rv)) {
   8732             goto cleanup;
   8733         }
   8734 
   8735         /* Uninstall entry parts keygen program profile entries from hardware. */
   8736         for (part = 0; part < parts_count; part++) {
   8737             rv = soc_profile_mem_delete(unit,
   8738                 &stage_fc->keygen_profile[fg->instance].profile,
   8739                 fg->ext_codes[part].keygen_index);
   8740             if (BCM_FAILURE(rv)) {
   8741                 goto cleanup;
   8742             }
   8743         }
   8744     }
   8745 
   8746     for (part = 0; part < _FP_MAX_ENTRY_WIDTH; part++)  {
   8747          offset_array[part] = NULL;
   8748          qid_array[part] = NULL;
   8749     }
   8750     sal_memcpy(fg->ext_codes, temp_fg->ext_codes,
   8751                       (sizeof(_field_ext_sel_t) * _FP_MAX_ENTRY_WIDTH));
   8752 
   8753     rv = _field_th_ingress_selcodes_update(unit, stage_fc, fg,fg->lt_slices);
   8754     if (BCM_FAILURE(rv)) {
   8755             goto cleanup;
   8756     }
   8757     for (qid = 0; qid < _bcmFieldQualifyCount; qid++) {
   8758         if (BCM_FIELD_QSET_TEST(*qset, qid)) {
   8759             BCM_FIELD_QSET_ADD(fg->qset, qid);
   8760         }
   8761     }
   8762 
   8763 cleanup:
   8764     for (part = 0; part < _FP_MAX_ENTRY_WIDTH; part++) {
   8765          if (NULL != qid_array[part]) {
   8766              sal_free(qid_array[part]);
   8767              qid_array[part] = NULL;
   8768          }
   8769 
   8770          if(NULL != offset_array[part]) {
   8771              sal_free(offset_array[part]);
   8772              offset_array[part] = NULL;
   8773          }
   8774     }
   8775 
   8776     if (NULL != temp_fg) {
   8777         sal_free(temp_fg);
   8778     }
   8779 
   8780     return (rv);
   8781 }
   8782 /*
   8783  * Function: _bcm_field_th_find_empty_slice
   8784  *
   8785  * Purpose:
   8786  *     Get a new slice for an existing group if available.
   8787  *     Used for auto-expansion of groups
   8788  *     Currently: supported in Raptor, Firebolt2.
   8789  *
   8790  * Parameters:
   8791  *     unit   - (IN) BCM device number
   8792  *     fg     - (IN) field group
   8793  *     fs_ptr - (IN/OUT) _field_slice_t for the PRIMARY if there is one available.
   8794  *
   8795  * Returns:
   8796  *     BCM_E_xxx
   8797  */
   8798 int
   8799 _bcm_field_th_find_empty_slice(int unit, _field_group_t *fg,
   8800                                _field_slice_t **fs_ptr)
   8801 {
   8802     _field_control_t *fc = NULL;       /* Field control structure. */
   8803     _field_stage_t *stage_fc = NULL;   /* Field stage control.     */
   8804     _field_slice_t   *fs = NULL;       /* Field slice pointer.     */
   8805     uint8 slice_idx = 0;               /* Slice iterator.          */
   8806     int parts_count = 0;               /* Number of entry parts.   */
   8807     uint32 entry_flags = 0;            /* Field entry part flags.  */
   8808     int rv = BCM_E_NONE;               /* Operation return status. */
   8809     int lt_part_prio = 0;              /* LT Partition priority.   */
   8810     int part_index = 0;
   8811     uint8 old_physical_slice = 0;      /* Last slice in group.     */
   8812     uint8 new_physical_slice = 0;      /* Allocated slice.         */
   8813     _field_group_t  *curr_fg = NULL;
   8814     _field_group_t  *next_fg = NULL;
   8815     uint8 *slice_arr = NULL;
   8816 
   8817     /* Get field control structure. */
   8818     rv = _field_control_get(unit, &fc);
   8819     BCM_IF_ERROR_RETURN(rv);
   8820 
   8821     /* Get stage field control structure. */
   8822     rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
   8823     BCM_IF_ERROR_RETURN(rv);
   8824 
   8825     if (0 == (stage_fc->flags & _FP_STAGE_AUTO_EXPANSION)) {
   8826         return (BCM_E_RESOURCE);
   8827     }
   8828 
   8829     fs = &fg->slices[0];
   8830     while (fs->next != NULL) {
   8831         fs = fs->next;
   8832     }
   8833     old_physical_slice = fs->slice_number;
   8834 
   8835     _FP_XGS3_ALLOC(slice_arr, sizeof(uint8) * stage_fc->tcam_slices,
   8836                       "Slice Array");
   8837     if (NULL == slice_arr) {
   8838         return BCM_E_MEMORY;
   8839     }
   8840 
   8841     for (slice_idx = 0; slice_idx < stage_fc->tcam_slices; slice_idx++) {
   8842         slice_arr[slice_idx] = slice_idx;
   8843     }
   8844 
   8845     if ((fg->flags & _FP_GROUP_AUTO_EXPAND_SMALL_SLICE)
   8846             || (fg->flags & _FP_GROUP_AUTO_EXPAND_LARGE_SLICE)){
   8847         /* Sort the slice array based on requested slice sizes */
   8848         rv = _field_fill_slice_array(unit, fg, slice_arr);
   8849         BCM_IF_ERROR_CLEANUP(rv);
   8850     }
   8851 
   8852     /*
   8853      * Find an empty slice
   8854      * Validate the ports and mode
   8855      */
   8856     for (slice_idx = 0; slice_idx < stage_fc->tcam_slices; slice_idx++) {
   8857         if (slice_arr[slice_idx] == old_physical_slice) {
   8858            continue;
   8859         }
   8860 
   8861         rv = _bcm_field_th_group_add_slice_validate(unit, stage_fc, fg,
   8862                                                     slice_arr[slice_idx]);
   8863         if (BCM_SUCCESS(rv)) {
   8864             uint8 empty;
   8865 
   8866             fs = stage_fc->slices[fg->instance] + slice_arr[slice_idx];
   8867             BCM_IF_ERROR_CLEANUP(_field_th_slice_is_empty(unit, fs, &empty));
   8868             if (empty == TRUE) {
   8869                break;
   8870             }
   8871         }
   8872     }
   8873 
   8874     if (slice_idx == stage_fc->tcam_slices) {
   8875         /* No free slice; attempt to compress existing auto expanded groups. */
   8876         rv = _field_th_stage_group_compress(unit, fc, stage_fc);
   8877         BCM_IF_ERROR_CLEANUP(rv);
   8878 
   8879         /* Retry slice allocation. */
   8880         for (slice_idx = 0; slice_idx < stage_fc->tcam_slices; slice_idx++) {
   8881             _field_slice_t *fs_next = NULL;
   8882             uint8 curr_grp_slice = 0;
   8883 
   8884             for (fs_next = &fg->slices[0]; fs_next; fs_next = fs_next->next) {
   8885                 /* Don't use current group's slices */
   8886                 if (fs_next->slice_number == slice_arr[slice_idx]) {
   8887                     curr_grp_slice = 1;
   8888                     break;
   8889                 }
   8890             }
   8891 
   8892             if (1 != curr_grp_slice) {
   8893                 rv = _bcm_field_th_group_add_slice_validate(unit, stage_fc, fg,
   8894                                                             slice_arr[slice_idx]);
   8895                 if (BCM_SUCCESS(rv)) {
   8896                     break;
   8897                 }
   8898             }
   8899         }
   8900 
   8901         if (slice_idx == stage_fc->tcam_slices)
   8902         {
   8903            /* No free slice */
   8904            rv = BCM_E_RESOURCE;
   8905            BCM_IF_ERROR_CLEANUP(rv);
   8906         }
   8907     }
   8908 
   8909     new_physical_slice = slice_arr[slice_idx];
   8910 
   8911     /* Get number of entry parts for the group. */
   8912     rv = _bcm_field_th_entry_tcam_parts_count(unit, fg->flags, &parts_count);
   8913     BCM_IF_ERROR_CLEANUP(rv);
   8914 
   8915     /* Retrieve the partition priority value for wide mode group's slices.*/
   8916     rv = _bcm_field_th_lt_part_prio_value_get(unit, fg, &lt_part_prio);
   8917     BCM_IF_ERROR_CLEANUP(rv);
   8918 
   8919     /* Set up the new physical slice parameters in Software */
   8920     for(part_index = 0; part_index < parts_count; part_index++) {
   8921         /* Get entry flags. */
   8922         rv = _bcm_field_th_tcam_part_to_entry_flags(unit, part_index, fg->flags,
   8923                                                     &entry_flags);
   8924         BCM_IF_ERROR_CLEANUP(rv);
   8925 
   8926         /* Get slice id for entry part */
   8927         rv = _bcm_field_th_tcam_part_to_slice_number(part_index, fg->flags,
   8928                                                      &slice_arr[slice_idx]);
   8929         BCM_IF_ERROR_CLEANUP(rv);
   8930 
   8931         /* Get slice pointer. */
   8932         fs = stage_fc->slices[fg->instance] + new_physical_slice
   8933                 + slice_arr[slice_idx];
   8934 
   8935         /* Enable slice. */
   8936         if (0 == (entry_flags & _FP_ENTRY_SECOND_HALF)) {
   8937             /*
   8938              * Initialize slice free entries count value based on group
   8939              * flags.
   8940              */
   8941 #if defined(BCM_TOMAHAWK3_SUPPORT)
   8942             if (SOC_IS_TOMAHAWK3(unit) &&
   8943                 (fg->stage_id == _BCM_FIELD_STAGE_INGRESS)) {
   8944                 fs->free_count = fs->entry_count;
   8945             } else
   8946 #endif
   8947             {
   8948                 if ((fg->flags & _FP_GROUP_SPAN_SINGLE_SLICE)
   8949                     && !(fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE)) {
   8950                     fs->free_count = fs->entry_count;
   8951                 } else {
   8952                     fs->entry_count >>= 1;
   8953                     fs->free_count = fs->entry_count;
   8954                     fs->start_tcam_idx >>= 1;
   8955                 }
   8956             } 
   8957 
   8958             /* Set group flags in in slice.*/
   8959             fs->group_flags = fg->flags & _FP_GROUP_STATUS_MASK;
   8960 
   8961             /* Add slice to slices linked list . */
   8962             stage_fc->slices[fg->instance][old_physical_slice + slice_arr[slice_idx]].next = fs;
   8963             fs->prev =
   8964              &stage_fc->slices[fg->instance][old_physical_slice + slice_arr[slice_idx]];
   8965         }
   8966 
   8967         curr_fg = NULL;
   8968         next_fg = NULL;
   8969         do {
   8970            rv = _bcm_field_slice_group_get_next(unit, fg->instance,
   8971                                                    fg->stage_id,
   8972                                                    old_physical_slice,
   8973                                                    &curr_fg, &next_fg);
   8974            /* Mark it as SUCCESS when you reach the end of the group's slices */
   8975            if (BCM_E_NOT_FOUND == rv) {
   8976                rv = BCM_E_NONE;
   8977                break;
   8978            } else if (BCM_FAILURE(rv)) {
   8979                break;
   8980            }
   8981 
   8982           /*
   8983            * Install TCAM keygen program configuration in hardware for all
   8984            * the groups for each slice.
   8985            */
   8986            rv = _field_th_ingress_group_expand_slice_install(unit, stage_fc,
   8987                                            next_fg,
   8988                                            new_physical_slice + slice_arr[slice_idx],
   8989                                            part_index, lt_part_prio);
   8990            BCM_IF_ERROR_CLEANUP(rv);
   8991            curr_fg = next_fg;
   8992         } while (next_fg != NULL);
   8993     }
   8994 
   8995     *fs_ptr = stage_fc->slices[fg->instance] + new_physical_slice;
   8996 
   8997 cleanup:
   8998     if (NULL != slice_arr) {
   8999         sal_free(slice_arr);
   9000         slice_arr = NULL;
   9001     }
   9002     return (rv);
   9003 }
   9004 
   9005 /*
   9006  * Function: _bcm_field_th_group_enable_set
   9007  *
   9008  * Purpose:
   9009  *     To enable/diable the field group operational status.
   9010  * Parameters:
   9011  *     unit   - (IN) BCM device number
   9012  *     group  - (IN) field group
   9013  *     enable - (IN) enable (or) disbale flag.
   9014  *
   9015  * Returns:
   9016  *     BCM_E_xxx
   9017  */
   9018 int
   9019 _bcm_field_th_group_enable_set(int unit, bcm_field_group_t group, uint32 enable)
   9020 {
   9021     int rv;                             /* operational status */
   9022     int tcam_idx[_FP_MAX_ENTRY_WIDTH];  /* Entry TCAM index.  */
   9023     int parts_count = -1;               /* Parts count.       */
   9024     int idx;                         /* Temporary pointer variable. */
   9025     uint32 entry[SOC_MAX_MEM_FIELD_WORDS] = {0}; /* Entry buffer. */
   9026     _field_group_t *fg;           /* Field Group Structure. */
   9027     soc_mem_t lt_tcam_mem;        /* TCAM memory ID. */
   9028     bcm_field_entry_t lt_entry;   /* Logical table entry. */
   9029     _field_lt_entry_t *lt_f_ent;  /* Field LT entry pointer. */
   9030     _field_stage_t *stage_fc;     /* Stage Field control structure. */
   9031     _field_control_t *fc;         /* Field Control Strucutre.       */
   9032 
   9033     /* Field control get. */
   9034     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   9035 
   9036     /* Get the group control pointer. */
   9037     BCM_IF_ERROR_RETURN(_field_group_get(unit, group, &fg));
   9038 
   9039     /* Get the stage control structure. */
   9040     BCM_IF_ERROR_RETURN(_field_stage_control_get(unit,
   9041                             fg->stage_id, &stage_fc));
   9042 
   9043     if (fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) {
   9044         return _bcm_field_th_group_presel_enable_set(unit, stage_fc, fg, enable);
   9045     }
   9046 
   9047     lt_entry = fc->lt_info[fg->instance][fg->lt_id]->lt_entry;
   9048 
   9049     /* Get all part of the entry. */
   9050     BCM_IF_ERROR_RETURN(_field_th_lt_entry_get_by_id(unit, lt_entry,
   9051         &lt_f_ent));
   9052 
   9053     /* Get number of entry parts. */
   9054     rv = _bcm_field_th_entry_tcam_parts_count(unit, lt_f_ent->group->flags,
   9055             &parts_count);
   9056     BCM_IF_ERROR_RETURN(rv);
   9057 
   9058     for (idx = 0; idx < parts_count; idx++) {
   9059         rv = _field_th_lt_entry_tcam_idx_get(unit, lt_f_ent + idx,
   9060                 (lt_f_ent + idx)->lt_fs, tcam_idx + idx);
   9061         BCM_IF_ERROR_RETURN(rv);
   9062     }
   9063 
   9064     /*
   9065      * Get TCAM view to be used for programming the hardware based on the group
   9066      * operational mode.
   9067      */
   9068     rv = _field_th_lt_tcam_mem_get(unit, stage_fc, lt_f_ent, &lt_tcam_mem);
   9069     BCM_IF_ERROR_RETURN(rv);
   9070 
   9071     for (idx = 0; idx < parts_count; idx++)  {
   9072         /*
   9073          * Maximum index value for entry in this TCAM is limited to
   9074          * No. of slices * No. of LT_IDs/slice (12 * 32 == 384).
   9075          */
   9076         if ((tcam_idx[idx] < soc_mem_index_min(unit, lt_tcam_mem))
   9077             || (tcam_idx[idx] > (stage_fc->lt_tcam_sz - 1) )) {
   9078             return (BCM_E_PARAM);
   9079         }
   9080 
   9081         /* Clear entry buffer. */
   9082         sal_memset(entry, 0, sizeof(uint32) * SOC_MAX_MEM_FIELD_WORDS);
   9083 
   9084         /* Read entry into SW buffer. */
   9085         rv = soc_th_ifp_mem_read(unit, lt_tcam_mem, MEM_BLOCK_ANY, tcam_idx[idx],
   9086                 entry);
   9087         BCM_IF_ERROR_RETURN(rv);
   9088 
   9089         /*valid bit in th2 is two bit width*/
   9090 #if defined(BCM_TOMAHAWK2_SUPPORT)
   9091         if (soc_feature(unit, soc_feature_field_multi_pipe_enhanced) &&
   9092             _BCM_FIELD_STAGE_INGRESS  == fg->stage_id) {
   9093             enable = enable ? 3 : 0;
   9094         } else
   9095 #endif /* BCM_TOMAHAWK2_SUPPORT */
   9096         {
   9097             enable = enable ? (soc_feature(unit, soc_feature_td3_style_fp) ? 3 : 1) : 0;
   9098         }
   9099         soc_mem_field32_set(unit, lt_tcam_mem, entry, VALIDf, enable);
   9100 
   9101         /* Install entry in hardware. */
   9102         rv = soc_th_ifp_mem_write(unit, lt_tcam_mem, MEM_BLOCK_ALL, tcam_idx[idx],
   9103                 entry);
   9104         BCM_IF_ERROR_RETURN(rv);
   9105     }
   9106 
   9107     /* Enable/Disable group flags. */
   9108     if (enable) {
   9109         fg->flags |= _FP_GROUP_LOOKUP_ENABLED;
   9110     } else {
   9111         fg->flags &= ~_FP_GROUP_LOOKUP_ENABLED;
   9112     }
   9113 
   9114     return BCM_E_NONE;
   9115 }
   9116 
   9117 /*
   9118  * Function:
   9119  *    _bcm_field_th_group_status_calc
   9120  * Purpose:
   9121  *    Fill in the values of a group status structure.
   9122  * Parameters:
   9123  *    unit - (IN)     BCM device number.
   9124  *    fg   - (IN/OUT) Group to update the status structure.
   9125  * Returns:
   9126  *    BCM_E_NONE - Success.
   9127  */
   9128 int
   9129 _bcm_field_th_group_status_calc(int unit, _field_group_t *fg)
   9130 {
   9131     bcm_field_group_status_t *status;   /* Group status structure pointer. */
   9132     _field_stage_t *stage_fc;           /* Stage field control structure.  */
   9133     _field_stage_t *stage_ingress;      /* Stage field control structure.  */
   9134     _field_slice_t *fs;                 /* Field slice control structure.  */
   9135     int count = 0;                      /* Generic purposes counter.       */
   9136     int rv = BCM_E_NONE;                /* Operation return status.        */
   9137     int slice_index;                    /* Hardware slice index.           */
   9138     uint8 single_wide = 0;              /* Single wide group indicator.    */
   9139 
   9140     /* Input parameter check. */
   9141     if (NULL == fg) {
   9142         return (BCM_E_PARAM);
   9143     }
   9144 
   9145     /* Get field group stage control structure. */
   9146     BCM_IF_ERROR_RETURN
   9147         (_field_stage_control_get(unit, fg->stage_id, &stage_fc));
   9148 
   9149     /* Get field group status structure pointer. */
   9150     status = &fg->group_status;
   9151     if (NULL == status) {
   9152         return (BCM_E_INTERNAL);
   9153     }
   9154 
   9155     /* Get group primary slice structure pointer. */
   9156     fs = &fg->slices[0];
   9157 
   9158     /* Get field group intraslice double wide status. */
   9159     single_wide = ((fg->flags & _FP_GROUP_SPAN_SINGLE_SLICE)
   9160                     && !(fg->flags & _FP_GROUP_INTRASLICE_DOUBLEWIDE)) ? 1 : 0;
   9161 
   9162     if (SOC_IS_TOMAHAWK3(unit)) {
   9163         single_wide = (fg->flags & _FP_GROUP_SPAN_SINGLE_SLICE);
   9164     }
   9165 
   9166     status->entries_total = 0;
   9167     status->entries_free = 0;
   9168 
   9169     if (fg->stage_id == _BCM_FIELD_STAGE_EXACTMATCH) {
   9170         int slice = 0;
   9171         /* Retreive Slice Instance. */
   9172         fs = stage_fc->slices[fg->instance];
   9173         /* Calculate free entry count. */
   9174         for (slice = 0; slice < stage_fc->tcam_slices; slice++) {
   9175             status->entries_free += fs[slice].free_count;
   9176             status->entries_total += fs[slice].entry_count;
   9177         }
   9178 #if defined(BCM_FLOWTRACKER_SUPPORT)
   9179     } else if (fg->stage_id == _BCM_FIELD_STAGE_FLOWTRACKER) {
   9180         single_wide = (fg->flags & _FP_GROUP_DW_DEPTH_EXPANDED) ? 0 : 1;
   9181         fs = stage_fc->slices[fg->instance];
   9182         if (single_wide) {
   9183             status->entries_total = fs->entry_count;
   9184             status->entries_free = fs->free_count;
   9185         } else {
   9186             status->entries_total = (fs->entry_count / 2);
   9187             status->entries_free = (fs->free_count / 2);
   9188         }
   9189 #endif
   9190     } else {
   9191         /* Calculate total entries count in slices allocated for the group. */
   9192         while (NULL != fs) {
   9193             status->entries_total += fs->entry_count;
   9194             fs = fs->next;
   9195         }
   9196 
   9197         /* Calculate total free entries count in slices allocated for the group. */
   9198         status->entries_free = 0;
   9199         fs = &fg->slices[0];
   9200         while (NULL != fs) {
   9201             /* Get free entries count in the slice. */
   9202             _bcm_field_entries_free_get(unit, fs, fg, &count);
   9203             status->entries_free += count;
   9204             fs = fs->next;
   9205         }
   9206     }
   9207 
   9208     if (_BCM_FIELD_STAGE_FLOWTRACKER != fg->stage_id) {
   9209         rv = _bcm_field_th_flex_counter_status_get(unit, fg,
   9210                                                &(status->counters_total),
   9211                                                &(status->counters_free));
   9212     }
   9213     BCM_IF_ERROR_RETURN(rv);
   9214     /*
   9215      * Calculate total counters and meters count, free counters and meters
   9216      * count.
   9217      */
   9218     fs = fg->slices;
   9219 
   9220     /* ExactMatch stage doesnt have meter pool seperately.
   9221      * It uses the meters allocated to ingress stage.
   9222      */
   9223     if(_BCM_FIELD_STAGE_EXACTMATCH == fg->stage_id)
   9224     {
   9225         /* Get ingress field group stage control structure. */
   9226         BCM_IF_ERROR_RETURN
   9227         (_field_stage_control_get(unit, _BCM_FIELD_STAGE_INGRESS, &stage_ingress));
   9228 
   9229         status->meters_total = _bcm_field_meters_total_get(stage_ingress,
   9230                                   fg->instance, fs);
   9231         status->meters_free = _bcm_field_meter_free_get(stage_ingress,
   9232                                   fg, fs);
   9233     } else {
   9234 
   9235         status->meters_total = _bcm_field_meters_total_get(stage_fc, fg->instance,
   9236                                    fs);
   9237         status->meters_free = _bcm_field_meter_free_get(stage_fc, fg,
   9238                                    fs);
   9239     }
   9240     /*
   9241      * Calculate total entries count and total free entries count for the group
   9242      * if it expands to other available slices.
   9243      */
   9244     if (stage_fc->flags & _FP_STAGE_AUTO_EXPANSION) {
   9245         for (slice_index = 0; slice_index < stage_fc->tcam_slices;
   9246              ++slice_index) {
   9247             /* Ignore the secondary and tertiary slices */
   9248             if ((fg->flags & _FP_GROUP_SPAN_DOUBLE_SLICE) ||
   9249                     (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE)) {
   9250                 if (fg->slices[1].slice_number == slice_index) {
   9251                     continue;
   9252                 }
   9253             }
   9254             if (fg->flags & _FP_GROUP_SPAN_TRIPLE_SLICE) {
   9255                 if (fg->slices[2].slice_number == slice_index) {
   9256                     continue;
   9257                 }
   9258             }
   9259             /*Ignore the primary slice as well as this is already accounted for*/
   9260             if (fg->slices[0].slice_number == slice_index) {
   9261                 continue;
   9262             }
   9263 
   9264             rv = _bcm_field_th_group_add_slice_validate(unit, stage_fc, fg,
   9265                     slice_index);
   9266             if (BCM_SUCCESS(rv)) {
   9267                 fs = stage_fc->slices[fg->instance] + slice_index;
   9268                 if (single_wide) {
   9269                     status->entries_total += fs->entry_count;
   9270                     status->entries_free += fs->free_count;
   9271                 } else {
   9272                     if (SOC_IS_TOMAHAWK3(unit)) {
   9273                         status->entries_total += fs->entry_count;
   9274                         status->entries_free += fs->free_count;
   9275                     } else {
   9276                         status->entries_total += (fs->entry_count / 2);
   9277                         status->entries_free += (fs->free_count / 2);
   9278                     }
   9279                 }
   9280             }
   9281         }
   9282     }
   9283 
   9284     return (BCM_E_NONE);
   9285 }
   9286 
   9287 /*
   9288  * Function:
   9289  *    _field_th_ingress_default_group_expand_install
   9290  * Purpose:
   9291  *    Allocate and Install LT Entries in a group expanded slice.
   9292  * Parameters:
   9293  *    unit       - (IN) BCM device number.
   9294  *    stage_fc   - (IN) Reference to Field Stage structure.
   9295  *    fg         - (IN) Reference to Field Group structure.
   9296  *    entry_part - (IN) Slice Entry Part.
   9297  *    lt_fs      - (IN) Reference to LT expanded slice.
   9298  * Returns:
   9299  *    BCM_E_xxx.
   9300  */
   9301 int
   9302 _field_th_ingress_default_group_expand_install(int unit,
   9303                                                _field_stage_t *stage_fc,
   9304                                                _field_group_t *fg,
   9305                                                int entry_part,
   9306                                                _field_lt_slice_t *lt_fs)
   9307 {
   9308     int rv;
   9309     int parts_count = -1;
   9310     int part;
   9311     uint8 slice_attached = 0;
   9312     _field_lt_slice_t     *lt_part_fs = NULL;
   9313     _field_lt_entry_t     *lt_f_entry;
   9314     _field_lt_entry_t     *lt_f_entry_p = NULL;
   9315     _field_control_t *fc;
   9316     bcm_field_entry_t lt_entry;
   9317 
   9318     /* Input parameters check. */
   9319     if ((NULL == fg) || (NULL == stage_fc) || (NULL == lt_fs)) {
   9320         return (BCM_E_PARAM);
   9321     }
   9322 
   9323     /* Field control get. */
   9324     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   9325 
   9326     if ((fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) != 0) {
   9327        return BCM_E_INTERNAL;
   9328     }
   9329 
   9330     LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   9331         "\n\r%s(): fg:%p fg->gid:%d lt_fs:%p slice_number:%d entry_part:%d\n\r"),
   9332         __func__, fg, fg->gid, lt_fs, lt_fs->slice_number, entry_part));
   9333 
   9334 
   9335     if (stage_fc->oper_mode == bcmFieldGroupOperModeGlobal) {
   9336          lt_entry = fc->lt_info[0][fg->lt_id]->lt_entry;
   9337     } else {
   9338          lt_entry = fc->lt_info[fg->instance][fg->lt_id]->lt_entry;
   9339     }
   9340 
   9341     /* Get all part of the entry. */
   9342     BCM_IF_ERROR_RETURN(_field_th_lt_entry_get_by_id(unit,
   9343                       lt_entry, &lt_f_entry));
   9344 
   9345     /* Get number of entry parts. */
   9346     rv = _bcm_field_th_entry_tcam_parts_count(unit, fg->flags,
   9347                                               &parts_count);
   9348     BCM_IF_ERROR_RETURN(rv);
   9349 
   9350     for (part = 0; part < parts_count; part++) {
   9351        if (part == entry_part) {
   9352           lt_f_entry_p = lt_f_entry + part;
   9353           break;
   9354        }
   9355     }
   9356 
   9357     if (lt_f_entry_p == NULL) {
   9358        LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   9359           "Error[%d]: LT Part[%d]-entry_part[%d] entry is NULL,"
   9360           " lt_f_entry->eid:%d\n\r"),
   9361           rv, part, entry_part, lt_f_entry->eid));
   9362        return BCM_E_INTERNAL;
   9363     }
   9364 
   9365     /* Get entry part flags. */
   9366     rv = _bcm_field_th_tcam_part_to_entry_flags(unit, part, fg->flags,
   9367                                                    &(lt_f_entry_p->flags));
   9368     if (BCM_FAILURE(rv)) {
   9369        LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   9370        "LT entry part flags get failed.\n\r")));
   9371        return rv;
   9372     }
   9373 
   9374     /* Given primary entry TCAM index calculate entry part tcam index. */
   9375     if (0 != part) {
   9376        lt_f_entry_p->index = lt_f_entry->index;
   9377     }
   9378 
   9379     /* Check if the given lt slice is already associated to the entry. */
   9380     lt_part_fs = lt_f_entry_p->lt_fs;
   9381     for (; lt_part_fs != NULL; lt_part_fs = lt_part_fs->next) {
   9382         if (lt_part_fs == lt_fs) {
   9383            slice_attached = 1;
   9384            break;
   9385         }
   9386     }
   9387 
   9388     if (slice_attached == 0) {
   9389        /* Attach the expanded slice for the part entry. */
   9390        lt_part_fs = lt_f_entry_p->lt_fs;
   9391        for (; lt_part_fs != NULL; lt_part_fs = lt_part_fs->next) {
   9392           if (lt_part_fs->next == NULL) {
   9393              lt_part_fs->next = lt_fs;
   9394              lt_part_fs->next->next = NULL;
   9395              lt_part_fs->next->prev = lt_part_fs;
   9396              break;
   9397           }
   9398        }
   9399     }
   9400 
   9401     /* Mark entry dirty. */
   9402     lt_f_entry_p->flags |= _FP_ENTRY_DIRTY;
   9403 
   9404     /* Update LT Slices. */
   9405     /* Decrement slice free entry count for primary entries. */
   9406     lt_fs->free_count--;
   9407     /* Assign entry to a slice. */
   9408     lt_fs->entries[lt_f_entry_p->index] = lt_f_entry_p;
   9409 
   9410     for (part = 0; part < parts_count; part++) {
   9411        lt_f_entry_p = lt_f_entry + part;
   9412 
   9413        if (entry_part == part) {
   9414           break;
   9415        }
   9416     }
   9417 
   9418     /* Install the LT Entry in HW. */
   9419     rv = _field_th_lt_default_tcam_entry_install(unit, lt_f_entry_p->eid, 1,
   9420                                                  entry_part, lt_fs);
   9421     if (BCM_FAILURE(rv)) {
   9422        LOG_ERROR(BSL_LS_BCM_FP, (BSL_META_U(unit,
   9423        "LT TCAM entry install failed[%d].\n\r"), rv));
   9424        return rv;
   9425     }
   9426 
   9427     LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   9428                "-----------------------------------------------------\n\r")));
   9429     LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit, "default_group_expand_install():"
   9430      "lt_f_entry:%p eid:%d lt_fs:%p slice_num:%d slice_idx:%d\n\r"),
   9431      lt_f_entry, lt_f_entry->eid, lt_fs,lt_fs->slice_number,lt_f_entry->index));
   9432     LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   9433                "-----------------------------------------------------\n\r")));
   9434 
   9435     return rv;
   9436 }
   9437 
   9438 /*
   9439  * Function:
   9440  *    _field_th_ingress_group_expand_install
   9441  * Purpose:
   9442  *    Allocate and Install Presel Entries in a group expanded slice.
   9443  * Parameters:
   9444  *    unit       - (IN) BCM device number.
   9445  *    stage_fc   - (IN) Reference to Field Stage structure.
   9446  *    fg         - (IN) Reference to Field Group structure.
   9447  *    entry_part - (IN) Slice Entry Part.
   9448  *    lt_fs      - (IN) Reference to LT expanded slice.
   9449  * Returns:
   9450  *    BCM_E_xxx.
   9451  */
   9452 STATIC int
   9453 _field_th_ingress_group_expand_install(int unit, _field_stage_t *stage_fc,
   9454                                        _field_group_t *fg, int entry_part,
   9455                                        _field_lt_slice_t *lt_fs)
   9456 {
   9457     int rv, idx;
   9458     int parts_count = -1;
   9459     int part;
   9460     uint8 slice_attached = 0;
   9461     _field_lt_slice_t     *lt_part_fs;
   9462     _field_presel_entry_t *f_presel_p;
   9463     _field_presel_entry_t *f_presel;
   9464 
   9465     /* Input parameters check. */
   9466     if ((NULL == fg) || (NULL == stage_fc) || (NULL == lt_fs)) {
   9467         return (BCM_E_PARAM);
   9468     }
   9469 
   9470     LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   9471         "%s(): fg:%p fg->gid:%d lt_fs:%p slice_number:%d entry_part:%d\n\r"),
   9472         __func__, fg, fg->gid, lt_fs, lt_fs->slice_number, entry_part));
   9473 
   9474     f_presel = fg->presel_ent_arr[0];
   9475     if (f_presel == NULL) {
   9476        return BCM_E_INTERNAL;
   9477     }
   9478 
   9479     /* Get number of entry parts. */
   9480     rv = _bcm_field_th_entry_tcam_parts_count(unit, fg->flags,
   9481                                               &parts_count);
   9482     BCM_IF_ERROR_RETURN(rv);
   9483 
   9484     f_presel_p = f_presel;
   9485     for (part = 0; (part < parts_count && f_presel_p != NULL); part++) {
   9486        if (part == entry_part) {
   9487           break;
   9488        }
   9489        f_presel_p = f_presel_p->next;
   9490     }
   9491 
   9492     if (f_presel_p == NULL || part >= parts_count) {
   9493        return BCM_E_INTERNAL;
   9494     }
   9495 
   9496     /* Get entry part flags. */
   9497     rv = _bcm_field_th_tcam_part_to_entry_flags(unit, part, fg->flags,
   9498                                                 &(f_presel_p->flags));
   9499     BCM_IF_ERROR_RETURN(rv);
   9500 
   9501     /* Given primary entry TCAM index calculate entry part tcam index. */
   9502     if (0 != part) {
   9503        f_presel_p->hw_index = f_presel->hw_index;
   9504     }
   9505 
   9506     /* Check if the given lt slice is already associated to the presel entry. */
   9507     lt_part_fs = f_presel_p->lt_fs;
   9508     for (; lt_part_fs != NULL; lt_part_fs = lt_part_fs->next) {
   9509         if (lt_part_fs == lt_fs) {
   9510            slice_attached = 1;
   9511            break;
   9512         }
   9513     }
   9514 
   9515     if (slice_attached == 0) {
   9516        /* Attach the expanded slice for the part entry. */
   9517        lt_part_fs = f_presel_p->lt_fs;
   9518        for (; lt_part_fs != NULL; lt_part_fs = lt_part_fs->next) {
   9519           if (lt_part_fs->next == NULL) {
   9520              lt_part_fs->next = lt_fs;
   9521              lt_part_fs->next->next = NULL;
   9522              lt_part_fs->next->prev = lt_part_fs;
   9523              break;
   9524           }
   9525        }
   9526     }
   9527 
   9528     if (lt_part_fs == NULL) {
   9529        return BCM_E_INTERNAL;
   9530     }
   9531 
   9532     /* Mark entry dirty. */
   9533     f_presel_p->flags |= _FP_ENTRY_DIRTY;
   9534 
   9535     /* Update Presel LT Slices. */
   9536     for (idx = 0; idx < _FP_PRESEL_ENTRIES_MAX_PER_GROUP; idx++) {
   9537         if (fg->presel_ent_arr[idx] != NULL) {
   9538            f_presel = fg->presel_ent_arr[idx];
   9539         } else {
   9540            continue;
   9541         }
   9542 
   9543         f_presel_p = f_presel;
   9544         for (part = 0; (part < parts_count && f_presel_p != NULL); part++) {
   9545            if (entry_part == part) {
   9546               break;
   9547            }
   9548            f_presel_p = f_presel_p->next;
   9549         }
   9550 
   9551         if (f_presel_p == NULL || part == parts_count) {
   9552            return BCM_E_INTERNAL;
   9553         }
   9554 
   9555         lt_part_fs = f_presel_p->lt_fs;
   9556         for (; lt_part_fs != NULL; lt_part_fs = lt_part_fs->next) {
   9557            /* Goto the last slice. */
   9558            if (lt_part_fs->next == NULL) {
   9559               /* Decrement slice free entry count for primary entries. */
   9560               lt_part_fs->free_count--;
   9561               /* Assign entry to a slice. */
   9562               lt_part_fs->p_entries[f_presel_p->hw_index] = f_presel_p;
   9563               break;
   9564            }
   9565         }
   9566 
   9567         LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   9568                "-----------------------------------------------------\n\r")));
   9569         LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit, "group_expand_install():"
   9570               "f_presel_p:%p presel:%d lt_fs:%p slice_num:%d slice_idx:%d\n\r"),
   9571               f_presel_p,f_presel_p->presel_id,lt_fs,lt_fs->slice_number,
   9572               f_presel_p->hw_index));
   9573         LOG_DEBUG(BSL_LS_BCM_FP, (BSL_META_U(unit,
   9574                "-----------------------------------------------------\n\r")));
   9575 
   9576         /* Install the LT Entry in HW. */
   9577         rv = _bcm_field_th_lt_entry_install(unit, f_presel_p, lt_fs);
   9578         BCM_IF_ERROR_RETURN(rv);
   9579     }
   9580 
   9581 
   9582     return BCM_E_NONE;
   9583 }
   9584 
   9585 
   9586 
   9587 /*
   9588  * Function:
   9589  *    _field_th_ingress_group_expand_slice_install
   9590  * Purpose:
   9591  *    Auxiliary routine used to install field group in hardware
   9592  *    for a given slice.
   9593  * Parameters:
   9594  *     unit          - (IN) BCM device number.
   9595  *     stage_fc      - (IN) Installed group structure.
   9596  *     fg            - (IN/OUT)  Field group structure.
   9597  *     slice_number  - (IN) Slice number group installed in.
   9598  *     part_index    - (IN) Entry Part Index.
   9599  *     group_slice_prio - (IN) Group's Priority for the particular slice.
   9600  * Returns:
   9601  *     BCM_E_XXX
   9602  */
   9603 STATIC int
   9604 _field_th_ingress_group_expand_slice_install(int unit, _field_stage_t *stage_fc,
   9605                                          _field_group_t *fg, uint8 slice_number,
   9606                                          int part_index, int group_slice_prio)
   9607 {
   9608     int rv;
   9609     _field_lt_slice_t *lt_fs;   /* LT Slice pointer.                */
   9610     _field_slice_t *fs;         /* Field slice structure pointer.   */
   9611     _field_control_t          *fc;           /* Field control structure. */
   9612 
   9613     /* Input parameters check. */
   9614     if ((NULL == stage_fc) || (NULL == fg) || (NULL == fg->lt_slices)) {
   9615         return (BCM_E_PARAM);
   9616     }
   9617 
   9618     /* Get field control structure. */
   9619     BCM_IF_ERROR_RETURN(_field_control_get(unit, &fc));
   9620 
   9621     /* Get LT entry part slice control structure. */
   9622     lt_fs = stage_fc->lt_slices[fg->instance] + slice_number;
   9623 
   9624     /* Set slice mode in hardware based on Group mode/flags. */
   9625     BCM_IF_ERROR_RETURN(_field_th_ingress_slice_mode_set(unit, stage_fc,
   9626         lt_fs->slice_number, fg, 0));
   9627     /*
   9628      * Initialize slice free entries count value to number of
   9629      * entries in the slice.
   9630      */
   9631     if (0 == fg->slices[0].lt_map) {
   9632         lt_fs->free_count = lt_fs->entry_count;
   9633     }
   9634 
   9635     /* Get IFP TCAM slice information. */
   9636     fs = stage_fc->slices[fg->instance] + slice_number;
   9637 
   9638     /* Update slice LT_ID mapping in group's slice. */
   9639     fs->lt_map |= (1 << fg->lt_id);
   9640 
   9641 
   9642     fc->lt_info[fg->instance][fg->lt_id]->lt_part_map |= (1 << fs->slice_number);
   9643     fc->lt_info[fg->instance][fg->lt_id]->lt_part_pri[fs->slice_number] = group_slice_prio;
   9644 
   9645     /* Install TCAM keygen program configuration in hardware for each slice. */
   9646     if (fg->flags & _FP_GROUP_PRESELECTOR_SUPPORT) {
   9647        rv = _field_th_ingress_group_expand_install(unit, stage_fc, fg,
   9648                                                    part_index, lt_fs);
   9649     } else {
   9650        /* Default case. */
   9651        rv = _field_th_ingress_default_group_expand_install(unit, stage_fc, fg,
   9652                                                            part_index, lt_fs);
   9653     }
   9654 
   9655     if (BCM_FAILURE(rv)) {
   9656         LOG_ERROR(BSL_LS_BCM_FP,
   9657             (BSL_META_U(unit, "Error[%d]: Group slice auto-expand failed for"
   9658              " group:%d part:%d slice:%d\n\r"),
   9659              rv, fg->gid, part_index, lt_fs->slice_number));
   9660         return rv;
   9661     }
   9662 
   9663     /* Set the partition Priority. */
   9664 #if defined (BCM_HELIX5_SUPPORT)
   9665     if (SOC_IS_HELIX5(unit)) {
   9666         rv = _bcm_field_hx5_ingress_lt_partition_prio_write(unit, stage_fc, fg,
   9667                                                            fg->lt_id, slice_number);
   9668     } else
   9669 #endif
   9670     {
   9671         rv =_bcm_field_th_ingress_lt_partition_prio_write(unit, stage_fc, fg,
   9672                                            fg->lt_id, slice_number);
   9673     }
   9674     if (BCM_FAILURE(rv)) {
   9675         LOG_ERROR(BSL_LS_BCM_FP,
   9676             (BSL_META_U(unit, "Error: LT Partition Set failed for"
   9677              " group:%d lt_id:%d slice:%d val:%d\n\r"),
   9678              fg->gid, fg->lt_id, slice_number, group_slice_prio));
   9679     }
   9680 
   9681     return (rv);
   9682 }
   9683 
   9684 /*
   9685  * Function:
   9686  *     _bcm_field_th_group_instance_set
   9687  *
   9688  * Purpose:
   9689  *     Set the group instance based on the group's operational mode
   9690  *     and group's pbmp.
   9691  *
   9692  * Parameters:
   9693  *     unit       -  (IN)  BCM device number.
   9694  *     fg         -  (IN)  Reference to Field Group structure.
   9695  *
   9696  * Returns:
   9697  *     BCM_E_XXX
   9698  */
   9699 int
   9700 _bcm_field_th_group_instance_set(int unit, _field_group_t *fg)
   9701 {
   9702     int                rv = BCM_E_NONE; /* Return Variable */
   9703     int                pipe;      /* Device pipe iterator.    */
   9704     _field_stage_t     *stage_fc; /* Stage control structure. */
   9705     bcm_pbmp_t         t_pbmp;    /* Pipe Port bitmap.        */
   9706     bcm_pbmp_t         all_pbmp;   /* Group port bitmap.      */
   9707 
   9708     /* Input parameters check. */
   9709     if (NULL == fg) {
   9710         return (BCM_E_PARAM);
   9711     }
   9712 
   9713     /* Read device port configuration. */ 
   9714     BCM_PBMP_CLEAR(all_pbmp);
   9715     BCM_IF_ERROR_RETURN(_bcm_field_valid_pbmp_get(unit, &all_pbmp));
   9716 
   9717    /* Get stage field control structure. */
   9718     rv = _field_stage_control_get(unit, fg->stage_id, &stage_fc);
   9719     if (BCM_FAILURE(rv)) {
   9720        goto bcm_error;
   9721     }
   9722 
   9723    /*
   9724     * Based on the Stage Group Operational mode, set the Field Group's instance
   9725     * information.
   9726     */
   9727     if (bcmFieldGroupOperModeGlobal == stage_fc->oper_mode) {
   9728 
   9729       /*
   9730        * Validate user supplied IPBM value.
   9731        * For global mode, all ports must be part of IPBM value, if supplied.
   9732        */
   9733        if (BCM_PBMP_NEQ(all_pbmp, fg->pbmp)) {
   9734            /* If port configuration get fails, go to end. */
   9735            rv = BCM_E_PARAM;
   9736            goto bcm_error;
   9737        }
   9738 
   9739        /* For group global operational mode, use the default instance.  */
   9740        fg->instance = _FP_DEF_INST;
   9741     } else {
   9742       /*
   9743        * For PipeLocal group oper mode, derive the instance
   9744        * information from group's PBM value.
   9745        */
   9746        for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) {
   9747 #ifdef BCM_TOMAHAWK3_SUPPORT
   9748            if (BCM_PBMP_IS_NULL(PBMP_PIPE(unit, pipe))) {
   9749                continue;
   9750            }
   9751 #endif
   9752            BCM_PBMP_ASSIGN(t_pbmp, PBMP_PIPE(unit, pipe));
   9753            BCM_PBMP_REMOVE(t_pbmp, PBMP_LB(unit));
   9754           /*
   9755            * User must use bcm_port_config_get API to retrieve Pipe PBMP value
   9756            * and pass this value in Group's pbmp parameter when creating
   9757            * PipeLocal groups.
   9758            */
   9759            if (BCM_PBMP_EQ(t_pbmp, fg->pbmp)) {
   9760               /*
   9761                * Pipe PBM matches user supplied PBM, update field group
   9762                * instance.
   9763                */
   9764                fg->instance = pipe;
   9765                break;
   9766            }
   9767        }
   9768 
   9769       /*
   9770        * Portbit map value supplied by the user not matching any of the pipe's
   9771        * port bitmap mask value, hence return input paramter error.
   9772        */
   9773        if (NUM_PIPE(unit) == pipe) {
   9774           rv = BCM_E_PARAM;
   9775           goto bcm_error;
   9776        }
   9777     }
   9778 
   9779 bcm_error:
   9780     return rv;
   9781 }
   9782 
   9783 #else /* BCM_TOMAHAWK_SUPPORT && BCM_FIELD_SUPPORT */
   9784 int _th_field_not_empty;
   9785 #endif /* !BCM_TOMAHAWK_SUPPORT && !BCM_FIELD_SUPPORT */