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 (49095B)


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