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

pstats.c (49927B)


      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  * Packetized Statistic
      8  * Purpose: API to set Packetized Stats registers.
      9  */
     10 
     11 #include <sal/core/libc.h>
     12 
     13 #include <shared/bsl.h>
     14 #include <soc/defs.h>
     15 
     16 #if defined(INCLUDE_PSTATS) && defined(BCM_TOMAHAWK2_SUPPORT)
     17 #include <soc/drv.h>
     18 #include <soc/mem.h>
     19 #include <soc/profile_mem.h>
     20 #include <soc/debug.h>
     21 #include <soc/tomahawk2.h>
     22 #include <soc/pstats.h>
     23 
     24 #include <bcm/error.h>
     25 #include <bcm/pstats.h>
     26 
     27 #include <bcm_int/esw/mbcm.h>
     28 #include <bcm_int/esw/tomahawk.h>
     29 #include <bcm_int/esw/tomahawk2.h>
     30 
     31 #include <bcm_int/esw_dispatch.h>
     32 #include <bcm_int/esw/pstats.h>
     33 
     34 #ifdef BCM_WARM_BOOT_SUPPORT
     35 #include <bcm_int/esw/switch.h>
     36 #endif /* BCM_WARM_BOOT_SUPPORT */
     37 
     38 #define PSTATS_SESSION_MIN          1
     39 #define PSTATS_SESSION_MAX          256
     40 /* Max 4 XPEs and 4 PIPEs */
     41 #define TH2_MAX_XPEPIPE             16
     42 #define TH2_MAX_POOL_COUNT          4
     43 #define TH2_MAX_UCQ_COUNT           1344
     44 
     45 /* Max Elements Count = UCQ + ING POOL + EGR POOL */
     46 #define TH2_MAX_ELEMENT_COUNT       TH2_MAX_UCQ_COUNT + TH2_MAX_POOL_COUNT * 2
     47 
     48 #define TH2_PORT_NUM_COS(unit, port)                            \
     49     ((IS_CPU_PORT(unit, port)) ? NUM_CPU_COSQ(unit) :           \
     50      (IS_LB_PORT(unit, port)) ? 10 : NUM_COS(unit))
     51 
     52 /*
     53  * Macro to get buffer index
     54  * Per XPE or PIPE instance (ING POOL & EGR POOL)
     55  * buffer_id = xpe or pipe
     56  *  ----------------------
     57  * | buffer | xpe or pipe |
     58  * |   0    |     0       |
     59  * |   1    |     1       |
     60  * |   2    |     2       |
     61  * |   3    |     3       |
     62  *  ----------------------
     63  * Per XPE-PIPE instance (UCQ)
     64  * buffer_id = xpe * NUM_PIPE(unit) + pipe
     65  *  --------------------
     66  * | buffer | xpe | pipe |
     67  * |   0    |  0  |  0   |
     68  * |   1    |  0  |  1   |
     69  * |   2    |  0  |  2   |
     70  * |   3    |  0  |  3   |
     71  * |   4    |  1  |  0   |
     72  * |   5    |  1  |  1   |
     73  * |   6    |  1  |  2   |
     74  * |   7    |  1  |  3   |
     75  * |   8    |  2  |  0   |
     76  * |   9    |  2  |  1   |
     77  * |   10   |  2  |  2   |
     78  * |   11   |  2  |  3   |
     79  * |   12   |  3  |  0   |
     80  * |   13   |  3  |  1   |
     81  * |   14   |  3  |  2   |
     82  * |   15   |  3  |  3   |
     83  *  ---------------------
     84  */
     85 #define TH2_XPE_PIPE_INDEX(unit, xpe, pipe)                     \
     86     (((xpe) == -1) ? (pipe) :                                   \
     87      ((pipe) == -1) ? (xpe) : (xpe) * NUM_PIPE(unit) + (pipe))
     88 
     89 #define TH2_XPE_VALID(unit, xpe, valid)                        \
     90         do {                                                    \
     91             if (soc_property_get(unit, "num_pipe", 4) == 2) {   \
     92                 if (xpe == 1 || xpe == 3) {                     \
     93                     valid = FALSE;                              \
     94                 }                                               \
     95             }                                                   \
     96         } while (0);
     97 
     98 typedef struct pstats_session_s {
     99     bcm_pstats_session_id_t         session_id;
    100 
    101     /* session buffer */
    102     bcm_pstats_timestamp_t          timestamp;
    103     bcm_pstats_data_t               *data_array;
    104 
    105     /* session element info */
    106     int                             element_array_count;
    107     bcm_pstats_session_element_t    element_array[TH2_MAX_ELEMENT_COUNT];
    108 
    109     uint32                          enable;
    110 
    111     /* prev session */
    112     struct pstats_session_s         *prev_session;
    113     /* next session */
    114     struct pstats_session_s         *next_session;
    115 } pstats_session_t;
    116 
    117 typedef struct pstats_buffer_s {
    118     soc_mem_t                       mem;
    119     soc_mem_t                       clear_mem;
    120     int                             min_idx;
    121     int                             max_idx;
    122     int                             num_entries;
    123     uint8                           *buf;
    124 } pstats_buffer_t;
    125 
    126 typedef struct pstats_control_s {
    127     /* full buffer */
    128 #ifdef BCM_PSTATS_MEASURE
    129     pstats_buffer_t                 local_time;
    130     pstats_buffer_t                 local_time_end;
    131 #endif
    132     pstats_buffer_t                 utc_time;
    133     pstats_buffer_t                 ucq_buffer[TH2_MAX_XPEPIPE];
    134     pstats_buffer_t                 ing_pool_buffer[TH2_MAX_POOL_COUNT];
    135     pstats_buffer_t                 egr_pool_buffer[TH2_MAX_POOL_COUNT];
    136 
    137     bcm_pstats_session_id_t         next_session_id;
    138     uint32                          session_count;
    139 #ifdef BCM_PSTATS_MEASURE
    140     uint64                          time_cost;
    141 #endif
    142     int                             stat_mode;
    143     int                             hw_cor_in_max_use_count;
    144     pstats_session_t                *first_session;
    145 } pstats_control_t;
    146 
    147 static soc_field_t                  ucq_field[4] = {UCQ_COUNT0f, UCQ_COUNT1f,
    148                                                     UCQ_COUNT2f, UCQ_COUNT3f};
    149 static soc_field_t                  isp_field[4] = {SP0f, SP1f, SP2f, SP3f};
    150 static soc_field_t                  esp_field[4] = {COUNT_0f, COUNT_1f,
    151                                                     COUNT_2f, COUNT_3f};
    152 
    153 static pstats_control_t             pstats_control[BCM_MAX_NUM_UNITS];
    154 #define PSTATS_CTRL(u)              pstats_control[u]
    155 
    156 STATIC int
    157 bcm_th2_pstats_session_create(int unit, int options, int array_count,
    158                               bcm_pstats_session_element_t  *element_array,
    159                               bcm_pstats_session_id_t *session_id);
    160 STATIC int
    161 bcm_th2_pstats_session_destroy(int unit, bcm_pstats_session_id_t session_id);
    162 STATIC int
    163 bcm_th2_pstats_session_get(int unit, bcm_pstats_session_id_t session_id,
    164                            int array_max,
    165                            bcm_pstats_session_element_t *element_array,
    166                            int *array_count);
    167 STATIC int bcm_th2_pstats_data_sync(int unit);
    168 STATIC int
    169 bcm_th2_pstats_session_data_get(int unit, bcm_pstats_session_id_t session_id,
    170                                 int sync,
    171                                 bcm_pstats_timestamp_t *timestamp,
    172                                 int array_max,
    173                                 bcm_pstats_data_t *data,
    174                                 int *array_count);
    175 STATIC int
    176 bcm_th2_pstats_session_data_clear(int unit, bcm_pstats_session_id_t session_id);
    177 STATIC int
    178 bcm_th2_pstats_session_traverse(int unit, bcm_pstats_session_traverse_cb cb,
    179                                 void *user_data);
    180 
    181 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP
    182 /*
    183  * Function:
    184  *     bcm_th2_pstats_sw_dump
    185  * Purpose:
    186  *     Displays PSTATS information maintained by software.
    187  * Parameters:
    188  *     unit - Device unit number
    189  * Returns:
    190  *     None
    191  */
    192 STATIC void
    193 bcm_th2_pstats_sw_dump(int unit)
    194 {
    195     pstats_session_t *cur_session;
    196 
    197     LOG_CLI((BSL_META_U(unit,
    198                         "=========== \n")));
    199     LOG_CLI((BSL_META_U(unit, "Pstats mode: %s\n"),
    200                         PSTATS_CTRL(unit).stat_mode ?
    201                         "Max-use-count" : "Instantaneous"));
    202     LOG_CLI((BSL_META_U(unit, "Total pstats session count: %d\n"),
    203                         PSTATS_CTRL(unit).session_count));
    204     cur_session = PSTATS_CTRL(unit).first_session;
    205     while (NULL != cur_session) {
    206         LOG_CLI((BSL_META_U(unit,
    207                             "Pstats session id: %d element count: %d\n"),
    208                             cur_session->session_id,
    209                             cur_session->element_array_count));
    210         cur_session = cur_session->next_session;
    211     }
    212     LOG_CLI((BSL_META_U(unit,
    213                         "=========== \n")));
    214     return;
    215 }
    216 #endif /* BCM_WARM_BOOT_SUPPORT_SW_DUMP */
    217 
    218 STATIC void
    219 _bcm_th2_pstats_session_cleanup(int unit, pstats_session_t *session)
    220 {
    221     session->enable = FALSE;
    222     if (NULL != session->data_array) {
    223         sal_free(session->data_array);
    224     }
    225 
    226     sal_memset(session, 0, sizeof(pstats_session_t));
    227 
    228     return;
    229 }
    230 
    231 STATIC pstats_session_t*
    232 _bcm_th2_pstats_session_get(int unit, bcm_pstats_session_id_t session_id)
    233 {
    234     int                 found = 0;
    235     pstats_session_t   *cur_session;
    236 
    237     cur_session = PSTATS_CTRL(unit).first_session;
    238     while (NULL != cur_session) {
    239         if (cur_session->session_id == session_id) {
    240             found = 1;
    241             break;
    242         }
    243         cur_session = cur_session->next_session;
    244     }
    245 
    246     if (found) {
    247         return cur_session;
    248     }
    249 
    250     return NULL;
    251 }
    252 
    253 /* Set a minimum available session id */
    254 STATIC void
    255 _bcm_th2_pstats_session_next_id_set(int unit)
    256 {
    257     pstats_session_t            *cur_session;
    258     bcm_pstats_session_id_t     id = PSTATS_SESSION_MIN;
    259 
    260     cur_session = PSTATS_CTRL(unit).first_session;
    261     while (NULL != cur_session) {
    262         if (id < cur_session->session_id) {
    263             break;
    264         } else if (id == cur_session->session_id) {
    265             /* this id already existed */
    266             id++;
    267         }
    268         cur_session = cur_session->next_session;
    269     }
    270 
    271     PSTATS_CTRL(unit).next_session_id = id;
    272 
    273     LOG_INFO(BSL_LS_BCM_PSTATS, (BSL_META_U(unit, "next %d\n"), id));
    274 }
    275 
    276 STATIC int
    277 _bcm_th2_pstats_session_delete(int unit, bcm_pstats_session_id_t session_id)
    278 {
    279     pstats_session_t            *cur_session;
    280 
    281     cur_session = _bcm_th2_pstats_session_get(unit, session_id);
    282     if (NULL == cur_session) {
    283         LOG_INFO(BSL_LS_BCM_PSTATS,
    284                  (BSL_META_U(unit, "pstats session %d not found\n"), session_id));
    285         return BCM_E_NOT_FOUND;
    286     }
    287     /* update session link */
    288     if ((NULL == cur_session->prev_session) &&
    289         (NULL == cur_session->next_session)) {
    290         /* only one session */
    291         PSTATS_CTRL(unit).first_session = NULL;
    292     } else if (NULL == cur_session->prev_session) {
    293         /* first session */
    294         PSTATS_CTRL(unit).first_session = cur_session->next_session;
    295         cur_session->next_session->prev_session = NULL;
    296     } else if (NULL == cur_session->next_session) {
    297         /* last session */
    298         cur_session->prev_session->next_session = NULL;
    299     } else {
    300         cur_session->prev_session->next_session = cur_session->next_session;
    301         cur_session->next_session->prev_session = cur_session->prev_session;
    302     }
    303     _bcm_th2_pstats_session_cleanup(unit, cur_session);
    304     if (NULL != cur_session) {
    305         sal_free(cur_session);
    306     }
    307     PSTATS_CTRL(unit).session_count--;
    308 
    309     _bcm_th2_pstats_session_next_id_set(unit);
    310 
    311     return BCM_E_NONE;
    312 }
    313 
    314 STATIC void
    315 _bcm_th2_pstats_session_insert(int unit, pstats_session_t *session)
    316 {
    317     pstats_session_t            *cur_session;
    318     bcm_pstats_session_id_t     id = session->session_id;
    319 
    320     cur_session = PSTATS_CTRL(unit).first_session;
    321     if (NULL == cur_session) {
    322         /* first session */
    323         PSTATS_CTRL(unit).first_session = session;
    324         session->prev_session = NULL;
    325         session->next_session = NULL;
    326     }
    327     while (NULL != cur_session) {
    328         if (id > cur_session->session_id) {
    329             /* last session */
    330             if (NULL == cur_session->next_session) {
    331                 cur_session->next_session = session;
    332                 session->prev_session = cur_session;
    333                 session->next_session = NULL;
    334                 break;
    335             } else {
    336                 cur_session = cur_session->next_session;
    337             }
    338         } else {
    339             /* first session */
    340             if (NULL == cur_session->prev_session) {
    341                 PSTATS_CTRL(unit).first_session = session;
    342                 session->prev_session = NULL;
    343                 session->next_session = cur_session;
    344                 cur_session->prev_session = session;
    345                 break;
    346             } else {
    347                 session->prev_session = cur_session->prev_session;
    348                 session->next_session = cur_session;
    349                 cur_session->prev_session->next_session = session;
    350                 cur_session->prev_session = session;
    351                 break;
    352             }
    353             break;
    354         }
    355     }
    356     PSTATS_CTRL(unit).session_count++;
    357 
    358     session->enable = TRUE;
    359 
    360     return;
    361 }
    362 
    363 STATIC void
    364 _bcm_th2_pstats_buffer_deinit(int unit, pstats_buffer_t *pbuf)
    365 {
    366     if (NULL == pbuf) {
    367         return;
    368     }
    369 
    370     if (NULL != pbuf->buf) {
    371         sal_free(pbuf->buf);
    372     }
    373     sal_memset(pbuf, 0, sizeof(pstats_buffer_t));
    374 
    375     return;
    376 }
    377 
    378 STATIC int
    379 _bcm_th2_pstats_buffer_init(int unit, soc_mem_t mem, soc_mem_t clear_mem,
    380                             pstats_buffer_t *pbuf)
    381 {
    382     int alloc_size;
    383 
    384     if (NULL == pbuf) {
    385         return BCM_E_PARAM;
    386     }
    387 
    388     if (NULL != pbuf->buf) {
    389         return BCM_E_PARAM;
    390     }
    391 
    392     pbuf->mem = mem;
    393     pbuf->clear_mem = clear_mem;
    394     pbuf->min_idx = soc_mem_index_min(unit, mem);
    395     pbuf->max_idx = soc_mem_index_max(unit, mem);
    396     pbuf->num_entries = soc_mem_index_max(unit, mem) + 1;
    397     alloc_size = sizeof(uint32) * soc_mem_entry_words(unit, mem);
    398     alloc_size *= pbuf->num_entries;
    399 
    400     pbuf->buf = sal_alloc(alloc_size, "pstats buffer");
    401     if (pbuf->buf == NULL) {
    402         return BCM_E_MEMORY;
    403     }
    404     sal_memset(pbuf->buf, 0, alloc_size);
    405 
    406     return BCM_E_NONE;
    407 }
    408 
    409 /*
    410  * Function:
    411  *      bcm_th2_pstats_deinit
    412  * Purpose:
    413  *      Deinitialize PSTATS driver functions
    414  *      for Tomahawk2 (BCM56970).
    415  * Parameters:
    416  *      unit - (IN) StrataSwitch unit number.
    417  * Returns:
    418  *      BCM_E_XXX
    419  */
    420 void
    421 bcm_th2_pstats_deinit(int unit)
    422 {
    423     pstats_session_t *cur_session, *next_session;
    424     int i;
    425 
    426     soc_pstats_deinit(unit);
    427 
    428 #ifdef BCM_PSTATS_MEASURE
    429     _bcm_th2_pstats_buffer_deinit(unit, &PSTATS_CTRL(unit).local_time);
    430     _bcm_th2_pstats_buffer_deinit(unit, &PSTATS_CTRL(unit).local_time_end);
    431 #endif
    432     _bcm_th2_pstats_buffer_deinit(unit, &PSTATS_CTRL(unit).utc_time);
    433     for (i = 0; i < TH2_MAX_XPEPIPE; i++) {
    434         _bcm_th2_pstats_buffer_deinit(unit, &PSTATS_CTRL(unit).ucq_buffer[i]);
    435     }
    436     for (i = 0; i < TH2_MAX_POOL_COUNT; i++) {
    437         _bcm_th2_pstats_buffer_deinit(unit, &PSTATS_CTRL(unit).ing_pool_buffer[i]);
    438         _bcm_th2_pstats_buffer_deinit(unit, &PSTATS_CTRL(unit).egr_pool_buffer[i]);
    439     }
    440 
    441     cur_session = PSTATS_CTRL(unit).first_session;
    442     while (NULL != cur_session) {
    443         next_session = cur_session->next_session;
    444         _bcm_th2_pstats_session_cleanup(unit, cur_session);
    445         if (NULL != cur_session) {
    446             sal_free(cur_session);
    447         }
    448         PSTATS_CTRL(unit).session_count--;
    449         cur_session = next_session;
    450     }
    451 
    452     if (PSTATS_CTRL(unit).session_count != 0) {
    453         /* debug info */
    454     }
    455     sal_memset(&PSTATS_CTRL(unit), 0, sizeof(pstats_control_t));
    456 
    457     return;
    458 }
    459 
    460 
    461 /*
    462  * Function:
    463  *      bcm_th2_pstats_init
    464  * Purpose:
    465  *      Initialize PSTATS driver functions
    466  *      for Tomahawk2 (BCM56970).
    467  * Parameters:
    468  *      unit - (IN) StrataSwitch unit number.
    469  * Returns:
    470  *      BCM_E_XXX
    471  */
    472 int
    473 bcm_th2_pstats_init(int unit)
    474 {
    475     _bcm_pstats_unit_driver_t   *pstats_driver;
    476     pstats_buffer_t             *pbuf;
    477     int                         rv = BCM_E_NONE;
    478     soc_mem_t                   mem, clear_mem, base_mem;
    479     int                         index, pipe, xpe;
    480     uint32                      flag;
    481 
    482     if (2 != soc_property_get(unit, spn_BUFFER_STATS_COLLECT_TYPE, 1)) {
    483         LOG_INFO(BSL_LS_BCM_PSTATS,
    484                  (BSL_META_U(unit, "current mode is not pstats, no need init\n")));
    485         return BCM_E_NONE;
    486     }
    487 
    488     pstats_driver = _BCM_PSTATS_UNIT_DRIVER(unit);
    489     if (pstats_driver == NULL) {
    490         return BCM_E_MEMORY;
    491     }
    492 
    493     /* Initializing Driver functions for PSTATS */
    494     pstats_driver->session_create = bcm_th2_pstats_session_create;
    495     pstats_driver->session_destroy = bcm_th2_pstats_session_destroy;
    496     pstats_driver->session_get = bcm_th2_pstats_session_get;
    497     pstats_driver->data_sync = bcm_th2_pstats_data_sync;
    498     pstats_driver->session_data_get = bcm_th2_pstats_session_data_get;
    499     pstats_driver->session_data_clear = bcm_th2_pstats_session_data_clear;
    500     pstats_driver->session_traverse = bcm_th2_pstats_session_traverse;
    501 #ifdef BCM_WARM_BOOT_SUPPORT_SW_DUMP
    502     pstats_driver->pstats_sw_dump = bcm_th2_pstats_sw_dump;
    503 #endif
    504 
    505     /* alloc buffer for full pstats table */
    506 #ifdef BCM_PSTATS_MEASURE
    507     /* local time */
    508     mem = MMU_INTFO_TIMESTAMPm;
    509     pbuf = &PSTATS_CTRL(unit).local_time;
    510     rv = _bcm_th2_pstats_buffer_init(unit, mem, mem, pbuf);
    511     if (BCM_FAILURE(rv)) {
    512         goto cleanup;
    513     }
    514     mem = MMU_INTFO_TIMESTAMPm;
    515     pbuf = &PSTATS_CTRL(unit).local_time_end;
    516     rv = _bcm_th2_pstats_buffer_init(unit, mem, mem, pbuf);
    517     if (BCM_FAILURE(rv)) {
    518         goto cleanup;
    519     }
    520 #endif
    521 
    522     /* utc time */
    523     mem = MMU_INTFO_UTC_TIMESTAMPm;
    524     pbuf = &PSTATS_CTRL(unit).utc_time;
    525     rv = _bcm_th2_pstats_buffer_init(unit, mem, mem, pbuf);
    526     if (BCM_FAILURE(rv)) {
    527         goto cleanup;
    528     }
    529 
    530     /* ucq buffer */
    531     base_mem = MMU_THDU_UCQ_STATS_TABLEm;
    532     for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) {
    533         for (xpe = 0; xpe < NUM_XPE(unit); xpe++) {
    534             mem = SOC_MEM_UNIQUE_ACC_XPE_PIPE(unit, base_mem, xpe, pipe);
    535             clear_mem = SOC_MEM_UNIQUE_ACC_XPE_PIPE(unit, MMU_THDU_UCQ_STATSm,
    536                                                     xpe, pipe);
    537             if (mem == INVALIDm) {
    538                 continue;
    539             }
    540 
    541             index = TH2_XPE_PIPE_INDEX(unit, xpe, pipe);
    542             if (index >= TH2_MAX_XPEPIPE) {
    543                 rv = BCM_E_INTERNAL;
    544                 goto cleanup;
    545             }
    546             pbuf = &PSTATS_CTRL(unit).ucq_buffer[index];
    547 
    548             rv = _bcm_th2_pstats_buffer_init(unit, mem, clear_mem, pbuf);
    549             if (BCM_FAILURE(rv)) {
    550                 goto cleanup;
    551             }
    552         }
    553     } /* ucq buffer */
    554 
    555     /* ing pool buffer */
    556     base_mem = THDI_PKT_STAT_SP_SHARED_COUNTm;
    557     for (xpe = 0; xpe < NUM_XPE(unit); xpe++) {
    558         mem = SOC_MEM_UNIQUE_ACC(unit, base_mem)[xpe];
    559         if (mem == INVALIDm) {
    560             continue;
    561         }
    562 
    563         index = TH2_XPE_PIPE_INDEX(unit, xpe, -1);
    564         if (index >= TH2_MAX_POOL_COUNT) {
    565             rv = BCM_E_INTERNAL;
    566             goto cleanup;
    567         }
    568         pbuf = &PSTATS_CTRL(unit).ing_pool_buffer[index];
    569 
    570         rv = _bcm_th2_pstats_buffer_init(unit, mem, mem, pbuf);
    571         if (BCM_FAILURE(rv)) {
    572             goto cleanup;
    573         }
    574     } /* ing pool buffer */
    575 
    576     /* egr pool buffer */
    577     base_mem = MMU_THDM_DB_POOL_MCUC_PKSTATm;
    578     for (xpe = 0; xpe < NUM_XPE(unit); xpe++) {
    579         mem = SOC_MEM_UNIQUE_ACC(unit, base_mem)[xpe];
    580         if (mem == INVALIDm) {
    581             continue;
    582         }
    583 
    584         index = TH2_XPE_PIPE_INDEX(unit, xpe, -1);
    585         if (index >= TH2_MAX_POOL_COUNT) {
    586             rv = BCM_E_INTERNAL;
    587             goto cleanup;
    588         }
    589         pbuf = &PSTATS_CTRL(unit).egr_pool_buffer[index];
    590 
    591         rv = _bcm_th2_pstats_buffer_init(unit, mem, mem, pbuf);
    592         if (BCM_FAILURE(rv)) {
    593             goto cleanup;
    594         }
    595     } /* egr pool buffer */
    596 
    597     PSTATS_CTRL(unit).next_session_id = PSTATS_SESSION_MIN;
    598 
    599     rv = soc_pstats_init(unit);
    600     if (BCM_FAILURE(rv)) {
    601         LOG_INFO(BSL_LS_SOC_COMMON,
    602                  (BSL_META_U(unit, "soc_pstats_init failed rv = %d\n"), rv));
    603         goto cleanup;
    604     }
    605 
    606 #ifdef BCM_WARM_BOOT_SUPPORT
    607     if (SOC_WARM_BOOT(unit)) {
    608         int config;
    609 
    610         /* get pstats config from HW */
    611         rv = soc_tomahawk2_mmu_pstats_mode_get(unit, &flag);
    612         if (BCM_FAILURE(rv)) {
    613             goto cleanup;
    614         }
    615 
    616         /* HW config is different with config property */
    617         if (!(flag & _TH2_MMU_PSTATS_ENABLE) ||
    618             !(flag & _TH2_MMU_PSTATS_PKT_MOD)) {
    619             LOG_ERROR(BSL_LS_SOC_COMMON,
    620                       (BSL_META_U(unit,
    621                                   "WARMBOOT ERROR.\n"
    622                                   "Current buffer stats mode is not pstats.\n")));
    623             rv = BCM_E_INIT;
    624             goto cleanup;
    625         }
    626 
    627         if (flag & _TH2_MMU_PSTATS_HWM_MOD) {
    628             PSTATS_CTRL(unit).stat_mode = 1;
    629             if (flag & _TH2_MMU_PSTATS_RESET_ON_READ) {
    630                 PSTATS_CTRL(unit).hw_cor_in_max_use_count = 1;
    631             } else {
    632                 PSTATS_CTRL(unit).hw_cor_in_max_use_count = 0;
    633             }
    634         } else {
    635             PSTATS_CTRL(unit).stat_mode = 0;
    636             PSTATS_CTRL(unit).hw_cor_in_max_use_count = 0;
    637         }
    638 
    639         config = soc_property_get(unit, spn_BUFFER_STATS_COLLECT_MODE, 0);
    640         if (config != PSTATS_CTRL(unit).stat_mode) {
    641             LOG_WARN(BSL_LS_SOC_COMMON,
    642                      (BSL_META_U(unit,
    643                                  "WARMBOOT WARNING.\n"
    644                                  "Config mode %d. HW mode %d.\n"),
    645                                  config, PSTATS_CTRL(unit).stat_mode));
    646         }
    647 
    648         flag |= _TH2_MMU_PSTATS_SYNC | _TH2_MMU_PSTATS_MOR_EN;
    649 
    650         /* Reset pstats mode in warmboot */
    651         rv = soc_tomahawk2_mmu_pstats_mode_set(unit, flag);
    652         if (BCM_FAILURE(rv)) {
    653             goto cleanup;
    654         }
    655     } else
    656 #endif
    657     {
    658         PSTATS_CTRL(unit).stat_mode =
    659                 soc_property_get(unit, spn_BUFFER_STATS_COLLECT_MODE, 0);
    660         if ((PSTATS_CTRL(unit).stat_mode == 1) &&
    661             soc_property_get(unit, "oob_pstats_hw_cor_en", 1)) {
    662             PSTATS_CTRL(unit).hw_cor_in_max_use_count = 1;
    663         }
    664 
    665         /* call soc function */
    666         flag = _TH2_MMU_PSTATS_ENABLE |
    667                _TH2_MMU_PSTATS_PKT_MOD |
    668                _TH2_MMU_PSTATS_SYNC |
    669                _TH2_MMU_PSTATS_MOR_EN;
    670 
    671 
    672         if (PSTATS_CTRL(unit).stat_mode) {
    673             flag |= _TH2_MMU_PSTATS_HWM_MOD;
    674             if (PSTATS_CTRL(unit).hw_cor_in_max_use_count == 1) {
    675                 flag |= _TH2_MMU_PSTATS_RESET_ON_READ;
    676             }
    677         }
    678 
    679         rv = soc_tomahawk2_mmu_pstats_mode_set(unit, flag);
    680         if (BCM_FAILURE(rv)) {
    681             goto cleanup;
    682         }
    683     }
    684 
    685     return BCM_E_NONE;
    686 
    687 cleanup:
    688     soc_pstats_deinit(unit);
    689     (void )bcm_th2_pstats_deinit(unit);
    690 
    691     return rv;
    692 }
    693 
    694 STATIC int
    695 _bcm_th2_pstats_session_element_check(int unit,
    696                                        bcm_pstats_session_element_t element)
    697 {
    698     bcm_gport_t                 gport;
    699     bcm_port_t                  local_port;
    700     bcm_cos_queue_t             cosq;
    701 
    702     LOG_INFO(BSL_LS_BCM_PSTATS,
    703              (BSL_META_U(unit, "pstats_session_element_check unit %d\n"), unit));
    704 
    705     if (element.type == bcmPStatsSessionUnicastQueue) {
    706         gport = element.gport;
    707         cosq = element.cosq;
    708         if (BCM_GPORT_IS_SET(gport)) {
    709             if (BCM_GPORT_IS_LOCAL(gport)) {
    710                 local_port = BCM_GPORT_LOCAL_GET(gport);
    711             } else if (BCM_GPORT_IS_MODPORT(gport)) {
    712                 BCM_IF_ERROR_RETURN(
    713                     bcm_esw_port_local_get(unit, gport, &local_port));
    714             } else if (BCM_GPORT_IS_UCAST_QUEUE_GROUP(gport)) {
    715                 return BCM_E_NONE;
    716             } else {
    717                 LOG_INFO(BSL_LS_BCM_PSTATS,
    718                          (BSL_META_U(unit,
    719                                      "pstats_session_element_check: "
    720                                      "gport 0x%x is illegal!\n"), gport));
    721                 return BCM_E_PARAM;
    722             }
    723         } else {
    724             local_port = gport;
    725         }
    726 
    727         if (!SOC_PORT_VALID(unit, local_port) || IS_CPU_PORT(unit, local_port)) {
    728             LOG_INFO(BSL_LS_BCM_PSTATS,
    729                      (BSL_META_U(unit,
    730                                  "pstats_session_element_check: "
    731                                  "gport 0x%x is illegal!\n"), gport));
    732             return BCM_E_PORT;
    733         }
    734         /* cosq check when gport is a port gport */
    735         if ((cosq < 0) || (cosq >= TH2_PORT_NUM_COS(unit, local_port))) {
    736             LOG_INFO(BSL_LS_BCM_PSTATS,
    737                      (BSL_META_U(unit,
    738                                  "pstats_session_element_check: "
    739                                  "cosq %d is illegal!\n"), cosq));
    740             return BCM_E_PARAM;
    741         }
    742     } else if ((element.type == bcmPStatsSessionIngPool) ||
    743                (element.type == bcmPStatsSessionEgrPool)) {
    744         if ((element.pool < 0) || (element.pool >= TH2_MAX_POOL_COUNT)) {
    745             LOG_INFO(BSL_LS_BCM_PSTATS,
    746                      (BSL_META_U(unit,
    747                                  "pstats_session_element_check: "
    748                                  "pool_id %d is illegal!\n"), element.pool));
    749             return BCM_E_PARAM;
    750         }
    751     } else {
    752         LOG_INFO(BSL_LS_BCM_PSTATS,
    753                  (BSL_META_U(unit,
    754                              "pstats_session_element_check: "
    755                              "unknow element type %d\n"), element.type));
    756         return BCM_E_PARAM;
    757     }
    758 
    759     return BCM_E_NONE;
    760 }
    761 
    762 
    763 /*
    764  * Function:
    765  *      bcm_th2_pstats_session_create
    766  * Purpose:
    767  *      Create a PKT STAT session instance for SDK management.
    768  * Parameters:
    769  *      unit - (IN) StrataSwitch unit number.
    770  *      options - (IN) BCM_PSTATS_REPLACE: replace existing.
    771  *                     BCM_PSTATS_WITH_ID: session_id argument is given.
    772  *      array_count - (IN) Number of elements in array.
    773  *      element_array - (IN) PSTATS session element array.
    774  *      session_id - (INOUT) id of a PSTATS session created via this API.
    775  * Returns:
    776  *      BCM_E_XXX
    777  */
    778 STATIC int
    779 bcm_th2_pstats_session_create(int unit, int options, int array_count,
    780                               bcm_pstats_session_element_t  *element_array,
    781                               bcm_pstats_session_id_t *session_id)
    782 {
    783     int                         rv, i, alloc_size;
    784     bcm_pstats_session_id_t     id = 0;
    785     pstats_session_t            *cur_session = NULL;
    786 
    787     LOG_INFO(BSL_LS_BCM_PSTATS,
    788              (BSL_META_U(unit, "pstats_session_create unit %d options %d "
    789                                "array_count %d\n"), unit, options, array_count));
    790 
    791     /* element check */
    792     if ((array_count < 0) ||
    793         (array_count > TH2_MAX_ELEMENT_COUNT)) {
    794         LOG_ERROR(BSL_LS_BCM_PSTATS,
    795                   (BSL_META_U(unit, "array_count %d is illegal!\n"), array_count));
    796         return BCM_E_PARAM;
    797     }
    798     if (NULL == element_array) {
    799         LOG_ERROR(BSL_LS_BCM_PSTATS,
    800                   (BSL_META_U(unit, "element_array is null\n")));
    801         return BCM_E_PARAM;
    802     }
    803 
    804     for (i = 0; i < array_count; i++) {
    805         BCM_IF_ERROR_RETURN(
    806                 _bcm_th2_pstats_session_element_check(unit, element_array[i]));
    807     }
    808 
    809     if (options & BCM_PSTATS_OPTIONS_REPLACE) {
    810         /* delete original session first */
    811         id = *session_id;
    812         BCM_IF_ERROR_RETURN(_bcm_th2_pstats_session_delete(unit, id));
    813     } else if (options & BCM_PSTATS_OPTIONS_WITH_ID) {
    814         id = *session_id;
    815         if (id < PSTATS_SESSION_MIN) {
    816             LOG_ERROR(BSL_LS_BCM_PSTATS,
    817                       (BSL_META_U(unit, "input session_id %d is illegal!\n"), id));
    818             return BCM_E_PARAM;
    819         }
    820         cur_session = _bcm_th2_pstats_session_get(unit, id);
    821         if (NULL != cur_session) {
    822             LOG_INFO(BSL_LS_BCM_PSTATS,
    823                      (BSL_META_U(unit, "pstats_session_create: "
    824                                        "session_id %d is existed\n"), id));
    825             return BCM_E_EXISTS;
    826         }
    827     } else {
    828         id = PSTATS_CTRL(unit).next_session_id;
    829     }
    830 
    831     /* SDK has a limitation of maxium session count */
    832     if (PSTATS_CTRL(unit).session_count >= PSTATS_SESSION_MAX) {
    833         LOG_INFO(BSL_LS_BCM_PSTATS,
    834                  (BSL_META_U(unit, "pstats_session_create: "
    835                                    "session count is full\n")));
    836         return BCM_E_FULL;
    837     }
    838 
    839     cur_session =
    840         (pstats_session_t*) sal_alloc(sizeof(pstats_session_t),
    841                                       "pstats session");
    842     if (NULL == cur_session) {
    843         return BCM_E_MEMORY;
    844     }
    845     sal_memset(cur_session, 0, sizeof(pstats_session_t));
    846 
    847     /* record session info */
    848     cur_session->session_id = id;
    849     cur_session->element_array_count = array_count;
    850     sal_memcpy(cur_session->element_array,
    851                element_array,
    852                array_count * sizeof(bcm_pstats_session_element_t));
    853 
    854     alloc_size = array_count * sizeof(bcm_pstats_data_t);
    855     cur_session->data_array = sal_alloc(alloc_size, "data array");
    856     if (NULL == cur_session->data_array) {
    857         rv = BCM_E_MEMORY;
    858         goto cleanup;
    859     }
    860     sal_memset(cur_session->data_array, 0, alloc_size);
    861 
    862     _bcm_th2_pstats_session_insert(unit, cur_session);
    863     _bcm_th2_pstats_session_next_id_set(unit);
    864 
    865     *session_id = id;
    866     return BCM_E_NONE;
    867 cleanup:
    868     _bcm_th2_pstats_session_cleanup(unit, cur_session);
    869     if (NULL != cur_session) {
    870         sal_free(cur_session);
    871     }
    872     return rv;
    873 }
    874 
    875 /*
    876  * Function:
    877  *      bcm_th2_pstats_session_destroy
    878  * Purpose:
    879  *      Destroy an existing PSTATS session.
    880  * Parameters:
    881  *      unit - (IN) StrataSwitch unit number.
    882  *      session_id - (IN) id of a PSTATS session created via the
    883  *                        bcm_pkt==stats_session_create
    884  * Returns:
    885  *      BCM_E_XXX
    886  */
    887 STATIC int
    888 bcm_th2_pstats_session_destroy(int unit,
    889                                bcm_pstats_session_id_t session_id)
    890 {
    891     return _bcm_th2_pstats_session_delete(unit, session_id);
    892 }
    893 
    894 /*
    895  * Function:
    896  *      bcm_th2_pstats_session_get
    897  * Purpose:
    898  *      Get an existing PSTATS session info.
    899  * Parameters:
    900  *      unit - (IN) StrataSwitch unit number.
    901  *      session_id - (IN) id of a PSTATS session created via the
    902  *                        bcm_pstats_session_create
    903  *      array_max - (IN) Maximum number of elements in array.
    904  *      element_array - (OUT) element array of a PSTATS session.
    905  *      array_count - (OUT) Number of elements in array.
    906  * Returns:
    907  *      BCM_E_XXX
    908  */
    909 STATIC int
    910 bcm_th2_pstats_session_get(int unit,
    911                            bcm_pstats_session_id_t session_id,
    912                            int array_max,
    913                            bcm_pstats_session_element_t *element_array,
    914                            int *array_count)
    915 {
    916     pstats_session_t *cur_session = NULL;
    917     LOG_INFO(BSL_LS_BCM_PSTATS,
    918              (BSL_META_U(unit, "pstats_session_get unit %d session_id %d\n"),
    919                                unit, session_id));
    920 
    921     if (NULL == element_array) {
    922         LOG_ERROR(BSL_LS_BCM_PSTATS,
    923                   (BSL_META_U(unit, "element_array is null\n")));
    924         return BCM_E_PARAM;
    925     }
    926 
    927     cur_session = _bcm_th2_pstats_session_get(unit, session_id);
    928     if (NULL == cur_session) {
    929         LOG_INFO(BSL_LS_BCM_PSTATS,
    930                  (BSL_META_U(unit, "pstats session %d not found\n"), session_id));
    931         return BCM_E_NOT_FOUND;
    932     }
    933 
    934     if (array_max >= cur_session->element_array_count) {
    935         *array_count = cur_session->element_array_count;
    936     } else if (array_max >= 0){
    937         *array_count = array_max;
    938     } else {
    939         return BCM_E_PARAM;
    940     }
    941 
    942     sal_memcpy(element_array,
    943                cur_session->element_array,
    944                *array_count * sizeof(bcm_pstats_session_element_t));
    945 
    946     return BCM_E_NONE;
    947 }
    948 
    949 STATIC int
    950 _bcm_th2_pstats_session_data_update(int unit,
    951                                     bcm_pstats_session_element_t element,
    952                                     bcm_pstats_data_t *data)
    953 {
    954     bcm_gport_t                 gport;
    955     bcm_port_t                  local_port;
    956     bcm_cos_queue_t             cosq;
    957     bcm_service_pool_id_t       pool;
    958     int                         index, pen_idx = 0;
    959     int                         mode, i, xpe, pipe, startq, offset;
    960     uint8                       *total_buf;
    961     uint32                      cur_val = 0, *pre_p;
    962     void                        *pentry;
    963     soc_info_t                  *si = &SOC_INFO(unit);
    964     soc_mem_t                   mem;
    965     soc_field_t                 field;
    966 
    967     mode = PSTATS_CTRL(unit).stat_mode;
    968 
    969     if (element.type == bcmPStatsSessionUnicastQueue) {
    970         /* update ucq use counts
    971          * ucq_buf:
    972          * 0-3   |xpeA-q0|xpeB-q0|
    973          */
    974         /* each XPE has two pipes */
    975         gport = element.gport;
    976         cosq = element.cosq;
    977         BCM_IF_ERROR_RETURN(
    978             _bcm_th_cosq_index_resolve(unit, gport, cosq,
    979                                        _BCM_TH_COSQ_INDEX_STYLE_UCAST_QUEUE,
    980                                        &local_port, &startq, NULL));
    981         pipe = si->port_pipe[local_port];
    982         for (xpe = 0, i = 0; xpe < NUM_XPE(unit); xpe++) {
    983 
    984             if(!((si->epipe_xpe_map[pipe] >> xpe) & 1)) {
    985                 continue;
    986             }
    987             index = TH2_XPE_PIPE_INDEX(unit, xpe, pipe);
    988             if (index >= TH2_MAX_XPEPIPE) {
    989                 return BCM_E_INTERNAL;
    990             }
    991             total_buf = PSTATS_CTRL(unit).ucq_buffer[index].buf;
    992             mem = PSTATS_CTRL(unit).ucq_buffer[index].mem;
    993             pen_idx = startq / 4;
    994             offset = startq % 4;
    995             pentry = soc_mem_table_idx_to_pointer(unit, mem, void*,
    996                                                   total_buf, pen_idx);
    997             cur_val = soc_mem_field32_get(unit, mem, pentry, ucq_field[offset]);
    998 
    999             pre_p = &data->use_counts_array[i];
   1000             if (mode) {
   1001                 if (cur_val > *pre_p) {
   1002                     *pre_p = cur_val;
   1003                 }
   1004             } else {
   1005                 *pre_p = cur_val;
   1006             }
   1007             i++;
   1008         }
   1009         data->array_count = i;
   1010     } else {
   1011         /* update pool use counts
   1012          * pool_buf:
   1013          * 0-3   |xpe0-p0|xpe1-p0|xpe2-p0|xpe3-p0|
   1014          */
   1015         pool = element.pool;
   1016         for (xpe = 0, i = 0; xpe < NUM_XPE(unit); xpe++) {
   1017 
   1018             index = TH2_XPE_PIPE_INDEX(unit, xpe, -1);
   1019             if (index >= TH2_MAX_POOL_COUNT) {
   1020                 return BCM_E_INTERNAL;
   1021             }
   1022             if (element.type == bcmPStatsSessionIngPool) {
   1023                 total_buf = PSTATS_CTRL(unit).ing_pool_buffer[xpe].buf;
   1024                 mem = PSTATS_CTRL(unit).ing_pool_buffer[pool].mem;
   1025                 field = isp_field[pool];
   1026             } else if (element.type == bcmPStatsSessionEgrPool) {
   1027                 total_buf = PSTATS_CTRL(unit).egr_pool_buffer[xpe].buf;
   1028                 mem = PSTATS_CTRL(unit).egr_pool_buffer[pool].mem;
   1029                 field = esp_field[pool];
   1030             } else {
   1031                 return BCM_E_INTERNAL;
   1032             }
   1033 
   1034             pentry = soc_mem_table_idx_to_pointer(unit, mem, void*,
   1035                                                   total_buf, pen_idx);
   1036             cur_val = soc_mem_field32_get(unit, mem, pentry, field);
   1037             pre_p = &data->use_counts_array[i];
   1038             if (mode) {
   1039                 if (cur_val > *pre_p) {
   1040                     *pre_p = cur_val;
   1041                 }
   1042             } else {
   1043                 *pre_p = cur_val;
   1044             }
   1045             i++;
   1046         }
   1047         data->array_count = i;
   1048     }
   1049 
   1050     return BCM_E_NONE;
   1051 }
   1052 
   1053 STATIC int
   1054 _bcm_th2_pstats_session_update(int unit, pstats_session_t *session)
   1055 {
   1056     bcm_pstats_session_element_t    element;
   1057     bcm_pstats_data_t               *data;
   1058     pstats_session_t                *cur_session = session;
   1059     uint8                           *total_buf;
   1060     int                             i;
   1061     void                            *pentry;
   1062     soc_mem_t                       mem;
   1063 
   1064     /*
   1065      * update timestamp
   1066      * if MMU_INTFO_TOD_TIMESTAMP is updated by ARM core,
   1067      * MMU_INTFO_UTC_TIMESTAMP is a utc time.
   1068      * otherwise it is a local time.
   1069      */
   1070     total_buf = PSTATS_CTRL(unit).utc_time.buf;
   1071     mem = PSTATS_CTRL(unit).utc_time.mem;
   1072     pentry = soc_mem_table_idx_to_pointer(unit, mem, void*,
   1073                                           total_buf, 0);
   1074     cur_session->timestamp.nanoseconds =
   1075             soc_mem_field32_get(unit, mem, pentry, UTC_TIMESTAMP_NSECf);
   1076     soc_mem_field64_get(unit, mem, pentry, UTC_TIMESTAMP_SECf,
   1077                         &cur_session->timestamp.seconds);
   1078 
   1079 #ifdef BCM_PSTATS_MEASURE
   1080     if (soc_property_get(unit, "pstats_timestamp_info", 0) == 1) {
   1081         COMPILER_64_TO_32_LO(cur_session->timestamp.nanoseconds,
   1082                              PSTATS_CTRL(unit).time_cost);
   1083     }
   1084 #endif
   1085 
   1086     /* update element data */
   1087     for (i = 0; i < cur_session->element_array_count; i++) {
   1088         element = cur_session->element_array[i];
   1089         data = &cur_session->data_array[i];
   1090         BCM_IF_ERROR_RETURN(
   1091             _bcm_th2_pstats_session_data_update(unit, element, data));
   1092     }
   1093 
   1094     return BCM_E_NONE;
   1095 }
   1096 
   1097 /*
   1098  * Function:
   1099  *      _bcm_th2_pstats_hw_sync
   1100  * Purpose:
   1101  *      Start a pstats sync operation.
   1102  * Parameters:
   1103  *      unit - (IN) StrataSwitch unit number
   1104  * Returns:
   1105  *      BCM_E_XXX
   1106  */
   1107 STATIC int
   1108 _bcm_th2_pstats_hw_sync(int unit)
   1109 {
   1110     pstats_buffer_t             *pbuf;
   1111     int                         index, pipe, xpe;
   1112     soc_info_t                  *si = &SOC_INFO(unit);
   1113 #ifdef BCM_PSTATS_MEASURE
   1114     void                        *pentry;
   1115     uint64                      start_ts, end_ts;
   1116 #endif
   1117 
   1118     SOC_IF_ERROR_RETURN(soc_pstats_sync(unit));
   1119 
   1120 #ifdef BCM_PSTATS_MEASURE
   1121     /* sync local time */
   1122     pbuf = &PSTATS_CTRL(unit).local_time;
   1123     SOC_IF_ERROR_RETURN(
   1124         soc_pstats_mem_get(unit, pbuf->mem, pbuf->buf, 0));
   1125     pentry = soc_mem_table_idx_to_pointer(unit, pbuf->mem, void*,
   1126                                           pbuf->buf, 0);
   1127     soc_mem_field64_get(unit, pbuf->mem, pentry, TIMESTAMPf, &start_ts);
   1128 
   1129     pbuf = &PSTATS_CTRL(unit).local_time_end;
   1130     SOC_IF_ERROR_RETURN(
   1131         soc_pstats_mem_get(unit, pbuf->mem, pbuf->buf, 1));
   1132     pentry = soc_mem_table_idx_to_pointer(unit, pbuf->mem, void*,
   1133                                           pbuf->buf, 0);
   1134     soc_mem_field64_get(unit, pbuf->mem, pentry, TIMESTAMPf, &end_ts);
   1135 
   1136     LOG_INFO(BSL_LS_BCM_PSTATS,
   1137              (BSL_META_U(unit, "start 0x%x%8x end 0x%x%8x\n"),
   1138              COMPILER_64_HI(start_ts), COMPILER_64_LO(start_ts),
   1139              COMPILER_64_HI(end_ts), COMPILER_64_LO(end_ts)));
   1140 
   1141     /* handle rollover */
   1142     if (COMPILER_64_LT(end_ts, start_ts)) {
   1143         uint64 wrap_amt;
   1144         int width;
   1145 
   1146         width = soc_mem_field_length(unit, MMU_INTFO_TIMESTAMPm, TIMESTAMPf);
   1147         COMPILER_64_SET(wrap_amt, 1UL << (width - 32), 0);
   1148         COMPILER_64_ADD_64(end_ts, wrap_amt);
   1149     }
   1150     COMPILER_64_DELTA(PSTATS_CTRL(unit).time_cost, start_ts, end_ts);
   1151 #endif
   1152 
   1153     /* sync utc time */
   1154     pbuf = &PSTATS_CTRL(unit).utc_time;
   1155     SOC_IF_ERROR_RETURN(
   1156         soc_pstats_mem_get(unit, pbuf->mem, pbuf->buf, 0));
   1157 
   1158     /* sync uc queue */
   1159     for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) {
   1160         for (xpe = 0; xpe < NUM_XPE(unit); xpe++) {
   1161 
   1162             if(!((si->epipe_xpe_map[pipe] >> xpe) & 1)) {
   1163                 continue;
   1164             }
   1165             index = TH2_XPE_PIPE_INDEX(unit, xpe, pipe);
   1166             if (index >= TH2_MAX_XPEPIPE) {
   1167                 return BCM_E_INTERNAL;
   1168             }
   1169             pbuf = &PSTATS_CTRL(unit).ucq_buffer[index];
   1170             SOC_IF_ERROR_RETURN(
   1171                 soc_pstats_mem_get(unit, pbuf->mem, pbuf->buf, 0));
   1172         }
   1173     }
   1174 
   1175     /* sync ing pool */
   1176     for (xpe = 0; xpe < NUM_XPE(unit); xpe++) {
   1177 
   1178         index = TH2_XPE_PIPE_INDEX(unit, xpe, -1);
   1179         if (index >= TH2_MAX_POOL_COUNT) {
   1180             return BCM_E_INTERNAL;
   1181         }
   1182         pbuf = &PSTATS_CTRL(unit).ing_pool_buffer[index];
   1183         SOC_IF_ERROR_RETURN(
   1184             soc_pstats_mem_get(unit, pbuf->mem, pbuf->buf, 0));
   1185     }
   1186 
   1187     /* sync egr pool */
   1188     for (xpe = 0; xpe < NUM_XPE(unit); xpe++) {
   1189 
   1190         index = TH2_XPE_PIPE_INDEX(unit, xpe, -1);
   1191         if (index >= TH2_MAX_POOL_COUNT) {
   1192             return BCM_E_INTERNAL;
   1193         }
   1194         pbuf = &PSTATS_CTRL(unit).egr_pool_buffer[index];
   1195         SOC_IF_ERROR_RETURN(
   1196             soc_pstats_mem_get(unit, pbuf->mem, pbuf->buf, 0));
   1197     }
   1198 
   1199     return BCM_E_NONE;
   1200 }
   1201 
   1202 /*
   1203  * Function:
   1204  *      _bcm_th2_pstats_session_data_sync
   1205  * Purpose:
   1206  *      Start a pstats sync operation for a special session
   1207  * Parameters:
   1208  *      unit - (IN) StrataSwitch unit number
   1209  * Returns:
   1210  *      BCM_E_XXX
   1211  */
   1212 STATIC int
   1213 _bcm_th2_pstats_session_data_sync(int unit, pstats_session_t *session)
   1214 {
   1215     BCM_IF_ERROR_RETURN(_bcm_th2_pstats_hw_sync(unit));
   1216     BCM_IF_ERROR_RETURN(_bcm_th2_pstats_session_update(unit, session));
   1217     return BCM_E_NONE;
   1218 }
   1219 
   1220 /*
   1221  * Function:
   1222  *      bcm_th2_pstats_data_sync
   1223  * Purpose:
   1224  *      Start a pstats sync operation.
   1225  * Parameters:
   1226  *      unit - (IN) StrataSwitch unit number
   1227  * Returns:
   1228  *      BCM_E_XXX
   1229  */
   1230 STATIC int
   1231 bcm_th2_pstats_data_sync(int unit)
   1232 {
   1233     pstats_session_t    *cur_session = NULL;
   1234     sal_usecs_t         start_time = sal_time_usecs();
   1235 
   1236     BCM_IF_ERROR_RETURN(_bcm_th2_pstats_hw_sync(unit));
   1237     LOG_DEBUG(BSL_LS_SOC_COMMON,
   1238               (BSL_META_U(unit, "Time taken for pstats dma: %d usec\n"),
   1239                           SAL_USECS_SUB(sal_time_usecs(), start_time)));
   1240     cur_session = PSTATS_CTRL(unit).first_session;
   1241     while (NULL != cur_session) {
   1242         if (cur_session->enable != TRUE) {
   1243             continue;
   1244         }
   1245         BCM_IF_ERROR_RETURN(
   1246                 _bcm_th2_pstats_session_update(unit, cur_session));
   1247         cur_session = cur_session->next_session;
   1248     }
   1249     return BCM_E_NONE;
   1250 }
   1251 
   1252 /*
   1253  * Function:
   1254  *      bcm_th2_pstats_session_data_get
   1255  * Purpose:
   1256  *      Get an existing PSTATS session data.
   1257  * Parameters:
   1258  *      unit - (IN) StrataSwitch unit number
   1259  *      session_id - (IN) id of a PSTATS session created via the
   1260  *                        bcm_pstats_session_create
   1261  *      sync - (IN) Need a sync operation
   1262  *      timestamp - (OUT) time stamp info.
   1263  *      array_max - (IN) Maximum number of elements in array.
   1264  *      data - (OUT) array of use count data.
   1265  *      array_count - (OUT) Number of elements in array.
   1266  * Returns:
   1267  *      BCM_E_XXX
   1268  */
   1269 STATIC int
   1270 bcm_th2_pstats_session_data_get(int unit, bcm_pstats_session_id_t session_id,
   1271                                 int sync,
   1272                                 bcm_pstats_timestamp_t *timestamp,
   1273                                 int array_max,
   1274                                 bcm_pstats_data_t *data_array,
   1275                                 int *array_count)
   1276 {
   1277     pstats_session_t        *cur_session = NULL;
   1278     int                     mode;
   1279 
   1280     LOG_INFO(BSL_LS_BCM_PSTATS,
   1281              (BSL_META_U(unit, "pstats_session_data_get unit %d session_id %d "
   1282                                "sync %d\n"), unit, session_id, sync));
   1283 
   1284     if (NULL == data_array) {
   1285         LOG_ERROR(BSL_LS_BCM_PSTATS,
   1286                   (BSL_META_U(unit, "data_array is null\n")));
   1287         return BCM_E_PARAM;
   1288     }
   1289 
   1290     mode = PSTATS_CTRL(unit).stat_mode;
   1291     cur_session = _bcm_th2_pstats_session_get(unit, session_id);
   1292     if (NULL == cur_session) {
   1293         LOG_INFO(BSL_LS_BCM_PSTATS,
   1294                  (BSL_META_U(unit, "pstats_session_data_get: "
   1295                                    "session_id %d is not found\n"), session_id));
   1296         return BCM_E_NOT_FOUND;
   1297     }
   1298 
   1299     if (array_max >= cur_session->element_array_count) {
   1300         *array_count = cur_session->element_array_count;
   1301     } else if (array_max >= 0){
   1302         *array_count = array_max;
   1303     } else {
   1304         LOG_ERROR(BSL_LS_BCM_PSTATS,
   1305                   (BSL_META_U(unit, "array_max %d is illegal\n"), array_max));
   1306         return BCM_E_PARAM;
   1307     }
   1308 
   1309     /* if PKT STAT mode is HWM, need to sync up all sessions */
   1310     if (TRUE == sync) {
   1311         if (mode) {
   1312             BCM_IF_ERROR_RETURN(bcm_th2_pstats_data_sync(unit));
   1313         } else {
   1314             BCM_IF_ERROR_RETURN(
   1315                     _bcm_th2_pstats_session_data_sync(unit, cur_session));
   1316         }
   1317     }
   1318 
   1319     sal_memcpy(data_array, cur_session->data_array,
   1320                *array_count * sizeof(bcm_pstats_data_t));
   1321 
   1322     sal_memcpy(timestamp, &cur_session->timestamp, sizeof(bcm_pstats_timestamp_t));
   1323 
   1324     return BCM_E_NONE;
   1325 }
   1326 
   1327 STATIC int
   1328 _bcm_th2_pstats_session_data_hw_clear(int unit, bcm_pstats_session_element_t element)
   1329 {
   1330     bcm_gport_t                 gport;
   1331     bcm_port_t                  local_port;
   1332     bcm_cos_queue_t             cosq;
   1333     bcm_service_pool_id_t       pool;
   1334     int                         index, xpe, pipe, startq;
   1335     soc_info_t                  *si = &SOC_INFO(unit);
   1336     soc_mem_t                   mem;
   1337     soc_field_t                 field;
   1338     uint32                      entry[SOC_MAX_MEM_WORDS];
   1339 
   1340     if (element.type == bcmPStatsSessionUnicastQueue) {
   1341         /* update ucq use counts
   1342          * ucq_buf:
   1343          * 0-3   |xpeA-q0|xpeB-q0|
   1344          */
   1345         /* each XPE has two pipes */
   1346         gport = element.gport;
   1347         cosq = element.cosq;
   1348         BCM_IF_ERROR_RETURN(
   1349             _bcm_th_cosq_index_resolve(unit, gport, cosq,
   1350                                        _BCM_TH_COSQ_INDEX_STYLE_UCAST_QUEUE,
   1351                                        &local_port, &startq, NULL));
   1352         pipe = si->port_pipe[local_port];
   1353         for (xpe = 0; xpe < NUM_XPE(unit); xpe++) {
   1354 
   1355             if(!((si->epipe_xpe_map[pipe] >> xpe) & 1)) {
   1356                 continue;
   1357             }
   1358             index = TH2_XPE_PIPE_INDEX(unit, xpe, pipe);
   1359             if (index >= TH2_MAX_XPEPIPE) {
   1360                 return BCM_E_INTERNAL;
   1361             }
   1362             mem = PSTATS_CTRL(unit).ucq_buffer[index].clear_mem;
   1363             SOC_IF_ERROR_RETURN(
   1364                 soc_mem_read(unit, mem, MEM_BLOCK_ALL, startq, entry));
   1365             soc_mem_field32_set(unit, mem, entry, UCQ_COUNTf, 0);
   1366             SOC_IF_ERROR_RETURN(
   1367                 soc_mem_write(unit, mem, MEM_BLOCK_ALL, startq, entry));
   1368         }
   1369     } else {
   1370         /* update pool use counts
   1371          * pool_buf:
   1372          * 0-3   |xpe0-p0|xpe1-p0|xpe2-p0|xpe3-p0|
   1373          */
   1374         pool = element.pool;
   1375         for (xpe = 0; xpe < NUM_XPE(unit); xpe++) {
   1376 
   1377             index = TH2_XPE_PIPE_INDEX(unit, xpe, -1);
   1378             if (index >= TH2_MAX_POOL_COUNT) {
   1379                 return BCM_E_INTERNAL;
   1380             }
   1381             if (element.type == bcmPStatsSessionIngPool) {
   1382                 mem = PSTATS_CTRL(unit).ing_pool_buffer[xpe].clear_mem;
   1383                 field = isp_field[pool];
   1384             } else if (element.type == bcmPStatsSessionEgrPool) {
   1385                 mem = PSTATS_CTRL(unit).egr_pool_buffer[xpe].clear_mem;
   1386                 field = esp_field[pool];
   1387             } else {
   1388                 return BCM_E_INTERNAL;
   1389             }
   1390             SOC_IF_ERROR_RETURN(
   1391                 soc_mem_read(unit, mem, MEM_BLOCK_ALL, 0, entry));
   1392             soc_mem_field32_set(unit, mem, entry, field, 0);
   1393             SOC_IF_ERROR_RETURN(
   1394                 soc_mem_write(unit, mem, MEM_BLOCK_ALL, 0, entry));
   1395         }
   1396     }
   1397 
   1398     return BCM_E_NONE;
   1399 }
   1400 
   1401 /*
   1402  * Function:
   1403  *      bcm_th2_pstats_session_data_clear
   1404  * Purpose:
   1405  *      Clear an existing PSTATS session hw use counts and sw use counts buffer.
   1406  * Parameters:
   1407  *      unit - (IN) StrataSwitch unit number.
   1408  *      session_id - (IN) id of a PSTATS session created via the
   1409  *                        bcm_pstats_session_create.
   1410  * Returns:
   1411  *      BCM_E_XXX
   1412  */
   1413 STATIC int
   1414 bcm_th2_pstats_session_data_clear(int unit, bcm_pstats_session_id_t session_id)
   1415 {
   1416     bcm_pstats_session_element_t    element;
   1417     pstats_session_t                *cur_session = NULL;
   1418     int                             i, need_hw_clear = 1;
   1419 
   1420     LOG_INFO(BSL_LS_BCM_PSTATS,
   1421              (BSL_META_U(unit, "pstats_session_data_clear unit %d session_id %d\n"),
   1422                                unit, session_id));
   1423 
   1424     cur_session = _bcm_th2_pstats_session_get(unit, session_id);
   1425     if (NULL == cur_session) {
   1426         LOG_INFO(BSL_LS_BCM_PSTATS,
   1427                  (BSL_META_U(unit, "pstats_session_data_clear: "
   1428                                    "session_id %d is not found\n"), session_id));
   1429         return BCM_E_NOT_FOUND;
   1430     }
   1431 
   1432     /* clear HW use count buffer */
   1433     if ((PSTATS_CTRL(unit).stat_mode == 1) &&
   1434         (PSTATS_CTRL(unit).hw_cor_in_max_use_count == 1)) {
   1435         /* HW clear on read is enabled, no need do hw clear */
   1436         need_hw_clear = 0;
   1437     }
   1438 
   1439     if (need_hw_clear == 1) {
   1440         for (i = 0; i < cur_session->element_array_count; i++) {
   1441             element = cur_session->element_array[i];
   1442             BCM_IF_ERROR_RETURN(
   1443                 _bcm_th2_pstats_session_data_hw_clear(unit, element));
   1444         }
   1445     }
   1446 
   1447     /* clear SW use count buffer */
   1448     sal_memset(cur_session->data_array, 0,
   1449                cur_session->element_array_count * sizeof(bcm_pstats_data_t));
   1450 
   1451     return BCM_E_NONE;
   1452 }
   1453 
   1454 /*
   1455  * Function:
   1456  *      bcm_th2_pstats_session_traverse
   1457  * Purpose:
   1458  *      Traverse through the pstats sessions and run callback at each session.
   1459  * Parameters:
   1460  *      unit - (IN) StrataSwitch unit number.
   1461  *      cb - (IN) bcm_pstats_session_traverse_cb.
   1462  *      user_data - (IN) User data to be passed to callback function.
   1463  * Returns:
   1464  *      BCM_E_XXX
   1465  */
   1466 STATIC int
   1467 bcm_th2_pstats_session_traverse(int unit, bcm_pstats_session_traverse_cb cb,
   1468                                 void *user_data)
   1469 {
   1470     bcm_pstats_session_element_t    element_array[TH2_MAX_ELEMENT_COUNT];
   1471     bcm_pstats_session_id_t         session_id;
   1472     pstats_session_t                *cur_session = NULL;
   1473     int                             array_count;
   1474     int                             rv = BCM_E_NONE;
   1475 
   1476     LOG_INFO(BSL_LS_BCM_PSTATS,
   1477              (BSL_META_U(unit, "pstats_session_travers unit %d\n"), unit));
   1478 
   1479     cur_session = PSTATS_CTRL(unit).first_session;
   1480     while (NULL != cur_session) {
   1481         session_id = cur_session->session_id;
   1482         array_count = cur_session->element_array_count;
   1483         sal_memcpy(element_array, cur_session->element_array,
   1484                    array_count * sizeof(bcm_pstats_session_element_t));
   1485 
   1486         cur_session = cur_session->next_session;
   1487 
   1488         rv = cb(unit, session_id, array_count, element_array, user_data);
   1489 #ifdef BCM_CB_ABORT_ON_ERR
   1490         if (BCM_FAILURE(rv) && SOC_CB_ABORT_ON_ERR(unit)) {
   1491             return rv;
   1492         }
   1493 #else
   1494         /*
   1495          * If CB_ABORT_ON_ERR is not defined don't return error
   1496          * and continue.
   1497          */
   1498         rv = BCM_E_NONE;
   1499 #endif
   1500     }
   1501 
   1502     return rv;
   1503 }
   1504 #else  /* INCLUDE_PSTATS && BCM_TOMAHAWK2_SUPPORT */
   1505 int bcm_esw_tomahawk2_pstats_not_empty;
   1506 #endif /* INCLUDE_PSTATS && BCM_TOMAHAWK2_SUPPORT */
   1507