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

tcam.c (31712B)


      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  * Diag CLI "tcam" command (5660x devices only)
      8  */
      9 
     10 #include <soc/defs.h>
     11 #if defined(BCM_TRIUMPH_SUPPORT)
     12 #include <shared/bsl.h>
     13 #include <appl/diag/system.h>
     14 #include <bcm/error.h>
     15 #include <soc/er_tcam.h>
     16 #include <soc/triumph.h>
     17 #include <soc/triumph3.h>
     18 
     19 char cmd_tcam_usage[] =
     20     "Usages:\n"
     21 #ifdef COMPILER_STRING_CONST_LIMIT
     22     "\t  tcam <subcmd> [options]\n"
     23 #else
     24     "\t  tcam info\n"
     25     "\t       - Show tcam configuration\n"
     26     "\t  tcam write Partition=<part> Index=<index> Mask=<mask> Data=<data>\n"
     27     "\t             [Count=<count>][Valid=<v>]\n"
     28     "\t  tcam dump Partition=<part> Index=<index> [Count=<count>]\n"
     29     "\t            [Display=<boolean>]\n"
     30     "\t  tcam search Partition=<part> [Partition2=<part>][Upper] Data=<data>\n"
     31     "\t  tcam ib Addr=address Data=opcode\n"
     32     "\t  tcam ima Addr=address [Data=<data>]\n"
     33     "\t  tcam dbreg Addr=address [Data=<data>]\n"
     34     "\t  tcam calc Partition=<part> Index=<index> Table=<table>\n"
     35     "\t  tcam prbs <set>|<get>|<clear> [poly={0|1|2|3}] <seed> \n"
     36     "\t       -For ex: \n" 
     37     "\t        tcam prbs set poly=3 seed=0xaaaaaaaa\n" 
     38     "\t  tcam latency\n"
     39     "\t       - Calculate external tcam request response latency\n"
     40     "\t \n"
     41 #endif
     42 ;
     43 
     44 static const char *partition_names[] = {
     45   "RAW",
     46   "ACL",
     47   "LPM",
     48   "FWD_L2",
     49   "FWD_L2_WIDE",
     50   "FWD_IP4_UCAST",
     51   "FWD_IP4_UCAST_WIDE",
     52   "FWD_IP4",
     53   "FWD_IP6U",
     54   "FWD_IP6_UCAST",
     55   "FWD_IP6_UCAST_WIDE",
     56   "FWD_IP6",
     57   "ACL_L2",
     58   "ACL_IP4",
     59   "ACL_IP6S",
     60   "ACL_IP6F",
     61   "ACL_L2C",
     62   "ACL_IP4C",
     63   "ACL_IP6C",
     64   "ACL_L2IP4",
     65   "ACL_L2IP6",
     66   "DEV0_TBL72",
     67   "DEV0_TBL144",
     68   "DEV1_TBL72",
     69   "DEV1_TBL144",
     70   "ACL_80",
     71   "ACL_160",
     72   "ACL_320",
     73   "ACL_480",
     74   "FWD_L2_DUPLICATE",
     75   "FWD_IP4_DUPLICATE",
     76   "FWD_IP6U_DUPLICATE",
     77   "FWD_IP6_DUPLICATE",
     78   NULL
     79 };
     80 
     81 static const char *partition_descs[] = {
     82   "",
     83   "",
     84   "",
     85   "L2 forwarding table",
     86   "L2 forwarding table (wide)",
     87   "IPv4 host table",
     88   "IPv4 host table(wide)",
     89   "IPv4 forwarding table",
     90   "IPv6 64-bit forwarding table",
     91   "IPv6 128-bit host forwarding table",
     92   "IPv6 128-bit host forwarding table(wide)",
     93   "IPv6 128-bit forwarding table",
     94   "L2 288-bit ACL table",
     95   "IPv4 288-bit ACL table",
     96   "IPv6 360-bit ACL table",
     97   "IPv6 432-bit ACL table",
     98   "L2 144-bit ACL table",
     99   "IPv4 144-bit ACL table",
    100   "IPv6 144-bit ACL table",
    101   "L2 + IPv4 432-bit ACL table",
    102   "L2 + IPv6 432-bit ACL table",
    103   "Device 0 72-bit test table",
    104   "Device 0 144-bit test table",
    105   "Device 1 72-bit test table",
    106   "Device 1 144-bit test table",
    107   "ACL 80",
    108   "ACL 160",
    109   "ACL 320",
    110   "ACL 480",
    111   "Duplicated L2 forwarding table",
    112   "Duplicated IPv4 forwarding table",
    113   "Duplicated IPv6 64 forwarding table",
    114   "Duplicated IPv6 128 forwarding table",
    115 };
    116 
    117 /*
    118  * convert hex string to multiple groups of 72-bit binary
    119  * each 72-bit binary group is padded and stored in a 128-bit unit
    120  * for multiple 72-bit group, LS bit is in highest offset unit
    121  * for example: convert following 128-bit string to 144-bit binary
    122  * hex: [0x]1234567890abcdef1357924680acebdf
    123  * bin: 00000000 00000000 00123456 7890abcd 00000000 000000ef 13579246 80acebdf
    124  */
    125 STATIC int
    126 hex_to_72bit_unit_bin(char *hex_str, uint32 *bin_str, int num_unit)
    127 {
    128     int len, len_per_unit, len_per_word, unit_idx, word_idx, nibble_idx;
    129     uint32 value;
    130     char hex_nibble;
    131 
    132     if (hex_str[0] == '0' && (hex_str[1] | 0x20) == 'x') {
    133         hex_str += 2;
    134     }
    135 
    136     len = strlen(hex_str);
    137     for (unit_idx = num_unit - 1; unit_idx >= 0; unit_idx--) {
    138         len_per_unit = len > 18 ? 18 : len;
    139         len -= len_per_unit;
    140         for (word_idx = 3; word_idx >= 0; word_idx--) {
    141             len_per_word = len_per_unit > 8 ? 8 : len_per_unit;
    142             len_per_unit -= len_per_word;
    143             value = 0;
    144             for (nibble_idx = 0; nibble_idx < len_per_word; nibble_idx++) {
    145                 value <<= 4;
    146                 hex_nibble = hex_str[len + len_per_unit + nibble_idx];
    147                 if (hex_nibble >= '0' && hex_nibble <= '9') {
    148                     value |= hex_nibble - '0';
    149                 } else {
    150                     hex_nibble |= 0x20;
    151                     if (hex_nibble >= 'a' && hex_nibble <= 'f') {
    152                         value |= hex_nibble - 'a' + 0x0a;
    153                     } else {
    154                         return CMD_FAIL;
    155                     }
    156                 }
    157             }
    158             bin_str[unit_idx * 4 + word_idx] = value;
    159         }
    160     }
    161 
    162     return CMD_OK;
    163 }
    164 
    165 STATIC int
    166 hex_to_80bit_unit_bin(char *hex_str, uint32 *bin_str, int num_unit)
    167 {
    168     int len, len_per_unit, len_per_word, unit_idx, word_idx, nibble_idx;
    169     uint32 value;
    170     char hex_nibble;
    171 
    172     if (hex_str[0] == '0' && (hex_str[1] | 0x20) == 'x') {
    173         hex_str += 2;
    174     }
    175 
    176     len = strlen(hex_str);
    177     for (unit_idx = num_unit - 1; unit_idx >= 0; unit_idx--) {
    178         len_per_unit = len > 20 ? 20 : len;
    179         len -= len_per_unit;
    180         for (word_idx = 3; word_idx >= 0; word_idx--) {
    181             len_per_word = len_per_unit > 8 ? 8 : len_per_unit;
    182             len_per_unit -= len_per_word;
    183             value = 0;
    184             for (nibble_idx = 0; nibble_idx < len_per_word; nibble_idx++) {
    185                 value <<= 4;
    186                 hex_nibble = hex_str[len + len_per_unit + nibble_idx];
    187                 if (hex_nibble >= '0' && hex_nibble <= '9') {
    188                     value |= hex_nibble - '0';
    189                 } else {
    190                     hex_nibble |= 0x20;
    191                     if (hex_nibble >= 'a' && hex_nibble <= 'f') {
    192                         value |= hex_nibble - 'a' + 0x0a;
    193                     } else {
    194                         return CMD_FAIL;
    195                     }
    196                 }
    197             }
    198             bin_str[unit_idx * 4 + word_idx] = value;
    199         }
    200     }
    201 
    202     return CMD_OK;
    203 }
    204 
    205 cmd_result_t
    206 cmd_tcam(int u, args_t * a)
    207 {
    208     soc_tcam_partition_t *partition;
    209     char * subcmd;
    210     parse_table_t pt;
    211     int rv, part, index, addr, valid, count, display, i, j;
    212     char *mask_str, *data_str, *table_str;
    213     uint32 mask[32], data[32];
    214     soc_tcam_info_t *tcam_info;
    215     int type, subtype, width;
    216 #ifdef BCM_TRIUMPH3_SUPPORT
    217     int idx;
    218 #endif
    219 
    220     if ((subcmd = ARG_GET(a)) == NULL) {
    221         return CMD_USAGE;
    222     }
    223 
    224 #ifdef BCM_TRIUMPH3_SUPPORT
    225     if (!SOC_IS_TRIUMPH3(u)) {
    226 #endif
    227         rv = soc_tcam_get_info(u, &type, &subtype, NULL, &tcam_info);
    228         if (rv >= 0 &&
    229             (!type || !tcam_info->partitions[TCAM_PARTITION_RAW].num_entries)) {
    230             rv = SOC_E_INIT;
    231         }
    232         if (rv < 0) {
    233             cli_out("%s: ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
    234             return CMD_FAIL;
    235         }
    236 #ifdef BCM_TRIUMPH3_SUPPORT
    237     } else {
    238         rv = soc_tcam_get_info(u, &type, &subtype, NULL, &tcam_info);
    239         type=0; subtype=0;
    240         if ((rv < 0) || (tcam_info == NULL)) {
    241             cli_out("TCAM info not found. Not initialized\n");
    242             return CMD_FAIL;
    243         }
    244     }
    245 #endif /* BCM_TRIUMPH3_SUPPORT */
    246 
    247     rv = SOC_E_NONE;
    248     if (sal_strcasecmp(subcmd, "init") == 0) {
    249 #if defined(BCM_TRIUMPH3_SUPPORT)
    250         if (SOC_IS_TRIUMPH3(u)) {
    251             if (soc_feature(u, soc_feature_esm_support)) {
    252                 SOC_IF_ERROR_RETURN(soc_tr3_esm_init_read_config(u));
    253                 if (SOC_CONTROL(u)->tcam_info) {
    254                     SOC_IF_ERROR_RETURN(soc_tr3_esmif_init(u));
    255                 }
    256             }
    257             soc_tcam_init(u);
    258             soc_triumph3_esm_init(u);
    259             cli_out("esm init done\n");
    260         } else {
    261 #endif
    262             soc_tcam_init(u);
    263 #if defined(BCM_TRIUMPH3_SUPPORT)
    264         }
    265 #endif
    266     } else if (sal_strcasecmp(subcmd, "info") == 0) {
    267         cli_out("tcam type %d subtype %d", type, subtype);
    268 #ifdef BCM_TRIUMPH3_SUPPORT
    269         if (SOC_IS_TRIUMPH3(u)) {
    270             for (idx = 0; idx < tr3_tcam_partition_order_num_entries; idx++) {
    271                 i = tr3_tcam_partition_order[idx];
    272                 if (i == 0) {
    273                     continue;
    274                 }
    275                 partition = &tcam_info->partitions[i];
    276                 if (partition->num_entries) {
    277                     cli_out("\n%-10s %s",
    278                             partition_names[i], partition_descs[i]);
    279                     cli_out("\n           %d entries",
    280                             partition->num_entries);
    281                     if (partition->num_entries_include_pad !=
    282                         partition->num_entries) {
    283                         cli_out(" plus %d padded entries",
    284                                 partition->num_entries_include_pad -
    285                                 partition->num_entries);
    286                     }
    287                     cli_out("\n           tcam_base:0x%x width:%d-bit",
    288                             partition->tcam_base,
    289                             80 << partition->tcam_width_shift);
    290                     cli_out("\n           ad_ba:%d ad_ra_base:%d ad_ca:%d",
    291                             partition->ad_info.ad_ba,
    292                             partition->ad_info.ad_ra_base,
    293                             partition->ad_info.ad_ca);
    294                     cli_out("\n           ad_width:%d et_width:%d",
    295                             35 * (partition->ad_info.ad_width + 1), 
    296                             80 << partition->ad_info.et_width);
    297                     if (partition->ad_info.hit_bit_enable) {
    298                         cli_out("\n           hit_bit_pa_base:%d",
    299                                 partition->ad_info.hit_bit_pa_base); 
    300                     }
    301                 }
    302             }
    303         } else {
    304 #endif
    305             for (i = TCAM_PARTITION_RAW + 1; i < TCAM_PARTITION_COUNT; i++) {
    306                 partition = &tcam_info->partitions[i];
    307                 if (partition->num_entries) {
    308                     cli_out("\n%-10s %s",
    309                             partition_names[i], partition_descs[i]);
    310                     cli_out("\n           %d entries",
    311                             partition->num_entries);
    312                     if (partition->num_entries_include_pad !=
    313                         partition->num_entries) {
    314                         cli_out(" plus %d padded entries",
    315                                 partition->num_entries_include_pad -
    316                                 partition->num_entries);
    317                     }
    318                     cli_out("\n           tcam_base:0x%x width:%d-bit",
    319                             partition->tcam_base,
    320                             72 << partition->tcam_width_shift);
    321                     if (partition->sram_base >= 0) {
    322                         cli_out("\n           sram_base:0x%x-0x%x width:%d-bit in",
    323                                 partition->sram_base,
    324                                 partition->sram_base +
    325                                 ((partition->num_entries_include_pad - 1) <<
    326                                 partition->sram_width_shift),
    327                                 SOC_IS_TRIUMPH3(u) ? 40 << partition->sram_width_shift :
    328                                 36 << partition->sram_width_shift);
    329                         if (partition->flags &
    330                             TCAM_PARTITION_FLAGS_AD_IN_SRAM0) {
    331                             cli_out(" sram0");
    332                         }
    333                         if (partition->flags &
    334                             TCAM_PARTITION_FLAGS_AD_IN_SRAM1) {
    335                             cli_out(" sram1");
    336                         }
    337                     }
    338                     if (partition->counter_base >= 0) {
    339                         cli_out("\n           counter_base:0x%x in %s",
    340                                 partition->counter_base, partition->flags &
    341                                 TCAM_PARTITION_FLAGS_COUNTER_IN_SRAM0 ?
    342                                 "sram0" : "sram1");
    343                     }
    344                     if (partition->hbit_base >= 0) {
    345                         cli_out("\n           hbit_base:0x%x",
    346                                 partition->hbit_base);
    347                     }
    348                 }
    349             }
    350 #ifdef BCM_TRIUMPH3_SUPPORT
    351         } /* SOC_IS_TRIUMPH3 */
    352 #endif
    353         cli_out("\n");
    354     } else if (sal_strcasecmp(subcmd, "write") == 0) {
    355         uint32 mask_r[32], data_r[32], pattern;
    356         int valid_r, readback, search;
    357 
    358         parse_table_init(u, &pt);
    359         parse_table_add(&pt, "Partition", PQ_MULTI, 0, &part, partition_names);
    360         parse_table_add(&pt, "Index", PQ_INT, (void *)-1, &index, 0);
    361         parse_table_add(&pt, "Mask", PQ_STRING, 0, &mask_str, 0);
    362         parse_table_add(&pt, "Data", PQ_STRING, 0, &data_str, 0);
    363         parse_table_add(&pt, "Pattern", PQ_INT, (void *)0, &pattern, 0);
    364         parse_table_add(&pt, "Valid", PQ_INT, (void *)-1, &valid, 0);
    365         parse_table_add(&pt, "Count", PQ_INT, (void *)1, &count, 0);
    366         parse_table_add(&pt, "Readback", PQ_INT, (void *)0, &readback, 0);
    367         parse_table_add(&pt, "Search", PQ_INT, (void *)0, &search, 0);
    368 
    369         if (parse_arg_eq(a, &pt) < 0 || index < 0 ||
    370             !mask_str[0] || !data_str[0]) {
    371             parse_arg_eq_done(&pt);
    372             return CMD_USAGE;
    373         }
    374         width = 1 << tcam_info->partitions[part].tcam_width_shift;
    375         SOC_IS_TRIUMPH3(u) ? hex_to_80bit_unit_bin(mask_str, mask, width) :
    376                              hex_to_72bit_unit_bin(mask_str, mask, width);
    377 
    378         SOC_IS_TRIUMPH3(u) ? hex_to_80bit_unit_bin(data_str, data, width) :
    379                              hex_to_72bit_unit_bin(data_str, data, width);
    380 
    381 
    382         parse_arg_eq_done(&pt);
    383 
    384         for (i = 0; i < count; i++) {
    385             rv = soc_tcam_write_entry(u, part, index + i, mask, data);
    386             if (rv < 0) {
    387                 break;
    388             }
    389             if (valid != -1) {
    390                 rv = soc_tcam_set_valid(u, part, index + i, valid);
    391                 if (rv < 0) {
    392                     break;
    393                 }
    394             }
    395             if (readback) {
    396                 rv = soc_tcam_read_entry(u, part, index + i, mask_r, data_r,
    397                                          &valid_r);
    398                 if (rv < 0) {
    399                     break;
    400                 }
    401                 if ((data[1] ^ data_r[1]) & 0xff ||
    402                     (mask[1] ^ mask_r[1]) & 0xff ||
    403                     data[2] != data_r[2] || data[3] != data_r[3]) {
    404                     cli_out("Mismatched readback: index %d\n", index + i);
    405                 }
    406                 if (width == 2) {
    407                     if ((data[5] ^ data_r[5]) & 0xff ||
    408                         (mask[5] ^ mask_r[5]) & 0xff ||
    409                         data[6] != data_r[6] || data[7] != data_r[7]) {
    410                         cli_out("Mismatched readback: index %d\n", index + i);
    411                     }
    412                 }
    413             }
    414             data[width * 4 - 1] += 0x100;
    415         }
    416     } else if (sal_strcasecmp(subcmd, "dump") == 0) {
    417         parse_table_init(u, &pt);
    418         parse_table_add(&pt, "Partition", PQ_MULTI, 0, &part, partition_names);
    419         parse_table_add(&pt, "Index", PQ_INT, (void *)-1, &index, 0);
    420         parse_table_add(&pt, "Count", PQ_INT, (void *)1, &count, 0);
    421         parse_table_add(&pt, "Display", PQ_INT, (void *)1, &display, 0);
    422 
    423         if (parse_arg_eq(a, &pt) < 0 || index < 0) {
    424             parse_arg_eq_done(&pt);
    425             return CMD_USAGE;
    426         }
    427         parse_arg_eq_done(&pt);
    428 
    429         width = 1 << tcam_info->partitions[part].tcam_width_shift;
    430         if (SOC_IS_TRIUMPH3(u)) {
    431             if (width == 8) width = 6;
    432         }
    433         for (i = 0; i < count; i++) {
    434             rv = soc_tcam_read_entry(u, part, index + i, mask, data, &valid);
    435             if (rv < 0) {
    436                 break;
    437             }
    438             if (!display) {
    439                 continue;
    440             }
    441             cli_out("%d: V=%d ", index + i, valid);
    442             cli_out("MASK=");
    443             for (j = 0; j < width; j++) {
    444                 if (SOC_IS_TRIUMPH3(u)) {
    445                     cli_out("%4.4x%8.8x%8.8x",
    446                             mask[j * 4 + 1], mask[j * 4 + 2], mask[j * 4 + 3]);
    447                 } else {
    448                     cli_out("%2.2x%8.8x%8.8x",
    449                             mask[j * 4 + 1], mask[j * 4 + 2], mask[j * 4 + 3]);
    450                 }
    451             }
    452             cli_out(" DATA=");
    453             for (j = 0; j < width; j++) {
    454                 if (SOC_IS_TRIUMPH3(u)) {
    455                     cli_out("%4.4x%8.8x%8.8x",
    456                             data[j * 4 + 1], data[j * 4 + 2], data[j * 4 + 3]);
    457                 } else {
    458                     cli_out("%2.2x%8.8x%8.8x",
    459                             data[j * 4 + 1], data[j * 4 + 2], data[j * 4 + 3]);
    460                 }
    461             }
    462             cli_out("\n");
    463         }
    464     } else if (sal_strcasecmp(subcmd, "search") == 0) {
    465         int upper, part2, index2, bist;
    466 
    467         sal_memset(data, 0, sizeof(data));
    468 
    469         parse_table_init(u, &pt);
    470         parse_table_add(&pt, "Partition", PQ_MULTI, 0, &part, partition_names);
    471         parse_table_add(&pt, "Partition2", PQ_MULTI, 0, &part2,
    472                         partition_names);
    473         parse_table_add(&pt, "Data", PQ_STRING, 0, &data_str, 0);
    474         parse_table_add(&pt, "Upper", PQ_INT, (void *)0, &upper, 0);
    475         parse_table_add(&pt, "Bist", PQ_INT, (void *)0, &bist, 0);
    476         parse_table_add(&pt, "Index", PQ_INT, (void *)0, &index, 0);
    477         parse_table_add(&pt, "Index2", PQ_INT, (void *)0, &index2, 0);
    478 
    479         if (parse_arg_eq(a, &pt) < 0 || !data_str[0]) {
    480             parse_arg_eq_done(&pt);
    481             return CMD_USAGE;
    482         }
    483         width = tcam_info->partitions[part].tcam_width_shift >
    484             tcam_info->partitions[part2].tcam_width_shift ?
    485             1 << tcam_info->partitions[part].tcam_width_shift :
    486             1 << tcam_info->partitions[part2].tcam_width_shift;
    487         SOC_IS_TRIUMPH3(u) ? hex_to_80bit_unit_bin(data_str, data, width) :
    488                              hex_to_72bit_unit_bin(data_str, data, width);
    489         parse_arg_eq_done(&pt);
    490 
    491         if (soc_feature(u, soc_feature_esm_support)) {
    492 #if defined(BCM_TRIUMPH_SUPPORT)
    493             if (bist) {
    494                 rv = soc_triumph_tcam_search_bist(u, part, part2, data, index,
    495                                                   index2, 10000);
    496             } else
    497 #endif /* BCM_TRIUMPH_SUPPORT */
    498             {
    499                 rv = soc_tcam_search_entry(u, part, part2, data, &index,
    500                                            &index2);
    501                 if(SOC_IS_TRIUMPH3(u)) {
    502                     if (rv >= 0) {
    503                         if(!(index & 0x40000000)) {
    504                             cli_out("NOT FOUND\n");
    505                         } else {
    506                             /* for single search, dbus[1] bits 23-0 have result */
    507                             index = index & 0x7FFFFF;
    508                             cli_out("Index=0x%x 0x%x\n", index, index2);
    509                         }
    510                     } else if (rv == SOC_E_NOT_FOUND) {
    511                         cli_out("NOT FOUND\n");
    512                         rv = SOC_E_NONE;
    513                     }
    514                 } else {
    515                     if (rv >= 0) {
    516                         cli_out("Index=0x%x 0x%x\n", index, index2);
    517                     } else if (rv == SOC_E_NOT_FOUND) {
    518                         cli_out("NOT FOUND\n");
    519                         rv = SOC_E_NONE;
    520                     }
    521                 }
    522             }
    523         }
    524     } else if (sal_strcasecmp(subcmd, "ib") == 0) {
    525         parse_table_init(u, &pt);
    526         parse_table_add(&pt, "Addr", PQ_INT, (void *) -1, &addr, 0);
    527         parse_table_add(&pt, "Data", PQ_STRING, 0, &data_str, 0);
    528 
    529         if (parse_arg_eq(a, &pt) < 0) {
    530             parse_arg_eq_done(&pt);
    531             return CMD_USAGE;
    532         }
    533         hex_to_72bit_unit_bin(data_str, data, 1);
    534         parse_arg_eq_done(&pt);
    535 
    536         rv = soc_tcam_write_ib(u, addr, data[3]);
    537     } else if (sal_strcasecmp(subcmd, "ima") == 0) {
    538         parse_table_init(u, &pt);
    539         parse_table_add(&pt, "Addr", PQ_INT, (void *)-1, &addr, 0);
    540         parse_table_add(&pt, "Data", PQ_STRING, 0, &data_str, 0);
    541 
    542         if (parse_arg_eq(a, &pt) < 0 || addr < 0) {
    543             parse_arg_eq_done(&pt);
    544             return CMD_USAGE;
    545         }
    546         display = !data_str[0];
    547         SOC_IS_TRIUMPH3(u) ? hex_to_80bit_unit_bin(data_str, data, 1) :
    548                              hex_to_72bit_unit_bin(data_str, data, 1);
    549         parse_arg_eq_done(&pt);
    550 
    551         if (display) {
    552             rv = soc_tcam_read_ima(u, addr, &data[2], &data[3]);
    553             if (rv >= 0) {
    554                 cli_out("Read from addr 0x%08x: 0x%08x %08x\n",
    555                         addr, data[2], data[3]);
    556             }
    557         } else {
    558             rv = soc_tcam_write_ima(u, addr, data[2], data[3]);
    559         }
    560     } else if (sal_strcasecmp(subcmd, "dbreg") == 0) {
    561         parse_table_init(u, &pt);
    562         parse_table_add(&pt, "Addr", PQ_INT, (void *)-1, &addr, 0);
    563         parse_table_add(&pt, "Data", PQ_STRING, 0, &data_str, 0);
    564 
    565         if (parse_arg_eq(a, &pt) < 0 || addr < 0) {
    566             parse_arg_eq_done(&pt);
    567             return CMD_USAGE;
    568         }
    569         display = !data_str[0];
    570         SOC_IS_TRIUMPH3(u) ? hex_to_80bit_unit_bin(data_str, data, 1) :
    571                              hex_to_72bit_unit_bin(data_str, data, 1);
    572         parse_arg_eq_done(&pt);
    573 
    574         if (display) {
    575             rv = soc_tcam_read_dbreg(u, addr, &data[1], &data[2], &data[3]);
    576             if (rv >= 0) {
    577                 cli_out("Read from addr 0x%08x: 0x%08x 0x%08x %08x\n",
    578                         addr, data[1], data[2], data[3]);
    579             }
    580         } else {
    581             rv = soc_tcam_write_dbreg(u, addr, data[1], data[2], data[3]);
    582         }
    583     } else if (sal_strcasecmp(subcmd, "calc") == 0) {
    584         int copyno, mem_index, raw_index;
    585         soc_mem_t mem, real_mem;
    586 
    587         parse_table_init(u, &pt);
    588         parse_table_add(&pt, "Partition", PQ_MULTI, 0, &part, partition_names);
    589         parse_table_add(&pt, "Index", PQ_INT, (void *)-1, &index, 0);
    590         parse_table_add(&pt, "Table", PQ_STRING, 0, &table_str, 0);
    591 
    592         if (parse_arg_eq(a, &pt) < 0 || index < 0) {
    593             parse_arg_eq_done(&pt);
    594             return CMD_USAGE;
    595         }
    596         if (parse_memory_name(u, &mem, table_str, &copyno, 0) < 0) {
    597             cli_out("%s: ERROR: unknown table %s\n", ARG_CMD(a), table_str);
    598             parse_arg_eq_done(&pt);
    599             return CMD_FAIL;
    600         }
    601         parse_arg_eq_done(&pt);
    602 
    603 	rv = soc_tcam_part_index_to_mem_index(u, part, index, mem, &mem_index);
    604         if (rv >= 0) {
    605 	    rv = soc_tcam_mem_index_to_raw_index(u, mem, mem_index,
    606                                                  &real_mem, &raw_index);
    607             if (rv >= 0) {
    608                 cli_out("logical index 0x%x raw index 0x%x\n",
    609                         mem_index, raw_index);
    610             }
    611         }
    612     } else if (sal_strcasecmp(subcmd, "prbs") == 0) {
    613 #ifdef BCM_TRIUMPH3_SUPPORT
    614         char *str = NULL;
    615         uint32 seed = 0x0, poly = 0;
    616         uint32 enable = 0;
    617         uint16 cmd = 0;
    618         uint32 status;
    619         uint16 max_lane = 0, num_tcams = 0, nl_dev_id = 0, lane = 0;
    620         uint16 crx_lanes = 0, ctx_lanes = 0, mdio_portid = 0, prbs_pass = 1;
    621         enum { _PHY_PRBS_SET_CMD, _PHY_PRBS_GET_CMD, _PHY_PRBS_CLEAR_CMD };
    622 
    623         if ((str = ARG_GET(a)) == NULL) {
    624             return CMD_USAGE;
    625         }
    626 
    627         if (sal_strcasecmp(str, "set") == 0) {
    628             cmd = _PHY_PRBS_SET_CMD;
    629             enable = 1;
    630         } else if (sal_strcasecmp(str, "get") == 0) {
    631             cmd = _PHY_PRBS_GET_CMD;
    632             enable = 0;
    633         } else if (sal_strcasecmp(str, "clear") == 0) {
    634             cmd = _PHY_PRBS_CLEAR_CMD;
    635             enable = 0;
    636         } else return CMD_USAGE;
    637 
    638         parse_table_init(u, &pt);
    639         parse_table_add(&pt, "poly", PQ_DFL|PQ_INT,
    640                 (void *)(0), &poly, NULL);
    641         parse_table_add(&pt, "seed", PQ_DFL|PQ_INT,
    642                 (void *)(0), &seed, NULL);
    643 
    644         if (parse_arg_eq(a, &pt) < 0) {
    645             cli_out("Error: invalid option: %s\n", ARG_CUR(a));
    646             parse_arg_eq_done(&pt);
    647             return CMD_USAGE;
    648         }
    649 
    650         /* Now free allocated strings */
    651         parse_arg_eq_done(&pt);
    652 
    653         num_tcams = ((soc_tcam_info_t *)SOC_CONTROL(u)->tcam_info)->num_tcams;
    654         max_lane = 23;
    655 
    656         
    657         if(num_tcams >1) {
    658             max_lane = 15;
    659         }
    660 
    661         if((cmd == _PHY_PRBS_SET_CMD) || 
    662                 (cmd == _PHY_PRBS_CLEAR_CMD)) {
    663 
    664             /* Enable prbs generation from TR3 */ 
    665             for(lane=0; lane <= max_lane; ++lane) {
    666                 if ((poly <= 3) && (poly !=1)) {
    667                     rv = wcmod_esm_serdes_control_set(u, 
    668                             lane, 
    669                             SOC_PHY_CONTROL_PRBS_POLYNOMIAL,   
    670                             &poly);
    671                     if( rv != BCM_E_NONE) {
    672                         cli_out("Setting prbs polynomial failed on ESM SerDes\n");
    673                         return CMD_FAIL;
    674                     }
    675                     /* Tx enable */
    676                     rv = wcmod_esm_serdes_control_set(u, 
    677                             lane, 
    678                             SOC_PHY_CONTROL_PRBS_TX_ENABLE,   
    679                             &enable);
    680                     if( rv != BCM_E_NONE) {
    681                         cli_out("Setting prbs tx enable failed\n");
    682                         return CMD_FAIL;
    683                     }
    684                 } else {
    685                     cli_out("Polynomial must be a value of 0,2,3, inclusive.\n");
    686                     return CMD_FAIL;
    687                 }
    688 
    689             }
    690             /* Enable prbs checkers on all the tcams */
    691             for(nl_dev_id=0; nl_dev_id < num_tcams; ++nl_dev_id) {
    692                 mdio_portid = mdio_portid_get(u, nl_dev_id);
    693                 /* CRX lanes active for all tcams except the first
    694                    TCAM in the chain directly connected to request \
    695                    line(tx) of serdes (nl_dev_id = 0)*/
    696                 crx_lanes = nl_dev_id? 1 : 0;
    697                 rv = nl_mdio_prbs_chk(u, mdio_portid, poly, seed, crx_lanes, enable);
    698                 if(rv < 0) {
    699                     cli_out("Enabling prbs checker on tcam(mdio_portid %d) failed \n",mdio_portid);
    700                     return CMD_FAIL;
    701                 }
    702             }
    703 
    704             /* Enable prbs generators in NL */
    705             for(nl_dev_id=0; nl_dev_id < num_tcams; ++nl_dev_id) {
    706                 mdio_portid = mdio_portid_get(u, nl_dev_id);
    707                 /* CTX lanes active for all tcams except the last
    708                    TCAM in the chain directly connected to response 
    709                    line(rx) of serdes */
    710                 ctx_lanes = (nl_dev_id == (num_tcams-1))? 0 : 1;
    711                 rv = nl_mdio_prbs_gen(u, mdio_portid, poly, seed, ctx_lanes, enable);
    712                 if(rv < 0) {
    713                     cli_out("Enabling prbs generator on tcam(mdio_portid %d) failed \n",mdio_portid);
    714                     return CMD_FAIL;
    715                 }
    716             }
    717 
    718 
    719             max_lane = 23; 
    720             /* Configure prbs checkers in TR3 for upper 12 rx lanes */
    721             for(lane=12; lane <= max_lane; ++lane) {
    722                 if (poly <= 3) {
    723                     rv = wcmod_esm_serdes_control_set(u, 
    724                             lane, 
    725                             SOC_PHY_CONTROL_PRBS_POLYNOMIAL,   
    726                             &poly);
    727                     if( rv != BCM_E_NONE) {
    728                         cli_out("Enabling prbs checker on ESM SerDes failed\n");
    729                         return CMD_FAIL;
    730                     }
    731                     /* Tx enable */
    732                     rv = wcmod_esm_serdes_control_set(u, 
    733                             lane, 
    734                             SOC_PHY_CONTROL_PRBS_TX_ENABLE,   
    735                             &enable);
    736                     if( rv != BCM_E_NONE) {
    737                         cli_out("Setting prbs tx enable failed\n");
    738                         return CMD_FAIL;
    739                     }
    740                 } else {
    741                     cli_out("Polynomial must be between 0 & 3, inclusive.\n");        
    742                     return CMD_FAIL;
    743                 }
    744             }
    745         } else if(cmd == _PHY_PRBS_GET_CMD) {
    746             /* Check for errors in NL prbs checkers, TR3 prbs checkers */
    747             for(nl_dev_id=0; nl_dev_id < num_tcams; ++nl_dev_id) {
    748                 mdio_portid = mdio_portid_get(u, nl_dev_id);
    749                 /* CRX lanes active for all tcams except the first
    750                    TCAM in the chain directly connected to request \
    751                    line(tx) of serdes (nl_dev_id = 0)*/
    752                 crx_lanes = nl_dev_id? 1 : 0;
    753                 cli_out("CHECKING PRBS: NL Tcam (%d)\n", mdio_portid);
    754                 rv = nl_mdio_prbs_chk_err(u, mdio_portid, crx_lanes);
    755                 if(rv < 0) {
    756                     cli_out("Getting prbs status on tcam(mdio_portid %d) failed \n",mdio_portid);
    757                     return CMD_FAIL;
    758                 }
    759 
    760             }
    761 
    762             /* Check for errors in TR3 prbs checkers */
    763             cli_out("CHECKING PRBS: TR3 ESM SerDes\n");
    764             max_lane = 23;
    765             for(lane=12; lane <= max_lane; ++lane) {
    766                 rv = wcmod_esm_serdes_control_get(u, 
    767                         lane, 
    768                         SOC_PHY_CONTROL_PRBS_RX_STATUS,   
    769                         &status);
    770                 if( rv != BCM_E_NONE) {
    771                     cli_out("ESM SerDes: Getting prbs status failed (lane:%d) \n", lane);
    772                     return CMD_FAIL;
    773                 }
    774                 switch (status) {
    775                     case 0:
    776                         /*cli_out("(%d):  WC PRBS OK!\n", lane);*/
    777                         break;
    778                     case 0xffffffff: /* -1 */ 
    779                         cli_out("\tPRBS not locked on lane %d of RX interface\n", lane - 12);
    780                         prbs_pass = 0;
    781                         break;
    782                     case 0xfffffffe: /* -2 */ 
    783                         cli_out("\tPRBS lost lock on lane %d of RX interface\n", lane - 12);
    784                         prbs_pass = 0;
    785                         break;
    786                     default:
    787                         cli_out("\t%d PRBS errors seen on lane %d of RX interface\n", status, lane - 12);
    788                         prbs_pass = 0;
    789                         break;
    790                 }
    791             }         
    792             if(prbs_pass) {
    793                 cli_out("\tPRBS OK\n");
    794             }
    795         }
    796 
    797 #else /*BCM_TRIUMPH3_SUPPORT*/
    798             return CMD_NOTIMPL;
    799 #endif /*BCM_TRIUMPH3_SUPPORT*/
    800     } else if (sal_strcasecmp(subcmd, "latency") == 0) { 
    801 #if defined(BCM_TRIUMPH3_SUPPORT)
    802         int ptr_fme_req;
    803         unsigned latency_ns;
    804         if (SOC_IS_TRIUMPH3(u)) {
    805             if (soc_feature(u, soc_feature_esm_support) && SOC_CONTROL(u)->tcam_info) {
    806                 ptr_fme_req = soc_tr3_esm_get_worst_fme(u);
    807                 cli_out("Calculating, please wait...");
    808                 rv = hwtl_find_idle_req_rsp_latency(u, ptr_fme_req, 30, &latency_ns);
    809                 
    810                 if( rv != BCM_E_NONE) {
    811                     cli_out("Get external tcam request response latency failed\n");
    812                     return CMD_FAIL;
    813                 } else {
    814                     cli_out("\nExternal tcam request response latency:%d\n", latency_ns);
    815                 }
    816             }
    817         }
    818 #else /*BCM_TRIUMPH3_SUPPORT*/
    819         return CMD_NOTIMPL;
    820 #endif /*BCM_TRIUMPH3_SUPPORT*/
    821     } else {
    822         return CMD_USAGE;
    823     }
    824 
    825     if (rv < 0) {
    826         cli_out("%s: ERROR: %s\n", ARG_CMD(a), bcm_errmsg(rv));
    827         return CMD_FAIL;
    828     }
    829 
    830     return CMD_OK;
    831 }
    832 
    833 #endif /* BCM_TRIUMPH_SUPPORT */