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

latency_monitor.c (82896B)


      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  */
      8 
      9 #include <shared/bsl.h>
     10 #include <sal/appl/sal.h>
     11 #include <sal/core/time.h>
     12 #include <appl/diag/system.h>
     13 #include <appl/diag/parse.h>
     14 #include <soc/mem.h>
     15 #include <soc/register.h>
     16 #include <soc/debug.h>
     17 #include <soc/dma.h>
     18 #include <soc/schanmsg_internal.h>
     19 #include <soc/sbusdma_internal.h>
     20 
     21 #include <bcm/error.h>
     22 #include <bcm_int/esw/latency_monitor.h>
     23 #include <soc/drv.h>
     24 #include <bcm_int/esw/flex_ctr.h>
     25 #include <bcm_int/common/debug.h>
     26 #include <include/soc/tomahawk3.h>
     27 
     28 #ifdef BCM_WARM_BOOT_SUPPORT
     29 #include <bcm_int/esw/switch.h>
     30 #endif /* BCM_WARM_BOOT_SUPPORT */
     31 
     32 extern int inside_bcm_shutdown[BCM_MAX_NUM_UNITS];
     33 
     34 static latency_monitor_driver_data_t latency_monitor_driver_data;
     35 static latency_monitor_mem_t latency_monitor_mem[BCM_MAX_NUM_UNITS][LATENCY_MONITOR_MAX_COUNT];
     36 int bcm_tomahawk3_latency_monitor_enable(int unit, uint8 monitor_id, uint8 enable);
     37 
     38 #ifdef BCM_WARM_BOOT_SUPPORT
     39 #ifdef BCM_TOMAHAWK3_SUPPORT
     40 STATIC int _bcm_th3_latency_monitor_scache_alloc(int unit, int create);
     41 STATIC int _bcm_th3_latency_monitor_wb_recover(int unit);
     42 #endif /* BCM_TOMAHAWK3_SUPPORT */
     43 #endif /* BCM_WARM_BOOT_SUPPORT */
     44 
     45 uint8   wb_post_init;
     46 
     47 /**
     48  * Initialize the linked list (fifo) to empty value.
     49  * @param desc_handle_list
     50  */
     51 void
     52 _sbusdma_desc_handle_list_init(_sbusdma_desc_handle_list_t * desc_handle_list)
     53 {
     54    desc_handle_list->head = desc_handle_list->tail = NULL;
     55 }
     56 
     57 /**
     58  * Push an entry to the end of the linked list
     59  *
     60  * @param desc_handle_list -linked list on which entry is added
     61  * @param handle entry - to get pushed.
     62  *
     63  * @return int BCM_E_MEMORY if memory allocation fails,
     64  *         BCM_E_NONE otherwise.
     65  */
     66 int
     67 _sbusdma_desc_handle_list_push(_sbusdma_desc_handle_list_t *desc_handle_list, const _sbusdma_desc_handle_data_t *data)
     68 {
     69     _sbusdma_desc_handle_node_t *new_node = sal_alloc(sizeof(_sbusdma_desc_handle_node_t), "sbus dma fifo");
     70     if (new_node == NULL) {
     71         return  BCM_E_MEMORY;
     72     }
     73     new_node->next = NULL;
     74     new_node->data = (_sbusdma_desc_handle_data_t *)data;
     75     if (desc_handle_list->head != NULL) {
     76        desc_handle_list->tail->next = new_node;
     77        desc_handle_list->tail = new_node;
     78     } else {
     79        desc_handle_list->head = desc_handle_list->tail = new_node;
     80     }
     81     return BCM_E_NONE;
     82 }
     83 
     84 
     85 /**
     86  * Pop an event from the front of the linked list (fifo)
     87  *
     88  * @param desc_handle_list - linked list where event is pushed.
     89  * @param handle - event is set here.
     90  *
     91  * @return int BCM_E_EMPTY if linked list is empty, BCM_E_NONE
     92  *         otherwise.
     93  */
     94 int
     95 _sbusdma_desc_handle_list_pop(_sbusdma_desc_handle_list_t *desc_handle_list, _sbusdma_desc_handle_data_t **data)
     96 {
     97    if (desc_handle_list->head) {
     98       _sbusdma_desc_handle_node_t *temp_head = desc_handle_list->head;
     99       *data = desc_handle_list->head->data;
    100       if (desc_handle_list->head == desc_handle_list->tail) {
    101           desc_handle_list->head = desc_handle_list->tail = NULL;
    102       } else {
    103           desc_handle_list->head = desc_handle_list->head->next;
    104       }
    105       sal_free(temp_head);
    106       return BCM_E_NONE;
    107    } else {
    108       return BCM_E_EMPTY;
    109    }
    110 }
    111 
    112 
    113 int 
    114 _sbusdma_desc_handle_list_is_empty(_sbusdma_desc_handle_list_t *desc_handle_list)
    115 {
    116     if (!desc_handle_list->head) {
    117         return TRUE;
    118     }
    119 
    120     return FALSE;
    121 }
    122 
    123 
    124 #ifdef BCM_TOMAHAWK3_SUPPORT
    125 static int
    126 latency_monitor_driver_data_init(int unit)
    127 {
    128     int i;
    129 
    130     if (!latency_monitor_driver_data.init_done) {
    131         latency_monitor_driver_data.desc_mode     = 1;
    132         latency_monitor_driver_data.dma_wr_en     = TRUE;
    133         latency_monitor_driver_data.dma_rd_en     = TRUE;
    134         latency_monitor_driver_data.num_mem       = 1;
    135         latency_monitor_driver_data.init_done     = TRUE;
    136 
    137         for (i=0; i<LATENCY_MONITOR_MAX_COUNT; i++) {
    138             SOC_LATENCY_MONITOR_INFO(unit, i).time_step = -1;
    139             SOC_LATENCY_MONITOR_INFO(unit, i).flex_pool_number = -1;
    140             BCM_PBMP_CLEAR(SOC_LATENCY_MONITOR_INFO(unit, i).src_pbmp);
    141             BCM_PBMP_CLEAR(SOC_LATENCY_MONITOR_INFO(unit, i).dest_pbmp);
    142         }
    143     }
    144 
    145     return BCM_E_NONE;
    146 }
    147 #endif /* BCM_TOMAHAWK3_SUPPORT */
    148 
    149 static void
    150 latency_monitor_sbusdma_cb(int unit, int status, sbusdma_desc_handle_t handle,
    151                    void *data)
    152 {
    153     int rv;
    154     int monitor_id;
    155     cb_data_t   *p_cb_data;
    156     uint32      *entbuf;
    157     uint8        frag_count;
    158     _sbusdma_desc_handle_data_t     *list_data;
    159 
    160     if (status != BCM_E_NONE) {
    161         LOG_ERROR(BSL_LS_BCM_LATENCY_MONITOR,
    162                     (BSL_META_U(unit, "SBUS DMA failed: type %d\n"),
    163                    PTR_TO_INT(data)));
    164         if (status == BCM_E_TIMEOUT)
    165             (void)soc_sbusdma_desc_delete(unit, handle);
    166     }
    167 
    168     if (data == NULL) {
    169         return;
    170     }
    171 
    172     p_cb_data = (cb_data_t *)data;
    173     monitor_id = p_cb_data->monitor_id;
    174 
    175     LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    176                 (BSL_META_U(unit, "latency_monitor_sbusdma_cb:: monitor_id:%d \n"),
    177                              monitor_id));
    178 
    179     if (p_cb_data->write_op) {
    180         BCM_EXIT;
    181     }
    182 
    183     frag_count = latency_monitor_mem[unit][monitor_id].frag_count;
    184     entbuf = sal_alloc(WORDS2BYTES(latency_monitor_mem[unit][monitor_id].bufwords/frag_count), "CB dma fifo");
    185     if (entbuf) {
    186         /* Since the DMA able memory is scarce, copy and free it at the earliest possible. */
    187         sal_memcpy(entbuf, p_cb_data->data, WORDS2BYTES((latency_monitor_mem[unit][monitor_id].bufwords)/frag_count));
    188         if (p_cb_data->data) {
    189             soc_cm_sfree(unit, p_cb_data->data);
    190         }
    191     } else {
    192         latency_monitor_driver_data.run[monitor_id] = FALSE;
    193         BCM_EXIT;
    194     }
    195 
    196     list_data = sal_alloc(sizeof(_sbusdma_desc_handle_data_t), "DMA handler list data");
    197     if (list_data) {
    198         list_data->dbuf = entbuf;
    199         list_data->pipe = p_cb_data->pipe_num;
    200     }
    201 
    202     if (latency_monitor_driver_data.run[monitor_id] == TRUE) {
    203         sal_sem_take(latency_monitor_mem[unit][monitor_id].dma_handle_queue_lock, sal_sem_FOREVER);
    204         _sbusdma_desc_handle_list_push(&latency_monitor_mem[unit][monitor_id].handle_list, list_data);
    205         sal_sem_give(latency_monitor_mem[unit][monitor_id].dma_handle_counter_sem);
    206         sal_sem_give(latency_monitor_mem[unit][monitor_id].dma_handle_queue_lock);
    207     } else {
    208         sal_free(entbuf);
    209         sal_free(list_data);
    210     }
    211 
    212     LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    213                 (BSL_META_U(unit,"Call back completed for handle:%d Monitor:%d data:%p\n"),
    214                              handle, monitor_id, p_cb_data->data));
    215 exit:
    216     rv = soc_sbusdma_desc_delete(unit, handle);
    217     if (rv != BCM_E_NONE) {
    218         LOG_ERROR(BSL_LS_BCM_LATENCY_MONITOR,
    219                     (BSL_META_U(unit,
    220                                 "Failed to delete sbusdma descriptor Monitor:%d\n"),
    221                                     monitor_id));
    222     } else {
    223         LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    224                      (BSL_META_U(unit,
    225                                 "Deleting handle %d Monitor:%d\n"),
    226                                  handle, monitor_id));
    227     }
    228     
    229     if (latency_monitor_driver_data.sbusdma_run_lock) {
    230         sal_sem_give(latency_monitor_driver_data.sbusdma_run_lock);
    231     }
    232     sal_free(p_cb_data);
    233     /*    coverity[leaked_storage : FALSE]    */
    234 }
    235 
    236 
    237 static int
    238 latency_monitor_sbusdma_setup(int unit, int monitor_id, int pipe, uint32 *entbuf, int index_min,
    239                       int index_max, int frag, int write, sbusdma_desc_handle_t *handle_to_run)
    240 {
    241     /* for soc_sbusdma_desc_create and soc_sbusdma_desc_run */
    242     soc_sbusdma_desc_ctrl_t ctrl;
    243     soc_sbusdma_desc_cfg_t cfg;
    244     soc_sbusdma_desc_cfg_t *cfg_array;
    245     int rv = BCM_E_NONE;
    246     int         i;
    247     uint8       at;
    248     cb_data_t   *p_cb_data;
    249 
    250     if (latency_monitor_driver_data.desc_mode > 0) {
    251         /* descriptor based sbus dma mode through sdk api */
    252         sal_memset(&ctrl, 0, sizeof(soc_sbusdma_desc_ctrl_t));
    253         sal_memset(&cfg, 0, sizeof(soc_sbusdma_desc_cfg_t));
    254         cfg_array = soc_cm_salloc(unit, sizeof(soc_sbusdma_desc_cfg_t) *
    255                                   latency_monitor_driver_data.desc_mode, "sbusdma_desc_cfg");
    256         ctrl.cfg_count = latency_monitor_driver_data.desc_mode;
    257         ctrl.cb = latency_monitor_sbusdma_cb;
    258         p_cb_data = sal_alloc(sizeof(cb_data_t), "CB Data");
    259         if (p_cb_data == NULL) {
    260             return  BCM_E_MEMORY;
    261         }
    262         p_cb_data->monitor_id = monitor_id;
    263         p_cb_data->data = entbuf;
    264         if (write == 0) {
    265             ctrl.flags = SOC_SBUSDMA_MEMORY_CMD_MSG;
    266         } else {
    267             ctrl.flags = SOC_SBUSDMA_WRITE_CMD_MSG | SOC_SBUSDMA_MEMORY_CMD_MSG;
    268         }
    269         p_cb_data->write_op = write;
    270         p_cb_data->pipe_num = pipe;
    271         ctrl.data = p_cb_data;
    272 
    273         cfg.acc_type = SOC_MEM_ACC_TYPE(unit, latency_monitor_mem[unit][monitor_id].mem+pipe);
    274         cfg.blk = SOC_BLOCK2SCH(unit, latency_monitor_mem[unit][monitor_id].copyno);
    275         cfg.addr = soc_mem_addr_get(unit, latency_monitor_mem[unit][monitor_id].mem+pipe, 0,
    276                                     latency_monitor_mem[unit][monitor_id].copyno, index_min, &at);
    277         cfg.width = latency_monitor_mem[unit][monitor_id].entwords;
    278         cfg.count = index_max - index_min + 1;
    279         cfg.buff = entbuf;
    280         cfg.addr_shift = 0;
    281         for (i = 0; i < latency_monitor_driver_data.desc_mode; i++) {
    282             sal_memcpy(cfg_array + i, &cfg, sizeof(soc_sbusdma_desc_cfg_t));
    283         }
    284 
    285         if (SOC_FAILURE((rv = (soc_sbusdma_desc_create(unit, &ctrl, cfg_array,
    286                                                        handle_to_run))))) {
    287             _SHR_ERROR_TRACE(rv);
    288         }
    289 
    290         LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    291                      (BSL_META_U(unit,"Create handle %d Monitor:%d\n"),
    292                                 *handle_to_run, monitor_id));
    293 
    294         soc_cm_sfree(unit, cfg_array);
    295     } 
    296 
    297     return rv;
    298 }
    299 
    300 void
    301 counter_accrue_thread(void* up)
    302 {
    303     int             unit = PTR_TO_INT(up) & 0xff;
    304     int             monitor_id;
    305     uint32          packet_count=0;
    306     uint64          byte_count;
    307     soc_memacc_t    memacc_pkt_x;
    308     soc_memacc_t    memacc_byte_x;
    309     egr_flex_ctr_counter_table_0_entry_t   *data_ptr;
    310     uint64          (*arr_pkt_cnt)[LATENCY_MONITOR_BUCKET_COUNT];
    311     uint64          (*arr_byte_cnt)[LATENCY_MONITOR_BUCKET_COUNT];
    312     int             l, j, k;
    313     int             data_buffer_idx = 0;
    314     uint32          *dbuf = NULL;
    315     int             frag_count;
    316     uint64          *sw_buff = NULL;
    317     uint32          sw_buf_idx = 0;
    318     _sbusdma_desc_handle_data_t *list_data;
    319     int             pipe = 0;
    320     int             pipe_lower = -1;
    321     uint64          byte_count_tmp;
    322     uint32          packet_count_tmp;
    323     uint8           pkt_ctr_f_width;
    324     uint64          tmp64;
    325     uint64          mask64;
    326 
    327     monitor_id = PTR_TO_INT(up) >> 8;
    328     if (((soc_memacc_init(unit, latency_monitor_mem[unit][monitor_id].mem, PACKET_COUNTERf, &memacc_pkt_x))) ||
    329         ((soc_memacc_init(unit, latency_monitor_mem[unit][monitor_id].mem, BYTE_COUNTERf, &memacc_byte_x)))) {
    330                   return;
    331     }
    332 
    333     frag_count = latency_monitor_mem[unit][monitor_id].frag_count;
    334     pkt_ctr_f_width = soc_mem_field_length(unit,latency_monitor_mem[unit][monitor_id].mem, PACKET_COUNTERf);
    335 
    336     while (TRUE) {
    337         if (sal_sem_take(latency_monitor_mem[unit][monitor_id].dma_handle_counter_sem, sal_sem_FOREVER) == 0) {
    338             if ((latency_monitor_driver_data.run[monitor_id] == FALSE) &&
    339                 (_sbusdma_desc_handle_list_is_empty(&latency_monitor_mem[unit][monitor_id].handle_list))) {
    340                 LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    341                      (BSL_META_U(unit, "Exiting the counter_accrue_thread monitor_id:%d \n"), monitor_id));
    342                 BCM_EXIT;
    343             }
    344             sal_sem_take(latency_monitor_mem[unit][monitor_id].dma_handle_queue_lock, sal_sem_FOREVER);
    345             _sbusdma_desc_handle_list_pop(&latency_monitor_mem[unit][monitor_id].handle_list, &list_data);
    346             sal_sem_give(latency_monitor_mem[unit][monitor_id].dma_handle_queue_lock);
    347  
    348             if (list_data) {
    349                 dbuf = list_data->dbuf;
    350                 pipe = list_data->pipe;
    351                 sal_free(list_data);
    352             } else {
    353                 BCM_EXIT;
    354             }
    355 
    356             if (latency_monitor_mem[unit][monitor_id].pipe_map_temp == 0) {
    357                 latency_monitor_mem[unit][monitor_id].pipe_map_temp = latency_monitor_mem[unit][monitor_id].dest_pbmp_pipe_map;
    358                 pipe_lower = pipe;
    359             } else {
    360                 pipe_lower = -1;
    361             }
    362 
    363             latency_monitor_mem[unit][monitor_id].pipe_map_temp &= ~(1 << pipe);
    364 
    365             if (dbuf) {
    366                 arr_pkt_cnt = (uint64 (*)[LATENCY_MONITOR_BUCKET_COUNT])latency_monitor_mem[unit][monitor_id].histogram_packet64_counter;
    367                 arr_byte_cnt = (uint64 (*)[LATENCY_MONITOR_BUCKET_COUNT])latency_monitor_mem[unit][monitor_id].histogram_byte64_counter;
    368                 data_ptr = (egr_flex_ctr_counter_table_0_entry_t *)dbuf;
    369                 data_buffer_idx = 0;
    370                 for (l=0; l<(TIME_STEP_SET_COUNT/frag_count); l++) {
    371                     if (latency_monitor_mem[unit][monitor_id].monitor_mode == bcmLatencyMonitorTimeSeriesMode) {
    372                         sw_buff = (uint64 *)latency_monitor_mem[unit][monitor_id].sw_buf_addr;
    373                     }
    374                     for (j=0; j<LATENCY_MONITOR_QUEUE_COUNT; j++) {
    375                         for (k=0; k<LATENCY_MONITOR_BUCKET_COUNT; k++) {
    376                             soc_memacc_field64_get(&memacc_byte_x,
    377                                     (uint64 *)&data_ptr[data_buffer_idx], &byte_count);
    378                             packet_count = soc_memacc_field32_get(&memacc_pkt_x,
    379                                     (uint32 *)&data_ptr[data_buffer_idx]);
    380                             COMPILER_64_ADD_32(arr_pkt_cnt[j][k], packet_count);
    381                             COMPILER_64_ADD_64(arr_byte_cnt[j][k], byte_count);
    382                             data_buffer_idx++;
    383                             if (latency_monitor_mem[unit][monitor_id].monitor_mode == bcmLatencyMonitorTimeSeriesMode) {
    384                                 sw_buf_idx = latency_monitor_mem[unit][monitor_id].sw_buf_wr_idx;
    385 
    386                                 packet_count_tmp = 0;
    387                                 COMPILER_64_ZERO(byte_count_tmp);
    388                                 if (pipe_lower != -1) {
    389                                     /* Overwrite counter for the the pipe corresponding to first port in dbmp */
    390                                     COMPILER_64_COPY(sw_buff[sw_buf_idx], byte_count);
    391                                 } else {
    392                                     COMPILER_64_COPY(tmp64, sw_buff[sw_buf_idx]);
    393                                     COMPILER_64_SHR(tmp64, pkt_ctr_f_width);
    394                                     COMPILER_64_COPY(byte_count_tmp, tmp64);
    395                                     COMPILER_64_COPY(tmp64, sw_buff[sw_buf_idx]);
    396                                     COMPILER_64_SET(mask64, 0, (uint32)((1 << pkt_ctr_f_width) - 1));
    397                                     COMPILER_64_AND(tmp64, mask64);
    398                                     packet_count_tmp =  COMPILER_64_LO(tmp64);
    399                                     /* Accumulate counter for the remaining pipe corresponding to port in dbmp */
    400                                     COMPILER_64_ADD_64(byte_count_tmp, byte_count);
    401                                     COMPILER_64_COPY(sw_buff[sw_buf_idx], byte_count_tmp);
    402                                 }
    403                                 packet_count_tmp += packet_count;
    404                                 COMPILER_64_SHL(sw_buff[sw_buf_idx], pkt_ctr_f_width);
    405                                 COMPILER_64_ADD_32(sw_buff[sw_buf_idx], packet_count_tmp);
    406                             
    407                                 latency_monitor_mem[unit][monitor_id].sw_buf_wr_idx++;
    408                                 latency_monitor_mem[unit][monitor_id].sw_buf_wr_idx %= latency_monitor_mem[unit][monitor_id].sw_buf_size;
    409                             }
    410                         }
    411                     }
    412                 }
    413 
    414                 LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    415                      (BSL_META_U(unit, "Freed buffer for dbuf:%p  Monitor:%d\n"), dbuf, monitor_id));
    416                 sal_free(dbuf);
    417 
    418                 /* Call the callback handler after accumilation for all the pipes */
    419                 if ((latency_monitor_mem[unit][monitor_id].monitor_mode == bcmLatencyMonitorTimeSeriesMode) &&
    420                     (latency_monitor_mem[unit][monitor_id].pipe_map_temp == 0) &&
    421                     (latency_monitor_mem[unit][monitor_id].cb)) {
    422                     latency_monitor_mem[unit][monitor_id].cb(unit, monitor_id, latency_monitor_mem[unit][monitor_id].status,
    423                                             (void *)sw_buff, latency_monitor_mem[unit][monitor_id].sw_buf_size, sw_buf_idx);
    424                 }
    425 
    426                 /* Counter accumilation pending for other pipes. Back track the sw_buf_wr_idx index in S/W Ring buffer */
    427                 if ((latency_monitor_mem[unit][monitor_id].monitor_mode == bcmLatencyMonitorTimeSeriesMode) &&
    428                     (latency_monitor_mem[unit][monitor_id].pipe_map_temp != 0)) {
    429                     if (latency_monitor_mem[unit][monitor_id].sw_buf_wr_idx == 0) {
    430                         latency_monitor_mem[unit][monitor_id].sw_buf_wr_idx = latency_monitor_mem[unit][monitor_id].sw_buf_size;
    431                     } 
    432 
    433                     if (latency_monitor_mem[unit][monitor_id].sw_buf_wr_idx) {
    434                         latency_monitor_mem[unit][monitor_id].sw_buf_wr_idx -=
    435                                  (LATENCY_MONITOR_QUEUE_COUNT * LATENCY_MONITOR_BUCKET_COUNT)*(TIME_STEP_SET_COUNT/frag_count);
    436                     }
    437                 }
    438             }
    439         }
    440     }
    441 
    442 exit:
    443     if (latency_monitor_mem[unit][monitor_id].dma_handle_counter_sem) {
    444         sal_sem_destroy(latency_monitor_mem[unit][monitor_id].dma_handle_counter_sem);
    445         latency_monitor_mem[unit][monitor_id].dma_handle_counter_sem = NULL;
    446     }
    447 
    448     if (latency_monitor_mem[unit][monitor_id].dma_handle_queue_lock) {
    449         sal_sem_destroy(latency_monitor_mem[unit][monitor_id].dma_handle_queue_lock);
    450         latency_monitor_mem[unit][monitor_id].dma_handle_queue_lock = NULL;
    451     }
    452     latency_monitor_mem[unit][monitor_id].init_done = FALSE;
    453 
    454     if (latency_monitor_mem[unit][monitor_id].status == LATENCY_MONITOR_STATE_RUNNING) {
    455         latency_monitor_mem[unit][monitor_id].status = LATENCY_MONITOR_STATE_IDLE;
    456     }
    457 
    458     sal_thread_exit(0);
    459 
    460     return;
    461 }
    462 
    463 static int
    464 _get_curr_histogram_set(int unit, int monitor_id)
    465 {
    466     soc_reg_t       histogram_set_reg;
    467     uint32          reg_value;
    468     int             rv = SOC_E_NONE;
    469     int             histogram_set;
    470 
    471     switch (monitor_id) {
    472     case MONITOR_ID_0:
    473         histogram_set_reg       = EGR_HISTO_MON_0_HISTOGRAM_SETr;
    474         break;
    475     case MONITOR_ID_1:
    476         histogram_set_reg       = EGR_HISTO_MON_1_HISTOGRAM_SETr;
    477         break;
    478     case MONITOR_ID_2:
    479         histogram_set_reg       = EGR_HISTO_MON_2_HISTOGRAM_SETr;
    480         break;
    481     case MONITOR_ID_3:
    482         histogram_set_reg       = EGR_HISTO_MON_3_HISTOGRAM_SETr;
    483         break;
    484     default:
    485         return SOC_E_PARAM;
    486     }
    487 
    488     rv = soc_reg32_get(unit, histogram_set_reg, REG_PORT_ANY, 0, &reg_value);
    489     SOC_IF_ERROR_RETURN(rv);
    490     histogram_set = soc_reg_field_get(unit,histogram_set_reg,reg_value, HISTOGRAM_SETf);
    491 
    492     return histogram_set;
    493 }
    494 
    495 static int
    496 _check_for_wraparound_condition(int unit, int monitor_id, int frag)
    497 {
    498     soc_reg_t       histogram_set_reg;
    499     soc_reg_t       flex_ctr_wrap_ctr_reg;
    500     int             histogram_set;
    501     uint32          flex_ctr_wrap_ctr_old;
    502     uint32          flex_ctr_wrap_ctr_new;
    503     uint32          reg_value;
    504     int             rv = SOC_E_NONE;
    505     int             frag_count;
    506     uint8           frag_set_idx;
    507 
    508     switch (monitor_id) {
    509     case MONITOR_ID_0:
    510         histogram_set_reg       = EGR_HISTO_MON_0_HISTOGRAM_SETr;
    511         flex_ctr_wrap_ctr_reg   = EGR_HISTO_MON_0_FLEX_COUNTER_WRAP_COUNTERr;
    512         break;
    513     case MONITOR_ID_1:
    514         histogram_set_reg       = EGR_HISTO_MON_1_HISTOGRAM_SETr;
    515         flex_ctr_wrap_ctr_reg   = EGR_HISTO_MON_1_FLEX_COUNTER_WRAP_COUNTERr;
    516         break;
    517     case MONITOR_ID_2:
    518         histogram_set_reg       = EGR_HISTO_MON_2_HISTOGRAM_SETr;
    519         flex_ctr_wrap_ctr_reg   = EGR_HISTO_MON_2_FLEX_COUNTER_WRAP_COUNTERr;
    520         break;
    521     case MONITOR_ID_3:
    522         histogram_set_reg       = EGR_HISTO_MON_3_HISTOGRAM_SETr;
    523         flex_ctr_wrap_ctr_reg   = EGR_HISTO_MON_3_FLEX_COUNTER_WRAP_COUNTERr;
    524         break;
    525     default:
    526         return BCM_E_PARAM;
    527     }
    528 
    529     frag_count = latency_monitor_mem[unit][monitor_id].frag_count;
    530 
    531     while (latency_monitor_driver_data.run[monitor_id]) {
    532         rv = soc_reg32_get(unit, histogram_set_reg, REG_PORT_ANY, 0, &reg_value);
    533         SOC_IF_ERROR_RETURN(rv);
    534         histogram_set = soc_reg_field_get(unit,histogram_set_reg,reg_value, HISTOGRAM_SETf);
    535 
    536         rv = soc_reg32_get(unit, flex_ctr_wrap_ctr_reg, REG_PORT_ANY, 0, &reg_value);
    537         SOC_IF_ERROR_RETURN(rv);
    538         flex_ctr_wrap_ctr_new = soc_reg_field_get(unit,flex_ctr_wrap_ctr_reg,reg_value, FLEX_COUNTER_WRAP_COUNTf);
    539 
    540         flex_ctr_wrap_ctr_old = latency_monitor_mem[unit][monitor_id].flex_ctr_wrap_ctr;
    541         /* On The H/W reg field FLEX_COUNTER_WRAP_COUNT wrap, reset the counters */ 
    542         if ((flex_ctr_wrap_ctr_old == 0xFFFFFFFF) && (flex_ctr_wrap_ctr_new == 0)) {
    543             flex_ctr_wrap_ctr_old = 0;
    544         }
    545         latency_monitor_mem[unit][monitor_id].flex_ctr_wrap_ctr = flex_ctr_wrap_ctr_new;
    546 
    547         if ((flex_ctr_wrap_ctr_new - flex_ctr_wrap_ctr_old) > 1 ) {
    548             /* Error: Data Overwrite Occurred */
    549             return BCM_E_FAIL;
    550         }
    551         if (frag == 0) {    /* Check for 1st Fragment */
    552             /* Checking to schedule DMA for 1st Half of the flex counter block */
    553             if (histogram_set >= (TIME_STEP_SET_COUNT/frag_count)) {
    554                 /*i.e the hardware is upgrading the 2nd half of the allocated flex pool */
    555                 if ((flex_ctr_wrap_ctr_new - flex_ctr_wrap_ctr_old) > 0) {
    556                     /* Error: Data Overwrite Occurred */
    557                     return BCM_E_FAIL;
    558                 } else {
    559                     frag_set_idx = histogram_set - (TIME_STEP_SET_COUNT/frag_count);
    560                     latency_monitor_mem[unit][monitor_id].dma_schedule_period = 
    561                         ((TIME_STEP_SET_COUNT/frag_count) - frag_set_idx) * latency_monitor_mem[unit][monitor_id].time_step;
    562                     /* We are good */
    563                     return BCM_E_NONE;
    564                 }
    565             } else {
    566                 if (latency_monitor_driver_data.run[monitor_id] == FALSE) {
    567                     return BCM_E_NONE;
    568                 }
    569             }
    570         } else if (frag == 1) {   /* Check for 2nd Fragment */ 
    571             /* Checking to schedule DMA for 2nd Half of the flex counter block */
    572             if (histogram_set < (TIME_STEP_SET_COUNT/frag_count)) {
    573                 /*i.e the hardware is upgrading the 1st half of the allocated flex pool */
    574                 if ((flex_ctr_wrap_ctr_new - flex_ctr_wrap_ctr_old) > 1) {
    575                     /* Error: Data Overwrite Occurred */
    576                     return BCM_E_FAIL;
    577                 } else {
    578                     latency_monitor_mem[unit][monitor_id].dma_schedule_period = 
    579                         ((TIME_STEP_SET_COUNT/frag_count) - histogram_set) * latency_monitor_mem[unit][monitor_id].time_step;
    580                     /* We are good */
    581                     return BCM_E_NONE;
    582                 }
    583             } else {
    584                 if (latency_monitor_driver_data.run[monitor_id] == FALSE) {
    585                     return BCM_E_NONE;
    586                 }
    587             }
    588         } else {
    589             /* We never enter here. Error condition. */
    590             return BCM_E_FAIL;
    591         }
    592     };
    593     
    594     return BCM_E_NONE;
    595 }
    596 
    597 static int
    598 sbusdma_handler_run (int unit, sbusdma_desc_handle_t handle)
    599 {
    600     soc_timeout_t   to;
    601     sal_usecs_t     dma_timeout = 1000000;
    602     int             ret;
    603 
    604     soc_timeout_init(&to, 2 * dma_timeout, 0);
    605     do {
    606         ret = soc_sbusdma_desc_run(unit, handle);
    607         if ((ret == BCM_E_BUSY) || (ret == BCM_E_INIT)) {
    608             if (ret == BCM_E_INIT) {
    609                 break;
    610             }
    611             if (soc_timeout_check(&to)) {
    612                 LOG_WARN(BSL_LS_BCM_LATENCY_MONITOR,
    613                          (BSL_META_U(unit,
    614                                      "sbusdma desc run operation timeout\n")));
    615                 return BCM_E_TIMEOUT;
    616             }
    617             sal_usleep(10);
    618         }
    619     } while ((ret == BCM_E_BUSY) || (ret == BCM_E_INIT));
    620 
    621     return BCM_E_NONE;
    622 }
    623 
    624 static void
    625 sbusdma_read(void* up)
    626 {
    627     int         unit = PTR_TO_INT(up) & 0xff;
    628     uint32      *entbuf;
    629     uint32      *cleanup_buf;
    630     int         frag;
    631     int         index_min, index_max;
    632     char        *access_type;
    633     int         cnt;
    634     int         monitor_id;
    635     sal_usecs_t dma_timeout = 1000000;
    636     sbusdma_desc_handle_t handle_to_run = 0;
    637     uint64      rval, val;
    638     int         frag_count;
    639     uint8       frag_set_idx;
    640     uint8       histogram_set;
    641     uint8       pipe;
    642     int         rv = BCM_E_NONE;
    643 
    644     if (latency_monitor_driver_data.dma_rd_en) {
    645         access_type = sal_strdup("SBUS DMA");
    646     } else {
    647         access_type = sal_strdup("SBUS    ");
    648     }
    649 
    650     monitor_id = PTR_TO_INT(up) >> 8;
    651     frag_count = latency_monitor_mem[unit][monitor_id].frag_count;
    652 
    653     latency_monitor_mem[unit][monitor_id].sbusdma_read_thread_pid = sal_thread_id_get();
    654 
    655     while (latency_monitor_driver_data.run[monitor_id] == FALSE) {
    656         sal_usleep(10);
    657     }
    658 
    659     cnt = WORDS2BYTES((latency_monitor_mem[unit][monitor_id].bufwords)/frag_count);
    660     cleanup_buf = soc_cm_salloc(unit, cnt, "latency monitor cleanup buffer");
    661     if (!cleanup_buf) {
    662         BCM_EXIT;
    663     }
    664     sal_memset(cleanup_buf, 0x0, cnt);
    665 
    666     histogram_set = _get_curr_histogram_set(unit, monitor_id);
    667     if (histogram_set >= (TIME_STEP_SET_COUNT/frag_count)) {
    668         frag = 1;       /* Start from second Half of the flex counter pool block */
    669         frag_set_idx = histogram_set - (TIME_STEP_SET_COUNT/frag_count);
    670         latency_monitor_mem[unit][monitor_id].dma_schedule_period = ((TIME_STEP_SET_COUNT/frag_count) - frag_set_idx) *
    671                                                     latency_monitor_mem[unit][monitor_id].time_step;
    672     } else {
    673         frag = 0;       /* Start from first Half of the flex counter pool block */
    674         latency_monitor_mem[unit][monitor_id].dma_schedule_period = ((TIME_STEP_SET_COUNT/frag_count) - histogram_set) *
    675                                                     latency_monitor_mem[unit][monitor_id].time_step;
    676     }
    677 
    678     while (latency_monitor_driver_data.run[monitor_id]) {
    679         frag %= latency_monitor_mem[unit][monitor_id].frag_count;
    680         for (; frag < latency_monitor_mem[unit][monitor_id].frag_count; frag++) {
    681             index_min = latency_monitor_mem[unit][monitor_id].frag_index_min[frag];
    682             index_max = latency_monitor_mem[unit][monitor_id].frag_index_max[frag];
    683 
    684             /* 
    685              * The Binary Semaphore time out here is used for periodic scheduling of SBUS DMA.
    686              * The semaphore is also used to signal that the monitor is disabled and quick termination of the thread.
    687              */
    688             sal_sem_take(latency_monitor_mem[unit][monitor_id].latency_monitor_thread_trigger, 
    689                             latency_monitor_mem[unit][monitor_id].dma_schedule_period);
    690             if (latency_monitor_driver_data.run[monitor_id] == FALSE) {
    691                 BCM_EXIT;
    692             }
    693             if (_check_for_wraparound_condition(unit, monitor_id, frag) != SOC_E_NONE) {
    694                 /* Disable Monitor */
    695                 bcm_tomahawk3_latency_monitor_enable(unit, monitor_id, 0);
    696                 latency_monitor_mem[unit][monitor_id].status = LATENCY_MONITOR_STATE_ERROR;
    697                 if (latency_monitor_mem[unit][monitor_id].cb) {
    698                     latency_monitor_mem[unit][monitor_id].cb(unit, monitor_id, LATENCY_MONITOR_STATE_ERROR, NULL,0,0);
    699                 }
    700                 BCM_EXIT;
    701             }
    702 
    703             entbuf = soc_cm_salloc(unit, cnt,
    704                             "latency_monitor_driver_data source");
    705             if (!entbuf) {
    706                 latency_monitor_driver_data.run[monitor_id] = FALSE;
    707                 BCM_EXIT;
    708             }
    709             sal_memset(entbuf, 0x0, cnt);
    710 
    711             LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    712                      (BSL_META_U(unit, "Allocated %d bytes addr:%p Monitor:%d\n"),
    713                                 cnt, entbuf, monitor_id));
    714             LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    715                      (BSL_META_U(unit, "New DMA Satrted index_min:%d index_max;%d Monitor:%d\n"),
    716                                  index_min, index_max, monitor_id));
    717 
    718             LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    719                       (BSL_META_U(unit, "%s reading from %s[%0d..%0d] to address 0x%08x\n"),
    720                       access_type, SOC_MEM_NAME(unit, latency_monitor_mem[unit][monitor_id].mem),
    721                       index_max,index_min, PTR_TO_INT(entbuf)));
    722 
    723             for (pipe = 0; pipe < NUM_PIPE(unit); pipe++) {
    724                 if (!(latency_monitor_mem[unit][monitor_id].dest_pbmp_pipe_map & (1 << pipe))) {
    725                     continue;
    726                 }
    727                 sal_sem_take(latency_monitor_driver_data.sbusdma_run_lock, sal_sem_FOREVER);
    728 
    729                 if (latency_monitor_driver_data.dma_rd_en) {
    730                     /* Setup DMA handler for read operation */
    731                     latency_monitor_sbusdma_setup(unit, monitor_id, pipe, entbuf, index_min,
    732                                           index_max, frag, 0, &handle_to_run);
    733                 }
    734 
    735                 LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    736                          (BSL_META_U(unit, "handle:%d Monitor:%d \n"), handle_to_run, monitor_id));
    737 
    738                 if (latency_monitor_driver_data.dma_rd_en && latency_monitor_driver_data.desc_mode > 0) {
    739                     soc_timeout_t to;
    740                     soc_timeout_init(&to, 2 * dma_timeout, 0);
    741                     /* Execute SBUS DMA command to read the flex pool block */
    742                     sbusdma_handler_run(unit, handle_to_run);
    743                     LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    744                                 (BSL_META_U(unit, "DMA RUN completed Monitor:%d\n"), monitor_id));
    745                 }
    746 
    747             }
    748         }
    749     }
    750 
    751 exit:
    752     if (latency_monitor_driver_data.monitors_in_use_count) {
    753         latency_monitor_driver_data.monitors_in_use_count--;
    754         if (latency_monitor_driver_data.monitors_in_use_count == 0) {
    755             if (latency_monitor_driver_data.sbusdma_run_lock) {
    756                 /* Wait for other thread to release the semaphore before deleting it */
    757                 sal_sem_take(latency_monitor_driver_data.sbusdma_run_lock, sal_sem_FOREVER);
    758                 sal_sem_destroy(latency_monitor_driver_data.sbusdma_run_lock);
    759                 latency_monitor_driver_data.sbusdma_run_lock = NULL;
    760             }
    761             latency_monitor_driver_data.init_done = FALSE;
    762             if (cleanup_buf) {
    763                 soc_cm_sfree(unit, cleanup_buf);
    764             }
    765             /* Since none of the monitors are in use, clear the hist_1us_enable bit */
    766             rv = soc_reg_get(unit, AUX_ARB_CONTROLr, REG_PORT_ANY, 0, &rval);
    767             if (rv == BCM_E_NONE) {
    768                 COMPILER_64_SET(val, 0, 0);
    769                 soc_reg64_field_set(unit, AUX_ARB_CONTROLr, &rval, HIST_1US_ENABLEf, val);
    770                 /* coverity[check_return : FALSE] */
    771                 soc_reg_set(unit, AUX_ARB_CONTROLr, REG_PORT_ANY, 0, rval);
    772             }
    773         }
    774     }
    775 
    776     latency_monitor_driver_data.run[monitor_id] = FALSE;
    777     sal_free(access_type);
    778 
    779     latency_monitor_mem[unit][monitor_id].sbusdma_read_thread_pid = 0;
    780     sal_thread_exit(0);
    781 }
    782 
    783 int
    784 latency_monitor_read(int unit, int monitor_id)
    785 {
    786     sal_thread_t pid;
    787 
    788     /* sbus dma read */
    789     latency_monitor_driver_data.mem_done[monitor_id] = FALSE;
    790 
    791     if (latency_monitor_mem[unit][monitor_id].sbusdma_read_thread_pid) {
    792         return BCM_E_NONE;
    793     }
    794 
    795     pid = sal_thread_create("bcm_latency_monitor_sbusdma_read",
    796                             SAL_THREAD_STKSZ,
    797                             200,
    798                             sbusdma_read,
    799                             INT_TO_PTR(monitor_id << 8 | unit));
    800 
    801     LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    802                  (BSL_META_U(unit, "\npid_sbusdma[%0d] = %p"), monitor_id, pid));
    803 
    804     if (pid == SAL_THREAD_ERROR) {
    805         LOG_ERROR(BSL_LS_BCM_LATENCY_MONITOR,
    806                         (BSL_META_U(unit, "Failed to create sbusdma_read thread for monitor ID:%d \n"),
    807                                      monitor_id));
    808         return BCM_E_FAIL;
    809     }
    810 
    811     pid = sal_thread_create("bcm_latency_monitor_counter_accrue",
    812                             SAL_THREAD_STKSZ,
    813                             200,
    814                             counter_accrue_thread,
    815                             INT_TO_PTR(monitor_id << 8 | unit));
    816 
    817     if (pid == SAL_THREAD_ERROR) {
    818         LOG_ERROR(BSL_LS_BCM_LATENCY_MONITOR,
    819                         (BSL_META_U(unit, "Failed to create counter_accrue_thread, for monitor ID:%d \n"),
    820                                      monitor_id));
    821         return BCM_E_FAIL;
    822     } else {
    823         LOG_DEBUG(BSL_LS_BCM_LATENCY_MONITOR,
    824                      (BSL_META_U(unit, "created counter_accrue_thread for monitor%d  \n"), monitor_id));
    825     }
    826 
    827     return BCM_E_NONE;
    828 }
    829 
    830 int
    831 latency_monitor_init(int unit, int monitor_id)
    832 {
    833     int index_min, index_max;
    834     int frag, delta;
    835 
    836     if (!latency_monitor_mem[unit][monitor_id].init_done) {
    837         latency_monitor_driver_data.monitors_in_use_count++;
    838         latency_monitor_mem[unit][monitor_id].frag_count  = LATENCY_MONITOR_DEFAULT_FRAG_COUNT;
    839         latency_monitor_mem[unit][monitor_id].dma_handle_counter_sem =
    840                     sal_sem_create("DMA Handler Count Semaphore", sal_sem_COUNTING, 0);
    841         latency_monitor_mem[unit][monitor_id].dma_handle_queue_lock =
    842                     sal_sem_create("DMA Handler Queue Lock", sal_sem_BINARY, 1);
    843         _sbusdma_desc_handle_list_init(&latency_monitor_mem[unit][monitor_id].handle_list);
    844         latency_monitor_mem[unit][monitor_id].latency_monitor_thread_trigger = 
    845                     sal_sem_create("Latency Monitor Thread Sempahore", sal_sem_BINARY, 0);
    846         latency_monitor_mem[unit][monitor_id].init_done = TRUE;
    847         latency_monitor_driver_data.run[monitor_id] = FALSE;
    848         latency_monitor_driver_data.mem_done[monitor_id] = TRUE;
    849     }
    850 
    851     if (latency_monitor_driver_data.sbusdma_run_lock == NULL) {
    852         latency_monitor_driver_data.sbusdma_run_lock =
    853                                     sal_sem_create("SBUS DMA RUN Lock", sal_sem_BINARY, 1);
    854     }
    855 
    856     latency_monitor_mem[unit][monitor_id].copyno = SOC_MEM_BLOCK_ANY(unit, latency_monitor_mem[unit][monitor_id].mem);
    857     if (!SOC_MEM_BLOCK_VALID(unit, latency_monitor_mem[unit][monitor_id].mem, latency_monitor_mem[unit][monitor_id].copyno)) {
    858         LOG_ERROR(BSL_LS_BCM_LATENCY_MONITOR,
    859                   (BSL_META_U(unit,
    860                   "Invalid copyno %d specified in %s\n"),
    861                   latency_monitor_mem[unit][monitor_id].copyno,
    862                   SOC_MEM_NAME(unit, latency_monitor_mem[unit][monitor_id].mem)));
    863         return BCM_E_FAIL;
    864     }
    865 
    866     index_min = soc_mem_index_min(unit, latency_monitor_mem[unit][monitor_id].mem);
    867     index_max = soc_mem_index_max(unit, latency_monitor_mem[unit][monitor_id].mem);
    868 
    869     if (latency_monitor_mem[unit][monitor_id].index_min <= index_min) {
    870         latency_monitor_mem[unit][monitor_id].index_min = index_min;
    871     }
    872     if (latency_monitor_mem[unit][monitor_id].index_min > index_max) {
    873         latency_monitor_mem[unit][monitor_id].index_min = index_min;
    874     }
    875 
    876     if (latency_monitor_mem[unit][monitor_id].count <= 0) {
    877         /*
    878          * do not use soc_mem_index_count, index_max may have been,
    879          * index_max may have been modified above
    880          */
    881        latency_monitor_mem[unit][monitor_id].count = index_max - index_min + 1;
    882     }
    883 
    884     if (latency_monitor_mem[unit][monitor_id].index_min + latency_monitor_mem[unit][monitor_id].count - 1 > index_max) {
    885         latency_monitor_mem[unit][monitor_id].count = index_max - latency_monitor_mem[unit][monitor_id].index_min + 1;
    886     }
    887 
    888     latency_monitor_mem[unit][monitor_id].index_max = latency_monitor_mem[unit][monitor_id].index_min +
    889                              latency_monitor_mem[unit][monitor_id].count - 1;
    890 
    891     if (latency_monitor_mem[unit][monitor_id].frag_count <= latency_monitor_driver_data.num_mem) {
    892         latency_monitor_mem[unit][monitor_id].frag_count = latency_monitor_driver_data.num_mem;
    893         latency_monitor_mem[unit][monitor_id].frag_index_min[0] = latency_monitor_mem[unit][monitor_id].index_min;
    894         latency_monitor_mem[unit][monitor_id].frag_index_max[0] = latency_monitor_mem[unit][monitor_id].index_max;
    895     } else {
    896         if (latency_monitor_mem[unit][monitor_id].frag_count > latency_monitor_mem[unit][monitor_id].count) {
    897             latency_monitor_mem[unit][monitor_id].frag_count = latency_monitor_mem[unit][monitor_id].count;
    898         }
    899 
    900         delta = (latency_monitor_mem[unit][monitor_id].index_max - latency_monitor_mem[unit][monitor_id].index_min + 1) /
    901                 latency_monitor_mem[unit][monitor_id].frag_count;
    902         for (frag = 0; frag < latency_monitor_mem[unit][monitor_id].frag_count; frag++) {
    903             latency_monitor_mem[unit][monitor_id].frag_index_min[frag] = latency_monitor_mem[unit][monitor_id].index_min +
    904                                                 frag * delta;
    905             latency_monitor_mem[unit][monitor_id].frag_index_max[frag] = latency_monitor_mem[unit][monitor_id].index_min +
    906                                                 (frag + 1) * delta - 1;
    907         }
    908         latency_monitor_mem[unit][monitor_id].frag_index_max[latency_monitor_mem[unit][monitor_id].frag_count - 1] =
    909             latency_monitor_mem[unit][monitor_id].index_max;
    910     }
    911 
    912     return BCM_E_NONE;
    913 }
    914 
    915 
    916 /* Set monitor with a given configuration. */
    917 int
    918 bcm_tomahawk3_latency_monitor_config_set(
    919     int unit,
    920     uint8 monitor_id,
    921     bcm_latency_monitor_config_t *config)
    922 {
    923 #ifdef BCM_TOMAHAWK3_SUPPORT
    924     pbmp_t                  src_pbm;
    925     pbmp_t                  dest_pbm;
    926     soc_field_t             field_ids[5];
    927     uint32                  field_values[5];
    928     int                     port_idx;
    929     bcm_stat_object_t       stat_obj;
    930     uint32                  stat_counter_id = 0;
    931     uint32                  num_entries;
    932     bcm_stat_group_mode_t   group;
    933     bcm_stat_object_t       object;
    934     uint32                  mode;
    935     uint32                  pool_number;
    936     uint32                  base_idx;
    937     soc_reg_t               flex_bank_sel_reg;
    938     soc_field_t             pbmp_field;
    939     uint32                  sw_buf_size;
    940     uint16                  time_step_incr;
    941     uint32                  time_step_set;
    942     soc_info_t              *si;
    943     int                     rv = BCM_E_NONE;
    944     uint8                   count_mode;
    945 
    946 
    947     if (monitor_id > MONITOR_ID_3) {
    948         return BCM_E_PARAM;
    949     }
    950 
    951     if (!config) {
    952         return BCM_E_PARAM;
    953     }
    954 
    955     if ((!wb_post_init) &&
    956         (latency_monitor_mem[unit][monitor_id].status == LATENCY_MONITOR_STATE_RUNNING)) {
    957         if (config->mode == bcmLatencyMonitorTimeSeriesMode) {
    958             latency_monitor_mem[unit][monitor_id].cb = config->cb;
    959         }
    960         return BCM_E_BUSY;
    961     }
    962 
    963     if ((config->mode != bcmLatencyMonitorAccrueMode) &&
    964         (config->mode != bcmLatencyMonitorTimeSeriesMode)) {
    965         return BCM_E_PARAM;
    966     }
    967 
    968     if ((config->count_mode < bcmLatencyMonitorCutThrough) ||
    969         (config->count_mode > bcmLatencyMonitorCountAll)) {
    970         return _SHR_E_PARAM;
    971     }
    972 
    973     if ((latency_monitor_mem[unit][monitor_id].status != LATENCY_MONITOR_STATE_CLEANUP) &&
    974         (config->time_step < LATENCY_MONITOR_MIN_TIME_STEP)) {
    975         return BCM_E_PARAM;
    976     }
    977 
    978     latency_monitor_mem[unit][monitor_id].monitor_mode = config->mode;
    979     latency_monitor_mem[unit][monitor_id].sw_buf_size = 0;
    980     if (config->mode == bcmLatencyMonitorTimeSeriesMode) {
    981         if (config->histogram_set_count < TIME_STEP_SET_COUNT) {
    982             return BCM_E_PARAM;
    983         }
    984 
    985         if (latency_monitor_mem[unit][monitor_id].sw_buf_addr) {
    986             sal_free(latency_monitor_mem[unit][monitor_id].sw_buf_addr);
    987         }
    988  
    989         sw_buf_size = (config->histogram_set_count) * COUNTERS_PER_STEP_SET * LATENCY_MONITOR_SW_BUF_WIDTH;
    990         latency_monitor_mem[unit][monitor_id].sw_buf_addr =
    991                                     sal_alloc(sw_buf_size, "sw ring buffer");
    992         if (latency_monitor_mem[unit][monitor_id].sw_buf_addr == NULL) {
    993             return BCM_E_MEMORY;
    994         }
    995 
    996         latency_monitor_mem[unit][monitor_id].cb = config->cb;
    997         /* Save the sw ring buffer size in terms of 64 bit word count */
    998         latency_monitor_mem[unit][monitor_id].sw_buf_size = config->histogram_set_count * COUNTERS_PER_STEP_SET;
    999     }
   1000 
   1001     if ((latency_monitor_mem[unit][monitor_id].status != LATENCY_MONITOR_STATE_CLEANUP) &&
   1002         (!latency_monitor_driver_data.init_done)) {
   1003         latency_monitor_driver_data_init(unit);
   1004     }
   1005 
   1006     SOC_LATENCY_MONITOR_INFO(unit, monitor_id).time_step = config->time_step;
   1007     SOC_LATENCY_MONITOR_INFO(unit, monitor_id).flex_pool_number = -1;
   1008     BCM_PBMP_ASSIGN(SOC_LATENCY_MONITOR_INFO(unit, monitor_id).src_pbmp, config->src_pbmp);
   1009     BCM_PBMP_ASSIGN(SOC_LATENCY_MONITOR_INFO(unit, monitor_id).dest_pbmp, config->dest_pbmp);
   1010 
   1011     /* Convert from zero indexed enum value to one indexed value. Register field value '0'  is reserved in HW */
   1012     count_mode = config->count_mode + 1;
   1013 
   1014     switch (monitor_id) {
   1015     case MONITOR_ID_0:
   1016         field_ids[0] = TIME_SERIES_STEPf;
   1017         field_values[0] = config->time_step;
   1018         BCM_IF_ERROR_RETURN
   1019             (soc_reg_fields32_modify(unit, EGR_HISTO_MON_0_FLEX_BANK_SEL_0r, REG_PORT_ANY, 1,
   1020                                      field_ids, field_values));
   1021 
   1022         field_ids[0] = MON_CUT_THROUGHf;
   1023         field_values[0] = count_mode;
   1024         BCM_IF_ERROR_RETURN
   1025             (soc_reg_fields32_modify(unit, EGR_HISTO_MON_0_CONFIGr, REG_PORT_ANY, 1,
   1026                                      field_ids, field_values));
   1027         pbmp_field = MONITOR_0f;
   1028         stat_obj = bcmIntStatObjectEgrLatencyMonitor0;
   1029         flex_bank_sel_reg = EGR_HISTO_MON_0_FLEX_BANK_SEL_1r;
   1030         break;
   1031     case MONITOR_ID_1:
   1032         field_ids[0] = TIME_SERIES_STEPf;
   1033         field_values[0] = config->time_step;
   1034         BCM_IF_ERROR_RETURN
   1035             (soc_reg_fields32_modify(unit, EGR_HISTO_MON_1_FLEX_BANK_SEL_0r, REG_PORT_ANY, 1,
   1036                                      field_ids, field_values));
   1037 
   1038         field_ids[0] = MON_CUT_THROUGHf;
   1039         field_values[0] = count_mode;
   1040         BCM_IF_ERROR_RETURN
   1041             (soc_reg_fields32_modify(unit, EGR_HISTO_MON_1_CONFIGr, REG_PORT_ANY, 1,
   1042                                      field_ids, field_values));
   1043         pbmp_field = MONITOR_1f;
   1044         stat_obj = bcmIntStatObjectEgrLatencyMonitor1;
   1045         flex_bank_sel_reg = EGR_HISTO_MON_1_FLEX_BANK_SEL_1r;
   1046         break;
   1047     case MONITOR_ID_2:
   1048         field_ids[0] = TIME_SERIES_STEPf;
   1049         field_values[0] = config->time_step;
   1050         BCM_IF_ERROR_RETURN
   1051             (soc_reg_fields32_modify(unit, EGR_HISTO_MON_2_FLEX_BANK_SEL_0r, REG_PORT_ANY, 1,
   1052                                      field_ids, field_values));
   1053 
   1054         field_ids[0] = MON_CUT_THROUGHf;
   1055         field_values[0] = count_mode;
   1056         BCM_IF_ERROR_RETURN
   1057             (soc_reg_fields32_modify(unit, EGR_HISTO_MON_2_CONFIGr, REG_PORT_ANY, 1,
   1058                                      field_ids, field_values));
   1059         pbmp_field = MONITOR_2f;
   1060         stat_obj = bcmIntStatObjectEgrLatencyMonitor2;
   1061         flex_bank_sel_reg = EGR_HISTO_MON_2_FLEX_BANK_SEL_1r;
   1062         break;
   1063     case MONITOR_ID_3:
   1064         field_ids[0] = TIME_SERIES_STEPf;
   1065         field_values[0] = config->time_step;
   1066         BCM_IF_ERROR_RETURN
   1067             (soc_reg_fields32_modify(unit, EGR_HISTO_MON_3_FLEX_BANK_SEL_0r, REG_PORT_ANY, 1,
   1068                                      field_ids, field_values));
   1069 
   1070         field_ids[0] = MON_CUT_THROUGHf;
   1071         field_values[0] = count_mode;
   1072         BCM_IF_ERROR_RETURN
   1073             (soc_reg_fields32_modify(unit, EGR_HISTO_MON_3_CONFIGr, REG_PORT_ANY, 1,
   1074                                      field_ids, field_values));
   1075         pbmp_field = MONITOR_3f;
   1076         stat_obj = bcmIntStatObjectEgrLatencyMonitor3;
   1077         flex_bank_sel_reg = EGR_HISTO_MON_3_FLEX_BANK_SEL_1r;
   1078         break;
   1079     default:
   1080         return BCM_E_PARAM;
   1081     }
   1082 
   1083     src_pbm = PBMP_PORT_ALL(unit);
   1084     dest_pbm = PBMP_PORT_ALL(unit);
   1085     if (latency_monitor_mem[unit][monitor_id].status != LATENCY_MONITOR_STATE_CLEANUP) {
   1086         field_values[0] = 1;
   1087         BCM_PBMP_AND(src_pbm, config->src_pbmp);
   1088         BCM_PBMP_AND(dest_pbm, config->dest_pbmp);
   1089     } else {
   1090         field_values[0] = 0;
   1091     }
   1092 
   1093     field_ids[0] = pbmp_field;
   1094     BCM_PBMP_ITER(src_pbm, port_idx) {
   1095         BCM_IF_ERROR_RETURN
   1096         (soc_reg_fields32_modify(unit, EGR_HISTO_SRC_PORT_MAPr, port_idx, 1,
   1097                                  field_ids, field_values));
   1098     }
   1099 
   1100     latency_monitor_mem[unit][monitor_id].dest_pbmp_pipe_map = 0;
   1101     si = &SOC_INFO(unit);
   1102     field_ids[0] = pbmp_field;
   1103     BCM_PBMP_ITER(dest_pbm, port_idx) {
   1104         latency_monitor_mem[unit][monitor_id].dest_pbmp_pipe_map |= 1 << si->port_pipe[port_idx];
   1105         BCM_IF_ERROR_RETURN
   1106         (soc_reg_fields32_modify(unit, EGR_HISTO_DST_PORT_MAPr, port_idx, 1,
   1107                                  field_ids, field_values));
   1108     }
   1109 
   1110     latency_monitor_mem[unit][monitor_id].time_step = config->time_step;
   1111     latency_monitor_mem[unit][monitor_id].wrap_around_time =
   1112                                         config->time_step * TIME_STEP_SET_COUNT;
   1113 
   1114     if (latency_monitor_mem[unit][monitor_id].status != LATENCY_MONITOR_STATE_CLEANUP) {
   1115         if (latency_monitor_mem[unit][monitor_id].stat_counter_id != 0) {
   1116             rv = _bcm_esw_stat_group_destroy(unit,
   1117                         latency_monitor_mem[unit][monitor_id].stat_counter_id);
   1118 
   1119             /* Return error if the stat group exists and on failure to delete it */
   1120             if ((rv != BCM_E_NONE) && (rv != BCM_E_NOT_FOUND)) {
   1121                 BCM_IF_ERROR_RETURN(rv);
   1122             }
   1123         }
   1124 
   1125         BCM_IF_ERROR_RETURN(_bcm_esw_stat_group_create(unit, stat_obj,
   1126                                                 bcmIntStatGroupModeLatencyMonitor,
   1127                                                 &stat_counter_id, &num_entries));
   1128 
   1129         _bcm_esw_stat_get_counter_id_info(unit, stat_counter_id, &group, &object,
   1130                                            &mode, &pool_number, &base_idx);
   1131 
   1132         time_step_incr = TIME_STEP_COUNTER_INCR;
   1133         time_step_set = (TIME_STEP_SET_COUNT - 1);
   1134     } else {
   1135         latency_monitor_mem[unit][monitor_id].cb = NULL;
   1136         latency_monitor_mem[unit][monitor_id].sw_buf_size = 0;
   1137         pool_number = 0;
   1138         base_idx = 0;
   1139         time_step_incr = 0;
   1140         time_step_set = 0;
   1141     }
   1142 
   1143     /* If the base index is zero, skip the first two reserved entries and select the next power of 2 entry */
   1144     if (base_idx == 0)
   1145         latency_monitor_mem[unit][monitor_id].index_min = base_idx + 4;
   1146     else
   1147         latency_monitor_mem[unit][monitor_id].index_min = base_idx;
   1148 
   1149     field_ids[0] = FLEX_CTR_POOL_NUMBERf;
   1150     field_values[0] = pool_number;
   1151     field_ids[1] = HISTOGRAM_OFFSETf;
   1152     field_values[1] = latency_monitor_mem[unit][monitor_id].index_min;
   1153     field_ids[2] = TIME_STEP_COUNTER_INCRf;
   1154     field_values[2] = time_step_incr;
   1155     field_ids[3] = FLEX_CTR_OFFSET_MODEf;
   1156     field_values[3] = 0;
   1157     field_ids[4] = MAX_TIME_STEP_SETSf;
   1158     field_values[4] = time_step_set;
   1159 
   1160     BCM_IF_ERROR_RETURN
   1161     (soc_reg_fields32_modify(unit, flex_bank_sel_reg, REG_PORT_ANY, 5,
   1162                              field_ids, field_values));
   1163 
   1164     latency_monitor_mem[unit][monitor_id].stat_counter_id = stat_counter_id;
   1165     latency_monitor_mem[unit][monitor_id].status = LATENCY_MONITOR_STATE_IDLE;
   1166 
   1167     latency_monitor_mem[unit][monitor_id].count = COUNTERS_PER_STEP_SET * TIME_STEP_SET_COUNT;
   1168     latency_monitor_mem[unit][monitor_id].index_max = latency_monitor_mem[unit][monitor_id].index_min + latency_monitor_mem[unit][monitor_id].count;
   1169     switch (pool_number) {
   1170     case 0:
   1171         latency_monitor_mem[unit][monitor_id].mem = EGR_FLEX_CTR_COUNTER_TABLE_0_PIPE0m;
   1172         break;
   1173     case 1:
   1174         latency_monitor_mem[unit][monitor_id].mem = EGR_FLEX_CTR_COUNTER_TABLE_1_PIPE0m;
   1175         break;
   1176     case 2:
   1177         latency_monitor_mem[unit][monitor_id].mem = EGR_FLEX_CTR_COUNTER_TABLE_2_PIPE0m;
   1178         break;
   1179     case 3:
   1180         latency_monitor_mem[unit][monitor_id].mem = EGR_FLEX_CTR_COUNTER_TABLE_3_PIPE0m;
   1181         break;
   1182     default:
   1183         return BCM_E_BADID;
   1184     }
   1185 
   1186     latency_monitor_mem[unit][monitor_id].entwords = soc_mem_entry_words(unit, latency_monitor_mem[unit][monitor_id].mem);
   1187     latency_monitor_mem[unit][monitor_id].bufwords = latency_monitor_mem[unit][monitor_id].entwords * latency_monitor_mem[unit][monitor_id].count;
   1188 
   1189 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1190 
   1191     return BCM_E_NONE;
   1192 }
   1193 
   1194 /* Get configuration for a given monitor. */
   1195 int
   1196 bcm_tomahawk3_latency_monitor_config_get(
   1197     int unit,
   1198     uint8 monitor_id,
   1199     bcm_latency_monitor_config_t *config)
   1200 {
   1201 #ifdef BCM_TOMAHAWK3_SUPPORT
   1202     uint32          reg_value;
   1203     int             rv, port_idx;
   1204     soc_field_t     pbmp_field;
   1205     soc_reg_t       mon_count_mode_reg;
   1206 
   1207     if (config == NULL)
   1208         return BCM_E_PARAM;
   1209 
   1210     switch (monitor_id) {
   1211     case MONITOR_ID_0:
   1212         rv = soc_reg32_get(unit, EGR_HISTO_MON_0_FLEX_BANK_SEL_0r, REG_PORT_ANY,0,
   1213                             &reg_value);
   1214         SOC_IF_ERROR_RETURN(rv);
   1215         config->time_step = soc_reg_field_get(unit,EGR_HISTO_MON_0_FLEX_BANK_SEL_0r,reg_value,
   1216                                TIME_SERIES_STEPf);
   1217         pbmp_field = MONITOR_0f;
   1218         mon_count_mode_reg = EGR_HISTO_MON_0_CONFIGr;
   1219         break;
   1220     case MONITOR_ID_1:
   1221         rv = soc_reg32_get(unit, EGR_HISTO_MON_1_FLEX_BANK_SEL_0r, REG_PORT_ANY,0,
   1222                             &reg_value);
   1223         SOC_IF_ERROR_RETURN(rv);
   1224         config->time_step = soc_reg_field_get(unit,EGR_HISTO_MON_1_FLEX_BANK_SEL_0r,reg_value,
   1225                                TIME_SERIES_STEPf);
   1226         pbmp_field = MONITOR_1f;
   1227         mon_count_mode_reg = EGR_HISTO_MON_1_CONFIGr;
   1228         break;
   1229     case MONITOR_ID_2:
   1230         rv = soc_reg32_get(unit, EGR_HISTO_MON_2_FLEX_BANK_SEL_0r, REG_PORT_ANY,0,
   1231                             &reg_value);
   1232         SOC_IF_ERROR_RETURN(rv);
   1233         config->time_step = soc_reg_field_get(unit,EGR_HISTO_MON_2_FLEX_BANK_SEL_0r,reg_value,
   1234                                TIME_SERIES_STEPf);
   1235         pbmp_field = MONITOR_2f;
   1236         mon_count_mode_reg = EGR_HISTO_MON_2_CONFIGr;
   1237         break;
   1238     case MONITOR_ID_3:
   1239         rv = soc_reg32_get(unit, EGR_HISTO_MON_3_FLEX_BANK_SEL_0r, REG_PORT_ANY,0,
   1240                             &reg_value);
   1241         SOC_IF_ERROR_RETURN(rv);
   1242         config->time_step = soc_reg_field_get(unit,EGR_HISTO_MON_3_FLEX_BANK_SEL_0r,reg_value,
   1243                                TIME_SERIES_STEPf);
   1244         pbmp_field = MONITOR_3f;
   1245         mon_count_mode_reg = EGR_HISTO_MON_3_CONFIGr;
   1246         break;
   1247     default:
   1248         return BCM_E_PARAM;
   1249     }
   1250 
   1251     config->mode = latency_monitor_mem[unit][monitor_id].monitor_mode;
   1252     if (config->mode == bcmLatencyMonitorTimeSeriesMode) {
   1253         config->histogram_set_count = (latency_monitor_mem[unit][monitor_id].sw_buf_size)/COUNTERS_PER_STEP_SET;
   1254         config->cb = latency_monitor_mem[unit][monitor_id].cb;
   1255     }
   1256 
   1257     rv = soc_reg32_get(unit, mon_count_mode_reg, REG_PORT_ANY, 0, &reg_value);
   1258     SOC_IF_ERROR_RETURN(rv);
   1259     config->count_mode = soc_reg_field_get(unit, EGR_HISTO_MON_0_CONFIGr, reg_value,
   1260                            MON_CUT_THROUGHf);
   1261 
   1262     /* Convert from '1' indexed register field value to '0' indexed enum type */
   1263     config->count_mode -= 1;
   1264 
   1265     BCM_PBMP_CLEAR(config->src_pbmp);
   1266     BCM_PBMP_ITER(PBMP_PORT_ALL(unit), port_idx) {
   1267         rv = soc_reg32_get(unit, EGR_HISTO_SRC_PORT_MAPr, port_idx, 0,
   1268                                          &reg_value);
   1269         SOC_IF_ERROR_RETURN(rv);
   1270         if (soc_reg_field_get(unit,EGR_HISTO_SRC_PORT_MAPr,reg_value,
   1271                            pbmp_field))
   1272             BCM_PBMP_PORT_ADD(config->src_pbmp, port_idx);
   1273     }
   1274 
   1275     BCM_PBMP_CLEAR(config->dest_pbmp);
   1276     BCM_PBMP_ITER(PBMP_PORT_ALL(unit), port_idx) {
   1277         rv = soc_reg32_get(unit, EGR_HISTO_DST_PORT_MAPr, port_idx, 0,
   1278                                          &reg_value);
   1279         SOC_IF_ERROR_RETURN(rv);
   1280         if (soc_reg_field_get(unit,EGR_HISTO_DST_PORT_MAPr,reg_value,
   1281                            pbmp_field))
   1282             BCM_PBMP_PORT_ADD(config->dest_pbmp, port_idx);
   1283     }
   1284 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1285     return BCM_E_NONE;
   1286 }
   1287 
   1288 /*
   1289  * Configures the LATENCY_LIMIT device table, which has 32 entries max
   1290  * and each entry is specified in terms of 64 nSec quanta.
   1291  */
   1292 int
   1293 bcm_tomahawk3_latency_monitor_latency_limit_table_set(
   1294     int unit,
   1295     uint8 table_size,
   1296     uint32 *latency_limit_table)
   1297 {
   1298 #ifdef BCM_TOMAHAWK3_SUPPORT
   1299     int i;
   1300     uint32  value;
   1301 
   1302     if (table_size > LATENCY_LIMIT_TABLE_SIZE)
   1303         return BCM_E_PARAM;
   1304 
   1305     if (latency_limit_table == NULL)
   1306         return BCM_E_PARAM;
   1307 
   1308     for (i=0; i<table_size; i++) {
   1309         if (latency_limit_table[i] < LATENCY_LIMIT_QUANTA)
   1310             value = 1;                  /* Min is 64 nS */
   1311         else
   1312             value = latency_limit_table[i]/LATENCY_LIMIT_QUANTA;
   1313 
   1314         BCM_IF_ERROR_RETURN
   1315             (soc_mem_field32_modify(unit, EGR_HISTO_LATENCY_LIMITm, i, LATENCY_LIMITf,
   1316                                     value));
   1317     }
   1318 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1319     return BCM_E_NONE;
   1320 }
   1321 
   1322 /*
   1323  * Output is the table size and configured values of LATENCY_LIMIT device
   1324  * table.
   1325  */
   1326 
   1327 int
   1328 bcm_tomahawk3_latency_monitor_latency_limit_table_get(
   1329     int unit,
   1330     uint8 table_size,
   1331     uint32 *latency_limit_table)
   1332 {
   1333 #ifdef BCM_TOMAHAWK3_SUPPORT
   1334     int i, rv;
   1335     uint32 value;
   1336 
   1337     if (table_size > LATENCY_LIMIT_TABLE_SIZE)
   1338         table_size = LATENCY_LIMIT_TABLE_SIZE;
   1339 
   1340     if (latency_limit_table == NULL)
   1341         return BCM_E_PARAM;
   1342 
   1343     for (i=0; i<table_size; i++) {
   1344         rv = soc_mem_read(unit, EGR_HISTO_LATENCY_LIMITm, MEM_BLOCK_ANY,
   1345                              i, &value);
   1346         if (SOC_FAILURE(rv)) {
   1347             return (rv);
   1348         }
   1349 
   1350         latency_limit_table[i] = soc_mem_field32_get(unit,
   1351                                                     EGR_HISTO_LATENCY_LIMITm,
   1352                                                     &value, LATENCY_LIMITf);
   1353         latency_limit_table[i] *= LATENCY_LIMIT_QUANTA;
   1354     }
   1355 #endif
   1356     return BCM_E_NONE;
   1357 }
   1358 
   1359 
   1360 /*
   1361  * Configure the bucket size and upper latency limit of each bucket, for a
   1362  * given cos queue and monitor id.
   1363  */
   1364 int
   1365 bcm_tomahawk3_latency_monitor_cosq_config_set(
   1366     int unit,
   1367     uint8 monitor_id,
   1368     uint8 cosq,
   1369     bcm_latency_monitor_cosq_info_t cosq_info)
   1370 {
   1371 #ifdef BCM_TOMAHAWK3_SUPPORT
   1372     int         i, j, index;
   1373     soc_mem_t   mem;
   1374     uint8   cosq_first;
   1375     uint8   cosq_last;
   1376 
   1377     if ((cosq >= LATENCY_MONITOR_QUEUE_COUNT) && ((int8)cosq != -1)) 
   1378         return BCM_E_PARAM;
   1379 
   1380     if (cosq_info.bucket_count > LATENCY_HISTOGRAM_BUCKET_COUNT)
   1381         return BCM_E_PARAM;
   1382 
   1383     switch (monitor_id) {
   1384     case MONITOR_ID_0:
   1385         mem = EGR_HISTO_MON_0_Q_LATENCY_LIMIT_SELm;
   1386         break;
   1387     case MONITOR_ID_1:
   1388         mem = EGR_HISTO_MON_1_Q_LATENCY_LIMIT_SELm;
   1389         break;
   1390     case MONITOR_ID_2:
   1391         mem = EGR_HISTO_MON_2_Q_LATENCY_LIMIT_SELm;
   1392         break;
   1393     case MONITOR_ID_3:
   1394         mem = EGR_HISTO_MON_3_Q_LATENCY_LIMIT_SELm;
   1395         break;
   1396     default:
   1397         return BCM_E_PARAM;
   1398     }
   1399 
   1400     cosq_first = cosq;
   1401     cosq_last  = cosq;
   1402     if ((int8)cosq == -1) {
   1403         cosq_first = 0;
   1404         cosq_last = (LATENCY_MONITOR_QUEUE_COUNT - 1);
   1405     }
   1406 
   1407     for (i=cosq_first; i<=cosq_last; i++) {
   1408         latency_monitor_mem[unit][monitor_id].cosq_info[i].bucket_count = cosq_info.bucket_count;
   1409         for (j=0; j<(cosq_info.bucket_count - 1); j++) {
   1410             if (cosq_info.latency_index_array[j] >= LATENCY_LIMIT_TABLE_SIZE)
   1411                 return BCM_E_PARAM;
   1412 
   1413             index = (i * (LATENCY_HISTOGRAM_BUCKET_COUNT - 1)) + j;
   1414             BCM_IF_ERROR_RETURN
   1415                 (soc_mem_field32_modify(unit, mem, index, Q_LATENCY_LIMIT_SELf,
   1416                                         cosq_info.latency_index_array[j]));
   1417 
   1418         }
   1419     }
   1420 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1421 
   1422     return BCM_E_NONE;
   1423 }
   1424 
   1425 /*
   1426  * Output is the bucket size and upper latency limit of each bucket for a
   1427  * given cos queue and monitor.
   1428  */
   1429 int
   1430 bcm_tomahawk3_latency_monitor_cosq_config_get(
   1431     int unit,
   1432     uint8 monitor_id,
   1433     uint8 cosq,
   1434     bcm_latency_monitor_cosq_info_t *cosq_info)
   1435 {
   1436 #ifdef BCM_TOMAHAWK3_SUPPORT
   1437     int         i, index, rv;
   1438     uint32      value;
   1439     soc_mem_t   mem;
   1440 
   1441     if (cosq_info == NULL)
   1442         return BCM_E_PARAM;
   1443 
   1444     if (cosq >= LATENCY_MONITOR_QUEUE_COUNT)
   1445         return BCM_E_PARAM;
   1446 
   1447     switch (monitor_id) {
   1448     case MONITOR_ID_0:
   1449         mem = EGR_HISTO_MON_0_Q_LATENCY_LIMIT_SELm;
   1450         break;
   1451     case MONITOR_ID_1:
   1452         mem = EGR_HISTO_MON_1_Q_LATENCY_LIMIT_SELm;
   1453         break;
   1454     case MONITOR_ID_2:
   1455         mem = EGR_HISTO_MON_2_Q_LATENCY_LIMIT_SELm;
   1456         break;
   1457     case MONITOR_ID_3:
   1458         mem = EGR_HISTO_MON_3_Q_LATENCY_LIMIT_SELm;
   1459         break;
   1460     default:
   1461         return BCM_E_PARAM;
   1462     }
   1463 
   1464     cosq_info->bucket_count = latency_monitor_mem[unit][monitor_id].cosq_info[cosq].bucket_count;
   1465 
   1466     for (i=0; i<(cosq_info->bucket_count - 1); i++) {
   1467         index = (cosq * (LATENCY_HISTOGRAM_BUCKET_COUNT - 1)) + i;
   1468 
   1469         rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, index, &value);
   1470         if (SOC_FAILURE(rv)) {
   1471             return (rv);
   1472         }
   1473 
   1474         cosq_info->latency_index_array[i] = soc_mem_field32_get(unit,
   1475                                                     mem, &value, Q_LATENCY_LIMIT_SELf);
   1476     }
   1477 
   1478 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1479 
   1480     return BCM_E_NONE;
   1481 }
   1482 
   1483 #ifdef BCM_TOMAHAWK3_SUPPORT
   1484 static int
   1485 _clear_debug_registers(int unit, uint8 monitor_id)
   1486 {
   1487     if (SOC_IS_TOMAHAWK3(unit)) {
   1488         switch (monitor_id) {
   1489         case MONITOR_ID_0:
   1490             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EGR_HISTO_MON_0_LAST_COUNTER_INDEXr, REG_PORT_ANY, 0, 0));
   1491             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EGR_HISTO_MON_0_HISTOGRAM_SETr, REG_PORT_ANY, 0, 0));
   1492             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EGR_HISTO_MON_0_FLEX_COUNTER_WRAP_COUNTERr, REG_PORT_ANY, 0, 0));
   1493             break;
   1494         case MONITOR_ID_1:
   1495             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EGR_HISTO_MON_1_LAST_COUNTER_INDEXr, REG_PORT_ANY, 0, 0));
   1496             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EGR_HISTO_MON_1_HISTOGRAM_SETr, REG_PORT_ANY, 0, 0));
   1497             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EGR_HISTO_MON_1_FLEX_COUNTER_WRAP_COUNTERr, REG_PORT_ANY, 0, 0));
   1498             break;
   1499         case MONITOR_ID_2:
   1500             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EGR_HISTO_MON_2_LAST_COUNTER_INDEXr, REG_PORT_ANY, 0, 0));
   1501             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EGR_HISTO_MON_2_HISTOGRAM_SETr, REG_PORT_ANY, 0, 0));
   1502             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EGR_HISTO_MON_2_FLEX_COUNTER_WRAP_COUNTERr, REG_PORT_ANY, 0, 0));
   1503             break;
   1504         case MONITOR_ID_3:
   1505             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EGR_HISTO_MON_3_LAST_COUNTER_INDEXr, REG_PORT_ANY, 0, 0));
   1506             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EGR_HISTO_MON_3_HISTOGRAM_SETr, REG_PORT_ANY, 0, 0));
   1507             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, EGR_HISTO_MON_3_FLEX_COUNTER_WRAP_COUNTERr, REG_PORT_ANY, 0, 0));
   1508             break;
   1509         default:
   1510             return BCM_E_PARAM;
   1511         }
   1512     }
   1513 
   1514     return BCM_E_NONE;
   1515 }
   1516 #endif
   1517 
   1518 /* Enable or Disable a given monitor */
   1519 int
   1520 bcm_tomahawk3_latency_monitor_enable(
   1521     int unit,
   1522     uint8 monitor_id,
   1523     uint8 enable)
   1524 {
   1525 #ifdef BCM_TOMAHAWK3_SUPPORT
   1526     soc_field_t         field_ids[1];
   1527     uint32              field_values[1];
   1528     soc_reg_t           mon_config_reg;
   1529     int                 rv = BCM_E_NONE;
   1530     uint32              hist_1us_enable;
   1531     uint32              rval;
   1532 
   1533     if (monitor_id > MONITOR_ID_3) {
   1534         return BCM_E_PARAM;
   1535     }
   1536 
   1537     if (!wb_post_init) {
   1538         /* If monitor is in cleanup/error state, return failure. */
   1539         if ((latency_monitor_mem[unit][monitor_id].status == LATENCY_MONITOR_STATE_CLEANUP) ||
   1540             (latency_monitor_mem[unit][monitor_id].status == LATENCY_MONITOR_STATE_ERROR)) {
   1541             return BCM_E_FAIL;
   1542         }
   1543 
   1544         /* If monitor is already enabled and running. */
   1545         if ((enable) &&(latency_monitor_mem[unit][monitor_id].status == LATENCY_MONITOR_STATE_RUNNING)) {
   1546             return BCM_E_NONE;
   1547         }
   1548 
   1549         /* If monitor is already disabled and idle. */
   1550         if ((!enable) && (latency_monitor_mem[unit][monitor_id].status == LATENCY_MONITOR_STATE_IDLE)) {
   1551             return BCM_E_NONE;
   1552         }
   1553     }
   1554 
   1555     if (enable)
   1556         latency_monitor_init(unit, monitor_id);
   1557 
   1558     switch (monitor_id) {
   1559     case MONITOR_ID_0:
   1560         mon_config_reg = EGR_HISTO_MON_0_CONFIGr;
   1561         break;
   1562     case MONITOR_ID_1:
   1563         mon_config_reg = EGR_HISTO_MON_1_CONFIGr;
   1564         break;
   1565     case MONITOR_ID_2:
   1566         mon_config_reg = EGR_HISTO_MON_2_CONFIGr;
   1567         break;
   1568     case MONITOR_ID_3:
   1569         mon_config_reg = EGR_HISTO_MON_3_CONFIGr;
   1570         break;
   1571     default:
   1572         return BCM_E_PARAM;
   1573     }
   1574 
   1575     field_ids[0] = MONITOR_ENf;
   1576     field_values[0] = enable;
   1577     BCM_IF_ERROR_RETURN
   1578         (soc_reg_fields32_modify(unit, mon_config_reg, REG_PORT_ANY, 1,
   1579                                  field_ids, field_values));
   1580 
   1581     if (enable) {
   1582         sal_memset(latency_monitor_mem[unit][monitor_id].histogram_packet64_counter, 0,
   1583                     sizeof(latency_monitor_mem[unit][monitor_id].histogram_packet64_counter));
   1584         sal_memset(latency_monitor_mem[unit][monitor_id].histogram_byte64_counter, 0,
   1585                     sizeof(latency_monitor_mem[unit][monitor_id].histogram_byte64_counter));
   1586 
   1587         if (latency_monitor_mem[unit][monitor_id].monitor_mode == bcmLatencyMonitorTimeSeriesMode) {
   1588             if (latency_monitor_mem[unit][monitor_id].sw_buf_addr) {
   1589                 sal_memset(latency_monitor_mem[unit][monitor_id].sw_buf_addr, 0,
   1590                         latency_monitor_mem[unit][monitor_id].sw_buf_size);
   1591             }
   1592             latency_monitor_mem[unit][monitor_id].sw_buf_wr_idx = 0;
   1593         }
   1594 
   1595         /* Clear below debug registers for the monitor */
   1596         SOC_IF_ERROR_RETURN(_clear_debug_registers(unit, monitor_id));
   1597 
   1598         latency_monitor_mem[unit][monitor_id].flex_ctr_wrap_ctr = 0;
   1599 
   1600         latency_monitor_mem[unit][monitor_id].status = LATENCY_MONITOR_STATE_RUNNING;
   1601 
   1602         SOC_IF_ERROR_RETURN(soc_reg32_get(unit, AUX_ARB_CONTROLr, REG_PORT_ANY, 0, &rval));
   1603         hist_1us_enable = soc_reg_field_get(unit, AUX_ARB_CONTROLr, rval, HIST_1US_ENABLEf);
   1604         if (!hist_1us_enable) {
   1605             soc_reg_field_set(unit, AUX_ARB_CONTROLr, &rval, HIST_1US_ENABLEf, 1);
   1606             SOC_IF_ERROR_RETURN(soc_reg32_set(unit, AUX_ARB_CONTROLr, REG_PORT_ANY, 0, rval));
   1607         }
   1608 
   1609         rv = latency_monitor_read(unit, monitor_id);
   1610         if (rv == BCM_E_NONE)
   1611             latency_monitor_driver_data.run[monitor_id] = TRUE;
   1612         else
   1613             return rv;
   1614     } else {
   1615         latency_monitor_mem[unit][monitor_id].pipe_map_temp = 0;
   1616         latency_monitor_driver_data.run[monitor_id] = FALSE;
   1617         /* Signal the sbusdma_read thread for termination */
   1618         sal_sem_give(latency_monitor_mem[unit][monitor_id].latency_monitor_thread_trigger);
   1619         /* Signal the counter_accrue_thread for termination */
   1620         sal_sem_give(latency_monitor_mem[unit][monitor_id].dma_handle_counter_sem);
   1621     }
   1622 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1623 
   1624     return BCM_E_NONE;
   1625 }
   1626 
   1627 /*
   1628  * Returns the accrued histogram counter values for a given monitor ID
   1629  * and cosq (Valid in Accrue mode only)
   1630  */
   1631 int
   1632 bcm_tomahawk3_latency_monitor_histogram_get(
   1633     int unit,
   1634     uint8 monitor_id,
   1635     uint8 cosq,
   1636     uint8 byte_counter_flag,
   1637     bcm_latency_monitor_histogram_t *histogram)
   1638 {
   1639 #ifdef BCM_TOMAHAWK3_SUPPORT
   1640     int         i;
   1641     uint64      (*arr_pkt_cnt)[LATENCY_MONITOR_BUCKET_COUNT];
   1642     uint64      (*arr_byte_cnt)[LATENCY_MONITOR_BUCKET_COUNT];
   1643 
   1644     if (histogram == NULL)
   1645         return BCM_E_PARAM;
   1646 
   1647     if (monitor_id >= LATENCY_MONITOR_MAX_COUNT)
   1648         return BCM_E_PARAM;
   1649 
   1650     if (latency_monitor_mem[unit][monitor_id].monitor_mode != bcmLatencyMonitorAccrueMode)
   1651         return BCM_E_UNAVAIL;
   1652 
   1653     if (cosq >= LATENCY_MONITOR_QUEUE_COUNT)
   1654         return BCM_E_PARAM;
   1655 
   1656     if (histogram->histogram_size > LATENCY_MONITOR_BUCKET_COUNT)
   1657         histogram->histogram_size = LATENCY_MONITOR_BUCKET_COUNT;
   1658 
   1659     arr_pkt_cnt = (uint64 (*)[LATENCY_MONITOR_BUCKET_COUNT])latency_monitor_mem[unit][monitor_id].histogram_packet64_counter;
   1660     arr_byte_cnt = (uint64 (*)[LATENCY_MONITOR_BUCKET_COUNT])latency_monitor_mem[unit][monitor_id].histogram_byte64_counter;
   1661 
   1662     for (i=0; i<histogram->histogram_size; i++) {
   1663         if (byte_counter_flag)
   1664             histogram->histogram[i] = arr_byte_cnt[cosq][i];
   1665         else
   1666             histogram->histogram[i] = arr_pkt_cnt[cosq][i];
   1667     }
   1668 #endif
   1669 
   1670     return BCM_E_NONE;
   1671 }
   1672 
   1673 int
   1674 bcm_tomahawk3_latency_monitor_info_get(
   1675     int unit,
   1676     uint8 monitor_id,
   1677     bcm_latency_monitor_info_t *monitor_info)
   1678 {
   1679 #ifdef BCM_TOMAHAWK3_SUPPORT
   1680     if (monitor_info == NULL)
   1681         return BCM_E_PARAM;
   1682 
   1683     if (monitor_id >= LATENCY_MONITOR_MAX_COUNT)
   1684         return BCM_E_PARAM;
   1685 
   1686     switch (latency_monitor_mem[unit][monitor_id].status) {
   1687     case LATENCY_MONITOR_STATE_RUNNING:
   1688         monitor_info->monitor_status = bcmLatencyMonitorStatusRunning;
   1689         break;
   1690     case LATENCY_MONITOR_STATE_IDLE:
   1691         monitor_info->monitor_status = bcmLatencyMonitorStatusIdle;
   1692         break;
   1693     case LATENCY_MONITOR_STATE_ERROR:
   1694         monitor_info->monitor_status = bcmLatencyMonitorStatusError;
   1695         break;
   1696     default:
   1697         monitor_info->monitor_status = bcmLatencyMonitorStatusUninit;
   1698         break;
   1699     }
   1700 
   1701     monitor_info->sw_buf_addr = latency_monitor_mem[unit][monitor_id].sw_buf_addr;
   1702     monitor_info->sw_buf_size = latency_monitor_mem[unit][monitor_id].sw_buf_size;
   1703     monitor_info->sw_buf_wr_idx = (latency_monitor_mem[unit][monitor_id].sw_buf_wr_idx - 1); 
   1704 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1705 
   1706     return BCM_E_NONE;
   1707 }
   1708 
   1709 /* Release all the resource allocated for a given monitor. */
   1710 int
   1711 bcm_tomahawk3_latency_monitor_destroy(
   1712     int unit,
   1713     uint8 monitor_id)
   1714 {
   1715 #ifdef BCM_TOMAHAWK3_SUPPORT
   1716     bcm_latency_monitor_config_t        monitor_cfg;
   1717     bcm_latency_monitor_cosq_info_t     cosq_cfg;
   1718 
   1719     if (monitor_id >= LATENCY_MONITOR_MAX_COUNT)
   1720         return BCM_E_PARAM;
   1721 
   1722     if (latency_monitor_mem[unit][monitor_id].status == LATENCY_MONITOR_STATE_RUNNING)
   1723         return BCM_E_BUSY;
   1724 
   1725     _bcm_esw_stat_group_destroy(unit, latency_monitor_mem[unit][monitor_id].stat_counter_id);
   1726     latency_monitor_mem[unit][monitor_id].stat_counter_id = 0;
   1727 
   1728     latency_monitor_mem[unit][monitor_id].status = LATENCY_MONITOR_STATE_CLEANUP;
   1729     bcm_latency_monitor_config_t_init(&monitor_cfg);
   1730     SOC_PBMP_ASSIGN(monitor_cfg.src_pbmp, SOC_LATENCY_MONITOR_INFO(unit, monitor_id).src_pbmp);
   1731     SOC_PBMP_ASSIGN(monitor_cfg.dest_pbmp, SOC_LATENCY_MONITOR_INFO(unit, monitor_id).dest_pbmp);
   1732     BCM_IF_ERROR_RETURN(bcm_tomahawk3_latency_monitor_config_set(unit, monitor_id, &monitor_cfg));
   1733     bcm_latency_monitor_cosq_info_t_init(&cosq_cfg);
   1734     BCM_IF_ERROR_RETURN(bcm_tomahawk3_latency_monitor_cosq_config_set(unit, monitor_id, -1, cosq_cfg));
   1735 
   1736     latency_monitor_mem[unit][monitor_id].status = 0;
   1737     latency_monitor_mem[unit][monitor_id].init_done = FALSE;
   1738 
   1739     SOC_LATENCY_MONITOR_INFO(unit, monitor_id).time_step = -1;
   1740     SOC_LATENCY_MONITOR_INFO(unit, monitor_id).flex_pool_number = -1;
   1741     BCM_PBMP_CLEAR(SOC_LATENCY_MONITOR_INFO(unit, monitor_id).src_pbmp);
   1742     BCM_PBMP_CLEAR(SOC_LATENCY_MONITOR_INFO(unit, monitor_id).dest_pbmp);
   1743 
   1744     sal_memset(latency_monitor_mem[unit][monitor_id].histogram_packet64_counter, 0,
   1745                 sizeof(latency_monitor_mem[unit][monitor_id].histogram_packet64_counter));
   1746     sal_memset(latency_monitor_mem[unit][monitor_id].histogram_byte64_counter, 0,
   1747                 sizeof(latency_monitor_mem[unit][monitor_id].histogram_byte64_counter));
   1748 
   1749     if (latency_monitor_mem[unit][monitor_id].monitor_mode == bcmLatencyMonitorTimeSeriesMode) {
   1750         if (latency_monitor_mem[unit][monitor_id].sw_buf_addr) {
   1751             sal_free(latency_monitor_mem[unit][monitor_id].sw_buf_addr);
   1752             latency_monitor_mem[unit][monitor_id].sw_buf_addr = NULL;
   1753         }
   1754     }
   1755 
   1756 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1757 
   1758     return BCM_E_NONE;
   1759 }
   1760 
   1761 int
   1762 bcm_tomahawk3_latency_monitor_detach (int unit)
   1763 {
   1764 #ifdef BCM_TOMAHAWK3_SUPPORT
   1765     int monitor_id;
   1766 
   1767     if (soc_feature(unit, soc_feature_latency_monitor)) {
   1768         for (monitor_id = 0; monitor_id < LATENCY_MONITOR_MAX_COUNT; monitor_id++) {
   1769             if (latency_monitor_mem[unit][monitor_id].status ==
   1770                         LATENCY_MONITOR_STATE_RUNNING) {
   1771                 latency_monitor_driver_data.run[monitor_id] = FALSE;
   1772                 bcm_tomahawk3_latency_monitor_enable(unit, monitor_id, 0);
   1773                 while (latency_monitor_mem[unit][monitor_id].status ==
   1774                                              LATENCY_MONITOR_STATE_RUNNING) {
   1775                     sal_usleep(5);
   1776                 }
   1777             }
   1778             bcm_tomahawk3_latency_monitor_destroy(unit, monitor_id);
   1779         }
   1780  
   1781         latency_monitor_driver_data.init_done = 0;
   1782     }
   1783 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1784 
   1785     return BCM_E_NONE;
   1786 }
   1787 
   1788 int
   1789 bcm_tomahawk3_latency_monitor_init (int unit)
   1790 {
   1791 #ifdef BCM_TOMAHAWK3_SUPPORT
   1792     int monitor_id;
   1793     int rv;
   1794 
   1795     if (soc_feature(unit, soc_feature_latency_monitor)) {
   1796         for (monitor_id = 0; monitor_id < LATENCY_MONITOR_MAX_COUNT; monitor_id++) {
   1797             if (latency_monitor_mem[unit][monitor_id].status ==
   1798                         LATENCY_MONITOR_STATE_RUNNING) {
   1799                 latency_monitor_driver_data.run[monitor_id] = FALSE;
   1800                 rv = bcm_tomahawk3_latency_monitor_enable(unit, monitor_id, 0);
   1801                 BCM_IF_ERROR_RETURN(rv);
   1802             }
   1803             rv = bcm_tomahawk3_latency_monitor_destroy(unit, monitor_id);
   1804             BCM_IF_ERROR_RETURN(rv);
   1805         }
   1806 
   1807         if (!latency_monitor_driver_data.init_done)
   1808             latency_monitor_driver_data_init(unit);
   1809 
   1810 #ifdef BCM_WARM_BOOT_SUPPORT
   1811         if (SOC_WARM_BOOT(unit)) {
   1812             rv = _bcm_th3_latency_monitor_wb_recover(unit);
   1813         } else {
   1814             rv = _bcm_th3_latency_monitor_scache_alloc(unit, 1);
   1815         }
   1816 
   1817         if (rv == BCM_E_NOT_FOUND) {
   1818             /* Continue with initialization if scache not found */
   1819             rv = BCM_E_NONE;
   1820         }
   1821 
   1822         if (BCM_FAILURE(rv)) {
   1823             return (rv);
   1824         }
   1825 #endif /* BCM_WARM_BOOT_SUPPORT */
   1826     }
   1827 #endif /* BCM_TOMAHAWK3_SUPPORT */
   1828 
   1829     return BCM_E_NONE;
   1830 }
   1831 
   1832 #ifdef BCM_WARM_BOOT_SUPPORT
   1833 #ifdef BCM_TOMAHAWK3_SUPPORT
   1834 
   1835 #define BCM_WB_LATENCY_MONITOR_VERSION_1_0      SOC_SCACHE_VERSION(1,0)
   1836 #define BCM_WB_LATENCY_MONITOR_DEFAULT_VERSION  BCM_WB_LATENCY_MONITOR_VERSION_1_0
   1837 
   1838 #define LATENCY_MONITOR_SCACHE_WRITE(_scache, _val, _type)                     \
   1839     do {                                                          \
   1840         _type _tmp = (_type) (_val);                              \
   1841         sal_memcpy((_scache), &(_tmp), sizeof(_type));            \
   1842         (_scache) += sizeof(_type);                               \
   1843     } while(0)
   1844 
   1845 #define LATENCY_MONITOR_SCACHE_READ(_scache, _var, _type)                      \
   1846     do {                                                          \
   1847         _type _tmp;                                               \
   1848         sal_memcpy(&(_tmp), (_scache), sizeof(_type));            \
   1849         (_scache) += sizeof(_type);                               \
   1850         (_var)     = (_tmp);                                      \
   1851     } while(0)
   1852 
   1853 /*
   1854  * Function:
   1855  *     _bcm_th3_latency_monitor_scache_v0_global_size_get
   1856  * Purpose:
   1857  *     Get the size required to sync Latency Monitor global data to scache v0
   1858  * Parameters:
   1859  *     unit   - (IN) Device unit number
   1860  * Returns:
   1861  *     Required size
   1862  */
   1863 STATIC uint32
   1864 _bcm_th3_latency_monitor_scache_v0_global_size_get(int unit)
   1865 {
   1866     uint32 size = 0;
   1867 
   1868     /* Reserved bits */
   1869     size += sizeof(uint32);
   1870 
   1871     /* Monitor status */
   1872     size += sizeof(uint8) * LATENCY_MONITOR_MAX_COUNT;
   1873 
   1874     /*Monitor Mode */
   1875     size += sizeof(uint8) * LATENCY_MONITOR_MAX_COUNT;
   1876 
   1877     /* SW Ring Buffer size (Timeseries mode only) */
   1878     size += sizeof(uint32) * LATENCY_MONITOR_MAX_COUNT;
   1879 
   1880     /* Store configured bucket count for each Queue */
   1881     size += sizeof(uint8) * LATENCY_MONITOR_QUEUE_COUNT * LATENCY_MONITOR_MAX_COUNT;
   1882 
   1883     return size;
   1884 }
   1885 
   1886 
   1887 /*
   1888  * Function:
   1889  *     _bcm_th3_latency_monitor_scache_v0_size_get
   1890  * Purpose:
   1891  *     Get Latency monitor scache v0 size
   1892  * Parameters:
   1893  *     unit   - (IN) Device unit number
   1894  * Returns:
   1895  *     Size required
   1896  */
   1897 STATIC uint32
   1898 _bcm_th3_latency_monitor_scache_v0_size_get(int unit)
   1899 {
   1900     uint32 size = 0;
   1901 
   1902     /* Get global data size */
   1903     size += _bcm_th3_latency_monitor_scache_v0_global_size_get(unit);
   1904 
   1905     return size;
   1906 }
   1907 
   1908 int
   1909 _bcm_th3_latency_monitor_wb_post_init(int unit)
   1910 {
   1911     int i=0;
   1912     bcm_latency_monitor_config_t cfg;
   1913     int monitor_status;
   1914  
   1915     wb_post_init = 1;   
   1916     for (i=0; i<LATENCY_MONITOR_MAX_COUNT; i++) {
   1917         if (latency_monitor_mem[unit][i].status) {
   1918             monitor_status = latency_monitor_mem[unit][i].status;
   1919             bcm_tomahawk3_latency_monitor_config_get(unit, i, &cfg);
   1920             bcm_tomahawk3_latency_monitor_config_set(unit, i, &cfg);
   1921             if (monitor_status == LATENCY_MONITOR_STATE_RUNNING) {
   1922                 bcm_tomahawk3_latency_monitor_enable(unit, i, 1);
   1923             }
   1924         }
   1925     }
   1926     wb_post_init = 0;
   1927     return BCM_E_NONE;
   1928 }
   1929 
   1930 /*
   1931  * Function:
   1932  *     _bcm_th3_latency_monitor_scache_v0_global_recover
   1933  * Purpose:
   1934  *     Recover Latency monitor global data from scache v0
   1935  * Parameters:
   1936  *     unit   - (IN) Device unit number
   1937  *     scache - (IN) Pointer to current scache location
   1938  * Returns:
   1939  *     BCM_E_XXX
   1940  */
   1941 STATIC int
   1942 _bcm_th3_latency_monitor_scache_v0_global_recover(int unit, uint8 **scache)
   1943 {
   1944     int i=0;
   1945     int j=0;
   1946 
   1947     /* Reserved bits */
   1948     *scache += sizeof(uint32);
   1949 
   1950     /* Restore Monitor state info */
   1951     for (i=0; i<LATENCY_MONITOR_MAX_COUNT; i++) {
   1952         LATENCY_MONITOR_SCACHE_READ(*scache, latency_monitor_mem[unit][i].status, uint8);
   1953     }
   1954     
   1955     /* Restore Monitor Mode */
   1956     for (i=0; i<LATENCY_MONITOR_MAX_COUNT; i++) {
   1957         LATENCY_MONITOR_SCACHE_READ(*scache, latency_monitor_mem[unit][i].monitor_mode, uint8);
   1958     }
   1959 
   1960     /* Restore Histogram set count in SW Ring buffer used for Timeseries mode */
   1961     for (i=0; i<LATENCY_MONITOR_MAX_COUNT; i++) {
   1962         LATENCY_MONITOR_SCACHE_READ(*scache, latency_monitor_mem[unit][i].sw_buf_size, uint32);
   1963     }
   1964 
   1965     /* Restore bucket count for each queues */
   1966     for (i=0; i<LATENCY_MONITOR_MAX_COUNT; i++) {
   1967         for (j=0; j<LATENCY_MONITOR_QUEUE_COUNT; j++) {
   1968             LATENCY_MONITOR_SCACHE_READ(*scache,
   1969                      latency_monitor_mem[unit][i].cosq_info[j].bucket_count, uint8);
   1970         }
   1971     }
   1972 
   1973     return BCM_E_NONE;
   1974 }
   1975 
   1976 
   1977 /*
   1978  * Function:
   1979  *     _bcm_th3_latency_monitor_scache_v0_recover
   1980  * Purpose:
   1981  *     Recover Latency Monitor scache v0 data
   1982  * Parameters:
   1983  *     unit   - (IN) Device unit number
   1984  *     scache - (IN) Pointer to current scache location
   1985  * Returns:
   1986  *     BCM_E_XXX
   1987  */
   1988 STATIC int
   1989 _bcm_th3_latency_monitor_scache_v0_recover(int unit, uint8 **scache)
   1990 {
   1991     /* Recover global data */
   1992     BCM_IF_ERROR_RETURN(_bcm_th3_latency_monitor_scache_v0_global_recover(unit, scache));
   1993 
   1994     return BCM_E_NONE;
   1995 }
   1996 
   1997 /*
   1998  * Function:
   1999  *      _bcm_th3_latency_monitor_scache_alloc
   2000  * Purpose:
   2001  *      Latency Monitor WB scache alloc
   2002  * Parameters:
   2003  *      unit    - (IN) Unit number.
   2004  *      create  - (IN) 1 - Create, 0 - Realloc
   2005  * Returns:
   2006  *      BCM_E_XXX
   2007  * Notes:
   2008  */
   2009 STATIC int _bcm_th3_latency_monitor_scache_alloc(int unit, int create)
   2010 {
   2011     uint32                  cur_size = 0;
   2012     uint32                  rqd_size = 0;
   2013     int                     rv = BCM_E_NONE;
   2014     soc_scache_handle_t     scache_handle;
   2015     uint8                  *scache = NULL;
   2016 
   2017     rqd_size += _bcm_th3_latency_monitor_scache_v0_size_get(unit);
   2018 
   2019     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_LATENCY_MONITOR, 0);
   2020 
   2021     if (create) {
   2022         rv = _bcm_esw_scache_ptr_get(unit, scache_handle, 1, rqd_size,
   2023                                      &scache, BCM_WB_LATENCY_MONITOR_DEFAULT_VERSION, NULL);
   2024         BCM_IF_ERROR_RETURN(rv);
   2025     } else {
   2026         /* Get current size */
   2027         rv = soc_scache_ptr_get(unit, scache_handle, &scache, &cur_size);
   2028         SOC_IF_ERROR_RETURN(rv);
   2029 
   2030         if (rqd_size > cur_size) {
   2031             /* Request the extra size */
   2032             rv = soc_scache_realloc(unit, scache_handle, rqd_size - cur_size);
   2033             SOC_IF_ERROR_RETURN(rv);
   2034         }
   2035     }
   2036 
   2037     return BCM_E_NONE;
   2038 }
   2039 
   2040 /*
   2041  * Function:
   2042  *      _BCM_th3_latency_monitor_wb_recover
   2043  * Purpose:
   2044  *      Latency Monitor WB recovery
   2045  * Parameters:
   2046  *      unit - (IN) Unit number.
   2047  * Returns:
   2048  *      BCM_E_XXX
   2049  * Notes:
   2050  */
   2051 STATIC int _bcm_th3_latency_monitor_wb_recover(int unit)
   2052 {
   2053     int                 stable_size;       /* Secondary storage size.   */
   2054     uint8               *scache = NULL;
   2055     soc_scache_handle_t scache_handle;
   2056     int                 rv = BCM_E_NONE;
   2057     uint16              recovered_ver = 0;
   2058 
   2059     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   2060 
   2061     if (!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit) && (stable_size > 0)) {
   2062         SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_LATENCY_MONITOR, 0);
   2063 
   2064         rv = _bcm_esw_scache_ptr_get(unit, scache_handle, 0, 0,
   2065                                      &scache, BCM_WB_LATENCY_MONITOR_DEFAULT_VERSION,
   2066                                      &recovered_ver);
   2067         if (BCM_E_NOT_FOUND == rv) {
   2068             /* Upgrading from SDK release that does not have warmboot state */
   2069             rv = _bcm_th3_latency_monitor_scache_alloc(unit, 1);
   2070             return rv;
   2071         } else if (BCM_FAILURE(rv)) {
   2072             return rv;
   2073         }
   2074 
   2075         if (NULL == scache) {
   2076             return BCM_E_NOT_FOUND;
   2077         }
   2078     } else {
   2079         return BCM_E_NONE;
   2080     }
   2081 
   2082     /* Scache recovery */
   2083     BCM_IF_ERROR_RETURN(_bcm_th3_latency_monitor_scache_v0_recover(unit, &scache));
   2084 
   2085     /* Realloc any extra scache that may be needed */
   2086     BCM_IF_ERROR_RETURN(_bcm_th3_latency_monitor_scache_alloc(unit, 0));
   2087 
   2088     return rv;
   2089 }
   2090 
   2091 /*
   2092  * Function:
   2093  *     _bcm_th3_latency_monitor_scache_v0_global_sync
   2094  * Purpose:
   2095  *     Sync Latency Monitor global data to scache v0
   2096  * Parameters:
   2097  *     unit   - (IN) Device unit number
   2098  *     scache - (IN) Pointer to current scache location
   2099  * Returns:
   2100  *     BCM_E_XXX
   2101  */
   2102 STATIC void
   2103 _bcm_th3_latency_monitor_scache_v0_global_sync(int unit, uint8 **scache)
   2104 {
   2105     int i;
   2106     int j;
   2107     uint8 tmp = 0;
   2108 
   2109     /* Reserve first 32 bits */
   2110     LATENCY_MONITOR_SCACHE_WRITE(*scache, 0, uint32);
   2111 
   2112     /* Store Monitor state info */
   2113     for (i=0; i<LATENCY_MONITOR_MAX_COUNT; i++) {
   2114         LATENCY_MONITOR_SCACHE_WRITE(*scache, latency_monitor_mem[unit][i].status, uint8);
   2115     }
   2116 
   2117     /* Store Monitor Mode */
   2118     for (i=0; i<LATENCY_MONITOR_MAX_COUNT; i++) {
   2119         if (latency_monitor_mem[unit][i].monitor_mode == bcmLatencyMonitorTimeSeriesMode) {
   2120             tmp = 1;
   2121         } else {
   2122             tmp = 0;
   2123         }
   2124         LATENCY_MONITOR_SCACHE_WRITE(*scache, tmp, uint8);
   2125     }
   2126 
   2127     /* Store SW ring buffer size (used in Timeseries mode */
   2128     for (i=0; i<LATENCY_MONITOR_MAX_COUNT; i++) {
   2129         LATENCY_MONITOR_SCACHE_WRITE(*scache, latency_monitor_mem[unit][i].sw_buf_size, uint32);
   2130     }
   2131 
   2132     /* Store bucket count for each queues */
   2133     for (i=0; i<LATENCY_MONITOR_MAX_COUNT; i++) {
   2134         for (j=0; j<LATENCY_MONITOR_QUEUE_COUNT; j++) {
   2135             LATENCY_MONITOR_SCACHE_WRITE(*scache, 
   2136                      latency_monitor_mem[unit][i].cosq_info[j].bucket_count, uint8);
   2137         }
   2138     }
   2139 
   2140 
   2141 }
   2142 
   2143 /*
   2144  * Function:
   2145  *     _bcm_th3_latency_monitor_scache_v0_sync
   2146  * Purpose:
   2147  *     Sync Latency Monitor scache v0
   2148  * Parameters:
   2149  *     unit   - (IN) Device unit number
   2150  *     scache - (IN) Pointer to current scache location
   2151  * Returns:
   2152  *     None
   2153  */
   2154 STATIC void
   2155 _bcm_th3_latency_monitor_scache_v0_sync(int unit, uint8 **scache)
   2156 {
   2157     /* Sync global data */
   2158     _bcm_th3_latency_monitor_scache_v0_global_sync(unit, scache);
   2159 }
   2160 
   2161 /*
   2162  * Function:
   2163  *      _bcm_th3_latency_monitor_sync
   2164  * Purpose:
   2165  *      Warmboot scache sync
   2166  * Parameters:
   2167  *      unit - (IN) Unit number.
   2168  * Returns:
   2169  *      BCM_E_XXX
   2170  * Notes:
   2171  */
   2172 int _bcm_th3_latency_monitor_sync(int unit)
   2173 {
   2174     int                     stable_size;
   2175     soc_scache_handle_t     scache_handle;
   2176     uint8                  *scache = NULL;
   2177 
   2178     /* Get FT module storage size. */
   2179     SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size));
   2180 
   2181     /* If level 2 store is not configured return from here. */
   2182     if (SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit) || (stable_size == 0)) {
   2183         return BCM_E_NONE;
   2184     }
   2185 
   2186     SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_LATENCY_MONITOR, 0);
   2187     BCM_IF_ERROR_RETURN(_bcm_esw_scache_ptr_get(unit, scache_handle, 0, 0,
   2188                                                 &scache, 0, NULL));
   2189     if (NULL == scache) {
   2190         return BCM_E_INTERNAL;
   2191     }
   2192 
   2193     /* Sync FT scache v0 */
   2194     _bcm_th3_latency_monitor_scache_v0_sync(unit, &scache);
   2195 
   2196     return BCM_E_NONE;
   2197 }
   2198 
   2199 #endif /* BCM_TOMAHAWK3_SUPPORT */
   2200 #endif /* BCM_WARM_BOOT_SUPPORT */
   2201