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

oam.c (100304B)


      1 /*
      2  * 
      3  * 
      4  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      5  * 
      6  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      7  */
      8 
      9 #include <sal/core/libc.h>
     10 #include <shared/bsl.h>
     11 #include <soc/defs.h>
     12 #include <soc/drv.h>
     13 #include <soc/scache.h>
     14 #include <soc/profile_mem.h>
     15 #include <soc/hash.h>
     16 #include <soc/l3x.h>
     17 #include <soc/triumph2.h>
     18 
     19 #include <bcm/l3.h>
     20 #include <bcm/oam.h>
     21 
     22 #include <bcm_int/esw/oam.h>
     23 #include <bcm_int/esw/port.h>
     24 #include <bcm_int/esw/l3.h>
     25 #include <bcm_int/esw/switch.h>
     26 #include <bcm_int/esw/stack.h>
     27 #include <bcm_int/esw/triumph2.h>
     28 
     29 #include <bcm_int/esw_dispatch.h>
     30 
     31 #if defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_APOLLO_SUPPORT) || \
     32     defined(BCM_VALKYRIE2_SUPPORT)
     33 
     34 #define LEVEL_BIT_COUNT 3
     35 #define LEVEL_COUNT (1 << (LEVEL_BIT_COUNT))
     36 #define MAX_ENDPOINT_LEVEL (LEVEL_COUNT - 1)
     37 #define MANGLED_GROUP_NAME_LENGTH (BCM_OAM_GROUP_NAME_LENGTH)
     38 
     39 #define UNSUPPORTED_ENDPOINT_FLAGS \
     40     (BCM_OAM_ENDPOINT_LOSS_MEASUREMENT)
     41 
     42 #define CHECK_INIT \
     43     if (!oam_info_p->initialized) \
     44     { \
     45         return BCM_E_INIT; \
     46     }
     47 
     48 #define SET_OAM_INFO oam_info_p = &oam_info[unit];
     49 
     50 #define SET_GROUP(_group_index_) group_p = \
     51     oam_info_p->groups + _group_index_;
     52 
     53 #define SET_ENDPOINT(_endpoint_index_) endpoint_p = \
     54     oam_info_p->endpoints + _endpoint_index_;
     55 
     56 #define VALIDATE_GROUP_INDEX(_group_index_) \
     57     if ((_group_index_) < 0 || (_group_index_) >= oam_info_p->group_count) \
     58     { \
     59         return BCM_E_PARAM; \
     60     } \
     61 
     62 #define VALIDATE_ENDPOINT_INDEX(_endpoint_index_) \
     63     if ((_endpoint_index_) < 0 || \
     64         (_endpoint_index_) >= oam_info_p->endpoint_count) \
     65     { \
     66         return BCM_E_PARAM; \
     67     } \
     68 
     69 
     70 static _bcm_oam_info_t oam_info[BCM_MAX_NUM_UNITS];
     71 
     72 static _bcm_oam_fault_t group_faults[] =
     73 {
     74     {CURRENT_XCON_CCM_DEFECTf, STICKY_XCON_CCM_DEFECTf,
     75         BCM_OAM_GROUP_FAULT_CCM_XCON, 0x08},
     76 
     77     {CURRENT_ERROR_CCM_DEFECTf, STICKY_ERROR_CCM_DEFECTf,
     78         BCM_OAM_GROUP_FAULT_CCM_ERROR, 0x04},
     79 
     80     {CURRENT_SOME_RMEP_CCM_DEFECTf, STICKY_SOME_RMEP_CCM_DEFECTf,
     81         BCM_OAM_GROUP_FAULT_CCM_TIMEOUT, 0x02},
     82 
     83     {CURRENT_SOME_RDI_DEFECTf, STICKY_SOME_RDI_DEFECTf,
     84         BCM_OAM_GROUP_FAULT_REMOTE, 0x01},
     85 
     86     {0, 0, 0, 0}
     87 };
     88 
     89 static _bcm_oam_fault_t endpoint_faults[] =
     90 {
     91     {CURRENT_RMEP_PORT_STATUS_DEFECTf, STICKY_RMEP_PORT_STATUS_DEFECTf,
     92         BCM_OAM_ENDPOINT_FAULT_PORT_DOWN, 0x08},
     93 
     94     {CURRENT_RMEP_INTERFACE_STATUS_DEFECTf,
     95         STICKY_RMEP_INTERFACE_STATUS_DEFECTf,
     96         BCM_OAM_ENDPOINT_FAULT_INTERFACE_DOWN, 0x04},
     97 
     98     {CURRENT_RMEP_CCM_DEFECTf, STICKY_RMEP_CCM_DEFECTf,
     99         BCM_OAM_ENDPOINT_FAULT_CCM_TIMEOUT, 0x20},
    100 
    101     {CURRENT_RMEP_LAST_RDIf, STICKY_RMEP_LAST_RDIf,
    102         BCM_OAM_ENDPOINT_FAULT_REMOTE, 0x10},
    103 
    104     {0, 0, 0, 0}
    105 };
    106 
    107 static _bcm_oam_interrupt_t interrupts[] =
    108 {
    109     {ANY_RMEP_TLV_PORT_DOWN_STATUSr, FIRST_RMEP_INDEXf, INVALIDf,
    110         ANY_RMEP_TLV_PORT_DOWN_INTRf, bcmOAMEventEndpointPortDown},
    111 
    112     {ANY_RMEP_TLV_PORT_UP_STATUSr, FIRST_RMEP_INDEXf, INVALIDf,
    113         ANY_RMEP_TLV_PORT_UP_INTRf, bcmOAMEventEndpointPortUp},
    114 
    115     {ANY_RMEP_TLV_INTERFACE_DOWN_STATUSr, FIRST_RMEP_INDEXf, INVALIDf,
    116         ANY_RMEP_TLV_INTERFACE_DOWN_INTRf, bcmOAMEventEndpointInterfaceDown},
    117 
    118     {ANY_RMEP_TLV_INTERFACE_UP_STATUSr, FIRST_RMEP_INDEXf, INVALIDf,
    119         ANY_RMEP_TLV_INTERFACE_UP_INTRf, bcmOAMEventEndpointInterfaceUp},
    120 
    121     {XCON_CCM_DEFECT_STATUSr, INVALIDf, FIRST_MA_INDEXf,
    122         ERROR_CCM_DEFECT_INTRf, bcmOAMEventGroupCCMxcon},
    123 
    124     {ERROR_CCM_DEFECT_STATUSr, INVALIDf, FIRST_MA_INDEXf,
    125         ERROR_CCM_DEFECT_INTRf, bcmOAMEventGroupCCMError},
    126 
    127     {SOME_RDI_DEFECT_STATUSr, FIRST_RMEP_INDEXf, FIRST_MA_INDEXf,
    128         SOME_RDI_DEFECT_INTRf, bcmOAMEventGroupRemote},
    129 
    130     {SOME_RMEP_CCM_DEFECT_STATUSr, FIRST_RMEP_INDEXf, FIRST_MA_INDEXf,
    131         SOME_RMEP_CCM_DEFECT_INTRf, bcmOAMEventGroupCCMTimeout},
    132 
    133     {INVALIDr, INVALIDf, 0}
    134 };
    135 
    136 static soc_field_t interrupt_enable_fields[bcmOAMEventCount] =
    137 {
    138     /* This must be in the same order as the bcm_oam_event_type_t enum */
    139 
    140     ANY_RMEP_TLV_PORT_DOWN_INT_ENABLEf,
    141     ANY_RMEP_TLV_PORT_UP_INT_ENABLEf,
    142     ANY_RMEP_TLV_INTERFACE_DOWN_INT_ENABLEf,
    143     ANY_RMEP_TLV_INTERFACE_UP_INT_ENABLEf,
    144     INVALIDf,
    145     INVALIDf,
    146     INVALIDf,
    147     INVALIDf,
    148     INVALIDf,
    149     INVALIDf,
    150     INVALIDf,
    151     INVALIDf,
    152     INVALIDf,
    153     INVALIDf,
    154     XCON_CCM_DEFECT_INT_ENABLEf,
    155     ERROR_CCM_DEFECT_INT_ENABLEf,
    156     SOME_RDI_DEFECT_INT_ENABLEf,
    157     SOME_RMEP_CCM_DEFECT_INT_ENABLEf,
    158     INVALIDf,
    159 };
    160 
    161 static uint32 ccm_periods[] =
    162 {
    163     BCM_OAM_ENDPOINT_CCM_PERIOD_DISABLED,
    164     BCM_OAM_ENDPOINT_CCM_PERIOD_3MS,
    165     BCM_OAM_ENDPOINT_CCM_PERIOD_10MS,
    166     BCM_OAM_ENDPOINT_CCM_PERIOD_100MS,
    167     BCM_OAM_ENDPOINT_CCM_PERIOD_1S,
    168     BCM_OAM_ENDPOINT_CCM_PERIOD_10S,
    169     BCM_OAM_ENDPOINT_CCM_PERIOD_1M,
    170     BCM_OAM_ENDPOINT_CCM_PERIOD_10M,
    171     _BCM_OAM_ENDPOINT_CCM_PERIOD_UNDEFINED
    172 };
    173 
    174 static void *_bcm_tr2x_oam_alloc_clear(unsigned int size, char *description)
    175 {
    176     void *block_p;
    177 
    178     block_p = sal_alloc(size, description);
    179 
    180     if (block_p != NULL)
    181     {
    182         sal_memset(block_p, 0, size);
    183     }
    184 
    185     return block_p;
    186 }
    187 
    188 static int _bcm_tr2x_oam_quantize_ccm_period(int period)
    189 {
    190     int quantized_period;
    191 
    192     if (period == 0) {
    193         quantized_period = 0;
    194     }
    195     else {
    196         /* Find closest supported period */
    197         for (quantized_period = 1;
    198             ccm_periods[quantized_period] !=
    199                 _BCM_OAM_ENDPOINT_CCM_PERIOD_UNDEFINED; ++quantized_period) {
    200             if (period < ccm_periods[quantized_period]) {
    201                 break;
    202             }
    203         }
    204 
    205         if (quantized_period > 1) {
    206             if (ccm_periods[quantized_period] ==
    207                 _BCM_OAM_ENDPOINT_CCM_PERIOD_UNDEFINED) {
    208                 /* Use the highest defined value */
    209                 --quantized_period;
    210             }
    211             else {
    212                 if (period - ccm_periods[quantized_period - 1] <
    213                     ccm_periods[quantized_period] - period) {
    214                     /* Closer to the lower value */
    215                     --quantized_period;
    216                 }
    217             }
    218         }
    219     }
    220 
    221     return quantized_period;
    222 }
    223 
    224 /*
    225  * Function:
    226  *     _bcm_tr2x_oam_clear_rmep
    227  * Purpose:
    228  *     Delete RMEP entry or Install fresh RMEP entry in the Hardware, clearing
    229  *     the faults.
    230  *
    231  * Parameters:
    232  *     unit       - (IN) BCM device number
    233  *     h_data_p   - (IN) Pointer to Endpoint info associated with RMEP entry
    234  *                       being cleared.
    235  *     valid      - (IN) 0 => Delete the H/w entry
    236  *                       1 => Install fresh entry with faults cleared.
    237  * Returns:
    238  *     BCM_E_XXX
    239  */
    240 STATIC int
    241 _bcm_tr2x_oam_clear_rmep (int unit, _bcm_oam_endpoint_t *endpoints, int valid)
    242 {
    243 
    244     rmep_entry_t       rmep_entry;          /* RMEP table entry.              */
    245     int                rv = BCM_E_INTERNAL; /* Operation return status entry  */
    246     uint32             oam_cur_time;    /* Current time in H/w state machine  */
    247 
    248     if (endpoints == NULL) {
    249         LOG_ERROR(BSL_LS_BCM_OAM,
    250                   (BSL_META_U(unit,
    251                               "OAM ERR: Arg h_data_p NULL check failed\n")));
    252         return BCM_E_INTERNAL;
    253     }
    254 
    255     LOG_VERBOSE(BSL_LS_BCM_OAM,
    256             (BSL_META_U(unit,
    257                         "OAM, EP id %d, valid %d\n"),
    258                          endpoints->remote_index, valid));
    259 
    260     /* RMEP table programming. */
    261     sal_memset(&rmep_entry, 0, sizeof(rmep_entry_t));
    262 
    263     /* if valid==0 delete RMEP entry, else create a clean RMEP entry */
    264     if (!(valid)) {
    265         rv = WRITE_RMEPm(unit, MEM_BLOCK_ALL, endpoints->remote_index,
    266                          &rmep_entry);
    267         if (rv != BCM_E_NONE) {
    268             LOG_ERROR(BSL_LS_BCM_OAM,
    269                       (BSL_META_U(unit,
    270                                   "OAM ERR: Deleting RMEP entry failied\n")));
    271         }
    272         return rv;
    273     }
    274 
    275     /* Set the MA group index. */
    276     soc_RMEPm_field32_set(unit, &rmep_entry, MAID_INDEXf,
    277                           endpoints->group_index);
    278 
    279     /*
    280      * The following steps are necessary to enable CCM timeout events
    281      * without having received any CCMs.
    282      */
    283     soc_RMEPm_field32_set(unit, &rmep_entry, RMEP_TIMESTAMP_VALIDf, 1);
    284 
    285     BCM_IF_ERROR_RETURN(READ_OAM_CURRENT_TIMEr(unit, &oam_cur_time));
    286 
    287     soc_RMEPm_field32_set(unit, &rmep_entry, RMEP_TIMESTAMPf, oam_cur_time);
    288 
    289     soc_RMEPm_field32_set(unit, &rmep_entry, RMEP_RECEIVED_CCMf,
    290                                   _bcm_tr2x_oam_quantize_ccm_period(endpoints->period));
    291     /* End of timeout setup */
    292 
    293 
    294     soc_RMEPm_field32_set(unit, &rmep_entry, VALIDf, 1);
    295 
    296     rv = WRITE_RMEPm(unit, MEM_BLOCK_ALL, endpoints->remote_index,
    297                      &rmep_entry);
    298     if (rv != BCM_E_NONE) {
    299         LOG_ERROR(BSL_LS_BCM_OAM,
    300                   (BSL_META_U(unit,
    301                               "OAM ERR: Clearing RMEP entry failied\n")));
    302         return (rv);
    303     }
    304 
    305     return BCM_E_NONE;
    306 }
    307 
    308 /*
    309  * Function:
    310  *     _bcm_tr2x_oam_clear_ma_state
    311  * Purpose:
    312  *     Delete MA_STATE entry or Install fresh MA_STATE entry in the Hardware,
    313  *     Clearing the faults.
    314  * Parameters:
    315  *     unit       - (IN) BCM device number
    316  *     group_info - (IN) Group info associated with MA_STATE entry being
    317  *                       cleared.
    318  *     index      - (IN) H/w index of MA_STATE entry to be modified.
    319  *     valid      - (IN) 0 => Delete the H/w entry
    320  *                       1 => Install fresh entry with faults cleared.
    321  * Returns:
    322  *     BCM_E_XXX
    323  */
    324 STATIC int
    325 _bcm_tr2x_oam_clear_ma_state(int unit, _bcm_oam_group_t *group_info,
    326                             int index, int valid)
    327 {
    328 
    329     ma_state_entry_t       ma_state_entry;       /* MA State table entry.     */
    330 
    331     LOG_VERBOSE(BSL_LS_BCM_OAM,
    332                 (BSL_META_U(unit,
    333                             "OAM *group_info %p, index %d, valid %d\n"),
    334                  group_info, index, valid));
    335 
    336     if (group_info == NULL) {
    337         LOG_ERROR(BSL_LS_BCM_OAM,
    338                   (BSL_META_U(unit,
    339                               "OAM ERR: Arg group_info NULL check failed\n")));
    340         return BCM_E_INTERNAL;
    341     }
    342 
    343     sal_memset(&ma_state_entry, 0, sizeof(ma_state_entry_t));
    344 
    345     /* Mark the entry as valid. */
    346     soc_MA_STATEm_field32_set(unit, &ma_state_entry, VALIDf, valid);
    347 
    348     /* Set the lowest alarm priority info. */
    349     if (valid) {
    350         soc_MA_STATEm_field32_set(unit, &ma_state_entry, LOWESTALARMPRIf,
    351                                   group_info->lowest_alarm_priority);
    352     }
    353 
    354     /* Write group information to hardware table. */
    355     SOC_IF_ERROR_RETURN(WRITE_MA_STATEm(unit, MEM_BLOCK_ALL, index,
    356                                         &ma_state_entry));
    357     return BCM_E_NONE;
    358 }
    359 
    360 /*
    361  * Function:
    362  *     _bcm_tr2x_oam_group_recreate
    363  * Purpose:
    364  *     Recreate MA_STATE and RMEP entries, due to current H/w limitation
    365  *     Currently there is a race condition between H/w and Software
    366  *     When RMEP is deleted and if it has any faults then,
    367  *     MA_STATE remote fault counters need to be decremented by software.
    368  *     However it may so happen that after reading RMEP faults and just
    369  *     before RMEP deletion, the fault gets cleared and H/w already decremented
    370  *     the MA_STATE table, now when software decrements the MA_STATE it would
    371  *     get MA_STATE table into an inconsistent state.
    372  *     As a solution we always recreate the entire group on a RMEP deletion.
    373  * Parameters:
    374  *     unit     - (IN) BCM device number
    375  *     group_id - (IN) Group Index,
    376  *                as per current implementation this is same as MA_STATE index.
    377  * Returns:
    378  *     BCM_E_XXX
    379  * Expects:
    380  *      OAM LOCK
    381  */
    382 STATIC int
    383 _bcm_tr2x_oam_group_recreate(int unit, int index)
    384 {
    385     _bcm_oam_info_t         *oam_info_p = NULL;
    386     _bcm_oam_group_t        *group_p = NULL;
    387     _bcm_oam_endpoint_t     *endpoint_p = NULL;
    388     int                     rv = BCM_E_NONE;
    389     bcm_oam_endpoint_t      endpoint_index;
    390 
    391     SET_OAM_INFO;
    392 
    393     CHECK_INIT;
    394 
    395     SET_GROUP(index);
    396     /*if unused Group, just clear the MA_STATE index, including the valid bit*/
    397     if (!(group_p->in_use)) {
    398         LOG_WARN(BSL_LS_BCM_OAM,
    399                  (BSL_META_U(unit,
    400                              "OAM, WARN: Recieved group recreate request for "
    401                               "unused Group Id %d\n"), index));
    402 
    403         rv = _bcm_tr2x_oam_clear_ma_state(unit, group_p, index, 0);
    404         if (BCM_FAILURE(rv)) {
    405             LOG_ERROR(BSL_LS_BCM_OAM,
    406                       (BSL_META_U(unit,
    407                                   "OAM Error: MA_STATE clear failed group id %d - "
    408                                    "%s.\n"), index, bcm_errmsg(rv)));
    409         }
    410 
    411         return rv;
    412     }
    413 
    414     for (endpoint_index = 0; endpoint_index < oam_info_p->endpoint_count;
    415          ++endpoint_index) {
    416         SET_ENDPOINT(endpoint_index);
    417         if (endpoint_p->in_use && endpoint_p->group_index == index) {
    418             rv = _bcm_tr2x_oam_clear_rmep(unit, endpoint_p, 0);
    419             if (BCM_FAILURE(rv)) {
    420                 LOG_ERROR(BSL_LS_BCM_OAM,
    421                           (BSL_META_U(unit,
    422                                       "OAM Error: RMEP clear failed EP id %d - "
    423                                       "%s.\n"), index, bcm_errmsg(rv)));
    424             }
    425         }
    426     }
    427 
    428     rv = _bcm_tr2x_oam_clear_ma_state(unit, group_p, index, 1);
    429     if (BCM_FAILURE(rv)) {
    430         LOG_ERROR(BSL_LS_BCM_OAM,
    431                   (BSL_META_U(unit,
    432                               "OAM Error: MA_STATE clear failed group id %d - "
    433                                "%s.\n"), index, bcm_errmsg(rv)));
    434         return rv;
    435     }
    436 
    437     for (endpoint_index = 0; endpoint_index < oam_info_p->endpoint_count;
    438         ++endpoint_index) {
    439         SET_ENDPOINT(endpoint_index);
    440         if (endpoint_p->in_use && endpoint_p->group_index == index) {
    441             rv = _bcm_tr2x_oam_clear_rmep(unit, endpoint_p, 1);
    442             if (BCM_FAILURE(rv)) {
    443                 LOG_ERROR(BSL_LS_BCM_OAM,
    444                       (BSL_META_U(unit,
    445                                   "OAM Error: RMEP clear failed EP id %d - "
    446                                    "%s.\n"), index, bcm_errmsg(rv)));
    447             }
    448         }
    449     }
    450 
    451     return rv;
    452 }
    453 
    454 STATIC int
    455 _bcm_tr2x_oam_ser_handler(int unit, soc_mem_t mem, int index)
    456 {
    457     int                 rv = BCM_E_NONE;
    458     bcm_oam_endpoint_t  remote_ep_index;
    459     _bcm_oam_info_t     *oam_info_p = NULL;
    460     _bcm_oam_endpoint_t *endpoints = NULL;
    461     rmep_entry_t        rmep_entry;
    462 
    463     SET_OAM_INFO;
    464 
    465     CHECK_INIT;
    466 
    467     LOG_VERBOSE(BSL_LS_BCM_OAM,
    468                 (BSL_META_U(unit,
    469                             "OAM SER on mem %s, index %d\n"),
    470                  SOC_MEM_NAME(unit, mem), index));
    471 
    472     switch(mem){
    473         case MA_STATEm:
    474             VALIDATE_GROUP_INDEX(index);
    475             BCM_IF_ERROR_RETURN(bcm_esw_oam_lock(unit));
    476             rv = _bcm_tr2x_oam_group_recreate(unit, index);
    477             bcm_esw_oam_unlock(unit);
    478             break;
    479 
    480         case RMEPm:
    481             VALIDATE_ENDPOINT_INDEX(index);
    482             BCM_IF_ERROR_RETURN(bcm_esw_oam_lock(unit));
    483 
    484             /* Get the logical index from H/w RMEP index */
    485             remote_ep_index = oam_info_p->remote_endpoints[index];
    486             if(remote_ep_index == BCM_OAM_ENDPOINT_INVALID) {
    487                 /* clean the HW RMEP index */
    488                 sal_memset(&rmep_entry, 0, sizeof(rmep_entry_t));
    489                 rv = WRITE_RMEPm(unit, MEM_BLOCK_ALL, index,
    490                          &rmep_entry);
    491                 bcm_esw_oam_unlock(unit);
    492                 break;
    493             }
    494             /* Get handle to Hash data */
    495             endpoints = &(oam_info_p->endpoints[remote_ep_index]);
    496 
    497             if (!(endpoints->in_use)) {
    498                 /* If endpoint not in use, just clear the RMEP entry in memory */
    499                 LOG_WARN(BSL_LS_BCM_OAM,
    500                          (BSL_META_U(unit,
    501                                      "OAM, WARN: Recieved Parity Error on"
    502                                       "unused Remote Id %d\n"), remote_ep_index));
    503                 /* Just clear this entry including valid bit */
    504                 rv = _bcm_tr2x_oam_clear_rmep(unit, endpoints, 0);
    505             } else {
    506                 /* Get the group Id from EP data, call group recreate routine */
    507                 rv = _bcm_tr2x_oam_group_recreate(unit, endpoints->group_index);
    508             }
    509 
    510             bcm_esw_oam_unlock(unit);
    511             break;
    512 
    513         default:
    514             LOG_ERROR(BSL_LS_BCM_OAM,
    515                       (BSL_META_U(unit,
    516                                   "OAM, ERR: Invalid mem in OAM SER correction "
    517                                    "routine %s\n"), SOC_MEM_NAME(unit, mem)));
    518                         bcm_esw_oam_unlock(unit);
    519 
    520             return BCM_E_INTERNAL;
    521     }
    522 
    523     LOG_VERBOSE(BSL_LS_BCM_OAM,
    524                 (BSL_META_U(unit,
    525                             "OAM SER completed on mem %s, index %d, rv %d\n"),
    526                  SOC_MEM_NAME(unit, mem), index, rv));
    527 
    528     return rv;
    529 
    530 }
    531 
    532 static int _bcm_tr2x_oam_handle_interrupt(int unit, soc_field_t fault_field)
    533 {
    534     _bcm_oam_info_t *oam_info_p;
    535     _bcm_oam_interrupt_t *interrupt_p;
    536     uint32 interrupt_status;
    537     bcm_oam_group_t group_index;
    538     bcm_oam_endpoint_t endpoint_index;
    539     _bcm_oam_event_handler_t *event_handler_p;
    540     uint32 flags = 0;
    541 
    542     SET_OAM_INFO;
    543 
    544     CHECK_INIT;
    545 
    546     BCM_IF_ERROR_RETURN(bcm_esw_oam_lock(unit));
    547 
    548     for (interrupt_p = interrupts;
    549         interrupt_p->status_register != INVALIDr;
    550         ++interrupt_p)
    551     {
    552         if (BCM_FAILURE(soc_reg32_get(unit, interrupt_p->status_register, 
    553                         REG_PORT_ANY, 0, &interrupt_status)))
    554         {
    555             continue;
    556         }
    557 
    558         if (soc_reg_field_get(unit, interrupt_p->status_register,
    559             interrupt_status, VALIDf) &&
    560             oam_info_p->event_handler_count[interrupt_p->event_type] > 0)
    561         {
    562             group_index = (interrupt_p->group_index_field != INVALIDf) ?
    563                 soc_reg_field_get(unit, interrupt_p->status_register,
    564                     interrupt_status, interrupt_p->group_index_field) :
    565                 BCM_OAM_GROUP_INVALID;
    566 
    567             endpoint_index = (interrupt_p->endpoint_index_field != INVALIDf) ?
    568                 soc_reg_field_get(unit, interrupt_p->status_register,
    569                     interrupt_status, interrupt_p->endpoint_index_field) :
    570                 BCM_OAM_ENDPOINT_INVALID;
    571 
    572             if (endpoint_index != BCM_OAM_ENDPOINT_INVALID)
    573             {
    574                 /* Find the logical endpoint for this RMEP */
    575 
    576                 endpoint_index = oam_info_p->remote_endpoints[endpoint_index];
    577             }
    578 
    579             flags = 0;
    580             flags |= soc_reg_field_get(unit, interrupt_p->status_register,
    581                 interrupt_status, MULTIf) ? BCM_OAM_EVENT_FLAGS_MULTIPLE : 0;
    582 
    583             for (event_handler_p = oam_info_p->event_handler_list_p;
    584                 event_handler_p != NULL;
    585                 event_handler_p = event_handler_p->next_p)
    586             {
    587                 if (SHR_BITGET(event_handler_p->event_types.w,
    588                     interrupt_p->event_type))
    589                 {
    590                     event_handler_p->cb(unit, flags, interrupt_p->event_type,
    591                         group_index, endpoint_index,
    592                         event_handler_p->user_data);
    593                 }
    594             }
    595         }
    596 
    597         /* Clear interrupt */
    598 
    599         if (BCM_FAILURE(soc_reg32_set(unit, interrupt_p->status_register, 
    600                         REG_PORT_ANY, 0, 0)))
    601         {
    602             continue;
    603         }
    604     }
    605 
    606     return bcm_esw_oam_unlock(unit);
    607 }
    608 
    609 #ifdef BCM_WARM_BOOT_SUPPORT
    610 
    611 #define BCM_WB_VERSION_1_1                SOC_SCACHE_VERSION(1,1)
    612 #define BCM_WB_VERSION_1_0                SOC_SCACHE_VERSION(1,0)
    613 #define BCM_WB_DEFAULT_VERSION            BCM_WB_VERSION_1_1
    614 
    615 STATIC
    616 int _bcm_oam_warm_boot(int unit)
    617 {
    618     _bcm_oam_info_t *oam_info_p;
    619     _bcm_oam_group_t *group_p;
    620     int group_index;
    621     maid_reduction_entry_t maid_reduction_entry;
    622     ma_state_entry_t ma_state_entry;
    623     int maid_reduction_valid;
    624     int ma_state_valid;
    625     _bcm_oam_endpoint_t *endpoint_p;
    626     int l3_entry_count;
    627     int l3_entry_index;
    628     l3_entry_ipv4_unicast_entry_t l3_entry;
    629     uint32 level_bitmap;
    630     int level;
    631     int lmep_index;
    632     int stable_size;
    633     int glp;
    634     int epidx;
    635     bcm_vlan_t vlan;
    636     lmep_entry_t lmep_entry;
    637     rmep_entry_t rmep_entry;
    638     ma_index_entry_t ma_index_entry;
    639     uint8 *group_names_p;
    640     soc_scache_handle_t scache_handle;
    641     uint16 recovered_ver;
    642     uint32 alloc_size;
    643 
    644     SET_OAM_INFO;
    645 
    646     /* Calculate the scache memory required for OAM module */
    647     alloc_size = oam_info_p->group_count * (BCM_OAM_GROUP_NAME_LENGTH);
    648 
    649     /* Get groups */
    650     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
    651     if (!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)
    652         && (stable_size > alloc_size)) {
    653 
    654         /* Point scache_handle to OAM module */
    655         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_OAM, 0);
    656 
    657         /* Get the OAM module base scache pointer value */
    658         BCM_IF_ERROR_RETURN(_bcm_esw_scache_ptr_get(unit, scache_handle,
    659             FALSE, alloc_size, &group_names_p, BCM_WB_DEFAULT_VERSION,
    660             &recovered_ver));
    661     }
    662 
    663     for (group_index = 0; group_index < oam_info_p->group_count;
    664         ++group_index)
    665     {
    666         SOC_IF_ERROR_RETURN(READ_MAID_REDUCTIONm(unit,
    667             MEM_BLOCK_ANY, group_index, &maid_reduction_entry));
    668 
    669         SOC_IF_ERROR_RETURN(READ_MA_STATEm(unit, MEM_BLOCK_ANY, group_index,
    670             &ma_state_entry));
    671 
    672         maid_reduction_valid = soc_MAID_REDUCTIONm_field32_get(unit,
    673             &maid_reduction_entry, VALIDf);
    674 
    675         ma_state_valid = soc_MA_STATEm_field32_get(unit,
    676             &ma_state_entry, VALIDf);
    677 
    678         if (maid_reduction_valid || ma_state_valid)
    679         {
    680             if (!maid_reduction_valid || !ma_state_valid)
    681             {
    682                 return BCM_E_INTERNAL;
    683             }
    684 
    685             SET_GROUP(group_index);
    686 
    687             if (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit) || (stable_size == 0)) {
    688                 /* Return zeros as the name */
    689                 sal_memset(group_p->name, 0, BCM_OAM_GROUP_NAME_LENGTH);
    690             } else {
    691                 /* Use stored values */
    692                 /*
    693                  * COVERITY 
    694                  * group_names_p has been initilized in soc_scache_ptr_get 
    695                  */ 
    696                  /* coverity[uninit_use_in_call : FALSE] */
    697                 sal_memcpy(group_p->name, group_names_p, BCM_OAM_GROUP_NAME_LENGTH);
    698                 group_names_p += BCM_OAM_GROUP_NAME_LENGTH;
    699             }
    700             group_p->in_use = 1;
    701         }
    702     }
    703 
    704     /* Get endpoints */
    705 
    706     endpoint_p = oam_info_p->endpoints;
    707     l3_entry_count = soc_mem_index_count(unit, L3_ENTRY_IPV4_UNICASTm);
    708 
    709     for (l3_entry_index = 0; l3_entry_index < l3_entry_count; ++l3_entry_index)
    710     {
    711         SOC_IF_ERROR_RETURN(READ_L3_ENTRY_IPV4_UNICASTm(unit, MEM_BLOCK_ANY,
    712             l3_entry_index, &l3_entry));
    713 
    714         if (soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry, VALIDf))
    715         {
    716             switch (soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry, KEY_TYPEf))
    717             {
    718                 case TR_L3_HASH_KEY_TYPE_RMEP:
    719                     endpoint_p->remote_index =
    720                         soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry,
    721                             RMEP__RMEP_PTRf);
    722 
    723                     SOC_IF_ERROR_RETURN(READ_RMEPm(unit, MEM_BLOCK_ANY,
    724                         endpoint_p->remote_index, &rmep_entry));
    725 
    726                     if (!soc_RMEPm_field32_get(unit, &rmep_entry, VALIDf))
    727                     {
    728                         return BCM_E_INTERNAL;
    729                     }
    730 
    731                     endpoint_p->in_use = 1;
    732                     endpoint_p->is_remote = 1;
    733 
    734                     endpoint_p->group_index = soc_RMEPm_field32_get(unit,
    735                         &rmep_entry, MAID_INDEXf);
    736 
    737                     endpoint_p->name = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit,
    738                         &l3_entry, RMEP__MEPIDf);
    739 
    740                     endpoint_p->level = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit,
    741                         &l3_entry, RMEP__MDLf);
    742 
    743                     endpoint_p->vlan = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit,
    744                         &l3_entry, RMEP__VIDf);
    745 
    746                     endpoint_p->glp = soc_L3_ENTRY_IPV4_UNICASTm_field32_get
    747                                            (unit, &l3_entry, RMEP__SGLPf);
    748 
    749                     SHR_BITSET(oam_info_p->remote_endpoints_in_use,
    750                         endpoint_p->remote_index);
    751 
    752                     ++endpoint_p;
    753 
    754                     break;
    755 
    756                 case TR_L3_HASH_KEY_TYPE_LMEP:
    757                     level_bitmap = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit,
    758                         &l3_entry, LMEP__MDL_BITMAPf);
    759 
    760                     for (level = 0; level < LEVEL_COUNT; ++level)
    761                     {
    762                         if (level_bitmap & (1 << level))
    763                         {
    764                             /* There's an endpoint here at this level */
    765 
    766                             endpoint_p->local_rx_index =
    767                                 soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit,
    768                                     &l3_entry, LMEP__MA_BASE_PTRf) <<
    769                                         LEVEL_BIT_COUNT | level;
    770 
    771                             SOC_IF_ERROR_RETURN(READ_MA_INDEXm(unit,
    772                                 MEM_BLOCK_ANY, endpoint_p->local_rx_index,
    773                                 &ma_index_entry));
    774 
    775                             endpoint_p->in_use = 1;
    776                             endpoint_p->is_remote = 0;
    777                             endpoint_p->local_rx_enabled = 1;
    778 
    779                             endpoint_p->group_index =
    780                                 soc_MA_INDEXm_field32_get(unit,
    781                                     &ma_index_entry, MA_PTRf);
    782 
    783                             /* Name is not used for receive-only endpoints */
    784                             endpoint_p->name = 0xffff;
    785 
    786                             endpoint_p->level = level;
    787 
    788                             endpoint_p->vlan =
    789                                 soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit,
    790                                     &l3_entry, LMEP__VIDf);
    791 
    792                             endpoint_p->glp = 
    793                                 soc_L3_ENTRY_IPV4_UNICASTm_field32_get
    794                                            (unit, &l3_entry, LMEP__SGLPf);
    795 
    796                             SHR_BITSET(oam_info_p->local_rx_endpoints_in_use,
    797                                 endpoint_p->local_rx_index);
    798 
    799                             ++endpoint_p;
    800                         }
    801                     }
    802 
    803                     break;
    804 
    805                 default:
    806                     continue;
    807             }
    808         }
    809     }
    810 
    811     for (lmep_index = 0; lmep_index < oam_info_p->local_tx_endpoint_count;
    812         ++lmep_index)
    813     {
    814         SOC_IF_ERROR_RETURN(READ_LMEPm(unit, MEM_BLOCK_ANY, lmep_index,
    815             &lmep_entry));
    816 
    817         group_index = soc_LMEPm_field32_get(unit,
    818             &lmep_entry, MAID_INDEXf);
    819 
    820         SOC_IF_ERROR_RETURN(READ_MAID_REDUCTIONm(unit,
    821             MEM_BLOCK_ANY, group_index, &maid_reduction_entry));
    822 
    823         if (soc_MAID_REDUCTIONm_field32_get(unit, &maid_reduction_entry, 
    824                                             VALIDf))
    825         {
    826             glp = soc_LMEPm_field32_get(unit, &lmep_entry, DESTf);
    827             vlan = soc_LMEPm_field32_get(unit, &lmep_entry, VLAN_IDf);
    828 
    829             /* Check if a receive entry exists for this LMEP */
    830 
    831             for (epidx = 0; epidx < oam_info_p->endpoint_count; epidx++)
    832             {
    833                 SET_ENDPOINT(epidx);
    834                 if (!endpoint_p->in_use) 
    835                 {
    836                     continue;
    837                 }
    838                 if ((endpoint_p->vlan == vlan) && (endpoint_p->glp == glp) && 
    839                     (endpoint_p->name == 0xffff)) 
    840                 {
    841                     break;
    842                 }
    843             }
    844             if (epidx == oam_info_p->endpoint_count)
    845             {
    846                 /* Receive entry not found - local TX only */ 
    847                 /* Allocate a new ID */
    848                 for (epidx = 0; epidx < oam_info_p->endpoint_count; epidx++)
    849                 {
    850                     SET_ENDPOINT(epidx);
    851                     if (!endpoint_p->in_use) 
    852                     {
    853                         endpoint_p->glp = glp;
    854                         endpoint_p->vlan = vlan;
    855                         break;
    856                     }
    857                 }
    858             }
    859 
    860             endpoint_p->in_use = 1;
    861             endpoint_p->is_remote = 0;
    862             endpoint_p->local_tx_enabled = 1;
    863             endpoint_p->local_tx_index = lmep_index;
    864             endpoint_p->name = soc_LMEPm_field32_get(unit, &lmep_entry,
    865                                                      MEPIDf);
    866             endpoint_p->level = soc_LMEPm_field32_get(unit, &lmep_entry,
    867                 MDLf);
    868             endpoint_p->group_index = group_index;
    869 
    870             SHR_BITSET(oam_info_p->local_tx_endpoints_in_use, lmep_index);
    871 
    872             ++endpoint_p;
    873         }
    874     }
    875 
    876     /* Upgrade case */
    877     if (!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit)
    878         && (stable_size > alloc_size)
    879         && (recovered_ver < BCM_WB_VERSION_1_1)) {
    880 
    881         /* Set scache_handle to OAM module */
    882         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_OAM, 0);
    883 
    884         /* realloc to store max OAM group information */
    885         SOC_IF_ERROR_RETURN(soc_scache_realloc(unit, scache_handle,
    886             alloc_size));
    887     }
    888 
    889     return BCM_E_NONE;
    890 }
    891 /*
    892  * Function:
    893  *      bcm_tr2x_oam_scache_alloc
    894  * Purpose:
    895  *      Allocate memory for OAM module in scache
    896  * Parameters:
    897  *      unit - (IN) Unit number.
    898  * Returns:
    899  *      BCM_E_XXX
    900  * Notes:
    901  */
    902 STATIC int
    903 bcm_tr2x_oam_scache_alloc(int unit)
    904 {
    905     _bcm_oam_info_t *oam_info_p;
    906     soc_scache_handle_t scache_handle;
    907     uint8 *oam_scache;
    908     int alloc_sz = 0;
    909 
    910     SET_OAM_INFO;
    911 
    912     alloc_sz = BCM_OAM_GROUP_NAME_LENGTH * (oam_info_p->group_count);
    913 
    914     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_OAM, 0);
    915     BCM_IF_ERROR_RETURN(_bcm_esw_scache_ptr_get(unit, scache_handle, 1,
    916                         alloc_sz, &oam_scache, BCM_WB_DEFAULT_VERSION, NULL));
    917     return BCM_E_NONE;
    918 }
    919 
    920 #endif /* BCM_WARM_BOOT_SUPPORT */
    921 
    922 static void _bcm_tr2x_oam_free_memory(_bcm_oam_info_t *oam_info_p)
    923 {
    924     sal_free(oam_info_p->remote_endpoints);
    925     sal_free(oam_info_p->remote_endpoints_in_use);
    926     sal_free(oam_info_p->local_rx_endpoints_in_use);
    927     sal_free(oam_info_p->local_tx_endpoints_in_use);
    928     sal_free(oam_info_p->endpoints);
    929     sal_free(oam_info_p->groups);
    930 }
    931 
    932 static void _bcm_tr2x_oam_event_unregister_all(_bcm_oam_info_t *oam_info_p)
    933 {
    934     _bcm_oam_event_handler_t *event_handler_p;
    935     _bcm_oam_event_handler_t *event_handler_to_delete_p;
    936 
    937     event_handler_p = oam_info_p->event_handler_list_p;
    938 
    939     while (event_handler_p != NULL)
    940     {
    941         event_handler_to_delete_p = event_handler_p;
    942         event_handler_p = event_handler_p->next_p;
    943 
    944         sal_free(event_handler_to_delete_p);
    945     }
    946     oam_info_p->event_handler_list_p = NULL;
    947 }
    948 
    949 /*
    950  * Function:
    951  *      bcm_tr2x_oam_init
    952  * Purpose:
    953  *      Initialize the OAM subsystem
    954  * Parameters:
    955  *      unit - (IN) Unit number.
    956  * Returns:
    957  *      BCM_E_XXX
    958  * Notes:
    959  */
    960 int 
    961 bcm_tr2x_oam_init(
    962     int unit)
    963 {
    964     _bcm_oam_info_t *oam_info_p;
    965     bcm_oam_endpoint_t endpoint_index;
    966     bcm_port_t port_index;
    967     uint32 register_value;
    968     int result;
    969 
    970     SET_OAM_INFO;
    971 
    972     if (oam_info_p->initialized)
    973     {
    974         /* Reset everything */
    975 
    976         _bcm_tr2x_oam_event_unregister_all(oam_info_p);
    977 
    978         BCM_IF_ERROR_RETURN(bcm_tr2x_oam_group_destroy_all(unit));
    979         _bcm_tr2x_oam_free_memory(oam_info_p);
    980     }
    981 
    982     oam_info_p->group_count = soc_mem_index_count(unit, MA_STATEm);
    983 
    984     oam_info_p->groups =
    985         _bcm_tr2x_oam_alloc_clear(oam_info_p->group_count *
    986             sizeof(_bcm_oam_group_t), "_bcm_oam_group");
    987 
    988     if (oam_info_p->groups == NULL)
    989     {
    990         return BCM_E_MEMORY;
    991     }
    992 
    993     oam_info_p->remote_endpoint_count = soc_mem_index_count(unit, RMEPm);
    994     oam_info_p->local_tx_endpoint_count = soc_mem_index_count(unit, LMEPm);
    995 
    996     oam_info_p->local_rx_endpoint_count =
    997         soc_mem_index_count(unit, MA_INDEXm);
    998 
    999     oam_info_p->endpoint_count = oam_info_p->remote_endpoint_count +
   1000         oam_info_p->local_tx_endpoint_count +
   1001         oam_info_p->local_rx_endpoint_count;
   1002 
   1003     oam_info_p->endpoints =
   1004         _bcm_tr2x_oam_alloc_clear(oam_info_p->endpoint_count *
   1005             sizeof(_bcm_oam_endpoint_t), "_bcm_oam_endpoint");
   1006 
   1007     if (oam_info_p->endpoints == NULL)
   1008     {
   1009         _bcm_tr2x_oam_free_memory(oam_info_p);
   1010 
   1011         return BCM_E_MEMORY;
   1012     }
   1013 
   1014     oam_info_p->local_tx_endpoints_in_use =
   1015         _bcm_tr2x_oam_alloc_clear(SHR_BITALLOCSIZE(oam_info_p->
   1016             local_tx_endpoint_count),
   1017         "local_tx_endpoints_in_use");
   1018 
   1019     if (oam_info_p->local_tx_endpoints_in_use == NULL)
   1020     {
   1021         _bcm_tr2x_oam_free_memory(oam_info_p);
   1022 
   1023         return BCM_E_MEMORY;
   1024     }
   1025 
   1026     oam_info_p->local_rx_endpoints_in_use =
   1027         _bcm_tr2x_oam_alloc_clear(SHR_BITALLOCSIZE(oam_info_p->
   1028             local_rx_endpoint_count),
   1029         "local_rx_endpoints_in_use");
   1030 
   1031     if (oam_info_p->local_rx_endpoints_in_use == NULL)
   1032     {
   1033         _bcm_tr2x_oam_free_memory(oam_info_p);
   1034 
   1035         return BCM_E_MEMORY;
   1036     }
   1037 
   1038     oam_info_p->remote_endpoints_in_use =
   1039         _bcm_tr2x_oam_alloc_clear(SHR_BITALLOCSIZE(oam_info_p->
   1040             remote_endpoint_count),
   1041         "remote_endpoints_in_use");
   1042 
   1043     if (oam_info_p->remote_endpoints_in_use == NULL)
   1044     {
   1045         _bcm_tr2x_oam_free_memory(oam_info_p);
   1046 
   1047         return BCM_E_MEMORY;
   1048     }
   1049 
   1050     oam_info_p->remote_endpoints =
   1051         sal_alloc(oam_info_p->remote_endpoint_count *
   1052             sizeof(bcm_oam_endpoint_t), "rmep reverse lookup");
   1053 
   1054     if (oam_info_p->remote_endpoints == NULL)
   1055     {
   1056         _bcm_tr2x_oam_free_memory(oam_info_p);
   1057 
   1058         return BCM_E_MEMORY;
   1059     }
   1060 
   1061     for (endpoint_index = 0;
   1062         endpoint_index < oam_info_p->remote_endpoint_count;
   1063         ++endpoint_index)
   1064     {
   1065         oam_info_p->remote_endpoints[endpoint_index] =
   1066             BCM_OAM_ENDPOINT_INVALID;
   1067     }
   1068 
   1069     soc_triumph2_oam_handler_register(unit, _bcm_tr2x_oam_handle_interrupt);
   1070     soc_triumph2_oam_ser_handler_register(unit, _bcm_tr2x_oam_ser_handler);
   1071 
   1072 #ifdef BCM_WARM_BOOT_SUPPORT
   1073     if (!SOC_WARM_BOOT(unit)) {
   1074         bcm_tr2x_oam_scache_alloc(unit);
   1075     }
   1076     if (SOC_WARM_BOOT(unit))
   1077     {
   1078         result = _bcm_oam_warm_boot(unit);
   1079         if (BCM_FAILURE(result)) {
   1080             soc_triumph2_oam_handler_register(unit, NULL);
   1081             _bcm_tr2x_oam_free_memory(oam_info_p);
   1082             return (BCM_E_INTERNAL);
   1083         }
   1084     }
   1085     else
   1086 #endif /* BCM_WARM_BOOT_SUPPORT */
   1087     {
   1088         /* Enable OAM message reception on all ports */
   1089 
   1090         PBMP_ALL_ITER(unit, port_index)
   1091         {
   1092             result = bcm_esw_port_control_set(unit, port_index,
   1093                                      bcmPortControlOAMEnable, 1);
   1094             if (BCM_FAILURE(result)) {
   1095                 soc_triumph2_oam_handler_register(unit, NULL);
   1096                 soc_triumph2_oam_ser_handler_register(unit, NULL);
   1097                 _bcm_tr2x_oam_free_memory(oam_info_p);
   1098                 return (result);
   1099             }
   1100 
   1101         }
   1102 
   1103         /* Enable CCM reception timeouts */
   1104 
   1105         register_value = 0;
   1106 
   1107         soc_reg_field_set(unit, OAM_TIMER_CONTROLr, &register_value,
   1108             TIMER_ENABLEf, 1);
   1109 
   1110         soc_reg_field_set(unit, OAM_TIMER_CONTROLr, &register_value,
   1111             CLK_GRANf, 1);
   1112 
   1113         result = WRITE_OAM_TIMER_CONTROLr(unit, register_value);
   1114 
   1115         if (SOC_FAILURE(result))
   1116         {
   1117             _bcm_tr2x_oam_free_memory(oam_info_p);
   1118 
   1119             return result;
   1120         }
   1121 
   1122         /* Common information for outgoing CCM packets */
   1123 
   1124         result = WRITE_LMEP_COMMON_1r(unit, _BCM_OAM_MAC_DA_UPPER_32);
   1125 
   1126         if (SOC_FAILURE(result))
   1127         {
   1128             _bcm_tr2x_oam_free_memory(oam_info_p);
   1129 
   1130             return result;
   1131         }
   1132 
   1133         /* Enable CCM transmission */
   1134 
   1135         register_value = 0;
   1136 
   1137         soc_reg_field_set(unit, OAM_TX_CONTROLr, &register_value,
   1138             TX_ENABLEf, 1);
   1139 
   1140         soc_reg_field_set(unit, OAM_TX_CONTROLr, &register_value,
   1141             CMIC_BUF_ENABLEf, 1);
   1142 
   1143         result = WRITE_OAM_TX_CONTROLr(unit, register_value);
   1144 
   1145         if (SOC_FAILURE(result))
   1146         {
   1147             _bcm_tr2x_oam_free_memory(oam_info_p);
   1148 
   1149             return result;
   1150         }
   1151 
   1152         register_value = 0;
   1153 
   1154         soc_reg_field_set(unit, LMEP_COMMON_2r, &register_value,
   1155             DA_15_3f, _BCM_OAM_MAC_DA_LOWER_13 >> 3);
   1156 
   1157         soc_reg_field_set(unit, LMEP_COMMON_2r, &register_value,
   1158             L3f, 1);
   1159 
   1160         result = WRITE_LMEP_COMMON_2r(unit, register_value);
   1161 
   1162         if (SOC_FAILURE(result))
   1163         {
   1164             _bcm_tr2x_oam_free_memory(oam_info_p);
   1165 
   1166             return result;
   1167         }
   1168     }
   1169 
   1170     oam_info_p->initialized = 1;
   1171 
   1172     return BCM_E_NONE;
   1173 }
   1174 
   1175 /*
   1176  * Function:
   1177  *      bcm_tr2x_oam_detach
   1178  * Purpose:
   1179  *      Shut down the OAM subsystem
   1180  * Parameters:
   1181  *      unit - (IN) Unit number.
   1182  * Returns:
   1183  *      BCM_E_XXX
   1184  * Notes:
   1185  */
   1186 int 
   1187 bcm_tr2x_oam_detach(
   1188     int unit)
   1189 {
   1190     _bcm_oam_info_t *oam_info_p;
   1191     bcm_port_t port_index;
   1192 
   1193     SET_OAM_INFO;
   1194 
   1195     if (!oam_info_p->initialized)
   1196     {
   1197         return BCM_E_NONE;
   1198     }
   1199 
   1200     /* Disable CCM transmission */
   1201 
   1202     SOC_IF_ERROR_RETURN(WRITE_OAM_TX_CONTROLr(unit, 0));
   1203 
   1204     /* Disable OAM message reception on all ports */
   1205 
   1206     PBMP_ALL_ITER(unit, port_index)
   1207     {
   1208         BCM_IF_ERROR_RETURN(bcm_esw_port_control_set(unit,
   1209             port_index, bcmPortControlOAMEnable, 0));
   1210     }
   1211 
   1212     soc_triumph2_oam_handler_register(unit, NULL);
   1213 
   1214     _bcm_tr2x_oam_event_unregister_all(oam_info_p);
   1215 
   1216     _bcm_tr2x_oam_free_memory(oam_info_p);
   1217 
   1218     oam_info_p->initialized = 0;
   1219 
   1220     return BCM_E_NONE;
   1221 }
   1222 
   1223 static void _bcm_tr2x_oam_group_name_mangle(uint8 *name_p,
   1224     uint8 *mangled_name_p)
   1225 {
   1226     uint8 *byte_p = name_p + BCM_OAM_GROUP_NAME_LENGTH - 1;
   1227     int bytes_left = BCM_OAM_GROUP_NAME_LENGTH;
   1228 
   1229     while (bytes_left > 0)
   1230     {
   1231         *mangled_name_p = *byte_p;
   1232 
   1233         ++mangled_name_p;
   1234         --byte_p;
   1235         --bytes_left;
   1236     }
   1237 }
   1238 
   1239 /*
   1240  * Function:
   1241  *      bcm_tr2x_oam_group_create
   1242  * Purpose:
   1243  *      Create or replace an OAM group object
   1244  * Parameters:
   1245  *      unit - (IN) Unit number.
   1246  *      group_info - (IN/OUT) Pointer to an OAM group structure
   1247  * Returns:
   1248  *      BCM_E_XXX
   1249  * Notes:
   1250  */
   1251 int 
   1252 bcm_tr2x_oam_group_create(
   1253     int unit, 
   1254     bcm_oam_group_info_t *group_info)
   1255 {
   1256     _bcm_oam_info_t *oam_info_p;
   1257     _bcm_oam_group_t *group_p;
   1258     int replace;
   1259     int group_index;
   1260 	int copy_to_cpu = 0;
   1261     maid_reduction_entry_t maid_reduction_entry;
   1262     ma_state_entry_t ma_state_entry;
   1263     uint8 mangled_group_name[MANGLED_GROUP_NAME_LENGTH];
   1264 
   1265     SET_OAM_INFO;
   1266 
   1267     CHECK_INIT;
   1268 
   1269     replace = group_info->flags & BCM_OAM_GROUP_REPLACE;
   1270 
   1271     if (group_info->flags & BCM_OAM_GROUP_WITH_ID)
   1272     {
   1273         group_index = group_info->id;
   1274 
   1275         VALIDATE_GROUP_INDEX(group_index);
   1276 
   1277         if (!replace && (oam_info_p->groups[group_index].in_use))
   1278         {
   1279             return BCM_E_EXISTS;
   1280         }
   1281     }
   1282     else
   1283     {
   1284         if (replace)
   1285         {
   1286             return BCM_E_PARAM;
   1287         }
   1288 
   1289         for (group_index = 0; group_index < oam_info_p->group_count;
   1290             ++group_index)
   1291         {
   1292             if (!oam_info_p->groups[group_index].in_use)
   1293             {
   1294                 break;
   1295             }
   1296         }
   1297 
   1298         if (group_index >= oam_info_p->group_count)
   1299         {
   1300             return BCM_E_FULL;
   1301         }
   1302 
   1303         group_info->id = group_index;
   1304     }
   1305 
   1306     SET_GROUP(group_index);
   1307 
   1308     sal_memcpy(group_p->name, group_info->name, BCM_OAM_GROUP_NAME_LENGTH);
   1309     /* Store Lowest Alarm Priority */
   1310     group_p->lowest_alarm_priority = group_info->lowest_alarm_priority;
   1311 
   1312     /* MAID_REDUCTION entry */
   1313 
   1314     _bcm_tr2x_oam_group_name_mangle(group_p->name, mangled_group_name);
   1315 
   1316     sal_memset(&maid_reduction_entry, 0, sizeof(maid_reduction_entry_t));
   1317 
   1318     soc_MAID_REDUCTIONm_field32_set(unit, &maid_reduction_entry, REDUCED_MAIDf,
   1319         soc_draco_crc32(mangled_group_name, MANGLED_GROUP_NAME_LENGTH));
   1320 
   1321     soc_MAID_REDUCTIONm_field32_set(unit, &maid_reduction_entry, SW_RDIf,
   1322         (group_info->flags & BCM_OAM_GROUP_REMOTE_DEFECT_TX) ? 1 : 0);
   1323 
   1324 	copy_to_cpu = ((group_info->flags & BCM_OAM_GROUP_COPY_TO_CPU) ? 1 : 0);
   1325 	soc_MAID_REDUCTIONm_field32_set(unit, &maid_reduction_entry,
   1326 										COPY_TO_CPUf, copy_to_cpu);
   1327 
   1328     soc_MAID_REDUCTIONm_field32_set(unit, &maid_reduction_entry, VALIDf, 1);
   1329 
   1330 	
   1331 
   1332     SOC_IF_ERROR_RETURN(WRITE_MAID_REDUCTIONm(unit, MEM_BLOCK_ALL,
   1333         group_index, &maid_reduction_entry));
   1334 
   1335     /* MA_STATE entry */
   1336 
   1337     sal_memset(&ma_state_entry, 0, sizeof(ma_state_entry_t));
   1338 
   1339     if (replace) {
   1340         /* Keep defect status if group is being replaced */
   1341         SOC_IF_ERROR_RETURN(READ_MA_STATEm(unit, MEM_BLOCK_ALL, group_index,
   1342             &ma_state_entry));
   1343     }
   1344 
   1345     soc_MA_STATEm_field32_set(unit, &ma_state_entry, LOWESTALARMPRIf, 
   1346 									group_info->lowest_alarm_priority);
   1347 
   1348     soc_MA_STATEm_field32_set(unit, &ma_state_entry, VALIDf, 1);
   1349 
   1350     SOC_IF_ERROR_RETURN(WRITE_MA_STATEm(unit, MEM_BLOCK_ALL, group_index,
   1351         &ma_state_entry));
   1352 
   1353     /* Local control block */
   1354 
   1355     group_p->in_use = 1;
   1356 
   1357 #ifdef BCM_WARM_BOOT_SUPPORT
   1358     SOC_CONTROL_LOCK(unit);
   1359     SOC_CONTROL(unit)->scache_dirty = 1;
   1360     SOC_CONTROL_UNLOCK(unit);
   1361 #endif
   1362 
   1363     return BCM_E_NONE;
   1364 }
   1365 
   1366 static int _bcm_tr2x_oam_read_clear_faults(int unit, int entry_index,
   1367     _bcm_oam_fault_t *faults, soc_mem_t mem, uint32 *entry_p,
   1368     uint32 *fault_bits_p, uint32 *persistent_fault_bits_p,
   1369     uint32 clear_persistent_fault_bits)
   1370 {
   1371     _bcm_oam_fault_t *fault_p;
   1372     uint32 ccm_read_control_reg_value = 0;
   1373 
   1374     for (fault_p = faults; fault_p->mask != 0; ++fault_p)
   1375     {
   1376         /* Current fault state */
   1377 
   1378         if (soc_mem_field32_get(unit, mem, entry_p,
   1379             fault_p->current_field) != 0)
   1380         {
   1381             *fault_bits_p |= fault_p->mask;
   1382         }
   1383 
   1384         /* Sticky fault state */
   1385 
   1386         if (soc_mem_field32_get(unit, mem, entry_p,
   1387             fault_p->sticky_field) != 0)
   1388         {
   1389             *persistent_fault_bits_p |= fault_p->mask;
   1390 
   1391             /* Clear persistent faults if requested */
   1392 
   1393             if (clear_persistent_fault_bits & fault_p->mask)
   1394             {
   1395                 soc_reg_field_set(unit, CCM_READ_CONTROLr,
   1396                     &ccm_read_control_reg_value, BITS_TO_CLEARf,
   1397                     fault_p->clear_sticky_mask);
   1398             }
   1399         }
   1400     }
   1401 
   1402     /* If any clear bits were set, do the clear now */
   1403 
   1404     if (ccm_read_control_reg_value != 0)
   1405     {
   1406         soc_reg_field_set(unit, CCM_READ_CONTROLr,
   1407             &ccm_read_control_reg_value, ENABLE_CLEARf, 1);
   1408 
   1409 		/*
   1410 		 * MA_STATE table, MEMORYf should be 0.
   1411 		 */
   1412 		if (mem == MA_STATEm) {
   1413 			soc_reg_field_set(unit, CCM_READ_CONTROLr,
   1414 								&ccm_read_control_reg_value, MEMORYf, 0);
   1415 		} else {
   1416 			soc_reg_field_set(unit, CCM_READ_CONTROLr,
   1417 								&ccm_read_control_reg_value, MEMORYf, 1);
   1418 		}
   1419 
   1420         soc_reg_field_set(unit, CCM_READ_CONTROLr,
   1421             &ccm_read_control_reg_value, INDEXf, entry_index);
   1422 
   1423         SOC_IF_ERROR_RETURN(WRITE_CCM_READ_CONTROLr(unit,
   1424             ccm_read_control_reg_value));
   1425     }
   1426 
   1427     return BCM_E_NONE;
   1428 }
   1429 
   1430 static int _bcm_tr2x_oam_get_group(int unit, int group_index,
   1431     _bcm_oam_group_t *group_p, bcm_oam_group_info_t *group_info)
   1432 {
   1433     maid_reduction_entry_t maid_reduction_entry;
   1434     ma_state_entry_t ma_state_entry;
   1435 
   1436     group_info->id = group_index;
   1437 
   1438     if (!(group_info->flags & BCM_OAM_GROUP_GET_FAULTS_ONLY)) {
   1439         sal_memcpy(group_info->name, group_p->name, BCM_OAM_GROUP_NAME_LENGTH);
   1440 
   1441         /* MAID_REDUCTION entry */
   1442 
   1443         SOC_IF_ERROR_RETURN(READ_MAID_REDUCTIONm(unit, MEM_BLOCK_ANY, group_index,
   1444             &maid_reduction_entry));
   1445 
   1446         if (soc_MAID_REDUCTIONm_field32_get(unit, &maid_reduction_entry,
   1447             SW_RDIf) != 0)
   1448         {
   1449             group_info->flags |= BCM_OAM_GROUP_REMOTE_DEFECT_TX;
   1450         }
   1451 
   1452 	    if (soc_MAID_REDUCTIONm_field32_get(unit, &maid_reduction_entry,
   1453             COPY_TO_CPUf) != 0)
   1454         {
   1455             group_info->flags |= BCM_OAM_GROUP_COPY_TO_CPU;
   1456         }
   1457     } else {
   1458          group_info->flags &= ~BCM_OAM_GROUP_GET_FAULTS_ONLY;
   1459     }
   1460     /* MA_STATE entry */
   1461 
   1462     SOC_IF_ERROR_RETURN(READ_MA_STATEm(unit, MEM_BLOCK_ANY, group_index,
   1463         &ma_state_entry));
   1464 
   1465 	/* Get the Lowest Alarm Priority value*/
   1466 	group_info->lowest_alarm_priority = 
   1467 			soc_MA_STATEm_field32_get(unit, &ma_state_entry, LOWESTALARMPRIf);
   1468 
   1469     return _bcm_tr2x_oam_read_clear_faults(unit, group_index, group_faults,
   1470         MA_STATEm, (uint32 *) &ma_state_entry, &group_info->faults,
   1471         &group_info->persistent_faults, group_info->clear_persistent_faults);
   1472 }
   1473 
   1474 /*
   1475  * Function:
   1476  *      bcm_tr2x_oam_group_get
   1477  * Purpose:
   1478  *      Get an OAM group object
   1479  * Parameters:
   1480  *      unit - (IN) Unit number.
   1481  *      group - (IN) The ID of the group object to get
   1482  *      group_info - (OUT) Pointer to an OAM group structure to receive the data
   1483  * Returns:
   1484  *      BCM_E_XXX
   1485  * Notes:
   1486  */
   1487 int 
   1488 bcm_tr2x_oam_group_get(
   1489     int unit, 
   1490     bcm_oam_group_t group, 
   1491     bcm_oam_group_info_t *group_info)
   1492 {
   1493     _bcm_oam_info_t *oam_info_p;
   1494     _bcm_oam_group_t *group_p;
   1495 
   1496     SET_OAM_INFO;
   1497 
   1498     CHECK_INIT;
   1499 
   1500     VALIDATE_GROUP_INDEX(group);
   1501 
   1502     SET_GROUP(group);
   1503 
   1504     if (!group_p->in_use)
   1505     {
   1506         return BCM_E_NOT_FOUND;
   1507     }
   1508 
   1509     return _bcm_tr2x_oam_get_group(unit, group, group_p, group_info);
   1510 }
   1511 
   1512 static int _bcm_tr2x_oam_destroy_group(int unit, int group_index,
   1513     _bcm_oam_group_t *group_p)
   1514 {
   1515     maid_reduction_entry_t maid_reduction_entry;
   1516     ma_state_entry_t ma_state_entry;
   1517 
   1518     /* Remove all associated endpoints */
   1519 
   1520     bcm_tr2x_oam_endpoint_destroy_all(unit, group_index);
   1521 
   1522     /* MAID_REDUCTION entry */
   1523 
   1524     soc_MAID_REDUCTIONm_field32_set(unit, &maid_reduction_entry, VALIDf, 0);
   1525 
   1526     SOC_IF_ERROR_RETURN(WRITE_MAID_REDUCTIONm(unit, MEM_BLOCK_ALL,
   1527         group_index, &maid_reduction_entry));
   1528 
   1529     /* MA_STATE entry */
   1530 
   1531     soc_MA_STATEm_field32_set(unit, &ma_state_entry, VALIDf, 0);
   1532 
   1533     SOC_IF_ERROR_RETURN(WRITE_MA_STATEm(unit, MEM_BLOCK_ALL, group_index,
   1534         &ma_state_entry));
   1535 
   1536     group_p->in_use = 0;
   1537 
   1538 #ifdef BCM_WARM_BOOT_SUPPORT
   1539     SOC_CONTROL_LOCK(unit);
   1540     SOC_CONTROL(unit)->scache_dirty = 1;
   1541     SOC_CONTROL_UNLOCK(unit);
   1542 #endif
   1543 
   1544     return BCM_E_NONE;
   1545 }
   1546 
   1547 /*
   1548  * Function:
   1549  *      bcm_tr2x_oam_group_destroy
   1550  * Purpose:
   1551  *      Destroy an OAM group object.  All OAM endpoints associated
   1552  *      with the group will also be destroyed.
   1553  * Parameters:
   1554  *      unit - (IN) Unit number.
   1555  *      group - (IN) The ID of the OAM group object to destroy
   1556  * Returns:
   1557  *      BCM_E_XXX
   1558  * Notes:
   1559  */
   1560 int 
   1561 bcm_tr2x_oam_group_destroy(
   1562     int unit, 
   1563     bcm_oam_group_t group)
   1564 {
   1565     _bcm_oam_info_t *oam_info_p;
   1566     _bcm_oam_group_t *group_p;
   1567 
   1568     SET_OAM_INFO;
   1569 
   1570     CHECK_INIT;
   1571 
   1572     VALIDATE_GROUP_INDEX(group);
   1573 
   1574     SET_GROUP(group);
   1575 
   1576     if (!group_p->in_use)
   1577     {
   1578         return BCM_E_NOT_FOUND;
   1579     }
   1580 
   1581     return _bcm_tr2x_oam_destroy_group(unit, group, group_p);
   1582 }
   1583 
   1584 /*
   1585  * Function:
   1586  *      bcm_tr2x_oam_group_destroy_all
   1587  * Purpose:
   1588  *      Destroy all OAM group objects.  All OAM endpoints will also be
   1589  *      destroyed.
   1590  * Parameters:
   1591  *      unit - (IN) Unit number.
   1592  * Returns:
   1593  *      BCM_E_XXX
   1594  * Notes:
   1595  */
   1596 int 
   1597 bcm_tr2x_oam_group_destroy_all(
   1598     int unit)
   1599 {
   1600     _bcm_oam_info_t *oam_info_p;
   1601     _bcm_oam_group_t *group_p;
   1602     int group_index;
   1603 
   1604     SET_OAM_INFO;
   1605 
   1606     CHECK_INIT;
   1607 
   1608     for (group_index = 0; group_index < oam_info_p->group_count;
   1609         ++group_index)
   1610     {
   1611         SET_GROUP(group_index);
   1612 
   1613         if (group_p->in_use)
   1614         {
   1615             BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_destroy_group(unit, group_index,
   1616                 group_p));
   1617         }
   1618     }
   1619 
   1620     return BCM_E_NONE;
   1621 }
   1622 
   1623 /*
   1624  * Function:
   1625  *      bcm_tr2x_oam_group_traverse
   1626  * Purpose:
   1627  *      Traverse the entire set of OAM groups, calling a specified
   1628  *      callback for each one
   1629  * Parameters:
   1630  *      unit - (IN) Unit number.
   1631  *      cb - (IN) A pointer to the callback function to call for each OAM group
   1632  *      user_data - (IN) Pointer to user data to supply in the callback
   1633  * Returns:
   1634  *      BCM_E_XXX
   1635  * Notes:
   1636  */
   1637 int 
   1638 bcm_tr2x_oam_group_traverse(
   1639     int unit, 
   1640     bcm_oam_group_traverse_cb cb, 
   1641     void *user_data)
   1642 {
   1643     _bcm_oam_info_t *oam_info_p;
   1644     _bcm_oam_group_t *group_p;
   1645     int group_index;
   1646     bcm_oam_group_info_t group_info;
   1647 
   1648     SET_OAM_INFO;
   1649 
   1650     CHECK_INIT;
   1651 
   1652     if (cb == NULL)
   1653     {
   1654         return BCM_E_PARAM;
   1655     }
   1656 
   1657     for (group_index = 0; group_index < oam_info_p->group_count;
   1658         ++group_index)
   1659     {
   1660         SET_GROUP(group_index);
   1661 
   1662         if (group_p->in_use)
   1663         {
   1664             bcm_oam_group_info_t_init(&group_info);
   1665 
   1666             BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_get_group(unit, group_index,
   1667                 group_p, &group_info));
   1668 
   1669             BCM_IF_ERROR_RETURN(cb(unit, &group_info, user_data));
   1670         }
   1671     }
   1672 
   1673     return BCM_E_NONE;
   1674 }
   1675 
   1676 static int _bcm_tr2x_oam_find_free_endpoint(SHR_BITDCL *endpoints,
   1677     int endpoint_count, int increment, int offset)
   1678 {
   1679     int endpoint_index;
   1680 
   1681     for (endpoint_index = 0; endpoint_index < endpoint_count;
   1682         endpoint_index += increment)
   1683     {
   1684         if (!SHR_BITGET(endpoints, endpoint_index + offset))
   1685         {
   1686             break;
   1687         }
   1688     }
   1689 
   1690     if (endpoint_index >= endpoint_count)
   1691     {
   1692         endpoint_index = _BCM_OAM_INVALID_INDEX;
   1693     }
   1694 
   1695     return endpoint_index + offset;
   1696 }
   1697 
   1698 static void _bcm_tr2x_oam_make_rmep_key(int unit,
   1699     l3_entry_ipv4_unicast_entry_t *l3_key_p, uint16 name, int level, bcm_vlan_t vlan,
   1700     uint32 sglp)
   1701 {
   1702     sal_memset(l3_key_p, 0, sizeof(l3_entry_ipv4_unicast_entry_t));
   1703 
   1704     soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, l3_key_p, RMEP__MEPIDf, name);
   1705     soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, l3_key_p, RMEP__MDLf, level);
   1706     soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, l3_key_p, RMEP__VIDf, vlan);
   1707     soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, l3_key_p, RMEP__SGLPf, sglp);
   1708 
   1709     soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, l3_key_p, KEY_TYPEf,
   1710         TR_L3_HASH_KEY_TYPE_RMEP);
   1711 }
   1712 
   1713 static int _bcm_tr2x_oam_delete_rmep(int unit, _bcm_oam_endpoint_t *endpoint_p)
   1714 {
   1715     _bcm_oam_info_t *oam_info_p;
   1716     l3_entry_ipv4_unicast_entry_t l3_key;
   1717 	rmep_entry_t rmep_entry;
   1718 	ma_state_entry_t ma_state_entry;
   1719 	int some_rmep_ccm_defect_counter = 0;
   1720 	int current_some_rmep_ccm_defect = 0;
   1721 	int some_rdi_defect_counter = 0;
   1722 	int current_some_rdi_defect = 0;
   1723 	int cur_rmep_ccm_defect = 0;
   1724 	int cur_rmep_last_rdi = 0;
   1725 
   1726     SET_OAM_INFO;
   1727 
   1728 	sal_memset(&ma_state_entry, 0, sizeof(ma_state_entry_t));
   1729 	sal_memset(&rmep_entry, 0, sizeof(rmep_entry_t));
   1730 	SOC_IF_ERROR_RETURN(READ_RMEPm(unit, MEM_BLOCK_ANY, endpoint_p->remote_index, 
   1731 									&rmep_entry));
   1732 
   1733 	cur_rmep_ccm_defect = soc_RMEPm_field32_get(unit, &rmep_entry, 
   1734 												CURRENT_RMEP_CCM_DEFECTf);
   1735 	cur_rmep_last_rdi = soc_RMEPm_field32_get(unit, &rmep_entry, 
   1736 												CURRENT_RMEP_LAST_RDIf);
   1737 
   1738 	if (cur_rmep_ccm_defect || cur_rmep_last_rdi) {
   1739 		SOC_IF_ERROR_RETURN(READ_MA_STATEm(unit, MEM_BLOCK_ANY, 
   1740 											endpoint_p->group_index, 
   1741 											&ma_state_entry));
   1742 
   1743 		some_rmep_ccm_defect_counter = soc_MA_STATEm_field32_get(unit,
   1744 																&ma_state_entry, 
   1745 																SOME_RMEP_CCM_DEFECT_COUNTERf);
   1746 		current_some_rmep_ccm_defect = soc_MA_STATEm_field32_get(unit,
   1747 																&ma_state_entry, 
   1748 																CURRENT_SOME_RMEP_CCM_DEFECTf);
   1749 
   1750 		if (cur_rmep_ccm_defect && some_rmep_ccm_defect_counter > 0) {
   1751 			--some_rmep_ccm_defect_counter;
   1752 			soc_MA_STATEm_field32_set(unit, &ma_state_entry, 
   1753 										SOME_RMEP_CCM_DEFECT_COUNTERf,
   1754 										some_rmep_ccm_defect_counter);
   1755 
   1756 			if (some_rmep_ccm_defect_counter == 0) {
   1757 				current_some_rmep_ccm_defect = 0;
   1758 				soc_MA_STATEm_field32_set(unit, &ma_state_entry, 
   1759 										CURRENT_SOME_RMEP_CCM_DEFECTf,
   1760 										current_some_rmep_ccm_defect);
   1761 			}
   1762 		}
   1763 		some_rdi_defect_counter = soc_MA_STATEm_field32_get(unit,
   1764 														&ma_state_entry, 
   1765 														SOME_RDI_DEFECT_COUNTERf);
   1766 		current_some_rdi_defect = soc_MA_STATEm_field32_get(unit,
   1767 														&ma_state_entry,
   1768 														CURRENT_SOME_RDI_DEFECTf);
   1769 		if (cur_rmep_last_rdi && some_rdi_defect_counter > 0) {
   1770 			--some_rdi_defect_counter;
   1771 			soc_MA_STATEm_field32_set(unit, &ma_state_entry,
   1772 										SOME_RDI_DEFECT_COUNTERf,
   1773 										some_rdi_defect_counter);
   1774 			if (some_rdi_defect_counter == 0) {
   1775 				current_some_rdi_defect = 0;
   1776 				soc_MA_STATEm_field32_set(unit, &ma_state_entry,
   1777 											CURRENT_SOME_RDI_DEFECTf,
   1778 											current_some_rdi_defect);
   1779 			}
   1780 		}
   1781 		
   1782 		SOC_IF_ERROR_RETURN(WRITE_MA_STATEm(unit, MEM_BLOCK_ALL,
   1783 											endpoint_p->group_index,
   1784 											&ma_state_entry));
   1785 	}
   1786 
   1787     /* RMEP entry */
   1788 
   1789     SOC_IF_ERROR_RETURN(
   1790     soc_mem_field32_modify(unit, RMEPm, endpoint_p->remote_index, VALIDf, 0));
   1791 
   1792     /* L3 entry */
   1793 
   1794     _bcm_tr2x_oam_make_rmep_key(unit, &l3_key, endpoint_p->name,
   1795         endpoint_p->level, endpoint_p->vlan, endpoint_p->glp);
   1796 
   1797     SOC_IF_ERROR_RETURN(soc_mem_delete(unit, L3_ENTRY_IPV4_UNICASTm,
   1798         MEM_BLOCK_ALL, &l3_key));
   1799 
   1800     /* Local control block */
   1801 
   1802     SHR_BITCLR(oam_info_p->remote_endpoints_in_use, endpoint_p->remote_index);
   1803 
   1804     oam_info_p->remote_endpoints[endpoint_p->remote_index] =
   1805         BCM_OAM_ENDPOINT_INVALID;
   1806 
   1807     return BCM_E_NONE;
   1808 }
   1809 
   1810 static int _bcm_tr2x_oam_find_lmep(int unit, bcm_vlan_t vlan, uint32 sglp,
   1811     int *index_p, l3_entry_ipv4_unicast_entry_t *l3_entry_p)
   1812 {
   1813     l3_entry_ipv4_unicast_entry_t l3_key;
   1814 
   1815     soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_key, LMEP__VIDf, vlan);
   1816 
   1817     soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_key, LMEP__SGLPf, sglp);
   1818 
   1819     soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_key, KEY_TYPEf,
   1820         TR_L3_HASH_KEY_TYPE_LMEP);
   1821 
   1822     return soc_mem_search(unit, L3_ENTRY_IPV4_UNICASTm, MEM_BLOCK_ANY,
   1823         index_p, &l3_key, l3_entry_p, 0);
   1824 }
   1825 
   1826 static int _bcm_tr2x_oam_find_free_local_endpoint_rx_index(int unit,
   1827     SHR_BITDCL *endpoints, int endpoint_count, int increment, int offset,
   1828     _bcm_oam_endpoint_t *endpoint_p)
   1829 {
   1830     int endpoint_index;
   1831     int mdl_set = 0;
   1832     int rv = BCM_E_NONE;
   1833     int l3_index = 0;
   1834     uint32 level_bitmap = 0;
   1835     l3_entry_ipv4_unicast_entry_t l3_entry;
   1836 
   1837     sal_memset(&l3_entry, 0, sizeof(l3_entry_ipv4_unicast_entry_t));
   1838 
   1839     /*
   1840      * Check if an entry already exists for this VLAN + GLP pair.
   1841      */
   1842     L3_LOCK(unit);
   1843     rv = _bcm_tr2x_oam_find_lmep(unit, endpoint_p->vlan, endpoint_p->glp,
   1844              &l3_index, &l3_entry);
   1845     if (rv == BCM_E_NOT_FOUND)
   1846     {
   1847         /*
   1848          * If Entry is NOT found, select a new MA_INDEX for this MDL.
   1849          */
   1850         L3_UNLOCK(unit);
   1851         for (endpoint_index = 0; endpoint_index < endpoint_count;
   1852             endpoint_index += increment)
   1853         {
   1854             SHR_BITTEST_RANGE(endpoints, endpoint_index, increment, mdl_set);
   1855             if (0 == mdl_set)
   1856             {
   1857                 break;
   1858             }
   1859         }
   1860         if (endpoint_index >= endpoint_count)
   1861         {
   1862             return BCM_E_FULL;
   1863         }
   1864         endpoint_p->local_rx_index = (endpoint_index + offset);
   1865         return BCM_E_NONE;
   1866     } else if (rv >= 0) {
   1867         /*
   1868          * If there is a  MATCH, check if this MD level is available at this
   1869          * index. If it's already occupied, report resource error.
   1870          * Else this MD level is available at this index.
   1871          */
   1872         L3_UNLOCK(unit);
   1873         level_bitmap = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, 
   1874                                             &l3_entry, LMEP__MDL_BITMAPf);
   1875         level_bitmap &= (1 << offset);
   1876         if (!level_bitmap) 
   1877         {
   1878             endpoint_p->local_rx_index =
   1879                 ((soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry,
   1880                         LMEP__MA_BASE_PTRf) << 3) | offset);
   1881             return BCM_E_NONE;
   1882         } else {
   1883             return BCM_E_RESOURCE;
   1884         }
   1885     } else {
   1886         /*
   1887          * L3_ENTRY_IPV4_UNICAST table search operation failed.
   1888          */
   1889         L3_UNLOCK(unit);
   1890         return rv;
   1891     }
   1892     return BCM_E_NONE;
   1893 }
   1894 
   1895 static int _bcm_tr2x_oam_delete_lmep(int unit,
   1896     _bcm_oam_endpoint_t *endpoint_p)
   1897 {
   1898     _bcm_oam_info_t *oam_info_p;
   1899     int l3_index;
   1900     l3_entry_ipv4_unicast_entry_t l3_entry;
   1901     uint32 level_bitmap;
   1902     int result = SOC_E_NONE;
   1903     lmep_entry_t lmep_entry;
   1904 
   1905     SET_OAM_INFO;
   1906 
   1907     if (endpoint_p->local_tx_enabled)
   1908     {
   1909         /* LMEP entry */
   1910 
   1911         sal_memset(&lmep_entry, 0, sizeof(lmep_entry_t)); 
   1912         WRITE_LMEPm(unit, MEM_BLOCK_ALL,
   1913          endpoint_p->local_tx_index, &lmep_entry); 
   1914 
   1915         /* Local control block */
   1916 
   1917         SHR_BITCLR(oam_info_p->local_tx_endpoints_in_use,
   1918             endpoint_p->local_tx_index);
   1919     }
   1920 
   1921     if (endpoint_p->local_rx_enabled)
   1922     {
   1923         /* MA_INDEX entry doesn't need to be touched */
   1924 
   1925         /* L3 entry */
   1926 
   1927         L3_LOCK(unit);
   1928 
   1929         if (BCM_SUCCESS(_bcm_tr2x_oam_find_lmep(unit, endpoint_p->vlan,
   1930             endpoint_p->glp, &l3_index, &l3_entry)))
   1931         {
   1932             level_bitmap = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit,
   1933                 &l3_entry, LMEP__MDL_BITMAPf);
   1934 
   1935             level_bitmap &= ~(1 << endpoint_p->level);
   1936 
   1937             if (level_bitmap != 0)
   1938             {
   1939                 /* Still endpoints here at other levels */
   1940 
   1941                 result = soc_mem_field32_modify(unit, L3_ENTRY_IPV4_UNICASTm,
   1942                     l3_index, LMEP__MDL_BITMAPf, level_bitmap);
   1943             }
   1944             else
   1945             {
   1946                 /* No endpoints left here at any level */
   1947 
   1948                 result = soc_mem_field32_modify(unit, L3_ENTRY_IPV4_UNICASTm,
   1949                     l3_index, VALIDf, 0);
   1950             }
   1951         }
   1952 
   1953         L3_UNLOCK(unit);
   1954 
   1955         SOC_IF_ERROR_RETURN(result);
   1956 
   1957         /* Local control block */
   1958 
   1959         SHR_BITCLR(oam_info_p->local_rx_endpoints_in_use,
   1960             endpoint_p->local_rx_index);
   1961     }
   1962 
   1963     return BCM_E_NONE;
   1964 }
   1965 
   1966 static int _bcm_tr2x_oam_destroy_endpoint(int unit,
   1967     _bcm_oam_endpoint_t *endpoint_p)
   1968 {
   1969     if (endpoint_p->is_remote)
   1970     {
   1971         BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_delete_rmep(unit, endpoint_p));
   1972     }
   1973     else
   1974     {
   1975         BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_delete_lmep(unit, endpoint_p));
   1976     }
   1977 
   1978     endpoint_p->in_use = 0;
   1979 
   1980     return BCM_E_NONE;
   1981 }
   1982 
   1983 /*
   1984  * Function:
   1985  *      bcm_tr2x_oam_endpoint_create
   1986  * Purpose:
   1987  *      Create or replace an OAM endpoint object
   1988  * Parameters:
   1989  *      unit - (IN) Unit number.
   1990  *      endpoint_info - (IN/OUT) Pointer to an OAM endpoint structure
   1991  * Returns:
   1992  *      BCM_E_XXX
   1993  * Notes:
   1994  */
   1995 int 
   1996 bcm_tr2x_oam_endpoint_create(
   1997     int unit, 
   1998     bcm_oam_endpoint_info_t *endpoint_info)
   1999 {
   2000     _bcm_oam_info_t *oam_info_p;
   2001     _bcm_oam_group_t *group_p;
   2002     _bcm_oam_endpoint_t *endpoint_p;
   2003     int replace;
   2004     int is_remote;
   2005     int local_tx_enabled = 0;
   2006     int local_rx_enabled = 0;
   2007     int endpoint_index;
   2008     bcm_module_t module_id;
   2009     bcm_port_t port_id;
   2010     bcm_trunk_t trunk_id;
   2011     int local_id;
   2012     rmep_entry_t rmep_entry;
   2013     lmep_entry_t lmep_entry;
   2014     ma_index_entry_t ma_index_entry;
   2015     l3_entry_ipv4_unicast_entry_t l3_entry;
   2016     int quantization_index;
   2017     int l3_index;
   2018     uint32 level_bitmap;
   2019     int result = SOC_E_NONE;
   2020     uint32 oam_current_time;
   2021     int chk_ep_index = 0;
   2022     int rv = BCM_E_NONE;
   2023     uint32 src_glp = _BCM_OAM_INVALID_INDEX;
   2024     uint32 dst_glp = _BCM_OAM_INVALID_INDEX;
   2025     bcm_trunk_member_t *member_array = NULL;
   2026     int member_count;
   2027     bcm_gport_t member_gport;
   2028     bcm_trunk_t tgid_out;
   2029     int id_out;
   2030 
   2031     SET_OAM_INFO;
   2032 
   2033     CHECK_INIT;
   2034 
   2035     VALIDATE_GROUP_INDEX(endpoint_info->group);
   2036 
   2037     if (endpoint_info->level > MAX_ENDPOINT_LEVEL)
   2038     {
   2039         /* Exceeds supported MDL level 0 - 7. */
   2040         return BCM_E_PARAM;
   2041     }
   2042 
   2043     if (endpoint_info->flags & UNSUPPORTED_ENDPOINT_FLAGS)
   2044     {
   2045         /* Invalid endpoint flag bit/s set. */
   2046         return BCM_E_UNAVAIL;
   2047     }
   2048 
   2049     if (endpoint_info->type != bcmOAMEndpointTypeEthernet)
   2050     {
   2051         /* Device supports Ethernet OAM only. */
   2052         return BCM_E_UNAVAIL;
   2053     }
   2054 
   2055     /* Replace operation. */
   2056     replace = (endpoint_info->flags & BCM_OAM_ENDPOINT_REPLACE) ? 1 : 0;
   2057 
   2058     if (endpoint_info->flags & BCM_OAM_ENDPOINT_REMOTE)
   2059     {
   2060         if (endpoint_info->flags &
   2061             (BCM_OAM_ENDPOINT_CCM_RX | BCM_OAM_ENDPOINT_LOOPBACK |
   2062             BCM_OAM_ENDPOINT_DELAY_MEASUREMENT | BCM_OAM_ENDPOINT_LINKTRACE |
   2063             BCM_OAM_ENDPOINT_PORT_STATE_TX |
   2064             BCM_OAM_ENDPOINT_INTERFACE_STATE_TX ))
   2065         {
   2066             /* Specified flags aren't valid for RMEPs */
   2067 
   2068             return BCM_E_PARAM;
   2069         }
   2070 
   2071         is_remote = 1;
   2072     }
   2073     else
   2074     {
   2075         /* Local */
   2076 
   2077         is_remote = 0;
   2078 
   2079         local_tx_enabled = (endpoint_info->ccm_period !=
   2080             BCM_OAM_ENDPOINT_CCM_PERIOD_DISABLED);
   2081 
   2082         local_rx_enabled = ((endpoint_info->flags &
   2083             (BCM_OAM_ENDPOINT_CCM_RX | BCM_OAM_ENDPOINT_LOOPBACK |
   2084             BCM_OAM_ENDPOINT_DELAY_MEASUREMENT |
   2085             BCM_OAM_ENDPOINT_LINKTRACE)) != 0);
   2086     }
   2087 
   2088     if (endpoint_info->flags & BCM_OAM_ENDPOINT_WITH_ID)
   2089     {
   2090         endpoint_index = endpoint_info->id;
   2091 
   2092         VALIDATE_ENDPOINT_INDEX(endpoint_index);
   2093 
   2094         if (replace && (!oam_info_p->endpoints[endpoint_index].in_use))
   2095         {
   2096             return BCM_E_NOT_FOUND;
   2097         }
   2098         else if (!replace && (oam_info_p->endpoints[endpoint_index].in_use))
   2099         {
   2100             return BCM_E_EXISTS;
   2101         }
   2102 
   2103         /*
   2104          * An MA_STATE/group entry is associated with one and only one LMEP
   2105          * If an rx LMEP entry already existed for current group, return error
   2106          */
   2107         for (chk_ep_index = 0; chk_ep_index < oam_info_p->endpoint_count;
   2108             ++chk_ep_index) {
   2109             if (!replace && oam_info_p->endpoints[chk_ep_index].in_use
   2110                 && !is_remote
   2111                 && (oam_info_p->endpoints[chk_ep_index].group_index
   2112                     == endpoint_info->group)
   2113                 && oam_info_p->endpoints[chk_ep_index].local_rx_enabled) {
   2114                 return BCM_E_RESOURCE;
   2115             }
   2116         }
   2117     }
   2118     else
   2119     {
   2120         if (replace)
   2121         {
   2122             /* Replace specified with no ID */
   2123 
   2124             return BCM_E_PARAM;
   2125         }
   2126 
   2127         /*
   2128          * An MA_STATE/group entry is associated with one and only one LMEP
   2129          * If an rx LMEP entry already existed for current group, return error
   2130          */
   2131         for (endpoint_index = 0; endpoint_index < oam_info_p->endpoint_count;
   2132              ++endpoint_index) {
   2133             if (oam_info_p->endpoints[endpoint_index].in_use
   2134                 && !is_remote
   2135                 && (oam_info_p->endpoints[endpoint_index].group_index
   2136                     == endpoint_info->group)
   2137                 && oam_info_p->endpoints[endpoint_index].local_rx_enabled) {
   2138                 return BCM_E_RESOURCE;
   2139             }
   2140         }
   2141 
   2142         for (endpoint_index = 0; endpoint_index < oam_info_p->endpoint_count;
   2143             ++endpoint_index)
   2144         {
   2145             if (!oam_info_p->endpoints[endpoint_index].in_use)
   2146             {
   2147                 break;
   2148             }
   2149         }
   2150 
   2151         if (endpoint_index >= oam_info_p->endpoint_count)
   2152         {
   2153             return BCM_E_FULL;
   2154         }
   2155 
   2156         endpoint_info->id = endpoint_index;
   2157     }
   2158 
   2159     SET_ENDPOINT(endpoint_index);
   2160 
   2161     SET_GROUP(endpoint_info->group);
   2162 
   2163     if (!group_p->in_use)
   2164     {
   2165         /* Associating to a nonexistent group */
   2166 
   2167         return BCM_E_PARAM;
   2168     }
   2169 
   2170     /* Get Trunk ID or (Modid + Port) value from Gport */
   2171     BCM_IF_ERROR_RETURN
   2172         (_bcm_esw_gport_resolve(unit, endpoint_info->gport, &module_id,
   2173                                 &port_id, &trunk_id, &local_id));
   2174 
   2175     /* 
   2176      * If Gport is Trunk type, _bcm_esw_gport_resolve() 
   2177      * sets trunk_id. Using Trunk ID, get Dst Modid and Port value.
   2178      */
   2179     if (BCM_GPORT_IS_TRUNK(endpoint_info->gport)) {
   2180 
   2181         if (BCM_TRUNK_INVALID == trunk_id)  {
   2182             /* Has to be a valid Trunk. */
   2183             return (BCM_E_PARAM);
   2184         }
   2185 
   2186         /* 
   2187          * CCM Tx is enabled on a trunk member port.
   2188          * trunk_index value is required to derive the Modid and Port info.
   2189          */
   2190         if (1 == local_tx_enabled
   2191             && _BCM_OAM_INVALID_INDEX == endpoint_info->trunk_index) {
   2192             /* Invalid Trunk member index passed. */
   2193             return (BCM_E_PORT);
   2194         }
   2195 
   2196         /* Get Trunk Info for the Trunk ID. */
   2197         BCM_IF_ERROR_RETURN
   2198             (bcm_esw_trunk_get(unit, trunk_id, NULL, 0, NULL, &member_count));
   2199         if (0 == member_count) {
   2200             /* No members have been added to the trunk group yet */
   2201             return BCM_E_PARAM;
   2202         }
   2203         member_array = sal_alloc(sizeof(bcm_trunk_member_t) * member_count,
   2204                 "trunk member array");
   2205         if (NULL == member_array) {
   2206             return BCM_E_MEMORY;
   2207         }
   2208         rv = bcm_esw_trunk_get(unit, trunk_id, NULL,
   2209                 member_count, member_array, &member_count);
   2210         if (BCM_FAILURE(rv)) {
   2211             sal_free(member_array);
   2212             return rv;
   2213         }
   2214 
   2215         /* Get the Modid and Port value using Trunk Index value. */
   2216         if (endpoint_info->trunk_index >= member_count) {
   2217             sal_free(member_array);
   2218             return BCM_E_PARAM;
   2219         }
   2220         member_gport = member_array[endpoint_info->trunk_index].gport;
   2221         sal_free(member_array);
   2222         BCM_IF_ERROR_RETURN
   2223             (_bcm_esw_gport_resolve(unit, member_gport, &module_id, &port_id,
   2224                                     &tgid_out, &id_out));
   2225         if ((-1 != tgid_out) || (-1 != id_out)) {
   2226             return BCM_E_PARAM;
   2227         }
   2228 
   2229         /* Calculate the SGLP and DGLP values to program the MEP */
   2230         src_glp = ((1 << SOC_TRUNK_BIT_POS(unit)) | trunk_id);
   2231         dst_glp = (module_id << 6) | port_id;
   2232     }
   2233 
   2234     /* 
   2235      * Application can resolve the trunk and pass the desginated
   2236      * port as Gport value. Check if the Gport belongs to a trunk.
   2237      */
   2238     if ((BCM_TRUNK_INVALID == trunk_id)
   2239         && (BCM_GPORT_IS_MODPORT(endpoint_info->gport)
   2240         || BCM_GPORT_IS_LOCAL(endpoint_info->gport))) {
   2241 
   2242         /* When Gport is ModPort or Port type, _bcm_esw_gport_resolve()
   2243          * returns Modid and Port value. Use these values to make the DGLP
   2244          * value.
   2245          */
   2246         dst_glp = ((module_id << 6) | port_id);
   2247 
   2248         /* Use the Modid, Port value and determine if the port
   2249          * belongs to a Trunk.
   2250          */
   2251         rv = bcm_esw_trunk_find(unit, module_id, port_id, &trunk_id);
   2252         if (BCM_SUCCESS(rv)) {
   2253             /* 
   2254              * Port is member of a valid trunk.
   2255              * Now create the SGLP value from Trunk ID.
   2256              */
   2257             src_glp = (1 << SOC_TRUNK_BIT_POS(unit)) | trunk_id;
   2258         } else {
   2259             /* Port not a member of trunk. DGLP and SGLP are the same. */
   2260             src_glp = dst_glp;
   2261         }
   2262     }
   2263 
   2264     /* 
   2265      * At this point, both src_glp and dst_glp should be valid.
   2266      * Gport types other than TRUNK, MODPORT or LOCAL are not valid.
   2267      */
   2268     if (_BCM_OAM_INVALID_INDEX == src_glp
   2269         || _BCM_OAM_INVALID_INDEX == dst_glp) {
   2270         return (BCM_E_PORT);
   2271     }
   2272 
   2273     if (replace)
   2274     {
   2275         /* Remove anything being replaced from tables */
   2276 
   2277         BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_destroy_endpoint(unit, endpoint_p));
   2278     }
   2279 
   2280     quantization_index = _bcm_tr2x_oam_quantize_ccm_period
   2281                             (endpoint_info->ccm_period);
   2282 
   2283     endpoint_p->is_remote = is_remote;
   2284     endpoint_p->local_tx_enabled = local_tx_enabled;
   2285     endpoint_p->local_rx_enabled = local_rx_enabled;
   2286     endpoint_p->group_index = endpoint_info->group;
   2287     endpoint_p->name = endpoint_info->name;
   2288     endpoint_p->level = endpoint_info->level;
   2289     endpoint_p->vlan = endpoint_info->vlan;
   2290     endpoint_p->glp = src_glp;
   2291     endpoint_p->period = endpoint_info->ccm_period;
   2292 
   2293    if (is_remote)
   2294     {
   2295         endpoint_p->remote_index =
   2296             _bcm_tr2x_oam_find_free_endpoint(oam_info_p->
   2297                 remote_endpoints_in_use,
   2298             oam_info_p->remote_endpoint_count, 1, 0);
   2299 
   2300         if (endpoint_p->remote_index < 0)
   2301         {
   2302             return BCM_E_FULL;
   2303         }
   2304 
   2305         /* RMEP entry */
   2306 
   2307         sal_memset(&rmep_entry, 0, sizeof(rmep_entry_t));
   2308 
   2309         soc_RMEPm_field32_set(unit, &rmep_entry, MAID_INDEXf,
   2310             endpoint_info->group);
   2311 
   2312         /* The following steps are necessary to enable CCM timeout events
   2313            without having received any CCMs */
   2314 
   2315         soc_RMEPm_field32_set(unit, &rmep_entry, RMEP_TIMESTAMP_VALIDf, 1);
   2316 
   2317         BCM_IF_ERROR_RETURN(READ_OAM_CURRENT_TIMEr(unit, &oam_current_time));
   2318 
   2319         soc_RMEPm_field32_set(unit, &rmep_entry, RMEP_TIMESTAMPf,
   2320             oam_current_time);
   2321 
   2322         soc_RMEPm_field32_set(unit, &rmep_entry, RMEP_RECEIVED_CCMf,
   2323             quantization_index);
   2324 
   2325         /* End of timeout setup */
   2326 
   2327         soc_RMEPm_field32_set(unit, &rmep_entry, VALIDf, 1);
   2328 
   2329         SOC_IF_ERROR_RETURN(WRITE_RMEPm(unit, MEM_BLOCK_ALL,
   2330             endpoint_p->remote_index, &rmep_entry));
   2331 
   2332         /* L3 entry */
   2333 
   2334         sal_memset(&l3_entry, 0, sizeof(l3_entry_ipv4_unicast_entry_t));
   2335 
   2336         soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, RMEP__CCMf,
   2337             quantization_index);
   2338 
   2339         soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, RMEP__RMEP_PTRf,
   2340             endpoint_p->remote_index);
   2341 
   2342         soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, RMEP__MEPIDf,
   2343             endpoint_info->name);
   2344 
   2345         soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, RMEP__MDLf,
   2346             endpoint_info->level);
   2347 
   2348         soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, RMEP__VIDf,
   2349             endpoint_info->vlan);
   2350 
   2351         soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, RMEP__SGLPf,
   2352                                                src_glp);
   2353 
   2354         soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, KEY_TYPEf,
   2355             TR_L3_HASH_KEY_TYPE_RMEP);
   2356 
   2357         soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, VALIDf, 1);
   2358 
   2359         SOC_IF_ERROR_RETURN(soc_mem_insert(unit, L3_ENTRY_IPV4_UNICASTm,
   2360             MEM_BLOCK_ALL, &l3_entry));
   2361 
   2362         /* Local control block */
   2363 
   2364         SHR_BITSET(oam_info_p->remote_endpoints_in_use,
   2365             endpoint_p->remote_index);
   2366 
   2367         oam_info_p->remote_endpoints[endpoint_p->remote_index] =
   2368             endpoint_index;
   2369     }
   2370     else
   2371     {
   2372         if (local_tx_enabled)
   2373         {
   2374             uint32 reversed_maid[BCM_OAM_GROUP_NAME_LENGTH / 4];
   2375             int word_index;
   2376 
   2377             endpoint_p->local_tx_index =
   2378                 _bcm_tr2x_oam_find_free_endpoint(oam_info_p->
   2379                     local_tx_endpoints_in_use,
   2380                 oam_info_p->local_tx_endpoint_count, 1, 0);
   2381 
   2382             if (endpoint_p->local_tx_index < 0)
   2383             {
   2384                 return BCM_E_FULL;
   2385             }
   2386 
   2387             /* LMEP entry */
   2388 
   2389             sal_memset(&lmep_entry, 0, sizeof(lmep_entry_t));
   2390 
   2391             soc_LMEPm_field32_set(unit, &lmep_entry, MAID_INDEXf,
   2392                 endpoint_info->group);
   2393 
   2394             soc_LMEPm_mac_addr_set(unit, &lmep_entry, SAf,
   2395                 endpoint_info->src_mac_address);
   2396 
   2397             soc_LMEPm_field32_set(unit, &lmep_entry, MDLf, endpoint_info->level);
   2398             soc_LMEPm_field32_set(unit, &lmep_entry, MEPIDf, endpoint_info->name);
   2399 
   2400             soc_LMEPm_field32_set(unit, &lmep_entry, PRIORITYf,
   2401                 endpoint_info->pkt_pri);
   2402 
   2403             soc_LMEPm_field32_set(unit, &lmep_entry, VLAN_IDf,
   2404                 endpoint_info->vlan);
   2405 
   2406             soc_LMEPm_field32_set(unit, &lmep_entry, CCMf, quantization_index);
   2407             soc_LMEPm_field32_set(unit, &lmep_entry, DESTf, dst_glp);
   2408 
   2409             soc_LMEPm_field32_set(unit, &lmep_entry, MH_OPCODEf,
   2410                 BCM_HG_OPCODE_UC);
   2411 
   2412             soc_LMEPm_field32_set(unit, &lmep_entry, INT_PRIf,
   2413                 endpoint_info->int_pri);
   2414 
   2415             /* Set Port status TLV in CCM Tx packets. */
   2416             if (endpoint_info->flags & BCM_OAM_ENDPOINT_PORT_STATE_UPDATE) {
   2417                 if ((endpoint_info->port_state != BCM_OAM_PORT_TLV_UP)
   2418                     && (endpoint_info->port_state != BCM_OAM_PORT_TLV_BLOCKED)) {
   2419                     return (BCM_E_PARAM);
   2420                 }
   2421                 soc_LMEPm_field32_set(unit, &lmep_entry, PORT_TLVf,
   2422                     (endpoint_info->port_state == BCM_OAM_PORT_TLV_UP)
   2423                      ? 1 : 0);
   2424                 }
   2425                 
   2426             /* Set Interface status TLV in CCM Tx packets - 1-bit wide. */
   2427             if (endpoint_info->flags
   2428                 & BCM_OAM_ENDPOINT_INTERFACE_STATE_UPDATE) {
   2429                 
   2430                 if ((endpoint_info->interface_state
   2431                      != BCM_OAM_INTERFACE_TLV_UP)
   2432                     && (endpoint_info->interface_state
   2433                         != BCM_OAM_INTERFACE_TLV_DOWN)) {
   2434                     return (BCM_E_PARAM);
   2435                 }
   2436                 soc_LMEPm_field32_set(unit, &lmep_entry, INTERFACE_TLVf,
   2437                     (endpoint_info->interface_state
   2438                      == BCM_OAM_INTERFACE_TLV_UP) ? 1: 0);
   2439             }
   2440             
   2441             /*
   2442              * When this bit is '1', both port and interface TLV values are set in
   2443              * CCM Tx packets.
   2444              */
   2445             if ((endpoint_info->flags
   2446                  & BCM_OAM_ENDPOINT_PORT_STATE_TX)
   2447                 || (endpoint_info->flags
   2448                     & BCM_OAM_ENDPOINT_INTERFACE_STATE_TX)) {
   2449                 soc_LMEPm_field32_set(unit, &lmep_entry, INSERT_TLVf, 1);
   2450             }
   2451 
   2452             /* Word-reverse the MAID bytes for the hardware */
   2453 
   2454             for (word_index = 0;
   2455                 word_index < (BCM_OAM_GROUP_NAME_LENGTH / 4);
   2456                 ++word_index)
   2457             {
   2458                 reversed_maid[word_index] =
   2459                     ((uint32 *) group_p->name)
   2460                         [((BCM_OAM_GROUP_NAME_LENGTH / 4) - 1) - word_index];
   2461             }
   2462 
   2463             soc_LMEPm_field_set(unit, &lmep_entry, MAIDf, reversed_maid);
   2464 
   2465             SOC_IF_ERROR_RETURN(WRITE_LMEPm(unit, MEM_BLOCK_ALL,
   2466                 endpoint_p->local_tx_index, &lmep_entry));
   2467 
   2468             /* Local control block */
   2469 
   2470             SHR_BITSET(oam_info_p->local_tx_endpoints_in_use,
   2471                 endpoint_p->local_tx_index);
   2472         }
   2473 
   2474         if (local_rx_enabled)
   2475         {
   2476             rv = _bcm_tr2x_oam_find_free_local_endpoint_rx_index(unit,
   2477                     oam_info_p->local_rx_endpoints_in_use,
   2478                     oam_info_p->local_rx_endpoint_count,
   2479                     8, endpoint_info->level, endpoint_p);
   2480             if (rv != BCM_E_NONE)
   2481             {
   2482                 /*
   2483                  * Clean LMEP TX configuration.
   2484                  */
   2485                 sal_memset(&lmep_entry, 0, sizeof(lmep_entry_t));
   2486                 SOC_IF_ERROR_RETURN(WRITE_LMEPm(unit, MEM_BLOCK_ALL,
   2487                     endpoint_p->local_tx_index, &lmep_entry)); 
   2488                 /*
   2489                  *  Local control block
   2490                  */
   2491                 SHR_BITCLR(oam_info_p->local_tx_endpoints_in_use,
   2492                     endpoint_p->local_tx_index);
   2493                 return rv;
   2494             }
   2495 
   2496             /* MA_INDEX entry */
   2497             sal_memset(&ma_index_entry, 0, sizeof(ma_index_entry));
   2498 
   2499             soc_MA_INDEXm_field32_set(unit, &ma_index_entry, MA_PTRf,
   2500                 endpoint_info->group);
   2501 
   2502             SOC_IF_ERROR_RETURN(WRITE_MA_INDEXm(unit, MEM_BLOCK_ALL,
   2503                 endpoint_p->local_rx_index, &ma_index_entry));
   2504 
   2505             /* L3 entry */
   2506 
   2507             L3_LOCK(unit);
   2508 
   2509             if (BCM_SUCCESS(_bcm_tr2x_oam_find_lmep(unit, endpoint_info->vlan,
   2510                 src_glp, &l3_index, &l3_entry)))
   2511             {
   2512                 /* There's already an entry for this vlan+glp */
   2513 
   2514                 level_bitmap = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry,
   2515                     LMEP__MDL_BITMAPf);
   2516 
   2517                 level_bitmap |= (1 << endpoint_info->level);
   2518 
   2519                 result = soc_mem_field32_modify(unit, L3_ENTRY_IPV4_UNICASTm,
   2520                     l3_index, LMEP__MDL_BITMAPf, level_bitmap);
   2521 
   2522                 L3_UNLOCK(unit);
   2523                 
   2524                 SHR_BITSET(oam_info_p->local_rx_endpoints_in_use,
   2525                     endpoint_p->local_rx_index);
   2526 
   2527                 SOC_IF_ERROR_RETURN(result);
   2528             }
   2529             else
   2530             {
   2531                 /* This is the first entry at this vlan+glp */
   2532 
   2533                 L3_UNLOCK(unit);
   2534 
   2535                 sal_memset(&l3_entry, 0, sizeof(l3_entry_ipv4_unicast_entry_t));
   2536 
   2537                 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry,
   2538                     LMEP__MDL_BITMAPf, 1 << endpoint_info->level);
   2539 
   2540                 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry,
   2541                     LMEP__MA_BASE_PTRf,
   2542                     endpoint_p->local_rx_index >> LEVEL_BIT_COUNT);
   2543 
   2544                 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry,
   2545                     LMEP__DM_ENABLEf, (endpoint_info->flags &
   2546                         BCM_OAM_ENDPOINT_DELAY_MEASUREMENT) ? 1 : 0);
   2547 
   2548                 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry,
   2549                     LMEP__CCM_ENABLEf, (endpoint_info->flags &
   2550                         BCM_OAM_ENDPOINT_CCM_RX) ? 1 : 0);
   2551 
   2552                 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry,
   2553                     LMEP__LB_ENABLEf, (endpoint_info->flags &
   2554                     BCM_OAM_ENDPOINT_LOOPBACK) ? 1 : 0);
   2555 
   2556                 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry,
   2557                     LMEP__LT_ENABLEf, (endpoint_info->flags &
   2558                     BCM_OAM_ENDPOINT_LINKTRACE) ? 1 : 0);
   2559 
   2560                 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, LMEP__VIDf,
   2561                     endpoint_info->vlan);
   2562 
   2563                 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, LMEP__SGLPf,
   2564                     src_glp);
   2565 
   2566                 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, KEY_TYPEf,
   2567                     TR_L3_HASH_KEY_TYPE_LMEP);
   2568 
   2569                 soc_L3_ENTRY_IPV4_UNICASTm_field32_set(unit, &l3_entry, VALIDf, 1);
   2570 
   2571                 SOC_IF_ERROR_RETURN(soc_mem_insert(unit, L3_ENTRY_IPV4_UNICASTm,
   2572                     MEM_BLOCK_ALL, &l3_entry));
   2573 
   2574                 /* Local control block */
   2575 
   2576                 SHR_BITSET(oam_info_p->local_rx_endpoints_in_use,
   2577                     endpoint_p->local_rx_index);
   2578             }
   2579         }
   2580     }
   2581 
   2582     /* Local control block */
   2583 
   2584     endpoint_p->in_use = 1;
   2585 
   2586     return BCM_E_NONE;
   2587 }
   2588 
   2589 static int _bcm_tr2x_oam_get_endpoint(int unit, int endpoint_index,
   2590     _bcm_oam_endpoint_t *endpoint_p, bcm_oam_endpoint_info_t *endpoint_info)
   2591 {
   2592     rmep_entry_t rmep_entry;
   2593     lmep_entry_t lmep_entry;
   2594     l3_entry_ipv4_unicast_entry_t l3_key;
   2595     l3_entry_ipv4_unicast_entry_t l3_entry;
   2596     int l3_index;
   2597     int quantization_index = 0;
   2598     bcm_module_t mod_in, mod_out;
   2599     bcm_port_t port_in, port_out;
   2600     _bcm_gport_dest_t dest;
   2601 
   2602     endpoint_info->id = endpoint_index;
   2603     endpoint_info->group = endpoint_p->group_index;
   2604     endpoint_info->name = endpoint_p->name;
   2605     endpoint_info->level = endpoint_p->level;
   2606     endpoint_info->vlan = endpoint_p->vlan;
   2607 
   2608     if (endpoint_p->is_remote)
   2609     {
   2610         endpoint_info->flags |= BCM_OAM_ENDPOINT_REMOTE;
   2611 
   2612         /* RMEP entry */
   2613 
   2614         SOC_IF_ERROR_RETURN(READ_RMEPm(unit, MEM_BLOCK_ANY,
   2615 										endpoint_p->remote_index, 
   2616 										&rmep_entry)); 
   2617 		
   2618         /* Get endpoint faults and clear presistent faults if Clear is SET */
   2619 		BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_read_clear_faults(unit,
   2620 															endpoint_p->remote_index, 
   2621 															endpoint_faults, 
   2622 															RMEPm, 
   2623 															(uint32 *) &rmep_entry,
   2624 															&endpoint_info->faults,
   2625 															&endpoint_info->persistent_faults,
   2626 															endpoint_info->clear_persistent_faults));
   2627 
   2628 
   2629         if (endpoint_info->flags2 & BCM_OAM_ENDPOINT_FLAGS2_GET_FAULTS_ONLY) {
   2630             endpoint_info->flags2 &= ~BCM_OAM_ENDPOINT_FLAGS2_GET_FAULTS_ONLY;
   2631             return BCM_E_NONE;
   2632         }        
   2633         /* L3 entry */
   2634         _bcm_tr2x_oam_make_rmep_key(unit, &l3_key, endpoint_p->name,
   2635             endpoint_p->level, endpoint_p->vlan, endpoint_p->glp);
   2636 
   2637         if (BCM_FAILURE(soc_mem_search(unit, L3_ENTRY_IPV4_UNICASTm, MEM_BLOCK_ANY,
   2638             &l3_index, &l3_key, &l3_entry, 0)))
   2639         {
   2640             return BCM_E_INTERNAL;
   2641         }
   2642 
   2643         quantization_index = soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry,
   2644             RMEP__CCMf);
   2645     }
   2646     else
   2647     {
   2648         /* Endpoint is local */
   2649 
   2650         if (endpoint_p->local_tx_enabled)
   2651         {
   2652             /* LMEP entry */
   2653 
   2654             SOC_IF_ERROR_RETURN(READ_LMEPm(unit, MEM_BLOCK_ANY,
   2655                 endpoint_p->local_tx_index, &lmep_entry));
   2656 
   2657             soc_LMEPm_mac_addr_get(unit, &lmep_entry, SAf,
   2658                 endpoint_info->src_mac_address);
   2659 
   2660             endpoint_info->pkt_pri = soc_LMEPm_field32_get(unit, &lmep_entry,
   2661                 PRIORITYf);
   2662 
   2663             endpoint_info->int_pri = soc_LMEPm_field32_get(unit, &lmep_entry,
   2664                 INT_PRIf);
   2665 
   2666             quantization_index = soc_LMEPm_field32_get(unit, &lmep_entry,
   2667                 CCMf);
   2668         }
   2669 
   2670         if (endpoint_p->local_rx_enabled)
   2671         {
   2672             /* L3 entry */
   2673 
   2674             if (BCM_FAILURE(_bcm_tr2x_oam_find_lmep(unit, endpoint_p->vlan,
   2675                 endpoint_p->glp, &l3_index, &l3_entry)))
   2676             {
   2677                 return BCM_E_INTERNAL;
   2678             }
   2679 
   2680             if (soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry,
   2681                 LMEP__DM_ENABLEf))
   2682             {
   2683                 endpoint_info->flags |= BCM_OAM_ENDPOINT_DELAY_MEASUREMENT;
   2684             }
   2685 
   2686             if (soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry,
   2687                 LMEP__CCM_ENABLEf))
   2688             {
   2689                 endpoint_info->flags |= BCM_OAM_ENDPOINT_CCM_RX;
   2690             }
   2691 
   2692             if (soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry,
   2693                 LMEP__LB_ENABLEf))
   2694             {
   2695                 endpoint_info->flags |= BCM_OAM_ENDPOINT_LOOPBACK;
   2696             }
   2697 
   2698             if (soc_L3_ENTRY_IPV4_UNICASTm_field32_get(unit, &l3_entry,
   2699                 LMEP__LT_ENABLEf))
   2700             {
   2701                 endpoint_info->flags |= BCM_OAM_ENDPOINT_LINKTRACE;
   2702             }
   2703         }
   2704     }
   2705 
   2706     if (endpoint_p->glp & (1 << 13))
   2707     {
   2708         /* Trunk */
   2709 
   2710         BCM_GPORT_TRUNK_SET(endpoint_info->gport, endpoint_p->glp & 0x7F);
   2711     }
   2712     else
   2713     {
   2714         /* Modport */
   2715 
   2716         mod_in = (endpoint_p->glp & 0x0FC0) >> 6;
   2717         port_in = (endpoint_p->glp & 0x3F);
   2718 
   2719         BCM_IF_ERROR_RETURN
   2720             (_bcm_esw_stk_modmap_map(unit, BCM_STK_MODMAP_GET,
   2721                                      mod_in, port_in, &mod_out, &port_out));
   2722 
   2723         _bcm_gport_dest_t_init(&dest);
   2724         dest.port = port_out;
   2725         dest.modid = mod_out;
   2726         dest.gport_type = BCM_GPORT_TYPE_MODPORT;
   2727         BCM_IF_ERROR_RETURN(
   2728             _bcm_esw_gport_construct(unit, &dest, &(endpoint_info->gport)));
   2729     }
   2730 
   2731 
   2732     endpoint_info->ccm_period = ccm_periods[quantization_index];
   2733 
   2734     return BCM_E_NONE;
   2735 }
   2736 
   2737 /*
   2738  * Function:
   2739  *      bcm_tr2x_oam_endpoint_get
   2740  * Purpose:
   2741  *      Get an OAM endpoint object
   2742  * Parameters:
   2743  *      unit - (IN) Unit number.
   2744  *      endpoint - (IN) The ID of the endpoint object to get
   2745  *      endpoint_info - (OUT) Pointer to an OAM endpoint structure to receive the data
   2746  * Returns:
   2747  *      BCM_E_XXX
   2748  * Notes:
   2749  */
   2750 int 
   2751 bcm_tr2x_oam_endpoint_get(
   2752     int unit, 
   2753     bcm_oam_endpoint_t endpoint, 
   2754     bcm_oam_endpoint_info_t *endpoint_info)
   2755 {
   2756     _bcm_oam_info_t *oam_info_p;
   2757     _bcm_oam_endpoint_t *endpoint_p;
   2758 
   2759     SET_OAM_INFO;
   2760 
   2761     CHECK_INIT;
   2762 
   2763     VALIDATE_ENDPOINT_INDEX(endpoint);
   2764 
   2765     SET_ENDPOINT(endpoint);
   2766 
   2767     if (!endpoint_p->in_use)
   2768     {
   2769         return BCM_E_NOT_FOUND;
   2770     }
   2771 
   2772     return _bcm_tr2x_oam_get_endpoint(unit, endpoint, endpoint_p,
   2773         endpoint_info);
   2774 }
   2775 
   2776 /*
   2777  * Function:
   2778  *      bcm_tr2x_oam_endpoint_destroy
   2779  * Purpose:
   2780  *      Destroy an OAM endpoint object
   2781  * Parameters:
   2782  *      unit - (IN) Unit number.
   2783  *      endpoint - (IN) The ID of the OAM endpoint object to destroy
   2784  * Returns:
   2785  *      BCM_E_XXX
   2786  * Notes:
   2787  */
   2788 int 
   2789 bcm_tr2x_oam_endpoint_destroy(
   2790     int unit, 
   2791     bcm_oam_endpoint_t endpoint)
   2792 {
   2793     _bcm_oam_info_t *oam_info_p;
   2794     _bcm_oam_endpoint_t *endpoint_p;
   2795 
   2796     SET_OAM_INFO;
   2797 
   2798     CHECK_INIT;
   2799 
   2800     VALIDATE_ENDPOINT_INDEX(endpoint);
   2801 
   2802     SET_ENDPOINT(endpoint);
   2803 
   2804     if (!endpoint_p->in_use)
   2805     {
   2806         return BCM_E_NOT_FOUND;
   2807     }
   2808 
   2809     return _bcm_tr2x_oam_destroy_endpoint(unit, endpoint_p);
   2810 }
   2811 
   2812 /*
   2813  * Function:
   2814  *      bcm_tr2x_oam_endpoint_destroy_all
   2815  * Purpose:
   2816  *      Destroy all OAM endpoint objects associated with a given OAM
   2817  *      group
   2818  * Parameters:
   2819  *      unit - (IN) Unit number.
   2820  *      group - (IN) The OAM group whose endpoints should be destroyed
   2821  * Returns:
   2822  *      BCM_E_XXX
   2823  * Notes:
   2824  */
   2825 int 
   2826 bcm_tr2x_oam_endpoint_destroy_all(
   2827     int unit, 
   2828     bcm_oam_group_t group)
   2829 {
   2830     _bcm_oam_info_t *oam_info_p;
   2831     _bcm_oam_endpoint_t *endpoint_p;
   2832     int endpoint_index;
   2833 
   2834     SET_OAM_INFO;
   2835 
   2836     CHECK_INIT;
   2837 
   2838     VALIDATE_GROUP_INDEX(group);
   2839 
   2840     for (endpoint_index = 0; endpoint_index < oam_info_p->endpoint_count;
   2841         ++endpoint_index)
   2842     {
   2843         SET_ENDPOINT(endpoint_index);
   2844 
   2845         if (endpoint_p->in_use && endpoint_p->group_index == group)
   2846         {
   2847             BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_destroy_endpoint(unit,
   2848                 endpoint_p));
   2849         }
   2850     }
   2851 
   2852     return BCM_E_NONE;
   2853 }
   2854 
   2855 /*
   2856  * Function:
   2857  *      bcm_tr2x_oam_endpoint_traverse
   2858  * Purpose:
   2859  *      Traverse the set of OAM endpoints associated with the
   2860  *      specified group, calling a specified callback for each one
   2861  * Parameters:
   2862  *      unit - (IN) Unit number.
   2863  *      group - (IN) The OAM group whose endpoints should be traversed
   2864  *      cb - (IN) A pointer to the callback function to call for each OAM endpoint in the specified group
   2865  *      user_data - (IN) Pointer to user data to supply in the callback
   2866  * Returns:
   2867  *      BCM_E_XXX
   2868  * Notes:
   2869  */
   2870 int 
   2871 bcm_tr2x_oam_endpoint_traverse(
   2872     int unit, 
   2873     bcm_oam_group_t group, 
   2874     bcm_oam_endpoint_traverse_cb cb, 
   2875     void *user_data)
   2876 {
   2877     _bcm_oam_info_t *oam_info_p;
   2878     _bcm_oam_endpoint_t *endpoint_p;
   2879     int endpoint_index;
   2880     bcm_oam_endpoint_info_t endpoint_info;
   2881 
   2882     SET_OAM_INFO;
   2883 
   2884     CHECK_INIT;
   2885 
   2886     VALIDATE_GROUP_INDEX(group);
   2887 
   2888     if (cb == NULL)
   2889     {
   2890         return BCM_E_PARAM;
   2891     }
   2892 
   2893     for (endpoint_index = 0; endpoint_index < oam_info_p->endpoint_count;
   2894         ++endpoint_index)
   2895     {
   2896         SET_ENDPOINT(endpoint_index);
   2897 
   2898         if (endpoint_p->in_use && endpoint_p->group_index == group)
   2899         {
   2900             bcm_oam_endpoint_info_t_init(&endpoint_info);
   2901 
   2902             BCM_IF_ERROR_RETURN(_bcm_tr2x_oam_get_endpoint(unit,
   2903                 endpoint_index, endpoint_p, &endpoint_info));
   2904 
   2905             BCM_IF_ERROR_RETURN(cb(unit, &endpoint_info, user_data));
   2906         }
   2907     }
   2908 
   2909     return BCM_E_NONE;
   2910 }
   2911 
   2912 /*
   2913  * Function:
   2914  *      bcm_tr2x_oam_event_register
   2915  * Purpose:
   2916  *      Register a callback for handling OAM events
   2917  * Parameters:
   2918  *      unit - (IN) Unit number.
   2919  *      event_types - (IN) The set of OAM events for which the specified callback should be called
   2920  *      cb - (IN) A pointer to the callback function to call for the specified OAM events
   2921  *      user_data - (IN) Pointer to user data to supply in the callback
   2922  * Returns:
   2923  *      BCM_E_XXX
   2924  * Notes:
   2925  */
   2926 int 
   2927 bcm_tr2x_oam_event_register(
   2928     int unit, 
   2929     bcm_oam_event_types_t event_types, 
   2930     bcm_oam_event_cb cb, 
   2931     void *user_data)
   2932 {
   2933     _bcm_oam_info_t *oam_info_p;
   2934     uint32 result;
   2935     _bcm_oam_event_handler_t *event_handler_p;
   2936     _bcm_oam_event_handler_t *previous_p = NULL;
   2937     bcm_oam_event_type_t event_type;
   2938     uint32 interrupt_control_register_value;
   2939     int update_interrupt_control = 0;
   2940 
   2941     SET_OAM_INFO;
   2942 
   2943     CHECK_INIT;
   2944 
   2945     if (cb == NULL)
   2946     {
   2947         return BCM_E_PARAM;
   2948     }
   2949 
   2950     /* Check and return error for unsupported events. */
   2951     SHR_BITTEST_RANGE(event_types.w,
   2952                       bcmOAMEventBHHLBTimeout,
   2953                       (bcmOAMEventCount - bcmOAMEventBHHLBTimeout),
   2954                       result);
   2955     if (0 != result) {
   2956         return (BCM_E_PARAM);
   2957     }
   2958 
   2959     SHR_BITTEST_RANGE(event_types.w, 0, bcmOAMEventCount, result);
   2960 
   2961     if (result == 0)
   2962     {
   2963         return BCM_E_PARAM;
   2964     }
   2965 
   2966     for (event_handler_p = oam_info_p->event_handler_list_p;
   2967         event_handler_p != NULL;
   2968         event_handler_p = event_handler_p->next_p)
   2969     {
   2970         if (event_handler_p->cb == cb)
   2971         {
   2972             break;
   2973         }
   2974 
   2975         previous_p = event_handler_p;
   2976     }
   2977 
   2978     if (event_handler_p == NULL)
   2979     {
   2980         /* This handler hasn't been registered yet */
   2981 
   2982         event_handler_p = sal_alloc(sizeof(_bcm_oam_event_handler_t),
   2983             "OAM event handler");
   2984 
   2985         if (event_handler_p == NULL)
   2986         {
   2987             return BCM_E_MEMORY;
   2988         }
   2989 
   2990         event_handler_p->next_p = NULL;
   2991         event_handler_p->cb = cb;
   2992 
   2993         SHR_BITCLR_RANGE(event_handler_p->event_types.w, 0, bcmOAMEventCount);
   2994 
   2995         if (previous_p != NULL)
   2996         {
   2997             previous_p->next_p = event_handler_p;
   2998         }
   2999         else
   3000         {
   3001             oam_info_p->event_handler_list_p = event_handler_p;
   3002         }
   3003     }
   3004 
   3005     SOC_IF_ERROR_RETURN(READ_CCM_INTERRUPT_CONTROLr(unit,
   3006         &interrupt_control_register_value));
   3007 
   3008     for (event_type = 0; event_type < bcmOAMEventCount; ++event_type)
   3009     {
   3010         if (SHR_BITGET(event_types.w, event_type))
   3011         {
   3012             if (interrupt_enable_fields[event_type] == INVALIDf)
   3013             {
   3014                 return BCM_E_PARAM;
   3015             }
   3016 
   3017             if (!SHR_BITGET(event_handler_p->event_types.w, event_type))
   3018             {
   3019                 /* This handler isn't handling this event yet */
   3020 
   3021                 SHR_BITSET(event_handler_p->event_types.w, event_type);
   3022 
   3023                 ++(oam_info_p->event_handler_count[event_type]);
   3024 
   3025                 if (oam_info_p->event_handler_count[event_type] == 1)
   3026                 {
   3027                     /* This is the first handler for this event */
   3028 
   3029                     update_interrupt_control = 1;
   3030 
   3031                     soc_reg_field_set(unit, CCM_INTERRUPT_CONTROLr,
   3032                         &interrupt_control_register_value,
   3033                         interrupt_enable_fields[event_type], 1);
   3034                 }
   3035             }
   3036         }
   3037     }
   3038 
   3039     event_handler_p->user_data = user_data;
   3040 
   3041     /* Enable any needed interrupts not yet enabled */
   3042 
   3043     if (update_interrupt_control)
   3044     {
   3045         SOC_IF_ERROR_RETURN(WRITE_CCM_INTERRUPT_CONTROLr(unit,
   3046             interrupt_control_register_value));
   3047     }
   3048 
   3049     return BCM_E_NONE;
   3050 }
   3051 
   3052 /*
   3053  * Function:
   3054  *      bcm_tr2x_oam_event_unregister
   3055  * Purpose:
   3056  *      Unregister a callback for handling OAM events
   3057  * Parameters:
   3058  *      unit - (IN) Unit number.
   3059  *      event_types - (IN) The set of OAM events for which the specified callback should not be called
   3060  *      cb - (IN) A pointer to the callback function to unregister from the specified OAM events
   3061  * Returns:
   3062  *      BCM_E_XXX
   3063  * Notes:
   3064  */
   3065 int 
   3066 bcm_tr2x_oam_event_unregister(
   3067     int unit, 
   3068     bcm_oam_event_types_t event_types, 
   3069     bcm_oam_event_cb cb)
   3070 {
   3071      _bcm_oam_info_t *oam_info_p;
   3072     uint32 result;
   3073     _bcm_oam_event_handler_t *event_handler_p;
   3074     _bcm_oam_event_handler_t *previous_p = NULL;
   3075     bcm_oam_event_type_t event_type;
   3076     uint32 interrupt_control_register_value;
   3077     int update_interrupt_control = 0;
   3078 
   3079     SET_OAM_INFO;
   3080 
   3081     CHECK_INIT;
   3082 
   3083     if (cb == NULL)
   3084     {
   3085         return BCM_E_PARAM;
   3086     }
   3087 
   3088     SHR_BITTEST_RANGE(event_types.w, 0, bcmOAMEventCount, result);
   3089 
   3090     if (result == 0)
   3091     {
   3092         return BCM_E_PARAM;
   3093     }
   3094 
   3095     for (event_handler_p = oam_info_p->event_handler_list_p;
   3096         event_handler_p != NULL;
   3097         event_handler_p = event_handler_p->next_p)
   3098     {
   3099         if (event_handler_p->cb == cb)
   3100         {
   3101             break;
   3102         }
   3103 
   3104         previous_p = event_handler_p;
   3105     }
   3106 
   3107     if (event_handler_p == NULL)
   3108     {
   3109         return BCM_E_NOT_FOUND;
   3110     }
   3111 
   3112     SOC_IF_ERROR_RETURN(READ_CCM_INTERRUPT_CONTROLr(unit,
   3113         &interrupt_control_register_value));
   3114 
   3115     for (event_type = 0; event_type < bcmOAMEventCount; ++event_type)
   3116     {
   3117         if (SHR_BITGET(event_types.w, event_type))
   3118         {
   3119             if (interrupt_enable_fields[event_type] == INVALIDf)
   3120             {
   3121                 return BCM_E_UNAVAIL;
   3122             }
   3123             if (oam_info_p->event_handler_count[event_type] > 0 &&
   3124                 SHR_BITGET(event_handler_p->event_types.w, event_type))
   3125             {
   3126                 /* This handler has been handling this event */
   3127 
   3128                 SHR_BITCLR(event_handler_p->event_types.w, event_type);
   3129 
   3130                 --(oam_info_p->event_handler_count[event_type]);
   3131 
   3132                 if (oam_info_p->event_handler_count[event_type] == 0)
   3133                 {
   3134                     /* No more handlers for this event */
   3135 
   3136                     update_interrupt_control = 1;
   3137 
   3138                     soc_reg_field_set(unit, CCM_INTERRUPT_CONTROLr,
   3139                         &interrupt_control_register_value,
   3140                         interrupt_enable_fields[event_type], 0);
   3141                 }
   3142             }
   3143         }
   3144     }
   3145 
   3146     /* Disable any interrupts that lost their last handler */
   3147 
   3148     if (update_interrupt_control)
   3149     {
   3150         SOC_IF_ERROR_RETURN(WRITE_CCM_INTERRUPT_CONTROLr(unit,
   3151             interrupt_control_register_value));
   3152     }
   3153 
   3154     SHR_BITTEST_RANGE(event_handler_p->event_types.w, 0, bcmOAMEventCount,
   3155         result);
   3156 
   3157     if (result == 0)
   3158     {
   3159         /* No more events for this handler to handle */
   3160 
   3161         if (previous_p != NULL)
   3162         {
   3163             previous_p->next_p = event_handler_p->next_p;
   3164         }
   3165         else
   3166         {
   3167             oam_info_p->event_handler_list_p = event_handler_p->next_p;
   3168         }
   3169 
   3170         sal_free(event_handler_p);
   3171     }
   3172 
   3173     return BCM_E_NONE;
   3174 }
   3175 
   3176 #if defined(BCM_WARM_BOOT_SUPPORT)
   3177 int _bcm_tr2x_oam_sync(int unit)
   3178 {
   3179     _bcm_oam_info_t *oam_info_p;
   3180     _bcm_oam_group_t *group_p;
   3181     int allocation_size = 0;
   3182     int group_index;
   3183     int stable_size;
   3184     soc_scache_handle_t scache_handle;
   3185     uint8 *group_names_p;
   3186     int rv = BCM_E_INTERNAL;
   3187 
   3188     SET_OAM_INFO;
   3189 
   3190     CHECK_INIT;
   3191 
   3192     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   3193     if (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit) || (stable_size == 0)) {
   3194         return BCM_E_NONE;
   3195     }
   3196 
   3197     /* Calculate memory size required to store group names on this device */
   3198     allocation_size = (oam_info_p->group_count
   3199                                 * (BCM_OAM_GROUP_NAME_LENGTH));
   3200 
   3201     /* Set OAM module scache handle */
   3202     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_OAM, 0);
   3203 
   3204     /* Check if memory has already been allocated */
   3205     rv = _bcm_esw_scache_ptr_get(unit, scache_handle, 0, allocation_size,
   3206                                  &group_names_p, BCM_WB_DEFAULT_VERSION,
   3207                                  NULL);
   3208     if (!SOC_WARM_BOOT(unit) && (BCM_E_NOT_FOUND == rv)) {
   3209         /* Allocate scache memory as it has not been allocated */
   3210         BCM_IF_ERROR_RETURN(_bcm_esw_scache_ptr_get(unit, scache_handle, 1,
   3211                                                     allocation_size,
   3212                                                     &group_names_p,
   3213                                                     BCM_WB_DEFAULT_VERSION,
   3214                                                     NULL));
   3215         if (group_names_p == NULL) {
   3216             return BCM_E_MEMORY;
   3217         }
   3218     }
   3219 
   3220     /* Save group names in the scache memory */
   3221     for (group_index = 0; group_index < oam_info_p->group_count;
   3222         ++group_index)
   3223     {
   3224         SET_GROUP(group_index);
   3225 
   3226         if (group_p->in_use)
   3227         {
   3228             sal_memcpy(group_names_p, group_p->name, BCM_OAM_GROUP_NAME_LENGTH);
   3229 
   3230             group_names_p += BCM_OAM_GROUP_NAME_LENGTH;
   3231         }
   3232     }
   3233 
   3234     return BCM_E_NONE;
   3235 }
   3236 #endif /* BCM_WARM_BOOT_SUPPORT */
   3237 
   3238 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP
   3239 /*
   3240  * Function:
   3241  *     _bcm_oam_sw_dump
   3242  * Purpose:
   3243  *     Displays oam information maintained by software.
   3244  * Parameters:
   3245  *     unit - Device unit number
   3246  * Returns:
   3247  *     None
   3248  */
   3249 void
   3250 _bcm_tr2x_oam_sw_dump(int unit)
   3251 {
   3252     _bcm_oam_info_t *oam_info_p;
   3253     _bcm_oam_endpoint_t *endpoint_p;
   3254     int group_idx, endpoint_idx;
   3255     SHR_BITDCL word;
   3256 
   3257     SET_OAM_INFO;
   3258 
   3259     LOG_CLI((BSL_META_U(unit,
   3260                         "\nSW Information OAM - Unit %d\n"), unit));
   3261     LOG_CLI((BSL_META_U(unit,
   3262                         "  Group Info    : \n")));
   3263     
   3264     for (group_idx = 0; group_idx < oam_info_p->group_count; group_idx++) {
   3265         if (oam_info_p->groups[group_idx].in_use) {
   3266             LOG_CLI((BSL_META_U(unit,
   3267                                 "Group %d is in use\n"), group_idx));
   3268         }
   3269     }
   3270 
   3271     LOG_CLI((BSL_META_U(unit,
   3272                         "\n local_tx_endpoints_in_use \n")));
   3273     for (word = 0; word < _SHR_BITDCLSIZE
   3274          (oam_info_p->local_tx_endpoint_count); word++) {
   3275         LOG_CLI((BSL_META_U(unit,
   3276                             " word %d value %x "), word, 
   3277                  oam_info_p->local_tx_endpoints_in_use[word]));
   3278     }
   3279 
   3280     LOG_CLI((BSL_META_U(unit,
   3281                         "\n local_rx_endpoints_in_use \n")));
   3282     for (word = 0; word < _SHR_BITDCLSIZE
   3283          (oam_info_p->local_rx_endpoint_count); word++) {
   3284         LOG_CLI((BSL_META_U(unit,
   3285                             " word %d value %x "), word, 
   3286                  oam_info_p->local_rx_endpoints_in_use[word]));
   3287     }
   3288 
   3289     LOG_CLI((BSL_META_U(unit,
   3290                         "\n remote_endpoints_in_use \n")));
   3291     for (word = 0; word < _SHR_BITDCLSIZE
   3292          (oam_info_p->remote_endpoint_count); word++) {
   3293         LOG_CLI((BSL_META_U(unit,
   3294                             " word %d value %x "), word, 
   3295                  oam_info_p->remote_endpoints_in_use[word]));
   3296     }
   3297 
   3298     LOG_CLI((BSL_META_U(unit,
   3299                         "\n Reverse RMEP lookup \n")));
   3300     for (endpoint_idx = 0; endpoint_idx < oam_info_p->remote_endpoint_count; 
   3301          endpoint_idx++) {
   3302         if (oam_info_p->endpoints
   3303             [oam_info_p->remote_endpoints[endpoint_idx]].in_use) {
   3304             LOG_CLI((BSL_META_U(unit,
   3305                                 "RMEP %x \n"), 
   3306                      oam_info_p->remote_endpoints[endpoint_idx]));
   3307         } 
   3308     }
   3309 
   3310     LOG_CLI((BSL_META_U(unit,
   3311                         "\n Endpoint Information \n")));
   3312     for (endpoint_idx = 0; endpoint_idx < oam_info_p->endpoint_count; 
   3313          endpoint_idx++) {
   3314         SET_ENDPOINT(endpoint_idx);
   3315         if (!endpoint_p->in_use) {
   3316             continue;
   3317         }
   3318         LOG_CLI((BSL_META_U(unit,
   3319                             "\n Endpoint index %d\n"), endpoint_idx));
   3320         LOG_CLI((BSL_META_U(unit,
   3321                             "\t Group index %d\n"), endpoint_p->group_index));
   3322         LOG_CLI((BSL_META_U(unit,
   3323                             "\t Name %x\n"), endpoint_p->name));
   3324         LOG_CLI((BSL_META_U(unit,
   3325                             "\t Level %d\n"), endpoint_p->level));
   3326         LOG_CLI((BSL_META_U(unit,
   3327                             "\t VLAN %d\n"), endpoint_p->vlan));
   3328         LOG_CLI((BSL_META_U(unit,
   3329                             "\t GLP %x\n"), endpoint_p->glp));
   3330         LOG_CLI((BSL_META_U(unit,
   3331                             "\t local_tx_enabled %d\n"), endpoint_p->local_tx_enabled));
   3332         LOG_CLI((BSL_META_U(unit,
   3333                             "\t local_rx_enabled %d\n"), endpoint_p->local_rx_enabled));
   3334         LOG_CLI((BSL_META_U(unit,
   3335                             "\t remote_index %d\n"), endpoint_p->remote_index));
   3336         LOG_CLI((BSL_META_U(unit,
   3337                             "\t local_tx_index %d\n"), endpoint_p->local_tx_index));
   3338         LOG_CLI((BSL_META_U(unit,
   3339                             "\t local_rx_index %d\n"), endpoint_p->local_rx_index));
   3340     }
   3341     return;
   3342 }
   3343 #endif
   3344 #endif /* defined(BCM_TRIUMPH2_SUPPORT) || defined(BCM_APOLLO_SUPPORT) || \
   3345           defined(BCM_VALKYRIE2_SUPPORT)*/