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

counter.c (61968B)


      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  * Counter CLI support
      8  */
      9 
     10 #include <appl/diag/system.h>
     11 #include <appl/diag/dport.h>
     12 #include <shared/bsl.h>
     13 #include <bcm/stat.h>
     14 #include <bcm/error.h>
     15 #include <soc/mem.h>
     16 
     17 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
     18 #include <bcm_int/esw/trident2.h>
     19 #endif
     20 
     21 
     22 #define SOC_CNAME_MAX       20
     23 
     24 /*
     25  * Data structure for saving the previous value of counters so we can
     26  * tell which counters that have changed since last shown.
     27  */
     28 
     29 STATIC uint64 *counter_val[SOC_MAX_NUM_DEVICES];
     30 static int prev_counter_interval[SOC_MAX_NUM_DEVICES];
     31 
     32 STATIC void
     33 counter_val_set(int unit, soc_port_t port, soc_reg_t ctr_reg,
     34                 int ar_idx, uint64 val)
     35 {
     36     static int          n;
     37     int                 ind = 0;
     38     soc_counter_non_dma_t *non_dma;
     39 
     40     if (counter_val[unit] == NULL) {
     41         n = SOC_CONTROL(unit)->counter_n32 + SOC_CONTROL(unit)->counter_n64 +
     42             SOC_CONTROL(unit)->counter_n64_non_dma;
     43         counter_val[unit] = sal_alloc(n * sizeof (uint64), "save_ctrs");
     44         if (counter_val[unit] == NULL) {
     45             return;
     46         }
     47         sal_memset(counter_val[unit], 0, n * sizeof (uint64));
     48     }
     49 
     50     if (port != SOC_PORT_INVALID) {
     51         if (ctr_reg >= SOC_COUNTER_NON_DMA_START &&
     52             ctr_reg < SOC_COUNTER_NON_DMA_END) {
     53             if (ar_idx < 0) {
     54                 if (SOC_CONTROL(unit)->counter_non_dma == NULL) {
     55                     return;
     56                 }
     57                 non_dma = &SOC_CONTROL(unit)->
     58                 counter_non_dma[ctr_reg - SOC_COUNTER_NON_DMA_START];
     59                 for (ar_idx = 0; ar_idx < non_dma->entries_per_port; ar_idx++) {
     60                     counter_val_set(unit, port, ctr_reg, ar_idx, val);
     61                 }
     62                 return;
     63             }
     64         }
     65         ind = soc_counter_idx_get(unit, ctr_reg, ar_idx, port);
     66     }
     67 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
     68     /*when port is invalid, rely on ar_idx to get ind*/
     69     else if (SOC_IS_TRIDENT2PLUS(unit) &&
     70              (ctr_reg >= SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT_UC &&
     71               ctr_reg <= SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE_UC)) {
     72         ind = soc_counter_idx_get(unit, ctr_reg, -1, SOC_PORT_MIN(unit, all));
     73         ind += ar_idx;
     74     }
     75 #endif
     76     if (ctr_reg >= SOC_COUNTER_TABLE_FIELD_END) {
     77         LOG_INFO(BSL_LS_APPL_COUNTER,
     78                  (BSL_META_U(unit,
     79                              "cval_set: Illegal counter index -- "
     80                              "ar_idx=%d p=%d idx=%d vh=%d vl=%d\n"),
     81                   ar_idx, port, ind,
     82                   COMPILER_64_HI(val),
     83                   COMPILER_64_LO(val)));
     84     } else if (SOC_REG_IS_COUNTER_TABLE(unit, ctr_reg)) {
     85         LOG_INFO(BSL_LS_APPL_COUNTER,
     86                  (BSL_META_U(unit,
     87                              "cval_set: %s ar_idx=%d p=%d idx=%d vh=%d vl=%d\n"),
     88                   SOC_FIELD_NAME(unit, ctr_reg - SOC_COUNTER_TABLE_FIELD_START),
     89                   ar_idx, port, ind,
     90                   COMPILER_64_HI(val),
     91                   COMPILER_64_LO(val)));
     92     } else if (ctr_reg >= SOC_COUNTER_NON_DMA_START &&
     93                ctr_reg < SOC_COUNTER_NON_DMA_END) {
     94         non_dma =
     95             &SOC_CONTROL(unit)->counter_non_dma[ctr_reg -
     96                                                 SOC_COUNTER_NON_DMA_START];
     97         LOG_INFO(BSL_LS_APPL_COUNTER,
     98                  (BSL_META_U(unit,
     99                              "cval_set: %s ar_idx=%d p=%d idx=%d vh=%d vl=%d\n"),
    100                   non_dma->cname,
    101                   ar_idx, port, ind,
    102                   COMPILER_64_HI(val),
    103                   COMPILER_64_LO(val)));
    104     } else if (ctr_reg >= NUM_SOC_REG) {
    105         return;
    106     } else {
    107         LOG_INFO(BSL_LS_APPL_COUNTER,
    108                  (BSL_META_U(unit,
    109                              "cval_set: %s ar_idx=%d p=%d idx=%d vh=%d vl=%d\n"),
    110                   SOC_REG_NAME(unit, ctr_reg),
    111                   ar_idx, port, ind,
    112                   COMPILER_64_HI(val),
    113                   COMPILER_64_LO(val)));
    114     }
    115 
    116     /* Unsupported non-DMA counters will return out-of-range index (-1) */
    117     if (ind >= 0 && ind < n) {
    118         counter_val[unit][ind] = val;
    119     }
    120 }
    121 
    122 void
    123 counter_val_set_by_port(int unit, soc_pbmp_t pbmp, uint64 val)
    124 {
    125     int			i;
    126     soc_port_t		port, dport;
    127     soc_reg_t		ctr_reg;
    128     soc_cmap_t          *cmap;
    129 
    130     /* coverity[overrun-local] */
    131     DPORT_SOC_PBMP_ITER(unit, pbmp, dport, port) {
    132         /* Non-DMA counters */ 
    133         for (i = SOC_COUNTER_NON_DMA_START; i < SOC_COUNTER_NON_DMA_END; i++) {
    134             /* coverity[overrun-call] */
    135             counter_val_set(unit, port, i, -1, val);
    136         }
    137         /* DMA counters */
    138         cmap = soc_port_cmap_get(unit, port);
    139 	if (cmap == NULL) {
    140 	    continue;
    141 	}
    142         for (i = 0; i < cmap->cmap_size; i++) {
    143             ctr_reg = cmap->cmap_base[i].reg;
    144             if (ctr_reg != INVALIDr) {
    145                 counter_val_set(unit, port, ctr_reg, -1, val);
    146             }
    147         }
    148     }
    149 }
    150 
    151 STATIC void
    152 counter_val_get(int unit, soc_port_t port, soc_reg_t ctr_reg,
    153                 int ar_idx, uint64 *val)
    154 {
    155     int			ind = 0;
    156     soc_counter_non_dma_t *non_dma;
    157 
    158     if (counter_val[unit] == NULL) {
    159 	COMPILER_64_SET(*val, 0, 0);
    160     } else {
    161        if (port != SOC_PORT_INVALID) {
    162             ind = soc_counter_idx_get(unit, ctr_reg, ar_idx, port);
    163         }
    164 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    165        /*when port is invalid, rely on ar_idx to get ind*/
    166        else if (SOC_IS_TRIDENT2PLUS(unit) &&
    167                 (ctr_reg >= SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT_UC &&
    168                  ctr_reg <= SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE_UC)) {
    169            ind = soc_counter_idx_get(unit, ctr_reg, -1, SOC_PORT_MIN(unit, all));
    170            ind += ar_idx;
    171        }
    172 #endif
    173 #if defined(BCM_TOMAHAWK3_SUPPORT)
    174        /*when port is invalid, rely on ar_idx to get ind*/
    175        else if (SOC_IS_TOMAHAWK3(unit) &&
    176                 (ctr_reg >= SOC_COUNTER_NON_DMA_PRIQ_DROP_PKT &&
    177                  ctr_reg <= SOC_COUNTER_NON_DMA_HDRM_POOL_DROP_PKT)) {
    178            ind = soc_counter_idx_get(unit, ctr_reg, -1, SOC_PORT_MIN(unit, all));
    179            ind += ar_idx;
    180        }
    181 #endif
    182 
    183         *val = counter_val[unit][ind];
    184 
    185         if (ctr_reg >= SOC_COUNTER_NON_DMA_END) {
    186             LOG_INFO(BSL_LS_APPL_COUNTER,
    187                      (BSL_META_U(unit,
    188                                  "cval_get: Illegal counter index -- "
    189                                  "ar_idx=%d p=%d idx=%d vh=%d vl=%d\n"),
    190                       ar_idx, port, ind,
    191                       COMPILER_64_HI(*val),
    192                       COMPILER_64_LO(*val)));
    193 
    194         } else if (ctr_reg >= SOC_COUNTER_NON_DMA_START &&
    195                    ctr_reg < SOC_COUNTER_NON_DMA_END) {
    196             non_dma =
    197                 &SOC_CONTROL(unit)->counter_non_dma[ctr_reg -
    198                                                SOC_COUNTER_NON_DMA_START];
    199             LOG_INFO(BSL_LS_APPL_COUNTER,
    200                      (BSL_META_U(unit,
    201                                  "cval_get: %s ar_idx=%d p=%d idx=%d vh=%d vl=%d\n"),
    202                       non_dma->cname,
    203                       ar_idx, port, ind,
    204                       COMPILER_64_HI(*val),
    205                       COMPILER_64_LO(*val)));
    206         } else {
    207             LOG_INFO(BSL_LS_APPL_COUNTER,
    208                      (BSL_META_U(unit,
    209                                  "cval_get: %s ar_idx=%d p=%d idx=%d vh=%d vl=%d\n"),
    210                       SOC_REG_NAME(unit, ctr_reg),
    211                       ar_idx, port, ind,
    212                       COMPILER_64_HI(*val),
    213                       COMPILER_64_LO(*val)));
    214         }
    215     }
    216 }
    217 
    218 /*
    219  * Function:
    220  *	do_resync_counters
    221  * Purpose:
    222  *	Resynchronize the previous counter values (stored in counter_val)
    223  *	with the actual counters.
    224  */
    225 
    226 int
    227 do_resync_counters(int unit, soc_pbmp_t pbmp)
    228 {
    229     soc_port_t		port, dport;
    230     int			i;
    231     soc_cmap_t          *cmap;
    232     soc_reg_t           reg;
    233     uint64		val;
    234     int                 ar_idx;
    235 
    236     /* coverity[overrun-local] */
    237     DPORT_SOC_PBMP_ITER(unit, pbmp, dport, port) {
    238         /* Non-DMA counters */ 
    239         for (i = SOC_COUNTER_NON_DMA_START; i < SOC_COUNTER_NON_DMA_END; i++) {
    240             /* coverity[overrun-call] */
    241             if (soc_counter_get(unit, port, i, -1, &val) == SOC_E_NONE )
    242                 counter_val_set(unit, port, i, -1, val);
    243         }
    244         /* DMA counters */
    245         cmap = soc_port_cmap_get(unit, port);
    246         for (i = 0; i < cmap->cmap_size; i++) {
    247             reg = cmap->cmap_base[i].reg;
    248             if (reg != INVALIDr) {
    249                 if (!SOC_REG_IS_COUNTER_TABLE(unit, reg) &&
    250                     (SOC_REG_INFO(unit, reg).flags & SOC_REG_FLAG_ARRAY)) {
    251                     for (ar_idx = 0;
    252                          ar_idx < SOC_REG_INFO(unit, reg).numels;
    253                          ar_idx++) {
    254                         if (soc_counter_get(unit, port, reg, ar_idx, &val) == SOC_E_NONE )
    255                              counter_val_set(unit, port, reg, ar_idx, val);
    256                     }
    257                 } else {
    258                     if (soc_counter_get(unit, port, reg, 0, &val) == SOC_E_NONE )
    259                           counter_val_set(unit, port, reg, 0, val);
    260                 }
    261             }
    262         }
    263     }
    264 
    265     return 0;
    266 }
    267 
    268 /*
    269  * do_show_counters
    270  *
    271  *   Displays counters for specified register(s) and port(s).
    272  *
    273  *	SHOW_CTR_HEX displays values in hex instead of decimal.
    274  *
    275  *	SHOW_CTR_RAW displays only the counter value, not the register
    276  *	name or delta.
    277  *
    278  *	SHOW_CTR_CHANGED: includes counters that have changed since the
    279  *	last call to do_show_counters().
    280  *
    281  *	SHOW_CTR_NOT_CHANGED: includes counters that have not changed since
    282  *	the last call to do_show_counters().
    283  *
    284  *   NOTE: to get any output, you need at least one of the above two flags.
    285  *
    286  *	SHOW_CTR_ZERO: includes counters that are zero.
    287  *
    288  *	SHOW_CTR_NOT_ZERO: includes counters that are not zero.
    289  *
    290  *   NOTE: to get any output, you need at least one of the above two flags.
    291  *
    292  *   SHOW_CTR_ED:
    293  *      Show only those registers marked as Error/Discard.
    294  *
    295  *   Columns will remain lined up properly until the following maximum
    296  *   limits are exceeded:
    297  *
    298  *	Current count: 99,999,999,999,999,999
    299  *	Increment: +99,999,999,999,999
    300  *	Rate: 999,999,999,999/s
    301  */
    302 
    303 void
    304 do_show_counter(int unit, soc_port_t port, soc_reg_t ctr_reg,
    305                 int ar_idx, int flags)
    306 {
    307     soc_counter_non_dma_t *non_dma;
    308     uint64		val, prev_val, diff, rate;
    309     int                 num_entries;
    310     int			changed;
    311     int                 is_ed_cntr, is_mmu_status;
    312     int			tabwidth = soc_property_get(unit, spn_DIAG_TABS, 8);
    313     int			commachr = soc_property_get(unit, spn_DIAG_COMMA, ',');
    314     int                 bit_position = 0;
    315 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    316     char                flex_que_name[10];
    317     int                 queue_mode;
    318     /*This flag SHOW_CTR_ALL_QUEUE is used in TD2+ to show flex assigned queues
    319           (endpoint queue and service queue) */
    320     soc_port_t port_backup = port;
    321     if (flags & SHOW_CTR_ALL_QUEUE) {
    322         /*make port an invalid port to rely on ar_idx to get counter index*/
    323         port = SOC_PORT_INVALID;
    324     }
    325 #endif
    326 
    327     is_ed_cntr = FALSE;
    328     is_mmu_status = FALSE;
    329     if(ctr_reg >= SOC_COUNTER_TABLE_FIELD_START) {
    330         ;
    331     } else if (ctr_reg >= SOC_COUNTER_NON_DMA_START &&
    332                ctr_reg < SOC_COUNTER_NON_DMA_END) {
    333         if (SOC_CONTROL(unit)->counter_non_dma == NULL) {
    334             return;
    335         }
    336         non_dma = &SOC_CONTROL(unit)->
    337             counter_non_dma[ctr_reg - SOC_COUNTER_NON_DMA_START];
    338         if (non_dma->flags &
    339             (_SOC_COUNTER_NON_DMA_PEAK | _SOC_COUNTER_NON_DMA_CURRENT)) {
    340             is_mmu_status = TRUE;
    341         }
    342         if (ar_idx < 0) {
    343             num_entries =
    344                 port < 0 ? non_dma->num_entries : non_dma->entries_per_port;
    345             for (ar_idx = 0; ar_idx < num_entries; ar_idx++) {
    346                 do_show_counter(unit, port, ctr_reg, ar_idx, flags);
    347             }
    348             return;
    349         }
    350     } else {
    351         is_ed_cntr = SOC_REG_INFO(unit, ctr_reg).flags & SOC_REG_FLAG_ED_CNTR;
    352 
    353         if (!(SOC_REG_INFO(unit, ctr_reg).flags & SOC_REG_FLAG_ARRAY)) {
    354             ar_idx = 0;
    355         } else {
    356             if (ar_idx < 0) { /* Set all elts of array */
    357                 for (ar_idx = 0; ar_idx < SOC_REG_INFO(unit, ctr_reg).numels;
    358                      ar_idx++) {
    359                     do_show_counter(unit, port, ctr_reg, ar_idx, flags);
    360                 }
    361                 return;
    362             }
    363         }
    364     }
    365 
    366     /*if port is an invalid port, will rely on ar_idx to get counter index*/
    367     if (soc_counter_get(unit, port, ctr_reg, ar_idx, &val) < 0) {
    368         return;
    369     }
    370     counter_val_get(unit, port, ctr_reg, ar_idx, &prev_val);
    371     /* Need to clear prev_val which stored in counter_val(SW) if current counter val < prev_val.
    372       * It only happen when soc counter is clear(ex: init all) but here counter_val not clear */
    373     if (COMPILER_64_LT(val, prev_val)) {
    374         COMPILER_64_ZERO(prev_val);
    375         counter_val_set(unit, port, ctr_reg, ar_idx, prev_val);
    376     }
    377 
    378     diff = val;
    379     COMPILER_64_SUB_64(diff, prev_val);
    380 
    381     if (COMPILER_64_IS_ZERO(diff)) {
    382 	changed = 0;
    383     } else {
    384 	counter_val_set(unit, port, ctr_reg, ar_idx, val);
    385 	changed = 1;
    386     }
    387 
    388 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    389     /*recover port info*/
    390     if (flags & SHOW_CTR_ALL_QUEUE) {
    391         port = port_backup;
    392     }
    393 #endif
    394     soc_counter_get_rate(unit, port, ctr_reg, ar_idx, &rate);
    395 
    396     if ((( changed && (flags & SHOW_CTR_CHANGED)) ||
    397 	 (!changed && (flags & SHOW_CTR_SAME))) &&
    398 	(( COMPILER_64_IS_ZERO(val) && (flags & SHOW_CTR_Z)) ||
    399 	 (!COMPILER_64_IS_ZERO(val) && (flags & SHOW_CTR_NZ))) &&
    400         ((!(flags & SHOW_CTR_ED) ||
    401           ((flags & SHOW_CTR_ED) && is_ed_cntr))) &&
    402         ((!(flags & SHOW_CTR_MS) && !is_mmu_status)||
    403           (((flags & SHOW_CTR_MS) && is_mmu_status)))
    404         ) {
    405     /* size of line must be equal or more then sum of cname, buf_val, 
    406       buf_diff and buf_rate. */
    407     /* The size of tabby must be greater than size of line */
    408 
    409 	char		tabby[130], line[120];
    410 	char		cname[32];
    411 	char		buf_val[32], buf_diff[32], buf_rate[32];
    412 
    413         if (ctr_reg >= SOC_COUNTER_NON_DMA_START &&
    414             ctr_reg < SOC_COUNTER_NON_DMA_END) {
    415             /* Non-DMA Counters */
    416             non_dma = &SOC_CONTROL(unit)->counter_non_dma[ctr_reg -
    417                                                     SOC_COUNTER_NON_DMA_START];
    418             if(!(SOC_PBMP_MEMBER(non_dma->pbmp, port))) {
    419                 /* Not a dma port member; don't show counters */
    420                 return;
    421             }
    422 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    423             if (flags & SHOW_CTR_ALL_QUEUE) {
    424                 /* coverity[check_return : FALSE] */
    425                 bcm_esw_port_control_get(unit, port,
    426                                bcmPortControlCustomerQueuing, &queue_mode);
    427                 if (queue_mode == 4) {
    428                     sal_strcpy(flex_que_name, "EP_");
    429                     sal_memcpy(cname, flex_que_name, 3);
    430                     bit_position = 3;
    431                 } else if (queue_mode == 3) {
    432                     sal_strcpy(flex_que_name, "SV_");
    433                     sal_memcpy(cname, flex_que_name, 3);
    434                     bit_position = 3;
    435                 } else {
    436                     return;
    437                 }
    438             }
    439 #endif
    440             if(sal_strlen(non_dma->cname) > SOC_CNAME_MAX) {
    441                 /* Truncate Name to fit in line */
    442                 sal_memcpy(cname, non_dma->cname, SOC_CNAME_MAX);
    443                 if (non_dma->entries_per_port > 1) {
    444                     sal_sprintf(&cname[SOC_CNAME_MAX], "(%d).%s", 
    445                                 ar_idx, 
    446                                 SOC_PORT_NAME(unit, port));
    447                 } else if (non_dma->entries_per_port == 1) {
    448                     sal_sprintf(&cname[SOC_CNAME_MAX], ".%s", 
    449                                 SOC_PORT_NAME(unit, port));
    450                 } else {
    451                     sal_sprintf(&cname[SOC_CNAME_MAX], "(%d)", 
    452                                 ar_idx);
    453                 }
    454             } else {
    455                 if (non_dma->entries_per_port > 1) {
    456                     sal_sprintf(&cname[bit_position], "%s(%d).%s", non_dma->cname, ar_idx,
    457                                 SOC_PORT_NAME(unit, port));
    458                 } else if (non_dma->entries_per_port == 1) {
    459                     sal_sprintf(&cname[bit_position], "%s.%s", non_dma->cname,
    460                                 SOC_PORT_NAME(unit, port));
    461                 } else {
    462                     sal_sprintf(&cname[bit_position], "%s(%d)", non_dma->cname, ar_idx);
    463                 }
    464             }
    465         } else  {
    466             /* Counter Tables */
    467             if(ctr_reg >= SOC_COUNTER_TABLE_FIELD_START) {
    468                 sal_sprintf(cname, "%s.%s",
    469                     SOC_FIELD_NAME(unit, (ctr_reg - SOC_COUNTER_TABLE_FIELD_START)),
    470                     SOC_PORT_NAME(unit, port));
    471 
    472             /* DMA Counters */   
    473             } else if (sal_strlen(SOC_REG_NAME(unit, ctr_reg)) > SOC_CNAME_MAX) {
    474 #if !defined(SOC_NO_ALIAS)
    475                 if (SOC_REG_ALIAS(unit, ctr_reg)
    476                     && *SOC_REG_ALIAS(unit, ctr_reg)
    477                     && sal_strlen(SOC_REG_ALIAS(unit, ctr_reg)) <= SOC_CNAME_MAX) {
    478                     if (SOC_REG_INFO(unit, ctr_reg).flags & SOC_REG_FLAG_ARRAY) {
    479                         sal_sprintf(cname, "%s(%d).%s",
    480                                     SOC_REG_ALIAS(unit, ctr_reg),
    481                                     ar_idx,
    482                                     SOC_PORT_NAME(unit, port));
    483                     } else {
    484                         sal_sprintf(cname, "%s.%s",
    485                                     SOC_REG_ALIAS(unit, ctr_reg),
    486                                     SOC_PORT_NAME(unit, port));
    487                     }
    488                 } else 
    489 #endif /* !defined(SOC_NO_ALIAS) */
    490                 {
    491                     sal_memcpy(cname, SOC_REG_NAME(unit, ctr_reg), SOC_CNAME_MAX);
    492                     /* Truncate Name to fit in line */
    493                     if (SOC_REG_INFO(unit, ctr_reg).flags & SOC_REG_FLAG_ARRAY) {
    494                         sal_sprintf(&cname[SOC_CNAME_MAX], "(%d).%s", 
    495                                     ar_idx, 
    496                                     SOC_PORT_NAME(unit, port));
    497                     } else {
    498                         sal_sprintf(&cname[SOC_CNAME_MAX], ".%s", 
    499                                     SOC_PORT_NAME(unit, port));
    500                     }
    501                 }
    502             } else {
    503                 if (SOC_REG_INFO(unit, ctr_reg).flags & SOC_REG_FLAG_ARRAY) {
    504                     sal_sprintf(cname, "%s(%d).%s", 
    505                                 SOC_REG_NAME(unit, ctr_reg),
    506                                 ar_idx, 
    507                                 SOC_PORT_NAME(unit, port));
    508                 } else {
    509                     sal_sprintf(cname, "%s.%s", 
    510                                 SOC_REG_NAME(unit, ctr_reg),
    511                                 SOC_PORT_NAME(unit, port));
    512                 }
    513             }
    514         }
    515 
    516 	if (flags & SHOW_CTR_RAW) {
    517 	    if (flags & SHOW_CTR_HEX) {
    518 		sal_sprintf(line, "0x%08x%08x",
    519 			COMPILER_64_HI(val), COMPILER_64_LO(val));
    520 	    } else {
    521 		format_uint64_decimal(buf_val, val, 0);
    522 		sal_sprintf(line, "%s", buf_val);
    523 	    }
    524 	} else {
    525 	    if (flags & SHOW_CTR_HEX) {
    526                 if (is_mmu_status) {
    527                     sal_sprintf(line, "%-22s: 0x%08x%08x",
    528                                 cname,
    529                                 COMPILER_64_HI(val), COMPILER_64_LO(val));
    530                 } else {
    531 		    sal_sprintf(line, "%-22s: 0x%08x%08x +0x%08x%08x 0x%08x%08x/s",
    532 			cname,
    533 			COMPILER_64_HI(val), COMPILER_64_LO(val),
    534 			COMPILER_64_HI(diff), COMPILER_64_LO(diff),
    535 			COMPILER_64_HI(rate), COMPILER_64_LO(rate));
    536                 }
    537 	    } else {
    538                 if (is_mmu_status) {
    539 		    format_uint64_decimal(buf_val, val, commachr);
    540 		    sal_sprintf(line, "%-28s:%22s", cname, buf_val);
    541                 } else {
    542 		    format_uint64_decimal(buf_val, val, commachr);
    543 		    buf_diff[0] = '+';
    544 		    format_uint64_decimal(buf_diff + 1, diff, commachr);
    545 		    sal_sprintf(line, "%-28s:%22s%20s",
    546 			    cname, buf_val, buf_diff);
    547 		    if (!COMPILER_64_IS_ZERO(rate)) {
    548 		        format_uint64_decimal(buf_rate, rate, commachr);
    549 		        sal_sprintf(line + sal_strlen(line), "%16s/s", buf_rate);
    550 		    }
    551                 }
    552 	    }
    553 	}
    554 
    555 	/*
    556 	 * Display is tremendously faster with tabify.
    557 	 * Set diag_tab property to desired value, or 0 to turn it off.
    558 	 */
    559 
    560 	tabify_line(tabby, line, tabwidth);
    561 
    562 	cli_out("%s\n", tabby);
    563     }
    564 }
    565 
    566 int
    567 do_show_counters(int unit, soc_reg_t ctr_reg, soc_pbmp_t pbmp, int flags)
    568 {
    569     soc_control_t	*soc = SOC_CONTROL(unit);
    570     soc_counter_non_dma_t *non_dma;
    571     soc_port_t		port, dport;
    572     int			i;
    573     soc_cmap_t          *cmap;
    574     soc_reg_t           reg;
    575     int                 numregs;
    576     char		pfmt[SOC_PBMP_FMT_LEN];
    577 
    578 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    579     int j, array_count = 0;
    580     int *ar_idx_array = NULL;
    581     soc_port_t *port_array = NULL;
    582 #endif
    583 
    584     /* coverity[overrun-local] */
    585     DPORT_SOC_PBMP_ITER(unit, pbmp, dport, port) {
    586         /* coverity[overrun-call] */
    587         cmap = soc_port_cmap_get(unit, port);
    588         if (!cmap) {
    589 	        cli_out("NOTE: Unit %d: No counter map found for port %d\n", unit, port);
    590             continue;
    591         }
    592         numregs = cmap->cmap_size;
    593 
    594         if (ctr_reg != INVALIDr) {
    595             /* coverity[negative_returns] : FALSE */
    596             do_show_counter(unit, port, ctr_reg, -1, flags);
    597         } else {
    598             for (i = 0; i < numregs; i++) {
    599                 reg = cmap->cmap_base[i].reg;
    600                 if (reg != INVALIDr) {
    601                     do_show_counter(unit, port, reg,
    602                                     cmap->cmap_base[i].index, flags);
    603                 }
    604             }
    605             for (i = SOC_COUNTER_NON_DMA_START; i < SOC_COUNTER_NON_DMA_END;
    606                  i++) {
    607                 non_dma = &SOC_CONTROL(unit)->
    608                     counter_non_dma[i - SOC_COUNTER_NON_DMA_START]; 
    609                 if (non_dma->entries_per_port == 0) {
    610                     continue;
    611                 }
    612                 /* coverity[negative_returns] : FALSE */
    613                 do_show_counter(unit, port, i, -1, flags);
    614             }
    615         }
    616     }
    617     if (ctr_reg == INVALIDr) {
    618         for (i = SOC_COUNTER_NON_DMA_START; i < SOC_COUNTER_NON_DMA_END; i++) {
    619             non_dma = &SOC_CONTROL(unit)->
    620                 counter_non_dma[i - SOC_COUNTER_NON_DMA_START];
    621             if (non_dma->entries_per_port != 0) {
    622                 continue;
    623             }
    624             if (non_dma->flags & _SOC_COUNTER_NON_DMA_NO_SHOW_C) {
    625                 /* Counter not present for diag show c output */
    626                 continue;
    627             }
    628             /* coverity[negative_returns] : FALSE */
    629             do_show_counter(unit, -1, i, -1, flags);
    630         }
    631     }
    632 #if defined(BCM_TRIDENT2PLUS_SUPPORT)
    633     if (SOC_IS_TRIDENT2PLUS(unit)) {
    634         flags |= SHOW_CTR_ALL_QUEUE;
    635         ar_idx_array = sal_alloc(sizeof(int) * 2960,
    636             "cosq hw index when show counter");
    637         if (NULL == ar_idx_array) {
    638             return BCM_E_MEMORY;
    639         }
    640         port_array = sal_alloc(sizeof(soc_port_t) * 2960,
    641             "port array of mmu queues when show counter");
    642         if (NULL == port_array) {
    643             sal_free(ar_idx_array);
    644             return BCM_E_MEMORY;
    645         }
    646         _bcm_td2_cosq_hw_idx_get(unit, 2960, port_array, ar_idx_array,&array_count);
    647         for (i = SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_PKT_UC;
    648              i <= SOC_COUNTER_NON_DMA_EGR_PERQ_XMT_BYTE_UC; i++) {
    649                for (j = 0; j < array_count; j++){
    650                    do_show_counter(unit, port_array[j], i, ar_idx_array[j], flags);
    651                 }
    652         }
    653         sal_free(ar_idx_array);
    654         sal_free(port_array);
    655     }
    656 #endif
    657 
    658     SOC_PBMP_REMOVE(pbmp, soc->counter_pbmp);
    659     if (soc->counter_interval == 0) {
    660 	cli_out("NOTE: counter collection is not running\n");
    661     } else if (SOC_PBMP_NOT_NULL(pbmp)) {
    662 	cli_out("NOTE: counter collection is not active for ports %s\n",
    663                 SOC_PBMP_FMT(pbmp, pfmt));
    664     }
    665 
    666     return 0;
    667 }
    668 
    669 /*
    670  * Counter collection configuration
    671  */
    672 
    673 cmd_result_t
    674 cmd_esw_counter(int unit, args_t *a)
    675 {
    676     soc_control_t	*soc = SOC_CONTROL(unit);
    677     soc_pbmp_t		pbmp;
    678     int			usec, dma, r;
    679     parse_table_t	pt;
    680     uint32		flags;
    681     int			sync = 0;
    682 
    683     if (!sh_check_attached(ARG_CMD(a), unit)) {
    684 	return CMD_FAIL;
    685     }
    686 
    687 
    688     flags = soc->counter_flags;
    689     usec = soc->counter_interval;
    690     SOC_PBMP_ASSIGN(pbmp, soc->counter_pbmp);
    691     dma = (flags & SOC_COUNTER_F_DMA) != 0;
    692 
    693     parse_table_init(unit, &pt);
    694     parse_table_add(&pt, "Interval", 	PQ_DFL|PQ_INT,
    695 		    (void *)( 0), &usec, NULL);
    696     parse_table_add(&pt, "PortBitMap", 	PQ_DFL|PQ_PBMP,
    697 		    (void *)(0), &pbmp, NULL);
    698     parse_table_add(&pt, "DMA", 	PQ_DFL|PQ_BOOL,
    699 		    INT_TO_PTR(dma), &dma, NULL);
    700 
    701     if (!ARG_CNT(a)) {			/* Display settings */
    702 	cli_out("Current settings:\n");
    703 	parse_eq_format(&pt);
    704 	parse_arg_eq_done(&pt);
    705 	return(CMD_OK);
    706     }
    707 
    708     if (parse_arg_eq(a, &pt) < 0) {
    709 	cli_out("%s: Error: Unknown option: %s\n", ARG_CMD(a), ARG_CUR(a));
    710 	parse_arg_eq_done(&pt);
    711 	return(CMD_FAIL);
    712     }
    713     parse_arg_eq_done(&pt);
    714 
    715     if (ARG_CNT(a) > 0 && !sal_strcasecmp(_ARG_CUR(a), "on")) {
    716         usec = prev_counter_interval[unit];
    717         ARG_NEXT(a);
    718     }
    719 
    720     if (ARG_CNT(a) > 0 && !sal_strcasecmp(_ARG_CUR(a), "off")) {
    721 	ARG_NEXT(a);
    722 	usec = 0;
    723     }
    724 
    725     if (ARG_CNT(a) > 0 && !sal_strcasecmp(_ARG_CUR(a), "sync")) {
    726 	ARG_NEXT(a);
    727 	sync = 1;
    728     }
    729 
    730     if (sync) {
    731         /* Sync driver info to HW */
    732 	if ((r = soc_counter_sync(unit)) < 0) {
    733 	    cli_out("%s: Error: Could not sync counters: %s\n",
    734                     ARG_CMD(a), soc_errmsg(r));
    735 	    return CMD_FAIL;
    736 	}
    737         /* Sync diag info with driver */
    738 	do_resync_counters(unit, pbmp);
    739 	return CMD_OK;
    740     }
    741 
    742     if (soc_feature(unit, soc_feature_cpuport_stat_dma)) {
    743         soc_pbmp_t temp_pbmp;
    744         SOC_PBMP_CLEAR(temp_pbmp);
    745         SOC_PBMP_OR(temp_pbmp, PBMP_PORT_ALL(unit));
    746         SOC_PBMP_OR(temp_pbmp, PBMP_CMIC(unit));
    747         SOC_PBMP_AND(pbmp, temp_pbmp);
    748     } else {
    749         SOC_PBMP_AND(pbmp, PBMP_PORT_ALL(unit));
    750     }
    751 
    752     if (dma) {
    753 	flags |= SOC_COUNTER_F_DMA;
    754     } else {
    755 	flags &= ~SOC_COUNTER_F_DMA;
    756     }
    757 
    758     if (usec > 0) {
    759 	r = soc_counter_start(unit, flags, usec, pbmp);
    760     } else {
    761         uint32 flags;
    762         pbmp_t pbmp;
    763         int prev_interval;
    764 
    765         r = soc_counter_status(unit, &flags,
    766                                &prev_interval, &pbmp);
    767         if (r < 0 || prev_interval <= 0) {
    768             prev_interval = SOC_COUNTER_INTERVAL_DEFAULT;
    769         }
    770         prev_counter_interval[unit] = prev_interval;
    771         r = soc_counter_stop(unit);
    772     }
    773 
    774     if (r < 0) {
    775 	cli_out("%s: Error: Could not set counter mode: %s\n",
    776                 ARG_CMD(a), soc_errmsg(r));
    777 	return CMD_FAIL;
    778     }
    779 
    780     return CMD_OK;
    781 }
    782 
    783 /*
    784  * routines for custom stats 
    785  */
    786 
    787 
    788 #define COL_SZ     0x05
    789 
    790 #define RDBGC             0x01
    791 #define TDBGC             0x02
    792 #define BOTH              0x03
    793 
    794 #define SET_FLAGS         0x01
    795 #define LIST_FLAGS        0x02
    796 #define SHOW_FLAGS        0x03
    797 #define SHOW_COUNTERS     0x04
    798 #define SHOW_TABLE        0x05
    799 
    800 #define ERROR_SET_FLAGS(_err) \
    801         if (cmd_type == SET_FLAGS) { \
    802             cli_out("Error: " _err); \
    803             return CMD_FAIL;  \
    804         }
    805 
    806 char      *head =
    807     "\n+------------------Programmable Statistics Counters[Port %4s]-------\
    808 -----------+";
    809 char      *menu =
    810     "\n| Type | No. |       Value       |                Enabled For       \
    811             |";
    812 char      *line =
    813     "\n+-------------------------------------------------------------------\
    814 ------------+";
    815 char      *trg_s = "\n|      |     |                   | ";
    816 
    817 char      *stat_names[] = BCM_STAT_NAME_INITIALIZER;
    818 typedef struct trig_name_s {
    819     char      *name;
    820     char      *about;
    821 } trig_name_t;
    822 
    823 trig_name_t _trig_names[] = {
    824     {"RIPD4", "         Rx IPv4 L3 discard packets"},
    825     {"RIPC4", "         Good rx L3 (V4 packets) includes tunneled"},
    826     {"RIPHE4", "        Rx IPv4 header error packets"},
    827     {"IMRP4", "         Routed IPv4 multicast packets"},
    828     {"RIPD6", "         Rx IPv6 L3 discard packet"},
    829     {"RIPC6", "         Good rx L3 (V6 packets) includes tunneled"},
    830     {"RIPHE6", "        Rx IPv6 header error packets"},
    831     {"IMRP6", "         Routed IPv6 multicast packets"},
    832     {"RDISC", "         IBP discard and CBP full"},
    833     {"RUC", "           Good rx unicast (L2+L3) packets"},
    834     {"RPORTD",
    835      "        Packets droppped when ingress port is not in forwarding state"},
    836     {"PDISC",
    837      "         Rx policy discard - DST_DISCARD, SRC_DISCARD, RATE_CONTROL"},
    838     {"IMBP", "          Bridged multicast packets"},
    839     {"RFILDR", "        Packets dropped by FP"},
    840     {"RIMDR", "         Multicast (L2+L3) packets that are dropped"},
    841     {"RDROP", "         Port bitmap zero drop condition"},
    842     {"IRPSE", "         HiGig IPIC pause rx"},
    843     {"IRHOL", "         HiGig End-to-End HOL rx packets"},
    844     {"IRIBP", "         HiGig End-to-End IBP rx packets"},
    845     {"DSL3HE", "        DOS L3 header error packets"},
    846     {"IUNKHDR", "       Unknown HiGig header type packet"},
    847     {"DSL4HE", "        DOS L4 header error packets"},
    848     {"IMIRROR", "       HiGig mirror packet"},
    849     {"DSICMP", "        DOS ICMP error packets"},
    850     {"DSFRAG", "        DOS fragment error packets"},
    851     {"MTUERR",
    852      "        Packets trapped to CPU due to egress L3 MTU violation"},
    853     {"RTUN", "          Number of tunnel packets received"},
    854     {"RTUNE", "         Rx tunnel error packets"},
    855     {"VLANDR", "        Rx VLAN drops"},
    856     {"RHGUC", "         Rx HiGig lookup UC cases"},
    857     {"RHGMC", "         Rx HiGig lookup MC cases"},
    858     {"MPLS", "          Received MPLS Packets"},
    859     {"MACLMT", "        packets dropped due to MAC Limit is hit"},
    860     {"MPLSERR", "       Received MPLS Packets with Error"},
    861     {"URPFERR", "       L3 src URPF check Fail"},
    862     {"HGHDRE", "        Higig Header error packets"},
    863     {"MCIDXE", "        Multicast Index error packets"},
    864     {"LAGLUP", "        LAG failover loopback packets"},
    865     {"LAGLUPD", "       LAG backup port down"},
    866     {"PARITYD", "       Parity error packets"},
    867     {"VFPDR", "         VLAN FP drop case"},
    868     {"URPF", "          Unicast RPF drop case"},
    869     {"DSTDISCARDROP", "      L2/L3 lookup DST_DISCARD drop"},
    870     {"CLASSBASEDMOVEDROP", " Class based station movement drop"},
    871     {"MACLMT_NODROP", "      Mac limit exceeded and packet not dropped"},
    872     {"MACSAEQUALMACDA", "    Dos Attack L2 Packets"},
    873     {"MACLMT_DROP", "        Mac limit exceeded and packet dropped"},
    874     {"TGIP4", "         Tx Good IPv4 L3 UC packets"},
    875     {"TIPD4", "         Tx IPv4 L3 UC Aged and Drop packets"},
    876     {"TGIPMC4", "       Tx Good IPv4 IPMC packets"},
    877     {"TIPMCD4", "       Tx IPv4 IPMC Aged and Drop packets"},
    878     {"TGIP6", "         Tx Good IPv6 L3 UC packets"},
    879     {"TIPD6", "         Tx IPv6 L3 UC Aged and Drop Packets"},
    880     {"TGIPMC6", "       Tx Good IPv6 IPMC packets"},
    881     {"TIPMCD6", "       Tx IPv6 IPMC Aged and Drop packets"},
    882     {"TTNL", "          Tx Tunnel packets"},
    883     {"TTNLE", "         Tx Tunnel error packets"},
    884     {"TTTLD", "         Pkts dropped due to TTL threshold counter"},
    885     {"TCFID",
    886      "         Pkts dropped when CFI set & pkt is untagged or L3 \
    887 switched for IPMC"},
    888     {"TVLAN", "         Tx VLAN tagged packets"},
    889     {"TVLAND", "        Pkts dropped due to invalid VLAN counter"},
    890     {"TVXLTMD", "       Pkts dropped due to miss in VXLT table counter"},
    891     {"TSTGD",
    892      "         Pkts dropped due to Spanning Tree State not in forwarding \
    893 state"},
    894     {"TAGED", "         Pkts dropped due to packet aged counter"},
    895     {"TL2MCD", "        L2 MC packet drop counter"},
    896     {"TPKTD", "         Pkts dropped due to any condition"},
    897     {"TMIRR", "         mirroring flag"},
    898     {"TSIPL", "         SIP Link Local Drop flag"},
    899     {"THGUC", "         Higig Lookedup L3UC Pkts"},
    900     {"THGMC", "         Higig Lookedup L3MC Pkts"},
    901     {"THIGIG2", "       Unknown HiGig2 Drop"},
    902     {"THGI", "          Unknown HiGig drop"},
    903     {"TL2_MTU", "       L2 MTU fail drop"},
    904     {"TPARITY_ERR", "   Parity Error drop"},
    905     {"TIP_LEN_FAIL", "  IP Length check fail drop"},
    906     {"TMTUD", "         EBAD_MTU_DROP"},
    907     {"TSLLD", "         ESIP_LINK_LOCAL"},
    908     {"TL2MPLS", "       L2_MPLS_ENCAP_TX"},
    909     {"TL3MPLS", "       L3_MPLS_ENCAP_TX"},
    910     {"TMPLS", "         MPLS_TX"},
    911     {"MODIDTOOLARGEDROP","  MODID greater than 31 drop counter"},
    912     {"PKTMODTOOLARGEDROP"," Byte additions too large drop counter"},
    913     {"RX_SYMBOL", "     Fabric I/F => Rx Errors (e.g.8B10B)"},
    914     {"TIME_ALIGNMENT_EVEN", " Fabric I/F => Time Alignment (even)"},
    915     {"TIME_ALIGNMENT_ODD", " Fabric I/F => Time Alignment (odd)"},
    916     {"BIT_INTERLEAVED_PARITY_EVEN", " Fabric I/F => BIP (even)"},
    917     {"BIT_INTERLEAVED_PARITY_ODD", " Fabric I/F => BIP (odd)"},
    918     {"FcmPortClass3RxFrames",   " FCOE L3 RX frames"},
    919     {"FcmPortClass3RxDiscards", " FCOE L3 RX discarded frames "},
    920     {"FcmPortClass3TxFrames",   " FCOE L3 TX frames "},
    921     {"FcmPortClass2RxFrames",   " FCOE L2 RX frames "},
    922     {"FcmPortClass2RxDiscards", " FCOE L2 RX discarded frames "},
    923     {"FcmPortClass2TxFrames",   " FCOE L2 TX frames "},
    924     {"NonHGoE", "       Non HGoE Rx frames on an HGoE port"},
    925     {"HGoE", "          HGoE Rx frames"},
    926     {"PROTSWITCHINGDROP", "      Pkts Dropped due to Protection switching in EPIPE"},
    927     {"VNTAG_ERROR", "          Rx VNTAG error packets"},
    928     {"NIV_FORWARDING_DROP", "  Rx NIV/PE packets dropped due to forwarding error"},
    929     {"IFP_PFC_DROP", "  Original ingress packets dropped due to IFP PfcTx action"},
    930     {"TECN_TABLE_DROP", "    Tx Egress packets dropped due to ECN error"},
    931     {"TNIV_PRUNE_DROP", "    Tx Egress NIV/PE packets dropped due to pruning check"},
    932     {"RxHigigLoopbackDrop", "           HiGig loopback packets dropped"},
    933     {"RxHigigUnknownOpcodeDrop", "      HiGig unknown opcode"},
    934     {"RxIpInIpDrop", "                  IPinIP tunnel process failure"},
    935     {"RxMimDrop", "                     MiM tunnel process failure"},
    936     {"RxTunnelInterfaceError",
    937      "        IPMC tunnel incoming interface is incorrect"},
    938     {"RxMplsControlWordInvalid", "      MPLS invalid control word"},
    939     {"RxMplsGalNotBosDrop", "           MPLS Generic Label is not BOS"},
    940     {"RxMplsPayloadInvalid", "          MPLS invalid payload"},
    941     {"RxMplsEntropyDrop", "             MPLS Entropy label in unallowed range"},
    942     {"RxMplsLabelLookupMiss", "         MPLS label lookup miss"},
    943     {"RxMplsActionInvalid", "           MPLS invalid action"},
    944     {"RxTunnelTtlError", "              Tunnel TTL check failure"},
    945     {"RxTunnelShimError", "             Tunnel shim header error"},
    946     {"RxTunnelObjectValidationFail", "  Tunnel termination failure"},
    947     {"RxVlanMismatch", "                VLAN ID invalid"},
    948     {"RxVlanMemberMismatch", "          Ingress port not in VLAN membership"},
    949     {"RxTpidMismatch", "                VLAN TPID mismatch"},
    950     {"RxPrivateVlanMismatch", "         PVLAN VID mismatch"},
    951     {"RxMacIpBindError", "              MAC to IP bind check failure"},
    952     {"RxVlanTranslate2LookupMiss", "    VLAN Translate2 lookup miss"},
    953     {"RxL3TunnelLookupMiss", "          L3 Tunnel lookup miss"},
    954     {"RxMplsLookupMiss", "              MPLS lookup miss"},
    955     {"RxVlanTranslate1LookupMiss", "    VLAN Translate1 lookup miss"},
    956     {"RxFcoeVftDrop", "                 FVT header error"},
    957     {"RxFcoeSrcBindError", "            FCOE source bind check failure"},
    958     {"RxFcoeSrcFpmaError", "            Source FPMA prefix check failure"},
    959     {"RxVfiP2pDrop",
    960      "                  Packets arrived from a VP that is not programmed \
    961 in PT2PT connection"},
    962     {"RxStgDrop", "                     STP not in forwarding state"},
    963     {"RxCompositeError",
    964      "              HW related error like lookup table with parity error"},
    965     {"RxBpduDrop", "                    BPUD packets dropped"},
    966     {"RxProtocolDrop", "                Protocol packets dropped"},
    967     {"RxUnknownMacSaDrop", "            Unknown MACSA packets dropped "},
    968     {"RxSrcRouteDrop", "                MACSA is multicast(bit 40 == 1)"},
    969     {"RxL2SrcDiscardDrop", "            L2 SRC_DISCARD drop"},
    970     {"RxL2SrcStaticMoveDrop", "         Port movement of static L2 addr"},
    971     {"RxL2DstDiscardDrop", "            L2 DST_DISCARD drop"},
    972     {"RxL3DisableDrop", "               V4/V6 L3_ENABLE unset drop"},
    973     {"RxMacSaEqual0Drop", "             Packets dropped due to MACSA == 0"},
    974     {"RxVlanCrossConnectOrNonUnicastDrop",
    975      "  L2 forwarding lookup miss or PBT non unicast packets drop"},
    976     {"RxTimeSyncDrop", "                Network time sync packets dropped"},
    977     {"RxIpmcDrop", "                    IPMC process failure"},
    978     {"RxMyStationDrop", "               MY_STATION.DISCARD drop"},
    979     {"RxPrivateVlanVpFilterDrop", "     Packets dropped based on src/dst VP type"},
    980     {"RxL3DstDiscardDrop", "            L3 DST_DISCARD drop"},
    981     {"RxTunnelDecapEcnError", "         Tunnel decap ECN error"},
    982     {"RxL3SrcDiscardDrop", "            L3 SRC_DISCARD drop"},
    983     {"RxFcoeZoneLookupMiss", "          FCOE_ZONE lookup miss"},
    984     {"RxL3TtlError", "                  L3 TTL check failure"},
    985     {"RxL3HeaderError", "               L3 header error"},
    986     {"RxL2HeaderError", "               L2 header error"},
    987     {"RxL3DstLookupDrop",
    988      "             IPMC processing drop, or L3_DESTINATION == 0 for L3UC packets"},
    989     {"RxL2TtlError", "                  L2 ZONE TTL check failure"},
    990     {"RxL2RpfError",
    991      "                  Incoming port/lag/svp check failure"},
    992     {"RxTagUntagDiscardDrop", "         PORT_DIS_UNTAG/PORT_DIS_TAG drop"},
    993     {"RxStormControlDrop", "            Storm control metering drop"},
    994     {"RxFcoeZoneError", "               FCOE_ZONE check failure"},
    995     {"RxFieldChangeL2NoRedirectDrop",
    996      " Change L2 fields without deploying redirect action drop"},
    997     {"RxNextHopDrop", "                 NEXT_HOP drop"},
    998     {"RxNatDrop", "                     NAT process failure"},
    999     {"IngressProtectionDataDrop", "     Protection data drop"},
   1000     {"RxSrcKnockoutDrop", "             SGPP == DGPP or SVP == DVP, etc"},
   1001     {"RxMplsSeqNumberError", "          MPLS control word sequence number error"},
   1002     {"RxBlockMaskDrop", "               Bitmap of ports blocked"},
   1003     {"RxDlbRhResolutionError", "        DLB or RH resolution error"},
   1004     {"TxFwdDomainNotFoundDrop", "       Forwarding domain not found"},
   1005     {"TxNotFwdDomainMemberDrop", "      Not forwarding domain member"},
   1006     {"TxIpmcL2SrcPortPruneDrop", "      IPMC L2 self port drop"},
   1007     {"TxNonUnicastPruneDrop", "         Non unicast pruning"},
   1008     {"TxSvpRemoveDrop", "               Virtual port pruning"},
   1009     {"TxVplagPruneDrop", "              VPLAG pruning"},
   1010     {"TxSplitHorizonDrop", "            Split horizon check failure"},
   1011     {"TxMmuPurgeDrop", "                Packets dropped due to MMU purge"},
   1012     {"TxStgDisableDrop", "              Packets dropped due to STG disabled"},
   1013     {"TxEgressPortDrop", "              EGR_LPORT_PROFILE.DROP"},
   1014     {"TxEgressFilterDrop", "            Packets dropped by EFP"},
   1015     {"TxVisibilityDrop", "              Visibility packets dropped"}
   1016 };
   1017 
   1018 /*
   1019  * Function:
   1020  *      get_counter
   1021  * Description:
   1022  *      Get numeric counter value from input string.
   1023  * Parameters:
   1024  *      c       - Input string.
   1025  *      rx_tx   - Counter type (RX/TX)?
   1026  *      counter - Counter value to be returned.
   1027  * Returns:
   1028  *      SUCCESS(0)/ FAILURE(-1).
   1029  */
   1030 static int
   1031 get_counter(char *c, int rx_tx, int *counter)
   1032 {
   1033     int        i;
   1034     int        n;
   1035 
   1036     i = 0;
   1037     n = 0;
   1038 
   1039     while (isdigit((unsigned) c[i])) {
   1040         n = n * 10 + c[i++] - '0';
   1041     }
   1042 
   1043     if (n < 0 || c[i]) {
   1044         return -1;
   1045     }
   1046 
   1047     if (rx_tx == RDBGC) {
   1048         n += snmpBcmCustomReceive0;
   1049         if (n < snmpBcmCustomReceive0 || n >= snmpBcmCustomTransmit0) {
   1050             return -1;
   1051         }
   1052     } else if (rx_tx == TDBGC) {
   1053         n += snmpBcmCustomTransmit0;
   1054         if (n < snmpBcmCustomTransmit0 || n >= snmpValCount) {
   1055             return -1;
   1056         }
   1057     }
   1058 
   1059     *counter = n;
   1060     return 0;
   1061 
   1062 }
   1063 
   1064 /*
   1065  * Function:
   1066  *      set_triggers
   1067  * Description:
   1068  *      Set triggers for given counter.
   1069  * Parameters:
   1070  *      unit    - StrataSwitch PCI device unit number.
   1071  *      port    - port number.
   1072  *      counter - counter number.
   1073  *      a       - argc/argv (sorta) structure for parsing arguments.
   1074  * Returns:
   1075  *      None.
   1076  */
   1077 static int
   1078 set_triggers(int unit, int port, uint32 counter, args_t * a)
   1079 {
   1080 
   1081     char      *c;
   1082     char       act = 5;
   1083     int        cur_config = 0;
   1084     int        rv = 0;
   1085     uint32     trig_typ = 0;
   1086 
   1087     while ((c = ARG_GET(a)) != NULL) {
   1088         if (c[0] == '+') {
   1089             act = 1;            /* add */
   1090             c++;
   1091         } else if (c[0] == '-') {
   1092             act = 2;            /* remove */
   1093             c++;
   1094         }
   1095         for (trig_typ = 0; trig_typ < bcmDbgCntNum; trig_typ++) {
   1096             if (parse_cmp(_trig_names[trig_typ].name, c, '\0')) {
   1097                 break;
   1098             }
   1099         }
   1100 
   1101         if (trig_typ == bcmDbgCntNum) {
   1102             cli_out("%s Not available: see CustomSTAT LS\n", c);
   1103             continue;
   1104         }
   1105 
   1106         switch (act) {
   1107             case 1:
   1108                 rv = bcm_stat_custom_add(unit, port, counter, trig_typ);
   1109                 break;
   1110             case 2:
   1111                 rv = bcm_stat_custom_delete(unit, port, counter, trig_typ);
   1112                 break;
   1113             default:           /* toggle */
   1114                 rv = bcm_stat_custom_check(unit, port,
   1115                                            counter, trig_typ, &cur_config);
   1116                 if (BCM_SUCCESS(rv)) {
   1117                     if (cur_config == 1) {
   1118                         rv = bcm_stat_custom_delete(unit, port, counter,
   1119                                                     trig_typ);
   1120                     } else {
   1121                         rv = bcm_stat_custom_add(unit, port, counter,
   1122                                                  trig_typ);
   1123                     }
   1124                 }
   1125         }
   1126 
   1127         if (BCM_FAILURE(rv)) {
   1128             cli_out("\t%18s\t%s %s (stat %d, port %d): %s\n", "-",
   1129                     stat_names[counter], _trig_names[trig_typ].name,
   1130                     counter, port, bcm_errmsg(rv));
   1131         }
   1132     }
   1133     return rv;
   1134 }
   1135 
   1136 /*
   1137  * Function:
   1138  *      cstat_flags_show
   1139  * Description:
   1140  *      Show programmed triggers for given counter.
   1141  * Parameters:
   1142  *      unit    - StrataSwitch PCI device unit number.
   1143  *      pbmp    - Bitmap of ports.
   1144  *      rx_tx   - counter type.
   1145  *      counter - counter number.
   1146  *                -1 means all.
   1147  * Returns:
   1148  *      None.
   1149  */
   1150 static void
   1151 cstat_flags_show(int unit, bcm_pbmp_t pbmp, int rx_tx, int counter)
   1152 {
   1153     uint32     count_index;
   1154     uint32     start;
   1155     uint32     end;
   1156     int        port, dport;
   1157     int        title;
   1158     int        i = 0;
   1159     int        rv = 0;
   1160     int        trig_typ = 0;
   1161     int        cur_config = 0;
   1162 
   1163     if (rx_tx == RDBGC) {
   1164         port = 0;
   1165         cli_out("Custom Receive stats are enabled for following triggers\n");
   1166         cli_out("[Triggers are common for all ports]\n");
   1167 
   1168         start = (counter == -1) ? snmpBcmCustomReceive0 : counter;
   1169         end = (counter == -1) ? snmpBcmCustomTransmit0 : counter + 1;
   1170 
   1171         for (count_index = start; count_index < end; count_index++) {
   1172             title = 1;
   1173             for (trig_typ = 0, i = 0; trig_typ < bcmDbgCntNum; trig_typ++) {
   1174                 cur_config = 0;
   1175                 rv = bcm_stat_custom_check(unit, port, count_index,
   1176                                            trig_typ, &cur_config);
   1177                 if (BCM_SUCCESS(rv) && cur_config) {
   1178                     if (title) {
   1179                         cli_out("\n%23s-\n\t\t", stat_names[count_index]);
   1180                         title = 0;
   1181                     }
   1182                     cli_out("%s%s", _trig_names[trig_typ].name,
   1183                             !((i + 1) % 5) ? "\n\t\t" : " ");
   1184                     i++;
   1185                 } else {
   1186                     continue;
   1187                 }
   1188             }
   1189         }
   1190         cli_out("\n");
   1191         return;
   1192     }
   1193 
   1194     if (rx_tx == TDBGC) {
   1195         start = (counter == -1) ? snmpBcmCustomTransmit0 : counter;
   1196         end = (counter == -1) ? snmpValCount : counter + 1;
   1197         cli_out("Custom Transmit stats are enabled for following triggers\n");
   1198         /* coverity[overrun-local] */
   1199         DPORT_BCM_PBMP_ITER(unit, pbmp, dport, port) {
   1200             BCM_PBMP_CLEAR(pbmp);
   1201             cli_out("[Triggers are common for all ports]\n");
   1202             for (count_index = start; count_index < end; count_index++) {
   1203                 title = 1;
   1204                 for (trig_typ = 0, i = 0; trig_typ < bcmDbgCntNum;
   1205                      trig_typ++) {
   1206                     cur_config = 0;
   1207                     rv = bcm_stat_custom_check(unit, port, count_index,
   1208                                                trig_typ, &cur_config);
   1209                     if (BCM_SUCCESS(rv) && cur_config) {
   1210                         if (title) {
   1211                             cli_out("\n%23s-\n\t\t",
   1212                                     stat_names[count_index]);
   1213                             title = 0;
   1214                         }
   1215                         cli_out("%s%s", _trig_names[trig_typ].name,
   1216                                 !((i + 1) % 5) ? "\n\t\t" : " ");
   1217                         i++;
   1218                     } else {
   1219                         continue;
   1220                     }
   1221                 }
   1222             }
   1223         }
   1224         cli_out("\n");
   1225         return;
   1226     }
   1227 
   1228 }
   1229 
   1230 /*
   1231  * Function:
   1232  *      cstat_stats_show
   1233  * Description:
   1234  *      Show programmable counters.
   1235  * Parameters:
   1236  *      unit    - StrataSwitch PCI device unit number.
   1237  *      pbmp    - Bitmap of ports.
   1238  *      rx_tx   - counter type to be displayed.
   1239  *      counter - counter number to be displayed.
   1240  *                -1 means all.
   1241  * Returns:
   1242  *      SUCCESS(0)/FAILURE(-1).
   1243  */
   1244 static int
   1245 cstat_stats_show(int unit, bcm_pbmp_t pbmp, int rx_tx, int counter)
   1246 {
   1247     uint32     count_index;
   1248     uint32     start;
   1249     uint32     end;
   1250     uint32     title;
   1251     uint64     value;
   1252     int        port, dport;
   1253     int        rv = 0;
   1254 
   1255     cli_out("%s Custom Statistics :\n", rx_tx == RDBGC ? "RX" : "TX");
   1256 
   1257     /* coverity[overrun-local] */
   1258     DPORT_BCM_PBMP_ITER(unit, pbmp, dport, port) {
   1259         switch (rx_tx) {
   1260             case RDBGC:
   1261                 start = (counter == -1) ? snmpBcmCustomReceive0 : counter;
   1262                 end = (counter == -1) ? snmpBcmCustomTransmit0 :
   1263                     counter + 1;
   1264                 title = 1;
   1265                 for (count_index = start; count_index < end; count_index++) {
   1266                     rv = bcm_stat_get(unit, port, count_index, &value);
   1267                     if (BCM_FAILURE(rv)) {
   1268                         cli_out("\t%18s\t%s (stat %d): %s\n", "-",
   1269                                 stat_names[count_index], count_index,
   1270                                 bcm_errmsg(rv));
   1271                         continue;
   1272                     }
   1273                     if (COMPILER_64_IS_ZERO(value)) {
   1274                         continue;
   1275                     }
   1276                     if (title) {
   1277                         cli_out(" %s:\n", SOC_PORT_NAME(unit, port));
   1278                         title = 0;
   1279                     }
   1280                     if (COMPILER_64_HI(value) == 0) {
   1281                         cli_out("    %18u\t%s (stat %d)\n",
   1282                                 COMPILER_64_LO(value),
   1283                                 stat_names[count_index], count_index);
   1284                     } else {
   1285                         cli_out("    0x%08x%08x\t%s (stat %d)\n",
   1286                                 COMPILER_64_HI(value),
   1287                                 COMPILER_64_LO(value),
   1288                                 stat_names[count_index], count_index);
   1289                     }
   1290                 }
   1291                 break;
   1292             case TDBGC:
   1293                 start = (counter == -1) ? snmpBcmCustomTransmit0 : counter;
   1294                 end = (counter == -1) ? snmpValCount : counter + 1;
   1295                 title = 1;
   1296                 for (count_index = start; count_index < end; count_index++) {
   1297                     rv = (bcm_stat_get(unit, port, count_index, &value));
   1298                     if (BCM_FAILURE(rv)) {
   1299                         cli_out("\t%18s\t%s (stat %d): %s\n", "-",
   1300                                 stat_names[count_index], count_index,
   1301                                 bcm_errmsg(rv));
   1302                         continue;
   1303                     }
   1304                     if (COMPILER_64_IS_ZERO(value)) {
   1305                         continue;
   1306                     }
   1307                     if (title) {
   1308                         cli_out(" %s:\n", SOC_PORT_NAME(unit, port));
   1309                         title = 0;
   1310                     }
   1311                     if (COMPILER_64_HI(value) == 0) {
   1312                         cli_out("    %18u\t%s (stat %d)\n",
   1313                                 COMPILER_64_LO(value),
   1314                                 stat_names[count_index], count_index);
   1315                     } else {
   1316                         cli_out("    0x%08x%08x\t%s (stat %d)\n",
   1317                                 COMPILER_64_HI(value),
   1318                                 COMPILER_64_LO(value),
   1319                                 stat_names[count_index], count_index);
   1320                     }
   1321                 }
   1322                 break;
   1323             default:
   1324                 cli_out("Invalid custom stats: valid values [RX,TX]\n");
   1325                 return -1;
   1326         }
   1327     }
   1328     cli_out("\n");
   1329     return rv;
   1330 }
   1331 
   1332 /*
   1333  * Function:
   1334  *      cstat_flags_set
   1335  * Description:
   1336  *      Set triggers for counters.
   1337  * Parameters:
   1338  *      unit    - StrataSwitch PCI device unit number.
   1339  *      pbmp    - Bitmap of ports.
   1340  *      rx_tx   - trigger type to be set.
   1341  *      counter - counter number to be programmed.
   1342  *      a       - argc/argv (sorta) structure for parsing arguments.
   1343  * Returns:
   1344  *      SUCCESS(0)/FAILURE(-1).
   1345  */
   1346 static int
   1347 cstat_flags_set(int unit, bcm_pbmp_t pbmp, int rx_tx, int counter,
   1348                 args_t * a)
   1349 {
   1350 
   1351     int        flags_index;
   1352     bcm_port_t port, dport;
   1353     uint32     count_index;
   1354     uint32     start;
   1355     uint32     end;
   1356 
   1357     if (!ARG_CUR(a)) {
   1358         cli_out("Error: No input triggers\n");
   1359         return -1;
   1360     }
   1361     /*
   1362      * save index of first flag 
   1363      */
   1364     flags_index = a->a_arg;
   1365 
   1366     /* coverity[overrun-local] */
   1367     DPORT_BCM_PBMP_ITER(unit, pbmp, dport, port) {
   1368         switch (rx_tx) {
   1369             case RDBGC:
   1370                 start = (counter == -1) ? snmpBcmCustomReceive3 : counter;
   1371                 end = (counter == -1) ? snmpBcmCustomTransmit0 :
   1372                     counter + 1;
   1373                 for (count_index = start; count_index < end; count_index++) {
   1374                     a->a_arg = flags_index;
   1375                     set_triggers(unit, port, count_index, a);
   1376                 }
   1377                 break;
   1378             case TDBGC:
   1379                 start = (counter == -1) ? snmpBcmCustomTransmit6 : counter;
   1380                 end = (counter == -1) ? snmpBcmCustomTransmit12 : counter + 1;
   1381                 for (count_index = start; count_index < end; count_index++) {
   1382                     a->a_arg = flags_index;
   1383                     set_triggers(unit, port, count_index, a);
   1384                 }
   1385                 break;
   1386             default:
   1387                  cli_out("Error: Invalid custom stats: valid values [RX,TX]\n");
   1388                 return -1;
   1389         }
   1390         break;
   1391     }
   1392     return 0;
   1393 }
   1394 
   1395 /*
   1396  * Function:
   1397  *      list_flags
   1398  * Description:
   1399  *      Display the triggers available for current device.
   1400  * Parameters:
   1401  *      unit  - StrataSwitch PCI device unit number.
   1402  *      about - (0/1) whether to display short description of each trigger?
   1403  *      rx_tx - trigger type to be displayed.
   1404  * Returns:
   1405  *      None.
   1406  */
   1407 static void
   1408 list_flags(int unit, int about, int rx_tx)
   1409 {
   1410     int        trig_typ;
   1411     int        res;
   1412     int        loop;
   1413     int        dummy_port = SOC_PORT_MIN(unit, port);
   1414 
   1415     cli_out("Custom stat\n");
   1416     if (rx_tx == RDBGC || rx_tx == BOTH) {
   1417         cli_out(" Available Rx trigger flags :\n  ");
   1418         for (trig_typ = 0, loop = 0; trig_typ < bcmDbgCntNum; trig_typ++) {
   1419             if (BCM_SUCCESS(bcm_stat_custom_check(unit, dummy_port,
   1420                                                   snmpBcmCustomReceive0,
   1421                                                   trig_typ, &res))) {
   1422                 if (!about) {
   1423                     cli_out("%-19s%s", _trig_names[trig_typ].name,
   1424                             !((loop + 1) % 4) ? "\n  " : "");
   1425                 } else {
   1426                     cli_out("%s%s\n  ", _trig_names[trig_typ].name,
   1427                             _trig_names[trig_typ].about);
   1428                 }
   1429                 loop++;
   1430             }
   1431         }
   1432         cli_out("\n");
   1433     }
   1434 
   1435     if (rx_tx == TDBGC || rx_tx == BOTH) {
   1436         cli_out(" Available Tx trigger flags :\n  ");
   1437         for (trig_typ = 0, loop = 0; trig_typ < bcmDbgCntNum; trig_typ++) {
   1438             if (BCM_SUCCESS(bcm_stat_custom_check(unit, dummy_port,
   1439                                                   snmpBcmCustomTransmit0,
   1440                                                   trig_typ, &res))) {
   1441                 if (!about) {
   1442                     cli_out("%-19s%s", _trig_names[trig_typ].name,
   1443                             !((loop + 1) % 4) ? "\n  " : "");
   1444                 } else {
   1445                     cli_out("%s%s\n  ", _trig_names[trig_typ].name,
   1446                             _trig_names[trig_typ].about);
   1447                 }
   1448                 loop++;
   1449             }
   1450         }
   1451         cli_out("\n");
   1452     }
   1453 }
   1454 
   1455 /*
   1456  * Function:
   1457  *      display_val
   1458  * Description:
   1459  *      Display value of counter.
   1460  * Parameters:
   1461  *      val          - Value to be displayed.
   1462  *      count_index  - Index of counter.
   1463  * Returns:
   1464  *      None.
   1465  */
   1466 static void
   1467 display_val(uint64 val, int count_index)
   1468 {
   1469 
   1470     char      *typ_s;
   1471     char      *no_s;
   1472 
   1473     typ_s = "  ";
   1474     no_s = "   ";
   1475 
   1476     if (count_index >= snmpBcmCustomTransmit0) {
   1477         if (count_index == snmpBcmCustomTransmit0) {
   1478             typ_s = "TX";
   1479         }
   1480         if (count_index < snmpBcmCustomTransmit6) {
   1481             no_s = "(R)";
   1482         }
   1483         count_index -= snmpBcmCustomTransmit0;
   1484     } else {
   1485         if (count_index == snmpBcmCustomReceive0) {
   1486             typ_s = "RX";
   1487         }
   1488         if (count_index < snmpBcmCustomReceive3) {
   1489             no_s = "(R)";
   1490         }
   1491         count_index -= snmpBcmCustomReceive0;
   1492     }
   1493 
   1494     cli_out("\n|  %s  |%2d%s|", typ_s, count_index, no_s);
   1495 
   1496     if (COMPILER_64_HI(val) == 0) {
   1497         cli_out("%19u| ", COMPILER_64_LO((val)));
   1498     } else {
   1499         cli_out(" 0x%08x%08x| ", COMPILER_64_HI(val), COMPILER_64_LO(val));
   1500     }
   1501 }
   1502 
   1503 /*
   1504  * Function:
   1505  *      list_table
   1506  * Description:
   1507  *      Display the counters and triggers in tabular format.
   1508  * Parameters:
   1509  *      unit  - StrataSwitch PCI device unit number.
   1510  *      pbmp  - Bitmap of ports.
   1511  *      show_zero - (0/1) Whether to include counters which are zero?
   1512  * Returns:
   1513  *      None.
   1514  */
   1515 static void
   1516 list_table(int unit, bcm_pbmp_t pbmp, int show_zero)
   1517 {
   1518 
   1519     int        n;
   1520     int        i;
   1521     int        j;
   1522     int        rv;
   1523     int        trig;
   1524     int        port = 0;
   1525     int        dport;
   1526     int        conf;
   1527     int        val_f;
   1528     int        title;
   1529     int        mid;
   1530     int        end;
   1531     char      *blnk = "                                             ";
   1532     uint64     value;
   1533 
   1534     /* coverity[overrun-local] */
   1535     DPORT_BCM_PBMP_ITER(unit, pbmp, dport, port) {
   1536         title = 1;
   1537         mid = 1;
   1538         end = 0;
   1539         for (n = snmpBcmCustomReceive0; n < snmpValCount; n++) {
   1540             rv = bcm_stat_get(unit, port, n, &value);
   1541             if (BCM_FAILURE(rv)) {
   1542                 continue;
   1543             }
   1544             if (!show_zero && (COMPILER_64_IS_ZERO(value))) {
   1545                 continue;
   1546             }
   1547             if (title) {
   1548                 /* coverity[non_const_printf_format_string] */
   1549                 cli_out(head, SOC_PORT_NAME(unit, (port)));
   1550                 cli_out("%s%s", menu, line);
   1551                 title = 0;
   1552                 end = 1;
   1553             }
   1554             if (n >= snmpBcmCustomTransmit0 && mid) {
   1555                 cli_out("%s", line);
   1556                 mid = 0;
   1557             }
   1558             val_f = 1;
   1559             j = 0;
   1560             for (trig = 0, i = 0; trig < bcmDbgCntNum; trig++) {
   1561                 conf = 0;
   1562                 rv = bcm_stat_custom_check(unit, port, n, trig, &conf);
   1563                 if (BCM_SUCCESS(rv) && conf) {
   1564                     if (val_f) {
   1565                         display_val(value, n);
   1566                         val_f = 0;
   1567                     }
   1568                     if (!((i + 1) % COL_SZ)) {
   1569                         cli_out("%.*s|%s", (int) (sal_strlen(blnk) - j),
   1570                                 blnk, trg_s);
   1571                         j = 0;
   1572                     }
   1573                     cli_out("%s ", _trig_names[trig].name);
   1574                     j = j + sal_strlen(_trig_names[trig].name) + 1;
   1575                     i++;
   1576                 }
   1577             }
   1578             if (j) {
   1579                 cli_out("%.*s|", (int) (sal_strlen(blnk) - j), blnk);
   1580             }
   1581         }
   1582         if (end) {
   1583             cli_out("%s", line);
   1584             end = 0;
   1585             cli_out("\n\n");
   1586         }
   1587     }
   1588 
   1589 }                               /* end of list_table */
   1590 
   1591 /*
   1592  * Function:
   1593  *      cmd_esw_custom_stat
   1594  * Description:
   1595  *      Main function to process CustomSTAT command.
   1596  * Parameters:
   1597  *      unit  - StrataSwitch PCI device unit number.
   1598  *      a     - argc/argv (sorta) structure for parsing arguments.
   1599  * Returns:
   1600  *      Result of command processing, SUCCESS, FAIL or print command usage.
   1601  */
   1602 cmd_result_t
   1603 cmd_esw_custom_stat(int unit, args_t * a)
   1604 {
   1605 
   1606     bcm_pbmp_t pbmp;
   1607     uint32     cmd_type;        /* show flags, set flags, show counters */
   1608     char      *c;
   1609     int        rx_tx;
   1610     int        rv = 0;
   1611     int        counter;         /* selected DBGC map, input */
   1612     int        display_zero;
   1613     int        display_info;
   1614 
   1615     if (!sh_check_attached(ARG_CMD(a), unit)) {
   1616         return CMD_FAIL;
   1617     }
   1618 
   1619     BCM_PBMP_CLEAR(pbmp);
   1620     BCM_PBMP_PORT_ADD(pbmp, 0); /* ge0 */
   1621     counter = -1;               /* all counters */
   1622     cmd_type = SHOW_TABLE;
   1623     rx_tx = BOTH;
   1624     display_zero = FALSE;
   1625     display_info = FALSE;
   1626 
   1627     if (!(c = ARG_GET(a))) {
   1628         goto do_stat_command;
   1629     } else {
   1630         if (!sal_strcasecmp(c, "ls")) {
   1631             cmd_type = LIST_FLAGS;
   1632         } else if (!sal_strcasecmp(c, "info")) {
   1633             cmd_type = LIST_FLAGS;
   1634             display_info = TRUE;
   1635         } else if (!sal_strcasecmp(c, "set")) {
   1636             cmd_type = SET_FLAGS;
   1637             c = ARG_GET(a);
   1638         } else if (!sal_strcasecmp(c, "get")) {
   1639             cmd_type = SHOW_FLAGS;
   1640             c = ARG_GET(a);
   1641         } else if (!sal_strcasecmp(c, "raw")) {
   1642             cmd_type = SHOW_COUNTERS;
   1643             c = ARG_GET(a);
   1644         }
   1645     }
   1646 
   1647     /*
   1648      * no input pbm 
   1649      */
   1650     if (!c) {
   1651         ERROR_SET_FLAGS("No input port\n");
   1652         goto do_stat_command;
   1653     } else if (cmd_type != LIST_FLAGS) {
   1654         if (parse_bcm_pbmp(unit, c, &pbmp) < 0) {
   1655             cli_out("%s: Error: unrecognized port bitmap: %s\n", ARG_CMD(a),
   1656                     c);
   1657             return CMD_FAIL;
   1658         }
   1659     }
   1660 
   1661     /*
   1662      * RX/TX ? 
   1663      */
   1664     if (!(c = ARG_GET(a))) {
   1665         ERROR_SET_FLAGS("No input type[rx|tx]\n");
   1666         goto do_stat_command;
   1667     } else {
   1668         if (!sal_strcasecmp(c, "rx")) {
   1669             rx_tx = RDBGC;
   1670         } else if (!sal_strcasecmp(c, "tx")) {
   1671             rx_tx = TDBGC;
   1672         } else if (sal_toupper((int)c[0]) == 'Z') {
   1673             display_zero = TRUE;
   1674             goto do_stat_command;
   1675         } else {
   1676             cli_out("Invalid input '%s'\n", c);
   1677             return CMD_FAIL;
   1678         }
   1679 
   1680     /*    coverity[new_values]    */
   1681         if (cmd_type == LIST_FLAGS) {
   1682             goto do_stat_command;
   1683         }
   1684     }
   1685 
   1686     /*
   1687      * counter bitmap 
   1688      */
   1689     if (!(c = ARG_GET(a))) {
   1690         ERROR_SET_FLAGS("No input counter\n");
   1691         goto do_stat_command;
   1692     } else {
   1693         if (!sal_strcasecmp(c, "all")) {
   1694             goto do_stat_command;
   1695         } else if (!get_counter(c, rx_tx, &counter)) {
   1696             goto do_stat_command;
   1697         } else {
   1698             cli_out("Invalid counter\n");
   1699             return CMD_FAIL;
   1700         }
   1701     }
   1702 
   1703   do_stat_command:
   1704     switch (cmd_type) {
   1705         case SHOW_FLAGS:
   1706             if (rx_tx == BOTH) {
   1707                 cstat_flags_show(unit, pbmp, RDBGC, counter);
   1708                 cstat_flags_show(unit, pbmp, TDBGC, counter);
   1709             } else {
   1710                 cstat_flags_show(unit, pbmp, rx_tx, counter);
   1711             }
   1712             break;
   1713         case SHOW_COUNTERS:
   1714             if (rx_tx == BOTH) {
   1715                 rv = cstat_stats_show(unit, pbmp, RDBGC, counter);
   1716                 rv = cstat_stats_show(unit, pbmp, TDBGC, counter);
   1717             } else {
   1718                 rv = cstat_stats_show(unit, pbmp, rx_tx, counter);
   1719             }
   1720             break;
   1721         case SHOW_TABLE:
   1722             list_table(unit, pbmp, display_zero);
   1723             break;
   1724         case SET_FLAGS:
   1725             rv = cstat_flags_set(unit, pbmp, rx_tx, counter, a);
   1726             break;
   1727         case LIST_FLAGS:
   1728             list_flags(unit, display_info, rx_tx);
   1729             break;
   1730         /* coverity[dead_error_begin] */
   1731         default:
   1732             /*
   1733              * should not reach here
   1734              */
   1735             return CMD_FAIL;
   1736     }
   1737 
   1738     if (rv < 0) {
   1739         return CMD_FAIL;
   1740     }
   1741 
   1742     return CMD_OK;
   1743 
   1744 }
   1745