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

switch.c (45799B)


      1 /*
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * Module : Switch
      8  *
      9  * Purpose:
     10  * Aggregation Monitor Management.
     11  */
     12 
     13 #include <soc/defs.h>
     14 #include <sal/core/libc.h>
     15 
     16 #if defined(BCM_TOMAHAWK_SUPPORT)
     17 #include <soc/drv.h>
     18 #include <soc/scache.h>
     19 #include <soc/debug.h>
     20 #include <soc/tomahawk.h>
     21 #include <soc/iproc.h>
     22 
     23 #include <bcm/debug.h>
     24 #include <bcm/error.h>
     25 #include <bcm/time.h>
     26 
     27 #include <bcm_int/esw/mbcm.h>
     28 #include <bcm_int/esw/tomahawk.h>
     29 #include <bcm_int/esw/switch.h>
     30 #include <bcm_int/esw/flex_ctr.h>
     31 #include <bcm_int/esw_dispatch.h>
     32 
     33 /* Definitions */
     34 
     35 #define AGM_CHECK(unit, agm_id) \
     36 	if ((agm_id) < AGM_CNTL(unit).agm_id_min || (agm_id) > AGM_CNTL(unit).agm_id_max) \
     37         { return BCM_E_PARAM; }
     38 #define AGM_LOCK(unit)        soc_mem_lock(unit, AGM_MONITOR_TABLEm)
     39 #define AGM_UNLOCK(unit)      soc_mem_unlock(unit, AGM_MONITOR_TABLEm)
     40 
     41 /* Data structure */
     42 typedef struct agm_cntl_s {
     43     int             agm_id_min;
     44     int             agm_id_max;
     45     int             agm_period_max;
     46     int             agm_timer_id;
     47     int             agm_pool_conf[_AGM_POOL_ID_CNT];
     48     agm_monitor_t   *agm_info;
     49 } agm_cntl_t;
     50 
     51 /*
     52  * One agm control entry for each SOC device containing AGM book keeping
     53  * info for that device.
     54  */
     55 static agm_cntl_t bcm_agm_control[BCM_MAX_NUM_UNITS];
     56 
     57 #define AGM_CNTL(unit)	        bcm_agm_control[unit]
     58 #define AGM_INFO(unit, aid)     bcm_agm_control[unit].agm_info[(aid)]
     59 
     60 /*
     61  * Cause a routine to return BCM_E_INIT if agm subsystem is not
     62  * initialized.
     63  */
     64 #define AGM_INIT(unit)	                    \
     65 	if ( (AGM_CNTL(unit).agm_id_max <= 0) && \
     66 	     (AGM_CNTL(unit).agm_period_max <= 0) ) { return BCM_E_INIT; }
     67 /*
     68  * 0: ECMP1, ECMP2
     69  * 1: ECMP1, TRUNK
     70  * 2: ECMP1, HG-TRUNK
     71  * 3: TRUNK, HG-TRUNK
     72  */
     73 #define _POOL_EMPTY(unit, pid) \
     74     (AGM_CNTL(unit).agm_pool_conf[(pid)] == _AGM_POOL_ID_INVALID)
     75 #define _POOL_CHECK(unit, pid, type) \
     76     (AGM_CNTL(unit).agm_pool_conf[(pid)] == (type))
     77 
     78 /* Functions */
     79 
     80 int
     81 bcm_th_switch_agm_deinit(int unit)
     82 {
     83     if (AGM_CNTL(unit).agm_info != NULL) {
     84         sal_free(AGM_CNTL(unit).agm_info);
     85     }
     86     sal_memset(&AGM_CNTL(unit), 0, sizeof(AGM_CNTL(unit)));
     87 
     88     return BCM_E_NONE;
     89 }
     90 
     91 int
     92 bcm_th_switch_agm_id_validate(int unit, bcm_switch_agm_id_t agm_id) {
     93     AGM_INIT(unit);
     94     AGM_CHECK(unit, agm_id);
     95     return BCM_E_NONE;
     96 }
     97 
     98 int
     99 _bcm_th_switch_agm_update_counter_id(
    100     int unit, bcm_switch_agm_id_t agm_id, int counter_id)
    101 {
    102     int rv = BCM_E_NONE;
    103 
    104     AGM_CHECK(unit, agm_id);
    105 
    106     if (AGM_INFO(unit, agm_id).in_use) {
    107         AGM_INFO(unit, agm_id).counter_id = counter_id;
    108     } else {
    109         rv = BCM_E_NOT_FOUND;
    110     }
    111 
    112     return rv;
    113 }
    114 
    115 int
    116 _bcm_th_switch_agm_info(int unit, bcm_switch_agm_id_t agm_id,
    117                        agm_monitor_t *agm_mnt)
    118 {
    119     int rv = BCM_E_NONE;
    120 
    121     if (AGM_INFO(unit, agm_id).in_use) {
    122         sal_memcpy(agm_mnt, &AGM_INFO(unit, agm_id), sizeof(*agm_mnt));
    123     } else {
    124         rv = BCM_E_NOT_FOUND;
    125     }
    126 
    127     return rv;
    128 }
    129 
    130 int
    131 bcm_th_switch_agm_init(int unit)
    132 {
    133     int i, agm_alloc_sz;
    134 
    135     soc_mem_t agm_tbl = AGM_MONITOR_TABLEm;
    136 
    137     AGM_CNTL(unit).agm_id_min = soc_mem_index_min(unit, agm_tbl);
    138     AGM_CNTL(unit).agm_id_max = soc_mem_index_max(unit, agm_tbl);
    139     AGM_CNTL(unit).agm_period_max = (1 << soc_mem_field_length(unit, agm_tbl,
    140                                     PERIOD_MAXf)) - 1;
    141     AGM_CNTL(unit).agm_timer_id = _AGM_TIME_ID_INVALID;
    142     for (i = 0; i < _AGM_POOL_ID_CNT; i++) {
    143         AGM_CNTL(unit).agm_pool_conf[i] = _AGM_POOL_ID_INVALID;
    144     }
    145 
    146     if (AGM_CNTL(unit).agm_info != NULL) {
    147         sal_free(AGM_CNTL(unit).agm_info);
    148         AGM_CNTL(unit).agm_info = NULL;
    149     }
    150 
    151     agm_alloc_sz = (AGM_CNTL(unit).agm_id_max - AGM_CNTL(unit).agm_id_min + 1) *
    152                    sizeof(agm_monitor_t);
    153     AGM_CNTL(unit).agm_info = sal_alloc(agm_alloc_sz, "agm_cntl.info");
    154     if (AGM_CNTL(unit).agm_info == NULL) {
    155         return BCM_E_MEMORY;
    156     }
    157     sal_memset(AGM_CNTL(unit).agm_info, 0, agm_alloc_sz);
    158 
    159     for (i = 0; i <= (AGM_CNTL(unit).agm_id_max - AGM_CNTL(unit).agm_id_min);
    160          i++) {
    161         AGM_INFO(unit, i).attr.agm_id = _AGM_ID_INVALID;
    162         AGM_INFO(unit, i).group_id = _AGM_GROUP_ID_INVALID;
    163     }
    164 
    165     return BCM_E_NONE;
    166 }
    167 
    168 #if defined (BCM_WARM_BOOT_SUPPORT)
    169 int
    170 bcm_th_switch_tflow_wb_scache_size_get(int unit, int *req_scache_size)
    171 {
    172     int alloc_size = 0;
    173 
    174     alloc_size += sizeof(_bcm_switch_tflow_mode_t);
    175     *req_scache_size += alloc_size;
    176 
    177     return BCM_E_NONE;
    178 }
    179 
    180 int
    181 bcm_th_switch_tflow_wb_sync(int unit, uint8 **scache_ptr)
    182 {
    183     _bcm_switch_tflow_mode_t *tflow_scache_p;
    184 
    185     tflow_scache_p = (_bcm_switch_tflow_mode_t *)(*scache_ptr);
    186 
    187     sal_memcpy(tflow_scache_p, &(_bcm_switch_tflow_mode_info[unit]), sizeof(_bcm_switch_tflow_mode_t));
    188     tflow_scache_p++;
    189 
    190     *scache_ptr = (uint8 *)tflow_scache_p;
    191 
    192     return BCM_E_NONE;
    193 }
    194 
    195 int
    196 bcm_th_switch_tflow_wb_reinit(int unit, uint8 **scache_ptr)
    197 {
    198     _bcm_switch_tflow_mode_t *tflow_scache_p;
    199 
    200     tflow_scache_p = (_bcm_switch_tflow_mode_t *)(*scache_ptr);
    201 
    202     sal_memcpy(&(_bcm_switch_tflow_mode_info[unit]), tflow_scache_p, sizeof(_bcm_switch_tflow_mode_t));
    203     tflow_scache_p++;
    204 
    205     *scache_ptr = (uint8 *)tflow_scache_p;
    206 
    207     return BCM_E_NONE;
    208 }
    209 
    210 
    211 int
    212 bcm_th_switch_agm_wb_scache_size_get(int unit, int *req_scache_size)
    213 {
    214     int alloc_size = 0;
    215 
    216     alloc_size += sizeof(agm_cntl_t);
    217     alloc_size += ((AGM_CNTL(unit).agm_id_max - AGM_CNTL(unit).agm_id_min + 1) *
    218                    sizeof(agm_monitor_t));
    219     
    220     *req_scache_size += alloc_size;
    221 
    222     return BCM_E_NONE;
    223 }
    224 
    225 int
    226 bcm_th_switch_agm_wb_sync(int unit, uint8 **scache_ptr)
    227 {
    228     agm_cntl_t *agm_cntl_scache_p;
    229     agm_monitor_t * agm_info_scache_p;
    230     int agm_info_num;
    231 
    232     agm_cntl_scache_p = (agm_cntl_t *)(*scache_ptr);
    233     
    234     sal_memcpy(agm_cntl_scache_p, &AGM_CNTL(unit), sizeof(agm_cntl_t));
    235     agm_cntl_scache_p ++;
    236 
    237     agm_info_scache_p = (agm_monitor_t *)agm_cntl_scache_p;
    238     agm_info_num = AGM_CNTL(unit).agm_id_max - AGM_CNTL(unit).agm_id_min + 1;
    239     sal_memcpy(agm_info_scache_p, AGM_CNTL(unit).agm_info, 
    240         agm_info_num * sizeof(agm_monitor_t));
    241     agm_info_scache_p += agm_info_num;
    242 
    243     *scache_ptr = (uint8 *)agm_info_scache_p;
    244     
    245     return BCM_E_NONE;
    246 }
    247 
    248 int
    249 bcm_th_switch_agm_wb_reinit(int unit, uint8 **scache_ptr)
    250 {
    251     agm_cntl_t *agm_cntl_scache_p;
    252     agm_monitor_t * agm_info_scache_p;
    253     int agm_info_num;
    254 
    255     agm_cntl_scache_p = (agm_cntl_t *)(*scache_ptr);
    256 
    257     sal_memcpy(&AGM_CNTL(unit), agm_cntl_scache_p, sizeof(agm_cntl_t));
    258     agm_cntl_scache_p ++;
    259 
    260     agm_info_scache_p = (agm_monitor_t *)agm_cntl_scache_p;
    261     agm_info_num = AGM_CNTL(unit).agm_id_max - AGM_CNTL(unit).agm_id_min + 1;
    262     AGM_CNTL(unit).agm_info = sal_alloc(agm_info_num * sizeof(agm_monitor_t), 
    263         "agm_cntl.info");
    264     if (AGM_CNTL(unit).agm_info == NULL) {
    265         return BCM_E_MEMORY;
    266     }
    267     sal_memcpy(AGM_CNTL(unit).agm_info, agm_info_scache_p, 
    268         agm_info_num * sizeof(agm_monitor_t));
    269     agm_info_scache_p += agm_info_num;
    270 
    271     *scache_ptr = (uint8 *)agm_info_scache_p;
    272     
    273     return BCM_E_NONE;
    274 }
    275 #endif 
    276 
    277 int
    278 bcm_th_switch_agm_dump(int unit)
    279 {
    280     /* For trouble-shooting */
    281     AGM_INIT(unit);
    282 
    283     return BCM_E_NONE;
    284 }
    285 
    286 /*
    287  * 0: ECMP, ECMP
    288  * 1: ECMP, TRUNK
    289  * 2: ECMP, HG-TRUNK
    290  * 3: TRUNK, HG-TRUNK
    291  */
    292 STATIC int
    293 _th_agm_pool_alloc(int unit, bcm_switch_agm_type_t agm_type, int *pool_id)
    294 {
    295     int i;
    296 
    297     for (i = 0; i < _AGM_POOL_ID_CNT; i++) {
    298         if (_POOL_EMPTY(unit, i) || _POOL_CHECK(unit, i, agm_type)) {
    299             *pool_id = i;
    300             return BCM_E_NONE;
    301         }
    302     }
    303 
    304     return BCM_E_FULL;
    305 
    306 }
    307 
    308 STATIC int
    309 _th_agm_id_alloc(int unit, int *agm_id)
    310 {
    311     int i;
    312 
    313     for (i = AGM_CNTL(unit).agm_id_min + 1; i <= AGM_CNTL(unit).agm_id_max; i++) {
    314         if (AGM_INFO(unit, i).attr.agm_id != _AGM_ID_INVALID) {
    315             continue;
    316         }
    317         *agm_id = i;
    318         return BCM_E_NONE;
    319     }
    320 
    321     return BCM_E_FULL;
    322 }
    323 
    324 STATIC int
    325 _th_agm_itvl2scale(int unit, bcm_switch_agm_period_interval_t itvl)
    326 {
    327     int scale = 0;
    328 
    329     switch (itvl) {
    330     case bcmSwitchAgmInterval1Second:
    331         scale = 5;
    332         break;
    333     case bcmSwitchAgmInterval100MiliSecond:
    334         scale = 4;
    335         break;
    336     case bcmSwtichAgmInterval10MiliSecond:
    337         scale = 3;
    338         break;
    339     case bcmSwitchAgmInterval1MiliSecond:
    340         scale = 2;
    341         break;
    342     case bcmSwitchAgmInterval100MacroSecond:
    343         scale = 1;
    344         break;
    345     default:
    346         break;
    347     }
    348 
    349     return scale;
    350 }
    351 
    352 /* Retrieve table info for AGM instance */
    353 int
    354 bcm_th_agm_stat_get_table_info(int unit, bcm_switch_agm_id_t agm_id,
    355                                 uint32 *num_of_tables, void *tbl_info)
    356 {
    357     int index = agm_id;
    358     bcm_stat_flex_table_info_t *table_info = NULL;
    359 
    360     (*num_of_tables) = 0;
    361     if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
    362         return BCM_E_UNAVAIL;
    363     }
    364 
    365     table_info = (bcm_stat_flex_table_info_t *) tbl_info;
    366     table_info[*num_of_tables].table        = AGM_MONITOR_TABLEm;
    367     table_info[*num_of_tables].index        = index;
    368     table_info[*num_of_tables].direction    = bcmStatFlexDirectionIngress;
    369     (*num_of_tables)++;
    370 
    371     return BCM_E_NONE;
    372 }
    373 
    374 /* Get counter id for accounnting table AGM */
    375 int
    376 bcm_th_agm_stat_id_get(int unit, bcm_switch_agm_id_t agm_id,
    377                     int agm_pid, int total_cntr_idxs, uint32 *stat_counter_id)
    378 {
    379     int rv = BCM_E_NONE;
    380 
    381     bcm_stat_group_mode_id_config_t stat_config;
    382     bcm_stat_group_mode_attr_selector_t attr_sel[1];
    383     uint32 mode_id;
    384     uint32 num_entries;
    385     uint32 num_sel;
    386 
    387     if (!soc_feature(unit,soc_feature_advanced_flex_counter)) {
    388         return BCM_E_UNAVAIL;
    389     }
    390 
    391     bcm_stat_group_mode_id_config_t_init(&stat_config);
    392     bcm_stat_group_mode_attr_selector_t_init(attr_sel);
    393 
    394     stat_config.flags = BCM_STAT_GROUP_MODE_INGRESS;
    395     stat_config.total_counters = total_cntr_idxs;
    396     stat_config.hint.type = bcmIntStatGroupAllocHintIngressAgmGroup;
    397     stat_config.hint.value = 1;
    398 
    399     /* Create custom mode id with config */
    400     attr_sel[0].attr = 0;
    401     attr_sel[0].attr_value = 0;
    402     attr_sel[0].counter_offset = 0;
    403     num_sel = 1;
    404     rv = bcm_esw_stat_group_mode_id_config_create(unit, 0, &stat_config,
    405             num_sel, attr_sel, &mode_id);
    406     if (BCM_FAILURE(rv) && rv != BCM_E_EXISTS) {
    407         return rv;
    408     }
    409 
    410     /* Create counter id */
    411     if (agm_pid) {
    412         rv = bcm_esw_stat_custom_group_create(unit, mode_id,
    413                 (bcm_stat_object_t)bcmIntStatObjectIngAgmSecondLookup,
    414                 stat_counter_id, &num_entries);
    415     } else {
    416         rv = bcm_esw_stat_custom_group_create(unit, mode_id,
    417                 (bcm_stat_object_t)bcmIntStatObjectIngAgm,
    418                 stat_counter_id, &num_entries);
    419     }
    420     if (BCM_FAILURE(rv)) {
    421         return rv;
    422     }
    423 
    424     /* Make sure there is space there */
    425     if (total_cntr_idxs > num_entries) {
    426         BCM_IF_ERROR_RETURN(bcm_esw_stat_group_destroy(unit, *stat_counter_id));
    427         return BCM_E_RESOURCE;
    428     }
    429 
    430     return rv;
    431 }
    432 
    433 /* Destroy AGM counter id */
    434 int
    435 bcm_th_agm_stat_id_clear(int unit, uint32 stat_counter_id)
    436 {
    437     bcm_stat_group_mode_t gmode;
    438     bcm_stat_object_t stat_object;
    439     uint32 mode, pool, base_idx;
    440     int rv;
    441 
    442 #if defined(BCM_TOMAHAWK3_SUPPORT)
    443     if (SOC_IS_TOMAHAWK3(unit) && !stat_counter_id) {
    444         return BCM_E_NONE;
    445     }
    446 #endif /* BCM_TOMAHAWK3_SUPPORT */
    447 
    448     _bcm_esw_stat_get_counter_id_info(unit, stat_counter_id, &gmode,
    449                                       &stat_object, &mode, &pool, &base_idx);
    450 
    451     BCM_IF_ERROR_RETURN(bcm_esw_stat_group_destroy(unit, stat_counter_id));
    452 
    453     /* This function could return BUSY if the reference count is non-zero */
    454     rv = _bcm_esw_stat_group_mode_id_destroy(unit, mode);
    455     if (rv == BCM_E_BUSY)
    456         return BCM_E_NONE;
    457     return rv;
    458 }
    459 
    460 /* Detach Flex counter from AGM monitor */
    461 int
    462 bcm_th_agm_stat_detach(int unit,
    463     bcm_switch_agm_id_t agm_id, int agm_pid, uint32 ctr_id)
    464 {
    465     soc_mem_t                  table;
    466     bcm_stat_flex_direction_t  direction;
    467     bcm_stat_object_t          object;
    468     uint32                     count = 0;
    469     uint32                     actual_num_tables = 0;
    470     uint32                     num_of_tables = 0;
    471     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
    472 
    473 #if defined(BCM_TOMAHAWK3_SUPPORT)
    474     if (SOC_IS_TOMAHAWK3(unit) && !ctr_id) {
    475         return BCM_E_NONE;
    476     }
    477 #else
    478     COMPILER_REFERENCE(ctr_id);
    479 #endif /* BCM_TOMAHAWK3_SUPPORT */
    480 
    481     direction   = bcmStatFlexDirectionIngress;
    482     if (agm_pid) {
    483         object      = bcmIntStatObjectIngAgmSecondLookup;
    484     } else {
    485         object      = bcmIntStatObjectIngAgm;
    486     }
    487 
    488     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit, object, &direction));
    489     BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info(unit, object, 1,
    490                             &actual_num_tables, &table, &direction));
    491 
    492     BCM_IF_ERROR_RETURN(bcm_th_agm_stat_get_table_info(unit, agm_id,
    493                         &num_of_tables, &table_info[0]));
    494     for (count = 0; count < num_of_tables; count++) {
    495         if ((table_info[count].direction == direction) &&
    496             (table_info[count].table == table)) {
    497             if (direction == bcmStatFlexDirectionIngress) {
    498                 return _bcm_esw_stat_flex_detach_ingress_table_counters1(
    499                             unit, table_info[count].table,
    500                             table_info[count].index, object);
    501             } else {
    502                 return _bcm_esw_stat_flex_detach_egress_table_counters(
    503                             unit, 0, table_info[count].table,
    504                             table_info[count].index);
    505             }
    506         }
    507     }
    508 
    509     return BCM_E_NOT_FOUND;
    510 }
    511 
    512 /* Attach a flex counter to AGM monitor */
    513 int
    514 bcm_th_agm_stat_attach(int unit, bcm_switch_agm_id_t agm_id,
    515                     int agm_pid, uint32 counter_id)
    516 {
    517     soc_mem_t                  table;
    518     bcm_stat_flex_direction_t  direction;
    519     uint32                     pool_number = 0;
    520     uint32                     base_index = 0;
    521     bcm_stat_flex_mode_t       offset_mode = 0;
    522     bcm_stat_object_t          object;
    523     bcm_stat_group_mode_t      group_mode;
    524     uint32                     count = 0;
    525     uint32                     actual_num_tables = 0;
    526     uint32                     num_of_tables = 0;
    527     bcm_stat_flex_table_info_t table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
    528 
    529     direction   = bcmStatFlexDirectionIngress;
    530     if (agm_pid) {
    531         object      = bcmIntStatObjectIngAgmSecondLookup;
    532     } else {
    533         object      = bcmIntStatObjectIngAgm;
    534     }
    535     group_mode  = bcmStatGroupModeSingle;
    536 
    537     _bcm_esw_stat_get_counter_id_info(unit, counter_id, &group_mode, &object,
    538                                       &offset_mode, &pool_number, &base_index);
    539     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_object(unit, object, &direction));
    540     BCM_IF_ERROR_RETURN(_bcm_esw_stat_validate_group(unit, group_mode));
    541     BCM_IF_ERROR_RETURN(_bcm_esw_stat_flex_get_table_info(unit, object, 1,
    542                             &actual_num_tables, &table, &direction));
    543 
    544     BCM_IF_ERROR_RETURN(bcm_th_agm_stat_get_table_info(unit, agm_id,
    545                         &num_of_tables, &table_info[0]));
    546     for (count = 0; count < num_of_tables ; count++) {
    547         if ((table_info[count].direction == direction) &&
    548             (table_info[count].table == table)) {
    549             if (direction == bcmStatFlexDirectionIngress) {
    550                 return _bcm_esw_stat_flex_attach_ingress_table_counters2(
    551                             unit, table_info[count].table,
    552                             table_info[count].index, offset_mode, base_index,
    553                             pool_number, object, NULL);
    554             } else {
    555                 return _bcm_esw_stat_flex_attach_egress_table_counters(
    556                             unit, table_info[count].table,
    557                             table_info[count].index, 0, offset_mode, base_index,
    558                             pool_number);
    559             }
    560         }
    561     }
    562 
    563     return BCM_E_NOT_FOUND;
    564 }
    565 
    566 /* Fill trunk member to AGM stat array */
    567 STATIC int
    568 _th_agm_trunk_member_fill(int unit, bcm_switch_agm_id_t agm_id,
    569                           bcm_trunk_t tid, int nstat,
    570                           bcm_switch_agm_stat_t *stat_arr)
    571 {
    572     int i, rv = BCM_E_NONE;
    573     bcm_trunk_info_t tinfo;
    574     int mbm_cnt, mbm_max;
    575     bcm_trunk_member_t *mbm_arr;
    576 
    577     mbm_max = AGM_INFO(unit, agm_id).attr.num_members;
    578     mbm_arr = sal_alloc(mbm_max * sizeof(*mbm_arr), "mbm_arr");
    579     if (mbm_arr == NULL) {
    580         return BCM_E_MEMORY;
    581     }
    582 
    583     rv = bcm_esw_trunk_get(unit, tid, &tinfo, mbm_max, mbm_arr, &mbm_cnt);
    584     if (BCM_FAILURE(rv)) {
    585         sal_free(mbm_arr);
    586         return rv;
    587     }
    588 
    589     if (mbm_cnt == 0) {
    590         sal_free(mbm_arr);
    591         return BCM_E_FAIL;
    592     }
    593 
    594     /* Could cross multi monitor period */
    595     for (i = 0; i < nstat; i++) {
    596         stat_arr[i].intf_id = BCM_IF_INVALID;
    597         stat_arr[i].gport_id = mbm_arr[i % mbm_cnt].gport;
    598     }
    599 
    600     sal_free(mbm_arr);
    601 
    602     return BCM_E_NONE;
    603 
    604 }
    605 
    606 #if defined(INCLUDE_L3)
    607 /* Fill l3 ecmp member to AGM stat array */
    608 STATIC int
    609 _th_agm_l3_ecmp_member_fill(int unit, bcm_switch_agm_id_t agm_id,
    610                             bcm_if_t l3_ecmp_id, int nstat,
    611                             bcm_switch_agm_stat_t *stat_arr)
    612 {
    613     int i, rv = BCM_E_NONE;
    614     int mbm_cnt = 0, mbm_max;
    615     bcm_if_t *mbm_arr;
    616 
    617     mbm_max = AGM_INFO(unit, agm_id).attr.num_members;
    618     mbm_arr = sal_alloc(mbm_max * sizeof(*mbm_arr), "mbm_arr");
    619     if (mbm_arr == NULL) {
    620         return BCM_E_MEMORY;
    621     }
    622 
    623     rv = bcm_esw_l3_egress_multipath_get(unit, l3_ecmp_id, mbm_max,
    624                                          mbm_arr, &mbm_cnt);
    625     if (BCM_FAILURE(rv)) {
    626         sal_free(mbm_arr);
    627         return rv;
    628     }
    629 
    630     if (mbm_cnt == 0) {
    631         sal_free(mbm_arr);
    632         return BCM_E_FAIL;
    633     }
    634 
    635     /* Could cross multi monitor period */
    636     for (i = 0; i < nstat; i++) {
    637         stat_arr[i].gport_id = BCM_GPORT_INVALID;
    638         stat_arr[i].intf_id  = mbm_arr[i % mbm_cnt];
    639     }
    640 
    641     sal_free(mbm_arr);
    642 
    643     return BCM_E_NONE;
    644 
    645 }
    646 #endif
    647 
    648 /*
    649  * Function:
    650  *      bcm_th_switch_agm_create
    651  * Purpose:
    652  *      Creates an aggregation monitoring entry which collects bandwidth and
    653  *      packet distribution information among members of a trunk group or
    654  *      an ecmp group.
    655  */
    656 int
    657 bcm_th_switch_agm_create(int unit,
    658                          uint32 options,
    659                          bcm_switch_agm_info_t *agm_info)
    660 {
    661     int rv = BCM_E_NONE;
    662     int agm_pid, agm_id;
    663     agm_monitor_table_entry_t entry;
    664     uint32 counter_id = 0;
    665     agm_monitor_t *agm_mng;
    666     int scale;
    667 
    668     /* Validate parameters */
    669     if (!SOC_UNIT_VALID(unit)) {
    670         return BCM_E_UNIT;
    671     }
    672 
    673     AGM_INIT(unit);
    674 
    675     if (agm_info == NULL) {
    676         return BCM_E_PARAM;
    677     }
    678 
    679     if (agm_info->period_interval < bcmSwitchAgmInterval1Second ||
    680         agm_info->period_interval >= bcmSwitchAgmIntervalCount) {
    681         LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    682                   "Invalid period interval %d\n"), agm_info->period_interval));
    683         return BCM_E_PARAM;
    684     }
    685 
    686     if (agm_info->period_num < 0 ||
    687         agm_info->period_num > AGM_CNTL(unit).agm_period_max) {
    688         LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    689                   "Invalid period number %d\n"), agm_info->period_num));
    690         return BCM_E_PARAM;
    691     }
    692 
    693 #if defined(BCM_TOMAHAWK3_SUPPORT)
    694     if (SOC_IS_TOMAHAWK3(unit)) {
    695         if(bcmSwitchAgmTypeFabricTrunk == agm_info->agm_type) {
    696             return BCM_E_PARAM;
    697         }
    698         if (agm_info->num_members <= 0) {
    699             return BCM_E_PARAM;
    700         }
    701     }
    702 #endif
    703 
    704     AGM_LOCK(unit);
    705 
    706     /* Check available agm pool */
    707     rv = _th_agm_pool_alloc(unit, agm_info->agm_type, &agm_pid);
    708     if (BCM_FAILURE(rv)) {
    709         AGM_UNLOCK(unit);
    710         return rv;
    711     }
    712 
    713     /* Alloc monitor id */
    714     rv = _th_agm_id_alloc(unit, &agm_id);
    715     if (BCM_FAILURE(rv)) {
    716         AGM_UNLOCK(unit);
    717         return rv;
    718     }
    719 
    720     LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    721                 "Allocated AGM pool id %d, monitor id %d\n"), agm_pid, agm_id));
    722 
    723 #if defined(BCM_TOMAHAWK3_SUPPORT)
    724     /* For TH3, skip creating Flex Stat counters for ECMP
    725      * AGMs as it will be taken care at ECMP attach phase.
    726      */
    727     if ((!SOC_IS_TOMAHAWK3(unit)) ||
    728         (bcmSwitchAgmTypeL3Ecmp != agm_info->agm_type &&
    729          bcmSwitchAgmTypeL3EcmpOverlay != agm_info->agm_type))
    730 #endif /* BCM_TOMAHAWK3_SUPPORT */
    731     {
    732 
    733         rv = bcm_th_agm_stat_id_get(unit,
    734                                  agm_id,
    735                                  agm_pid,
    736                                  agm_info->num_members * (agm_info->period_num + 1),
    737                                  &counter_id);
    738         if (BCM_FAILURE(rv)) {
    739             AGM_UNLOCK(unit);
    740             return rv;
    741         }
    742 
    743         LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    744                     "Allocated counter id %d for AGM accouting table\n"), counter_id));
    745 
    746         rv = bcm_th_agm_stat_attach(unit, agm_id, agm_pid, counter_id);
    747         if (BCM_FAILURE(rv)) {
    748             bcm_th_agm_stat_id_clear(unit, counter_id);
    749             AGM_UNLOCK(unit);
    750             return rv;
    751         }
    752 
    753         LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    754                     "Attached counter id %d to AGM %d\n"), counter_id, agm_id));
    755     }
    756 
    757     rv = READ_AGM_MONITOR_TABLEm(unit, MEM_BLOCK_ANY, agm_id, &entry);
    758     if (BCM_FAILURE(rv)) {
    759         (void)bcm_th_agm_stat_detach(unit, agm_id, agm_pid, counter_id);
    760         (void)bcm_th_agm_stat_id_clear(unit, counter_id);
    761         AGM_UNLOCK(unit);
    762         return rv;
    763     }
    764 
    765     /* For unlimited period, we need to set SCALE to 0 */
    766     if (agm_info->period_num == 0) {
    767         scale = 0;
    768     } else {
    769         scale = _th_agm_itvl2scale(unit, agm_info->period_interval);
    770     }
    771     soc_mem_field32_set(unit, AGM_MONITOR_TABLEm, &entry, SCALEf, scale);
    772     soc_mem_field32_set(unit, AGM_MONITOR_TABLEm, &entry, PERIOD_MAXf,
    773                         agm_info->period_num);
    774     rv = WRITE_AGM_MONITOR_TABLEm(unit, MEM_BLOCK_ANY, agm_id, &entry);
    775     if (BCM_FAILURE(rv)) {
    776         (void)bcm_th_agm_stat_detach(unit, agm_id, agm_pid, counter_id);
    777         (void)bcm_th_agm_stat_id_clear(unit, counter_id);
    778         AGM_UNLOCK(unit);
    779         return rv;
    780     }
    781 
    782     /* Update software bookkeeping information */
    783     AGM_CNTL(unit).agm_pool_conf[agm_pid] = agm_info->agm_type;
    784     agm_mng = &AGM_INFO(unit, agm_id);
    785     agm_mng->in_use         = TRUE;
    786     agm_mng->agm_pool_id    = agm_pid;
    787     agm_mng->counter_id     = counter_id;
    788 
    789     sal_memcpy(&agm_mng->attr, agm_info, sizeof(*agm_info));
    790     agm_mng->attr.agm_id    = agm_id;
    791     agm_info->agm_id        = agm_id;
    792 
    793     AGM_UNLOCK(unit);
    794     return rv;
    795 }
    796 
    797 /*
    798  * Function:
    799  *      bcm_esw_switch_agm_enable_set
    800  * Purpose:
    801  *      Enable or disable the aggregation group monitoring.
    802  */
    803 int
    804 bcm_th_switch_agm_enable_set(int unit,
    805                              bcm_switch_agm_id_t agm_id,
    806                              int enable)
    807 {
    808     int i, rv = BCM_E_NONE;
    809     agm_monitor_table_entry_t entry;
    810     uint32 start_ts[2] = {0};
    811     bcm_time_interface_t time_intf;
    812 
    813     /* Validate parameters */
    814     if (!SOC_UNIT_VALID(unit)) {
    815         return BCM_E_UNIT;
    816     }
    817 
    818     AGM_INIT(unit);
    819     AGM_CHECK(unit, agm_id);
    820 
    821     AGM_LOCK(unit);
    822     if (!AGM_INFO(unit, agm_id).in_use) {
    823         AGM_UNLOCK(unit);
    824         return BCM_E_NOT_FOUND;
    825     }
    826 
    827     /* Reentry check */
    828     if ((enable && AGM_INFO(unit, agm_id).running) ||
    829         (!enable && !AGM_INFO(unit, agm_id).running)) {
    830         AGM_UNLOCK(unit);
    831         return BCM_E_NONE;
    832     }
    833 
    834     /* Enable timer for the first time */
    835     if (enable &&
    836         AGM_INFO(unit, agm_id).attr.period_num > 0) {
    837         time_intf.id = _AGM_TIME_ID_DFLT;
    838 
    839         if (AGM_CNTL(unit).agm_timer_id == _AGM_TIME_ID_INVALID) {
    840             time_intf.flags = BCM_TIME_ENABLE | BCM_TIME_WITH_ID;
    841             sal_memset(&time_intf.drift, 0, sizeof(time_intf.drift));
    842             sal_memset(&time_intf.offset, 0, sizeof(time_intf.offset));
    843             sal_memset(&time_intf.accuracy, 0, sizeof(time_intf.accuracy));
    844             time_intf.heartbeat_hz      = 4000;
    845             time_intf.clk_resolution    = 0;
    846             time_intf.bitclock_hz       = 10000000;
    847 
    848             rv = bcm_esw_time_interface_add(unit, &time_intf);
    849             if (BCM_FAILURE(rv) && rv != BCM_E_EXISTS) {
    850                 AGM_UNLOCK(unit);
    851                 return rv;
    852             }
    853 
    854             AGM_CNTL(unit).agm_timer_id = _AGM_TIME_ID_DFLT;
    855 
    856             LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    857                 "Created a time interface id %d for AGM %d.\n"),
    858                 AGM_CNTL(unit).agm_timer_id, agm_id));\
    859         }
    860 
    861 #if defined(BCM_TOMAHAWK3_SUPPORT)
    862         if (SOC_IS_TOMAHAWK3(unit)) {
    863             READ_NS_TIMESYNC_TS0_TIMESTAMP_UPPER_STATUSr(unit, &start_ts[1]);
    864             READ_NS_TIMESYNC_TS0_TIMESTAMP_LOWER_STATUSr(unit, &start_ts[0]);
    865             READ_NS_TIMESYNC_TS0_TIMESTAMP_UPPER_STATUSr(unit, &start_ts[1]);
    866             start_ts[0] =
    867                 (start_ts[0] >> 4 & 0x0FFFFFFF) | ((start_ts[1] & 0xF) << 28);
    868             start_ts[1] >>= 4;
    869         } else
    870 #endif
    871         {
    872             bcm_time_capture_t time1;
    873             bcm_time_capture_t_init(&time1);
    874             (void) bcm_esw_time_capture_get(unit, time_intf.id, &time1);
    875 
    876             READ_CMIC_TIMESYNC_INPUT_TIME_FIFO_TS_UPPERr(unit, &start_ts[1]);
    877             READ_CMIC_TIMESYNC_INPUT_TIME_FIFO_TS_LOWERr(unit, &start_ts[0]);
    878         }
    879     } else if (!enable || AGM_INFO(unit, agm_id).attr.period_num <= 0) {
    880         start_ts[0] = 0;
    881         start_ts[1] = 0;
    882     }
    883 
    884     LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    885                 "Start time stamp 0x%x_0x%x for AGM %d.\n"), start_ts[1],
    886                 start_ts[0], agm_id));
    887 
    888     /* Update to AGM monitor table */
    889     rv = READ_AGM_MONITOR_TABLEm(unit, MEM_BLOCK_ANY, agm_id, &entry);
    890     if (BCM_FAILURE(rv)) {
    891         AGM_UNLOCK(unit);
    892         return rv;
    893     }
    894 
    895     soc_mem_field_set(unit, AGM_MONITOR_TABLEm, (uint32 *)&entry,
    896                       START_TIMESTAMPf, start_ts);
    897     soc_mem_field32_set(unit, AGM_MONITOR_TABLEm, &entry, ENABLEf, enable);
    898     rv = WRITE_AGM_MONITOR_TABLEm(unit, MEM_BLOCK_ANY, agm_id, &entry);
    899     if (BCM_FAILURE(rv)) {
    900         AGM_UNLOCK(unit);
    901         return rv;
    902     }
    903 
    904     /* Update running state */
    905     AGM_INFO(unit, agm_id).running = enable ? TRUE : FALSE;
    906 
    907     /* Destroy time interface if all monitors disabled. */
    908     if (!enable && AGM_CNTL(unit).agm_timer_id != _AGM_TIME_ID_INVALID) {
    909         for (i = AGM_CNTL(unit).agm_id_min;
    910              i <= AGM_CNTL(unit).agm_id_max; i++) {
    911             if (AGM_INFO(unit, i).running) {
    912                 break;
    913             }
    914         }
    915 
    916         /* All AGM instances are not running, remove time interface. */
    917         if (i > AGM_CNTL(unit).agm_id_max) {
    918             rv = bcm_esw_time_interface_delete(unit, AGM_CNTL(unit).agm_timer_id);
    919             if (BCM_FAILURE(rv) && rv != BCM_E_NOT_FOUND) {
    920                 AGM_UNLOCK(unit);
    921                 return rv;
    922             }
    923 
    924             LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    925                 "All AGM monitor are stopped, delete time interface.\n")));
    926 
    927             AGM_CNTL(unit).agm_timer_id = _AGM_TIME_ID_INVALID;
    928         }
    929     }
    930 
    931     AGM_UNLOCK(unit);
    932     return rv;
    933 }
    934 
    935 /*
    936  * Function:
    937  *      bcm_esw_switch_agm_stat_get
    938  * Purpose:
    939  *      Retrieve bandwidth and packet distribution information that were
    940  *      collected via aggregation group monitoring
    941  */
    942 int
    943 bcm_th_switch_agm_stat_get(int unit,
    944                            bcm_switch_agm_id_t agm_id,
    945                            int nstat,
    946                            bcm_switch_agm_stat_t *stat_arr)
    947 {
    948     int     i, rv = BCM_E_NONE;
    949     int     group_size;
    950     uint32  *counter_indexes = NULL;
    951     bcm_stat_value_t *counter_values = NULL;
    952     bcm_switch_agm_type_t agm_type;
    953 
    954     uint32  num_of_tables = 0;
    955     int     sync_mode = TRUE;
    956     int     byte_flag;
    957     bcm_stat_flex_direction_t   direction = bcmStatFlexDirectionIngress;
    958     bcm_stat_flex_table_info_t  table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
    959 
    960     /* Validate parameters */
    961     if (!SOC_UNIT_VALID(unit)) {
    962         return BCM_E_UNIT;
    963     }
    964 
    965     if (stat_arr == NULL) {
    966         return BCM_E_PARAM;
    967     }
    968 
    969     AGM_INIT(unit);
    970     AGM_CHECK(unit, agm_id);
    971 
    972     AGM_LOCK(unit);
    973 
    974     if (!AGM_INFO(unit, agm_id).in_use) {
    975         AGM_UNLOCK(unit);
    976         return BCM_E_NOT_FOUND;
    977     }
    978 
    979     counter_indexes = sal_alloc(sizeof(uint32) * nstat, "cntidx");
    980     if (counter_indexes == NULL) {
    981         AGM_UNLOCK(unit);
    982         return BCM_E_MEMORY;
    983     }
    984     counter_values = sal_alloc(sizeof(bcm_stat_value_t) * nstat, "cntval");
    985     if (counter_values == NULL) {
    986         sal_free(counter_indexes);
    987         AGM_UNLOCK(unit);
    988         return BCM_E_MEMORY;
    989     }
    990 
    991     group_size = AGM_INFO(unit, agm_id).attr.num_members;
    992     for (i = 0; i < nstat; i++) {
    993         counter_indexes[i] = i;
    994         stat_arr[i].period = i / group_size;
    995     }
    996     sal_memset(counter_values, 0, sizeof(bcm_stat_value_t) * nstat);
    997 
    998     LOG_VERBOSE(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
    999         "AGM %d stat get: group member count %d, period %d.\n"), agm_id,
   1000         group_size, (nstat / group_size) + 1 ));
   1001 
   1002     rv = bcm_th_agm_stat_get_table_info(
   1003             unit, agm_id, &num_of_tables, &table_info[0]);
   1004     if (BCM_FAILURE(rv)) {
   1005         goto _free_exit;
   1006     }
   1007 
   1008     if (table_info[0].direction == direction) {
   1009         /* Collect packet counters */
   1010         byte_flag = 0;
   1011         for (i = 0; i < nstat; i++) {
   1012             rv = _bcm_esw_stat_counter_get(unit, sync_mode, table_info[0].index,
   1013                     table_info[0].table, 0, byte_flag, counter_indexes[i],
   1014                     &counter_values[i]);
   1015             if (BCM_FAILURE(rv)) {
   1016                 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1017                     "AGM %d collected packet counter %d failed, rv = %d.\n"),
   1018                     agm_id, i, rv));
   1019                 goto _free_exit;
   1020             }
   1021             stat_arr[i].packets = counter_values[i].packets64;
   1022         }
   1023 
   1024         /* Collect byte counters */
   1025         byte_flag = 1;
   1026         for (i = 0; i < nstat; i++) {
   1027             rv = _bcm_esw_stat_counter_get(unit, sync_mode, table_info[0].index,
   1028                     table_info[0].table, 0, byte_flag, counter_indexes[i],
   1029                     &counter_values[i]);
   1030             if (BCM_FAILURE(rv)) {
   1031                 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1032                     "AGM %d collected byte counter %d failed, rv = %d.\n"),
   1033                     agm_id, i, rv));
   1034                 goto _free_exit;
   1035             }
   1036             stat_arr[i].bytes = counter_values[i].bytes;
   1037         }
   1038     }
   1039 
   1040     /* Convert to agm_stat_attr */
   1041     agm_type = AGM_INFO(unit, agm_id).attr.agm_type;
   1042     if (agm_type == bcmSwitchAgmTypeTrunk ||
   1043         agm_type == bcmSwitchAgmTypeFabricTrunk) {
   1044         rv = _th_agm_trunk_member_fill(unit, agm_id,
   1045                     (bcm_trunk_t)AGM_INFO(unit, agm_id).group_id,
   1046                     nstat, stat_arr);
   1047     } else if ((agm_type == bcmSwitchAgmTypeL3Ecmp) ||
   1048                (agm_type == bcmSwitchAgmTypeL3EcmpOverlay)) {
   1049 #if defined(INCLUDE_L3)
   1050         if (soc_feature(unit, soc_feature_l3)) {
   1051             rv = _th_agm_l3_ecmp_member_fill(unit, agm_id,
   1052                         (bcm_if_t)AGM_INFO(unit, agm_id).group_id,
   1053                         nstat, stat_arr);
   1054         } else
   1055 #endif
   1056         rv = BCM_E_UNAVAIL;
   1057     }
   1058 
   1059     if (BCM_FAILURE(rv)) {
   1060         LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1061             "AGM %d group member fill failed, group_id %d, rv = %d.\n"), agm_id,
   1062             AGM_INFO(unit, agm_id).group_id, rv));
   1063     }
   1064 
   1065 _free_exit:
   1066     AGM_UNLOCK(unit);
   1067     if (counter_indexes) {
   1068         sal_free(counter_indexes);
   1069     }
   1070 
   1071     if (counter_values) {
   1072         sal_free(counter_values);
   1073     }
   1074 
   1075     return rv;
   1076 }
   1077 
   1078 /*
   1079  * Function:
   1080  *      bcm_esw_switch_agm_stat_clear
   1081  * Purpose:
   1082  *      Clear stats of counter entries attached to the aggregation monitor (id)
   1083  */
   1084 int
   1085 bcm_th_switch_agm_stat_clear(int unit, bcm_switch_agm_id_t agm_id)
   1086 {
   1087     int     i, rv = BCM_E_NONE;
   1088     int     group_size, group_num;
   1089     uint32  *counter_indexes = NULL;
   1090     bcm_stat_value_t *counter_values = NULL;
   1091     int     nstat;
   1092 
   1093     uint32  num_of_tables = 0;
   1094     int     byte_flag;
   1095     bcm_stat_flex_direction_t   direction = bcmStatFlexDirectionIngress;
   1096     bcm_stat_flex_table_info_t  table_info[BCM_STAT_FLEX_COUNTER_MAX_DIRECTION];
   1097 
   1098     /* Validate parameters */
   1099     if (!SOC_UNIT_VALID(unit)) {
   1100         return BCM_E_UNIT;
   1101     }
   1102 
   1103     AGM_INIT(unit);
   1104     AGM_CHECK(unit, agm_id);
   1105 
   1106     AGM_LOCK(unit);
   1107     if (!AGM_INFO(unit, agm_id).in_use) {
   1108         AGM_UNLOCK(unit);
   1109         return BCM_E_NOT_FOUND;
   1110     }
   1111 
   1112     group_size = AGM_INFO(unit, agm_id).attr.num_members;
   1113     group_num  = AGM_INFO(unit, agm_id).attr.period_num;
   1114     nstat = group_size * (group_num + 1);
   1115     AGM_UNLOCK(unit);
   1116 
   1117     counter_indexes = sal_alloc(sizeof(uint32) * nstat, "cntidx");
   1118     if (counter_indexes == NULL) {
   1119         return BCM_E_MEMORY;
   1120     }
   1121     counter_values = sal_alloc(sizeof(bcm_stat_value_t) * nstat, "cntval");
   1122     if (counter_values == NULL) {
   1123         sal_free(counter_indexes);
   1124         return BCM_E_MEMORY;
   1125     }
   1126 
   1127     for (i = 0; i < nstat; i++) {
   1128         counter_indexes[i] = i;
   1129     }
   1130     sal_memset(counter_values, 0, sizeof(bcm_stat_value_t) * nstat);
   1131 
   1132     rv = bcm_th_agm_stat_get_table_info(
   1133             unit, agm_id, &num_of_tables, &table_info[0]);
   1134     if (rv < 0) {
   1135         goto _free_exit;
   1136     }
   1137 
   1138     if (table_info[0].direction == direction) {
   1139         /* Clear packet counters */
   1140         byte_flag = 0;
   1141         for (i = 0; i < nstat; i++) {
   1142             rv = _bcm_esw_stat_counter_set(unit, table_info[0].index,
   1143                     table_info[0].table, 0, byte_flag, counter_indexes[i],
   1144                     &counter_values[i]);
   1145             if (BCM_FAILURE(rv)) {
   1146                 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1147                     "AGM %d clear packet counter %d failed, rv = %d.\n"),
   1148                     agm_id, i, rv));
   1149                 goto _free_exit;
   1150             }
   1151         }
   1152 
   1153         /* Clear byte counters */
   1154         byte_flag = 1;
   1155         for (i = 0; i < nstat; i++) {
   1156             rv = _bcm_esw_stat_counter_set(unit, table_info[0].index,
   1157                     table_info[0].table, 0, byte_flag, counter_indexes[i],
   1158                     &counter_values[i]);
   1159             if (BCM_FAILURE(rv)) {
   1160                 LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1161                     "AGM %d clear byte counter %d failed, rv = %d.\n"),
   1162                     agm_id, i, rv));
   1163                 goto _free_exit;
   1164             }
   1165         }
   1166     }
   1167 
   1168 _free_exit:
   1169     if (counter_indexes) {
   1170         sal_free(counter_indexes);
   1171     }
   1172 
   1173     if (counter_values) {
   1174         sal_free(counter_values);
   1175     }
   1176 
   1177     return rv;
   1178 }
   1179 
   1180 /*
   1181  * Function:
   1182  *      bcm_esw_switch_agm_destroy
   1183  * Purpose:
   1184  *      Destroy an existing aggregation monitoring entry
   1185  */
   1186 int
   1187 bcm_th_switch_agm_destroy(int unit, bcm_switch_agm_id_t agm_id)
   1188 {
   1189     int i, rv = BCM_E_NONE;
   1190     agm_monitor_t *agm_mnt;
   1191     int pool_id;
   1192 
   1193     /* Validate parameters */
   1194     if (!SOC_UNIT_VALID(unit)) {
   1195         return BCM_E_UNIT;
   1196     }
   1197 
   1198     AGM_INIT(unit);
   1199     AGM_CHECK(unit, agm_id);
   1200 
   1201     agm_mnt = &AGM_INFO(unit, agm_id);
   1202     if (agm_mnt->attr.agm_id == _AGM_ID_INVALID) {
   1203         return BCM_E_NOT_FOUND;
   1204     }
   1205 
   1206     /* Disable running AGM */
   1207     AGM_LOCK(unit);
   1208     if (!agm_mnt->in_use) {
   1209         AGM_UNLOCK(unit);
   1210         return BCM_E_NOT_FOUND;
   1211     }
   1212 
   1213     if (agm_mnt->in_use && agm_mnt->group_id != _AGM_GROUP_ID_INVALID) {
   1214         LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1215             "AGM %d is attached need to detach first\n"), agm_id));
   1216         return BCM_E_BUSY;
   1217     }
   1218 
   1219     if (agm_mnt->running) {
   1220         rv = bcm_th_switch_agm_enable_set(unit, agm_id, FALSE);
   1221         if (BCM_FAILURE(rv)) {
   1222             AGM_UNLOCK(unit);
   1223             LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1224                 "AGM %d disable failed, rv = %d.\n"), agm_id, rv));
   1225             return rv;
   1226         }
   1227     }
   1228 
   1229     /* Destory flex counter */
   1230     rv = bcm_th_agm_stat_detach(unit, agm_mnt->attr.agm_id,
   1231                 agm_mnt->agm_pool_id, (uint32)agm_mnt->counter_id);
   1232     if (BCM_FAILURE(rv)) {
   1233         AGM_UNLOCK(unit);
   1234         LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1235             "AGM %d detach failed, rv = %d.\n"), agm_id, rv));
   1236         return rv;
   1237     }
   1238 
   1239     rv = bcm_th_agm_stat_id_clear(unit, agm_mnt->counter_id);
   1240     if (BCM_FAILURE(rv)) {
   1241         AGM_UNLOCK(unit);
   1242         LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1243             "AGM %d destroy counter id failed, rv = %d.\n"), agm_id, rv));
   1244         return rv;
   1245     }
   1246 
   1247     /* Restore AGM bookeeping info to default value */
   1248     pool_id = agm_mnt->agm_pool_id;
   1249     agm_mnt->in_use         = FALSE;
   1250     agm_mnt->running        = FALSE;
   1251     agm_mnt->agm_pool_id    = _AGM_POOL_ID_INVALID;
   1252     agm_mnt->group_id       = _AGM_GROUP_ID_INVALID;
   1253     agm_mnt->counter_id     = 0;
   1254     sal_memset(&agm_mnt->attr, 0, sizeof(agm_mnt->attr));
   1255     agm_mnt->attr.agm_id    = _AGM_ID_INVALID;
   1256 
   1257     rv = WRITE_AGM_MONITOR_TABLEm(unit, MEM_BLOCK_ANY, agm_id,
   1258             soc_mem_entry_null(unit, AGM_MONITOR_TABLEm));
   1259     if (BCM_SUCCESS(rv)) {
   1260         /* Using ref_cnt? */
   1261         for (i = AGM_CNTL(unit).agm_id_min; i <= AGM_CNTL(unit).agm_id_max; i++) {
   1262             if (AGM_INFO(unit, i).in_use &&
   1263                 AGM_INFO(unit, i).agm_pool_id == pool_id) {
   1264                 break;
   1265             }
   1266         }
   1267 
   1268         /* Free pool_id if nobody use it */
   1269         if (i > AGM_CNTL(unit).agm_id_max) {
   1270             AGM_CNTL(unit).agm_pool_conf[pool_id] = _AGM_POOL_ID_INVALID;
   1271         }
   1272     }
   1273 
   1274     AGM_UNLOCK(unit);
   1275     return rv;
   1276 }
   1277 
   1278 /*
   1279  * Function:
   1280  *      bcm_esw_switch_agm_trunk_attach_get
   1281  * Purpose:
   1282  *      Retrieve a (fabric) trunk_id where the monitor entry is attached
   1283  */
   1284 int
   1285 bcm_th_switch_agm_trunk_attach_get(int unit, bcm_switch_agm_id_t agm_id,
   1286                                    bcm_trunk_t *trunk_id)
   1287 {
   1288     int rv = BCM_E_NONE;
   1289 
   1290     /* Validate parameters */
   1291     if (!SOC_UNIT_VALID(unit)) {
   1292         return BCM_E_UNIT;
   1293     }
   1294 
   1295     if (trunk_id == NULL) {
   1296         return BCM_E_PARAM;
   1297     }
   1298 
   1299     AGM_INIT(unit);
   1300     AGM_CHECK(unit, agm_id);
   1301 
   1302     AGM_LOCK(unit);
   1303 
   1304     if (!AGM_INFO(unit, agm_id).in_use ||
   1305         AGM_INFO(unit, agm_id).group_id == _AGM_GROUP_ID_INVALID ||
   1306         (AGM_INFO(unit, agm_id).attr.agm_type != bcmSwitchAgmTypeTrunk &&
   1307          AGM_INFO(unit, agm_id).attr.agm_type != bcmSwitchAgmTypeFabricTrunk)
   1308         ){
   1309         AGM_UNLOCK(unit);
   1310         LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1311             "AGM %d trunk attach not found\n"), agm_id));
   1312         return BCM_E_NOT_FOUND;
   1313     }
   1314 
   1315     *trunk_id = (bcm_trunk_t)AGM_INFO(unit, agm_id).group_id;
   1316 
   1317     AGM_UNLOCK(unit);
   1318 
   1319     return rv;
   1320 }
   1321 
   1322 /*
   1323  * Function:
   1324  *      bcm_esw_switch_agm_l3_ecmp_attach_get
   1325  * Purpose:
   1326  *      Retrieve a l3 ecmp group id where the monitor entry is attached
   1327  */
   1328 int
   1329 bcm_th_switch_agm_l3_ecmp_attach_get(int unit, bcm_switch_agm_id_t agm_id,
   1330                                      bcm_if_t *l3_ecmp_id)
   1331 {
   1332     int rv = BCM_E_NONE;
   1333 
   1334     /* Validate parameters */
   1335     if (!SOC_UNIT_VALID(unit)) {
   1336         return BCM_E_UNIT;
   1337     }
   1338 
   1339     if (l3_ecmp_id == NULL) {
   1340         return BCM_E_PARAM;
   1341     }
   1342 
   1343     AGM_INIT(unit);
   1344     AGM_CHECK(unit, agm_id);
   1345 
   1346     AGM_LOCK(unit);
   1347     if (!AGM_INFO(unit, agm_id).in_use ||
   1348         AGM_INFO(unit, agm_id).group_id == _AGM_GROUP_ID_INVALID ||
   1349         ((AGM_INFO(unit, agm_id).attr.agm_type != bcmSwitchAgmTypeL3Ecmp) &&
   1350          (AGM_INFO(unit, agm_id).attr.agm_type != bcmSwitchAgmTypeL3EcmpOverlay))) {
   1351         AGM_UNLOCK(unit);
   1352         LOG_ERROR(BSL_LS_BCM_SWITCH, (BSL_META_U(unit,
   1353             "AGM %d l3 ecmp attach not found\n"), agm_id));
   1354         return BCM_E_NOT_FOUND;
   1355     }
   1356 
   1357     *l3_ecmp_id = (bcm_if_t)AGM_INFO(unit, agm_id).group_id;
   1358 
   1359     AGM_UNLOCK(unit);
   1360 
   1361     return rv;
   1362 }
   1363 
   1364 /*
   1365  * Function:
   1366  *      bcm_esw_switch_agm_get
   1367  * Purpose:
   1368  *      Retrieve the AGM monitor info of the specified AGM id.
   1369  */
   1370 int
   1371 bcm_th_switch_agm_get(int unit, bcm_switch_agm_info_t *agm_info)
   1372 {
   1373     int rv = BCM_E_NONE;
   1374     bcm_switch_agm_id_t agm_id;
   1375 
   1376     /* Validate parameters */
   1377     if (!SOC_UNIT_VALID(unit)) {
   1378         return BCM_E_UNIT;
   1379     }
   1380 
   1381     if (agm_info == NULL) {
   1382         return BCM_E_PARAM;
   1383     }
   1384 
   1385     AGM_INIT(unit);
   1386     agm_id = agm_info->agm_id;
   1387     AGM_CHECK(unit, agm_id);
   1388 
   1389     AGM_LOCK(unit);
   1390     if (!AGM_INFO(unit, agm_id).in_use) {
   1391         AGM_UNLOCK(unit);
   1392         return BCM_E_NOT_FOUND;
   1393     }
   1394 
   1395     sal_memcpy(agm_info, &AGM_INFO(unit, agm_id).attr, sizeof(*agm_info));
   1396 
   1397     AGM_UNLOCK(unit);
   1398     return rv;
   1399 }
   1400 
   1401 /*
   1402  * Function:
   1403  *      bcm_esw_switch_agm_enable_get
   1404  * Purpose:
   1405  *      Return a monitor entry's enable status
   1406  */
   1407 int
   1408 bcm_th_switch_agm_enable_get(int unit, bcm_switch_agm_id_t agm_id, int *enable)
   1409 {
   1410     int rv = BCM_E_NONE;
   1411 
   1412     /* Validate parameters */
   1413     if (!SOC_UNIT_VALID(unit)) {
   1414         return BCM_E_UNIT;
   1415     }
   1416 
   1417     if (enable == NULL) {
   1418         return BCM_E_PARAM;
   1419     }
   1420 
   1421     AGM_INIT(unit);
   1422     AGM_CHECK(unit, agm_id);
   1423 
   1424     AGM_LOCK(unit);
   1425     if (!AGM_INFO(unit, agm_id).in_use) {
   1426         AGM_UNLOCK(unit);
   1427         return BCM_E_NOT_FOUND;
   1428     }
   1429     *enable = AGM_INFO(unit, agm_id).running;
   1430 
   1431     AGM_UNLOCK(unit);
   1432 
   1433     return rv;
   1434 }
   1435 
   1436 /*
   1437  * Function:
   1438  *      bcm_esw_switch_agm_traverse
   1439  * Purpose:
   1440  *      Traverse over the aggregation monitor table (63 total entries)
   1441  *      and run callback at each entry.
   1442  */
   1443 int
   1444 bcm_th_switch_agm_traverse(int unit, int flags,
   1445                            bcm_switch_agm_traverse_cb trav_fn,
   1446                            void *user_data)
   1447 {
   1448     int i, rv = BCM_E_NONE;
   1449 
   1450     /* Validate parameters */
   1451     if (!SOC_UNIT_VALID(unit)) {
   1452         return BCM_E_UNIT;
   1453     }
   1454 
   1455     AGM_INIT(unit);
   1456 
   1457     if (trav_fn == NULL) {
   1458         return BCM_E_PARAM;
   1459     }
   1460 
   1461     /* Traverse each AGM in use */
   1462     AGM_LOCK(unit);
   1463     for (i = AGM_CNTL(unit).agm_id_min; i <= AGM_CNTL(unit).agm_id_max; i++) {
   1464         if (!AGM_INFO(unit, i).in_use) {
   1465             continue;
   1466         }
   1467 
   1468         rv = (*trav_fn)(unit, &AGM_INFO(unit, i).attr, user_data);
   1469         if (BCM_FAILURE(rv)) {
   1470             break;
   1471         }
   1472     }
   1473     AGM_UNLOCK(unit);
   1474 
   1475     return rv;
   1476 }
   1477 
   1478 int
   1479 bcm_th_switch_agm_info(int unit, bcm_switch_agm_id_t agm_id,
   1480                        agm_monitor_t *agm_mnt)
   1481 {
   1482     int rv = BCM_E_NONE;
   1483 
   1484     if (agm_mnt == NULL) {
   1485         return BCM_E_PARAM;
   1486     }
   1487 
   1488     AGM_CHECK(unit, agm_id);
   1489 
   1490     AGM_LOCK(unit);
   1491     rv = _bcm_th_switch_agm_info(unit, agm_id, agm_mnt);
   1492     AGM_UNLOCK(unit);
   1493 
   1494     return rv;
   1495 }
   1496 
   1497 int
   1498 bcm_th_switch_agm_fwd_grp_update(int unit, bcm_switch_agm_id_t agm_id,
   1499                                  int group_id)
   1500 {
   1501     int rv = BCM_E_NONE;
   1502 
   1503     AGM_CHECK(unit, agm_id);
   1504 
   1505     AGM_LOCK(unit);
   1506     if (AGM_INFO(unit, agm_id).in_use) {
   1507         AGM_INFO(unit, agm_id).group_id = group_id;
   1508     } else {
   1509         rv = BCM_E_NOT_FOUND;
   1510     }
   1511     AGM_UNLOCK(unit);
   1512 
   1513     return rv;
   1514 }
   1515 
   1516 int
   1517 bcm_th_switch_agm_id_get_by_group(int unit, int group_id,
   1518                                   bcm_switch_agm_id_t *agm_id)
   1519 {
   1520     int i;
   1521 
   1522     if (agm_id == NULL) {
   1523         return BCM_E_PARAM;
   1524     }
   1525 
   1526     AGM_LOCK(unit);
   1527     for (i = AGM_CNTL(unit).agm_id_min; i <= AGM_CNTL(unit).agm_id_max; i++) {
   1528         if (AGM_INFO(unit, i).in_use &&
   1529             AGM_INFO(unit, i).group_id == group_id) {
   1530             *agm_id = i;
   1531             AGM_UNLOCK(unit);
   1532             return BCM_E_NONE;
   1533         }
   1534     }
   1535     AGM_UNLOCK(unit);
   1536 
   1537     return BCM_E_NOT_FOUND;
   1538 }
   1539 /*
   1540  * Update following registers/field
   1541  *     IFP_METER_CONTROLr, PACKET_IFG_BYTESf
   1542  *     EGR_COUNTER_CONTROLr, PACKET_IFG_BYTESf
   1543  *     EGR_COUNTER_CONTROLr, PACKET_IFG_BYTES_2f
   1544  *     EGR_SHAPING_CONTROLr, PACKET_IFG_BYTESf
   1545  *     EGR_SHAPING_CONTROLr, PACKET_IFG_BYTES_2f
   1546  */
   1547 int
   1548 bcm_th_xgs3_meter_adjust_set(int unit, bcm_port_t port, int arg)
   1549 {
   1550     int len, max_val;
   1551     int i;
   1552     soc_reg_t reg[3] = { IFP_METER_CONTROLr,
   1553                          EGR_COUNTER_CONTROLr,
   1554                          EGR_SHAPING_CONTROLr };
   1555 
   1556     if (!soc_feature(unit, soc_feature_meter_adjust)) {
   1557         return BCM_E_UNAVAIL;
   1558     }
   1559 
   1560     for (i = 0; i < 3 ; ++i ) { 
   1561         if (SOC_REG_FIELD_VALID(unit, reg[i], PACKET_IFG_BYTESf)) {
   1562             len = soc_reg_field_length(unit, reg[i], PACKET_IFG_BYTESf);
   1563             max_val = (1 << len) - 1;
   1564             if (arg < 0 || arg > max_val) {
   1565                 return BCM_E_PARAM;
   1566             }
   1567             SOC_IF_ERROR_RETURN(
   1568                 soc_reg_field32_modify(unit, reg[i], port,
   1569                                        PACKET_IFG_BYTESf, arg));
   1570         }
   1571 
   1572         if (SOC_REG_FIELD_VALID(unit, reg[i], PACKET_IFG_BYTES_2f)) {
   1573             len = soc_reg_field_length(unit, reg[i], PACKET_IFG_BYTES_2f);
   1574             max_val = (1 << len) - 1;
   1575             if (arg < 0 || arg > max_val) {
   1576                 return BCM_E_PARAM;
   1577             }
   1578             SOC_IF_ERROR_RETURN(
   1579                 soc_reg_field32_modify(unit, reg[i], port,
   1580                                        PACKET_IFG_BYTES_2f, arg));
   1581         }
   1582     }
   1583 
   1584     return BCM_E_NONE;
   1585 }
   1586 
   1587 int
   1588 bcm_th_xgs3_meter_adjust_get(int unit, bcm_port_t port, int *arg)
   1589 {
   1590     uint32 val;
   1591 
   1592     BCM_IF_ERROR_RETURN(
   1593         READ_EGR_COUNTER_CONTROLr(unit, port, &val));
   1594     *arg = soc_reg_field_get(unit, EGR_COUNTER_CONTROLr, val,
   1595                                PACKET_IFG_BYTESf);
   1596     return BCM_E_NONE;
   1597 }
   1598 
   1599 
   1600 #endif  /* defined(BCM_TOMAHAWK_SUPPORT) */
   1601