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, ©no, 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 */