mcs.c (37766B)
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 * File: mcs.c 8 * Purpose: Micro Controller Subsystem Support 9 */ 10 11 #include <assert.h> 12 #include <sal/core/libc.h> 13 #include <shared/bsl.h> 14 #include <bcm/error.h> 15 #include <soc/types.h> 16 #include <soc/dma.h> 17 #if defined(BCM_JERICHO_SUPPORT) 18 #include <soc/dpp/JER/jer_drv.h> 19 #endif 20 #include <appl/diag/shell.h> 21 #include <appl/diag/system.h> 22 #include <appl/diag/diag_mcs.h> 23 24 #if defined(BCM_CMICM_SUPPORT) || defined(BCM_IPROC_SUPPORT) 25 26 #include <soc/uc.h> 27 #include <soc/iproc.h> 28 #include <soc/shared/mos_coredump.h> 29 #include <soc/uc_msg.h> 30 #include <soc/uc_dbg.h> 31 32 extern void format_uint64_decimal(char *buf, uint64 n, int comma); 33 uKernel_info_t fwInfo[MAX_UCS]; 34 35 void dumpbuf(uint8 *buf, int count) { 36 int i; 37 uint8 *bp = buf; 38 for(i = 0; i < count; i++) { 39 cli_out("%02X", *bp++); 40 if ((i % 16) == 15) { 41 cli_out("\n"); 42 } 43 } 44 } 45 46 #ifndef NO_FILEIO 47 48 #define DUMP_BUFFER_SIZE 1024 49 50 STATIC cmd_result_t 51 _mcs_dump_region(int unit, FILE *fp, uint32 *buffer, mos_coredump_region_t *reg) { 52 53 uint32 addr = reg->baseaddr; 54 uint32 len = reg->end - reg->start; 55 int buf_idx = 0; 56 while (len > 0) { 57 buffer[buf_idx] = soc_uc_mem_read(unit, addr); 58 59 len -= sizeof(uint32); 60 addr += sizeof(uint32); 61 62 /* Flush buffer to disk if it is full, or we are done with the region */ 63 if (++buf_idx >= (DUMP_BUFFER_SIZE / sizeof(uint32)) || (len == 0)) { 64 if (sal_fwrite(buffer, 4, buf_idx, fp) != buf_idx) { 65 return(CMD_FAIL); 66 } 67 buf_idx = 0; 68 } 69 } 70 71 return (CMD_OK); 72 } 73 74 STATIC cmd_result_t 75 mcs_dump(int unit, FILE *fp, int addr, int mem_size) 76 { 77 /* Set up the region */ 78 mos_coredump_region_t reg; 79 uint32 *buffer; 80 81 /* Init the regions descriptors */ 82 reg.cores = 1; 83 reg.baseaddr = addr; 84 reg.start = addr; 85 reg.end = reg.start + mem_size; 86 87 /* allocate 1k for data */ 88 buffer = (uint32 *) soc_cm_salloc(unit, DUMP_BUFFER_SIZE, "MCS Dump Buffer"); 89 if(buffer == NULL) { 90 cli_out("Unable to allocate buffer\n"); 91 return(CMD_FAIL); 92 } 93 94 /* Write the desriptors */ 95 sal_memcpy(buffer, ®, sizeof(mos_coredump_region_t)); 96 /* Ensure that descriptors are in network byte order */ 97 buffer[0] = soc_htonl(buffer[0]); 98 99 if (sal_fwrite(buffer, sizeof(mos_coredump_region_t), 1, fp) != 1) { 100 cli_out("Error writing header\n"); 101 return(CMD_FAIL); 102 } 103 104 if (_mcs_dump_region(unit, fp, buffer, ®) != CMD_OK) { 105 cli_out("Error writing dump\n"); 106 return(CMD_FAIL); 107 } 108 109 soc_cm_sfree(unit, buffer); 110 111 return(CMD_OK); 112 } 113 114 uint32 ihex_ext_addr[SOC_MAX_NUM_DEVICES]; /* Extended Address */ 115 116 117 /* 118 * returs -1 if error 119 * returns number of bytes. (0 if this record doesn't contain any data). 120 */ 121 STATIC int 122 mcs_parse_ihex_record(int unit, char *line, uint32 *off) 123 { 124 int count; 125 uint32 address; 126 127 switch (line[8]) { /* Record Type */ 128 case '0' : /* Data Record */ 129 count = (xdigit2i(line[1]) << 4) | 130 (xdigit2i(line[2])); 131 132 address = (xdigit2i(line[3]) << 12) | 133 (xdigit2i(line[4]) << 8) | 134 (xdigit2i(line[5]) << 4) | 135 (xdigit2i(line[6])); 136 137 *off = ihex_ext_addr[unit] + address; 138 return count; 139 break; /* Not Reachable */ 140 case '4' : /* Extended Linear Address Record */ 141 address = (xdigit2i(line[9]) << 12) | 142 (xdigit2i(line[10]) << 8) | 143 (xdigit2i(line[11]) << 4) | 144 (xdigit2i(line[12])); 145 146 ihex_ext_addr[unit] = (address << 16); 147 cli_out("Exteded Linear Address 0x%x\n", ihex_ext_addr[unit]); 148 return 0; 149 break; /* Not Reachable */ 150 default : /* We don't parse all other records */ 151 cli_out("Unsupported Record\n"); 152 return 0; 153 } 154 return -1; /* Why are we here? */ /* Not Reachable */ 155 } 156 157 STATIC int 158 mcs_parse_srec_record (int unit, char *line, uint32 *off) 159 { 160 int count; 161 uint32 address; 162 163 switch (line[1]) { /* Record Type */ 164 case '0': /* Header record - ignore */ 165 return 0; 166 break; /* Not Reachable */ 167 168 case '1' : /* Data Record with 2 byte address */ 169 count = (xdigit2i(line[2]) << 4) | 170 (xdigit2i(line[3])); 171 count -= 3; /* 2 address + 1 checksum */ 172 173 address = (xdigit2i(line[4]) << 12) | 174 (xdigit2i(line[5]) << 8) | 175 (xdigit2i(line[6]) << 4) | 176 (xdigit2i(line[7])); 177 178 *off = address; 179 return count; 180 break; /* Not Reachable */ 181 182 case '2' : /* Data Record with 3 byte address */ 183 count = (xdigit2i(line[2]) << 4) | 184 (xdigit2i(line[3])); 185 count -= 4; /* 3 address + 1 checksum */ 186 187 address = (xdigit2i(line[4]) << 20) | 188 (xdigit2i(line[5]) << 16) | 189 (xdigit2i(line[6]) << 12) | 190 (xdigit2i(line[7]) << 8) | 191 (xdigit2i(line[8]) << 4) | 192 (xdigit2i(line[9])); 193 194 *off = address; 195 return count; 196 break; /* Not Reachable */ 197 198 case '3' : /* Data Record with 4 byte address */ 199 count = (xdigit2i(line[2]) << 4) | 200 (xdigit2i(line[3])); 201 count -= 5; /* 4 address + 1 checksum */ 202 203 address = (xdigit2i(line[4]) << 28) | 204 (xdigit2i(line[5]) << 24) | 205 (xdigit2i(line[6]) << 20) | 206 (xdigit2i(line[7]) << 16) | 207 (xdigit2i(line[8]) << 12) | 208 (xdigit2i(line[9]) << 8) | 209 (xdigit2i(line[10]) << 4) | 210 (xdigit2i(line[11])); 211 212 *off = address; 213 return count; 214 break; /* Not Reachable */ 215 216 case '5': /* Record count - ignore */ 217 case '6': /* End of block - ignore */ 218 case '7': /* End of block - ignore */ 219 case '8': /* End of block - ignore */ 220 case '9': /* End of block - ignore */ 221 return 0; 222 break; /* Not Reachable */ 223 224 default : /* We don't parse all other records */ 225 cli_out("Unsupported Record S%c\n", line[1]); 226 return 0; 227 } 228 return -1; /* Why are we here? */ /* Not Reachable */ 229 } 230 231 232 /* 233 * It is assumed that by the time this routine is called 234 * the record is already validated. So, blindly get data 235 */ 236 STATIC void 237 mcs_get_rec_data(char *line, int count, uint8 *dat) 238 { 239 int i, datpos = 9; /* 9 is valid for ihex */ 240 241 if (!count) { 242 return; 243 } 244 245 if (line[0] != ':') { 246 /* not ihex */ 247 switch (line[1]) { 248 case '1': /* S1 record */ 249 datpos = 8; 250 break; 251 case '2': /* S2 record */ 252 datpos = 10; 253 break; 254 case '3': /* S3 record */ 255 datpos = 12; 256 break; 257 default: 258 cli_out("Unexpected record type: '%c'\n", line[1]); 259 SOC_CMIC_UCDBG_LOG_ADD((0, _bcmCmicUcDbgLogHostMcsLoad, 260 "%s: Unexpected record type\n", FUNCTION_NAME())); 261 break; 262 } 263 } 264 265 /*1 count = 2 hex chars */ 266 for(i = 0; i < count; i++) { 267 *(dat + i) = ((xdigit2i(line[datpos + (i * 2)])) << 4) | 268 (xdigit2i(line[datpos + (i * 2) + 1])); 269 } 270 } 271 272 STATIC cmd_result_t 273 mcs_file_load(int unit, FILE *fp, int ucnum, uint32 *lowaddr, int stage, uint32 twostageaddr) 274 { 275 uint32 addr=0; 276 int rv = 0; 277 char input[256], *cp = NULL; 278 unsigned char data[256]; 279 280 if (lowaddr != NULL) { 281 *lowaddr = 0xffff0000; 282 } 283 ihex_ext_addr[unit] = 0; /* Until an extended addr record is met.. */ 284 285 while (NULL != (cp = sal_fgets(input, sizeof(input) - 1, fp))) { 286 if (input[0] == 'S') { 287 rv = mcs_parse_srec_record(unit, cp, &addr); 288 } else if (input[0] == ':') { 289 rv = mcs_parse_ihex_record(unit, cp, &addr); 290 } else { 291 cli_out("unknown Record Type\n"); 292 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostMcsLoad, 293 "%s: unknown Record Type\n", FUNCTION_NAME())); 294 rv = -1; 295 } 296 297 if (-1 == rv) { 298 return (CMD_FAIL); 299 } 300 301 if (rv % 4) { 302 cli_out("record Not Multiple of 4\n"); 303 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostMcsLoad, 304 "%s: record Not Multiple of 4\n", FUNCTION_NAME())); 305 return (CMD_FAIL); 306 } 307 308 /* Do this only if first stage */ 309 if (stage == 0) { 310 /* track lowest seen address with data */ 311 if ((rv > 0) && (lowaddr != NULL) && (addr < *lowaddr)) { 312 *lowaddr = addr; 313 } 314 } 315 316 if ((stage == 0) && (addr >= twostageaddr)) { 317 /* No Need to parse teh remaining now... */ 318 return CMD_OK; 319 } 320 321 if ( ((stage == 0) && (addr < twostageaddr)) || 322 ((stage == 1) && (addr >= twostageaddr))) { 323 mcs_get_rec_data(cp, rv, data); 324 soc_uc_load(unit, ucnum, addr, rv, data); 325 } 326 } 327 return(CMD_OK); 328 } 329 330 #endif 331 332 333 char mcsload_usage[] = 334 "Parameters: <uCnum> <file.hex>\n\t\t" 335 #ifndef COMPILER_STRING_CONST_LIMIT 336 "[InitMCS|ResetUC|StartUC|StartMSG]=true|false]\n\t\t" 337 "Load the MCS memory area from <file.srec>.\n\t" 338 "uCnum = uC number to be loaded.\n\t" 339 "InitMCS = Init the MCS (not just one UC) (false)\n\t" 340 "ResetUC = Reset the uC (true)\n\t" 341 "StartUC = uC out of halt after load (true)\n\t" 342 "StartMSG = Start messaging (true)\n" 343 #endif 344 ; 345 346 cmd_result_t 347 mcsload_cmd(int unit, args_t *a) 348 /* 349 * Function: mcsload_cmd 350 * Purpose: Load a file into MCS. 351 * Parameters: unit - unit 352 * a - args, each of the files to be displayed. 353 * Returns: CMD_OK/CMD_FAIL/CMD_USAGE 354 */ 355 { 356 cmd_result_t rv = CMD_OK; 357 parse_table_t pt; 358 char *c , *filename; 359 int ucnum, resetuc = 1, startuc=1, startmsg=1, initmcs = 0, twostage = 0; 360 uint32 twostageaddr = 0xffffffff; 361 362 #ifndef NO_FILEIO 363 #ifndef NO_CTRL_C 364 jmp_buf ctrl_c; 365 #endif 366 FILE * volatile fp = NULL; 367 uint32 lowaddr; 368 #endif 369 #ifdef BCM_SABER2_SUPPORT 370 uint16 dev_id; 371 uint8 rev_id; 372 #endif 373 374 if (!sh_check_attached("mcsload", unit)) { 375 return(CMD_FAIL); 376 } 377 378 if (!soc_feature(unit, soc_feature_uc)) { 379 return (CMD_FAIL); 380 } 381 382 if (ARG_CNT(a) < 2) { 383 return(CMD_USAGE); 384 } 385 386 c = ARG_GET(a); 387 if (!isint(c)) { 388 cli_out("%s: Error: uC Num not specified\n", ARG_CMD(a)); 389 return(CMD_USAGE); 390 } 391 392 ucnum = parse_integer(c); 393 if (ucnum < 0 || ucnum >= SOC_INFO(unit).num_ucs) { 394 cli_out("Invalid uProcessor number: %d\n", ucnum); 395 return(CMD_FAIL); 396 } 397 398 c = ARG_GET(a); 399 filename = c; 400 if (filename == NULL) { 401 cli_out("%s: Error: No file specified\n", ARG_CMD(a)); 402 return(CMD_USAGE); 403 } 404 405 if (ARG_CNT(a) > 0) { 406 parse_table_init(unit, &pt); 407 parse_table_add(&pt, "InitMCS", PQ_DFL|PQ_BOOL, 408 0, &initmcs, NULL); 409 parse_table_add(&pt, "ResetUC", PQ_DFL|PQ_BOOL, 410 0, &resetuc, NULL); 411 parse_table_add(&pt, "StartUC", PQ_DFL|PQ_BOOL, 412 0, &startuc, NULL); 413 parse_table_add(&pt, "StartMSG", PQ_DFL|PQ_BOOL, 414 0, &startmsg, NULL); 415 parse_table_add(&pt, "TwoStage", PQ_DFL|PQ_BOOL, 416 0, &twostage, NULL); 417 parse_table_add(&pt, "TwoStageAddress", PQ_DFL|PQ_INT, 418 0, &twostageaddr, NULL); 419 if (!parseEndOk(a, &pt, &rv)) { 420 if (CMD_OK != rv) { 421 return rv; 422 } 423 } 424 } 425 426 #ifdef BCM_SABER2_SUPPORT 427 /* mHost1 is disabled in dagger2 (BCM56233) */ 428 soc_cm_get_id(unit, &dev_id, &rev_id); 429 if (SOC_IS_SABER2(unit) && (dev_id == BCM56233_DEVICE_ID) && (ucnum == 1)) { 430 return(CMD_FAIL); 431 } 432 #endif 433 434 if (twostage) { 435 startuc = 1; /* Force Start */ 436 } else { 437 twostageaddr = 0xffffffff; 438 } 439 440 /* check for simulation*/ 441 if (SAL_BOOT_BCMSIM) { 442 return(rv); 443 } 444 445 /* initialize ukernel debug module */ 446 soc_cmic_ucdebug_init(unit, ucnum); 447 448 449 #ifdef NO_FILEIO 450 cli_out("no filesystem\n"); 451 #else 452 #ifndef NO_CTRL_C 453 if (!setjmp(ctrl_c)) { 454 sh_push_ctrl_c(&ctrl_c); 455 #endif 456 /* See if we can open the file before doing anything else */ 457 fp = sal_fopen(filename, "r"); 458 if (!fp) { 459 cli_out("%s: Error: Unable to open file: %s\n", 460 ARG_CMD(a), filename); 461 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostMcsLoad, 462 "Error: Unable to open file: %s\n", filename)); 463 rv = CMD_FAIL; 464 #ifndef NO_CTRL_C 465 sh_pop_ctrl_c(); 466 #endif 467 return rv; 468 } 469 470 /* Reset the UC to stop messages before stopping the msg system */ 471 if (resetuc || initmcs) { 472 soc_uc_reset(unit, ucnum); 473 } 474 475 if (initmcs) { 476 soc_uc_init(unit); 477 } 478 479 soc_uc_preload(unit, ucnum); 480 481 rv = mcs_file_load(unit, fp, ucnum, &lowaddr, 0, twostageaddr); 482 483 if (startuc) { 484 soc_uc_start(unit, ucnum, lowaddr); 485 sal_usleep(100 * 1000); 486 } 487 488 #if defined(BCM_IPROC_SUPPORT) 489 if (twostage) { 490 int retries; 491 uint32 rval; 492 rv = CMD_OK; 493 if (soc_cm_get_bus_type(unit) & SOC_DEV_BUS_ALT) { 494 WRITE_PAXB_1_PCIE_EP_AXI_CONFIGr(unit, 0xfffdff7f); 495 } else { 496 WRITE_PAXB_0_PCIE_EP_AXI_CONFIGr(unit, 0xfffdff7f); 497 } 498 499 cli_out("Waiting for Core-%d to start", ucnum); 500 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostMcsLoad, 501 "Waiting for Core-%d to start\n", ucnum)); 502 rval = 0; 503 retries = 0; 504 while (rval != 0x10c8ed) { /* Locked?? */ 505 sal_usleep(10 * 1000); 506 rval = soc_cm_iproc_read(unit, 0x1b07f000); 507 cli_out("."); 508 if (++retries > 100) { 509 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostMcsLoad, 510 "Error: Unable to start Core-%d rval:0x%x\n", 511 ucnum, rval)); 512 rv = CMD_FAIL; 513 break; 514 } 515 } 516 /* L2$ Cache has been Initialized */ 517 518 if (rv == CMD_OK) { 519 cli_out("\nWaiting for L2$ to be configured"); 520 rval = 0; 521 retries = 0; 522 while (rval != 0xdeadc0de) { 523 sal_usleep(10 * 1000); 524 rval = soc_cm_iproc_read(unit, twostageaddr); 525 cli_out("."); 526 if (++retries > 100) { 527 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostMcsLoad, 528 "Error: Waiting for L2$ to be configured rval: 0x%x\n", 529 rval)); 530 rv = CMD_FAIL; 531 break; 532 } 533 } 534 cli_out("\n"); 535 } 536 /* L2$ Cache has been configured as RAM */ 537 538 /* Last read was for first line of 2nd stage. So close/reopen 539 so that next load doesn't miss that line 540 */ 541 542 sal_fclose((FILE *)fp); 543 fp = NULL; 544 545 if (rv != CMD_OK) { 546 /* Last Load failed: Timed Out */ 547 #ifndef NO_CTRL_C 548 sh_pop_ctrl_c(); 549 #endif 550 return rv; 551 } 552 553 fp = sal_fopen(filename, "r"); 554 if (!fp) { 555 cli_out("%s: Error: Unable to open file: %s\n", 556 ARG_CMD(a), filename); 557 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostMcsLoad, 558 "%s: Error: Unable to open file: %s\n", 559 ARG_CMD(a), filename)); 560 rv = CMD_FAIL; 561 #ifndef NO_CTRL_C 562 sh_pop_ctrl_c(); 563 #endif 564 return rv; 565 } 566 567 rv = mcs_file_load(unit, fp, ucnum, &lowaddr, 1, twostageaddr); 568 soc_cm_iproc_write(unit, twostageaddr, 0x10aded); /*Loaded */ 569 } 570 #endif /* IPROC_SUPPORT */ 571 572 sal_fclose((FILE *)fp); 573 fp = NULL; 574 575 #ifdef BCM_MONTEREY_SUPPORT 576 /* In monterey ucnum:2 is M7 and no messaging required */ 577 if (!(SOC_IS_MONTEREY(unit) && (ucnum == 2))) { 578 #endif 579 if (startmsg) { 580 soc_cmic_uc_msg_start(unit); 581 soc_cmic_uc_msg_uc_start(unit, ucnum); 582 } 583 #ifdef BCM_MONTEREY_SUPPORT 584 } 585 #endif 586 587 #ifndef NO_CTRL_C 588 } else if (fp) { 589 sal_fclose((FILE *)fp); 590 fp = NULL; 591 rv = CMD_INTR; 592 } 593 sh_pop_ctrl_c(); 594 #endif 595 #endif /* NO_FILEIO */ 596 sal_usleep(10000); 597 598 /* WA for "bus error" issue that SDK configure the RSVD field of 599 * MHOST_0_CR5_CFG_CTRL, then uKernel polling this register field to kill 600 * or stop the thread. 601 */ 602 #if defined(BCM_JERICHO_SUPPORT) 603 if (SOC_IS_JERICHO(unit)) { 604 soc_restore_bcm88x7x(unit, 0); 605 } 606 #endif 607 608 return(rv); 609 } 610 611 char mcsdump_usage[] = 612 "Parameters: [uCnum|<dumpfile>] <ADDR> <MEM_SIZE> [Halt=true|false]\n\t" 613 "Dump both uCs memory in BRCM dumpfile format.\n\t" 614 "<file.hex> = dumpfile to write.\n\t" 615 "Halt = Halt the UCs prior to the dump.\n\t" 616 "Address = Base address + Offset.\n\t" 617 "Size of memory to be read.\n\t" 618 "uCnum = uC core Cpu and Memory usage report \n"; 619 620 cmd_result_t 621 mcsdump_cmd(int unit, args_t *a) 622 /* 623 * Function: mcsdump_cmd 624 * Purpose: Dump the MCS. 625 * Parameters: unit - unit 626 * a - args, each of the files to be displayed. 627 * Returns: CMD_OK/CMD_FAIL/CMD_USAGE 628 */ 629 { 630 cmd_result_t rv = CMD_OK; 631 parse_table_t pt; 632 char *c , *filename; 633 int halt = 0, ucnum = 0; 634 uint32 reg0, reg1, regs; 635 char *thread_info; 636 #ifndef NO_FILEIO 637 int addr, mem_size; 638 #endif 639 640 #ifndef NO_FILEIO 641 #ifndef NO_CTRL_C 642 jmp_buf ctrl_c; 643 #endif 644 FILE * volatile fp = NULL; 645 #endif 646 647 if (!sh_check_attached("mcsload", unit)) { 648 return(CMD_FAIL); 649 } 650 651 /* CMICm only at the moment */ 652 if (!soc_feature(unit, soc_feature_uc)) { 653 return (CMD_FAIL); 654 } 655 656 if (ARG_CNT(a) < 1) { 657 return(CMD_USAGE); 658 } 659 660 c = ARG_GET(a); 661 if (isint(c)) { 662 ucnum = parse_integer(c); 663 if (ucnum < SOC_INFO(unit).num_ucs) { 664 cli_out("ID Name %% Base Size sp free Priority run_time\n"); 665 thread_info = soc_uc_firmware_thread_info(unit, ucnum); 666 if (thread_info) { 667 cli_out("%s\n", thread_info); 668 soc_cm_sfree(unit, thread_info); 669 } 670 return (CMD_OK); 671 } else { 672 cli_out("%s: Error: uC Num not legal\n", ARG_CMD(a)); 673 return(CMD_USAGE); 674 } 675 } 676 filename = c; 677 if (filename == NULL) { 678 cli_out("%s: Error: No file specified\n", ARG_CMD(a)); 679 return(CMD_USAGE); 680 } 681 682 #ifndef NO_FILEIO 683 if (ARG_CNT(a) < 2) { 684 cli_out("%s: Error: provide valid address and size\n", ARG_CMD(a)); 685 return(CMD_USAGE); 686 } 687 c = ARG_GET(a); 688 if (isint(c)) { 689 addr = parse_integer(c); 690 c = ARG_GET(a); 691 if (isint(c)) { 692 mem_size = parse_integer(c); 693 } else { 694 cli_out("%s: Error: provide memory size\n", ARG_CMD(a)); 695 return(CMD_USAGE); 696 } 697 } else { 698 cli_out("%s: Error: provide base address\n", ARG_CMD(a)); 699 return(CMD_USAGE); 700 } 701 #endif 702 703 parse_table_init(unit, &pt); 704 parse_table_add(&pt, "Halt", PQ_DFL|PQ_BOOL, 705 0, &halt, NULL); 706 if (!parseEndOk(a, &pt, &rv)) { 707 if (CMD_OK != rv) { 708 return rv; 709 } 710 } 711 712 713 if (halt) { 714 /* Halt both uCs so that the dump is clean */ 715 READ_UC_0_RST_CONTROLr(unit, ®0); 716 regs = reg0; 717 soc_reg_field_set(unit, UC_0_RST_CONTROLr, ®s, CPUHALT_Nf, 0); 718 WRITE_UC_0_RST_CONTROLr(unit, regs); 719 720 READ_UC_0_RST_CONTROLr(unit, ®1); 721 regs = reg0; 722 soc_reg_field_set(unit, UC_0_RST_CONTROLr, ®s, CPUHALT_Nf, 0); 723 WRITE_UC_1_RST_CONTROLr(unit, regs); 724 } 725 726 #ifdef NO_FILEIO 727 cli_out("no filesystem\n"); 728 #else 729 #ifndef NO_CTRL_C 730 if (!setjmp(ctrl_c)) { 731 sh_push_ctrl_c(&ctrl_c); 732 #endif 733 734 fp = sal_fopen(filename, "w"); 735 if (!fp) { 736 cli_out("%s: Error: Unable to open file: %s\n", 737 ARG_CMD(a), filename); 738 rv = CMD_FAIL; 739 } else { 740 rv = mcs_dump(unit, fp, addr, mem_size); 741 sal_fclose((FILE *)fp); 742 fp = NULL; 743 } 744 #ifndef NO_CTRL_C 745 } else if (fp) { 746 sal_fclose((FILE *)fp); 747 fp = NULL; 748 rv = CMD_INTR; 749 } 750 751 sh_pop_ctrl_c(); 752 #endif 753 #endif /* NO_FILEIO */ 754 755 if (halt) { 756 /* Put both uCs back in previous state */ 757 WRITE_UC_0_RST_CONTROLr(unit, reg0); 758 WRITE_UC_1_RST_CONTROLr(unit, reg1); 759 } 760 761 762 return(rv); 763 } 764 765 char mcsmsg_usage[] = 766 "Parameters: [ucnum|Start|Stop]\n\t" 767 "Control messaging with the UCs.\n\t" 768 "ucnum = ucnum to start comminicating with (must start first).\n\t" 769 "Init = Init messaging with all uCs.\n\t" 770 "Halt = Halt messaging with all uCs.\n\t" 771 "Stop = Stop messaging with uC.\n"; 772 773 cmd_result_t 774 mcsmsg_cmd(int unit, args_t *a) 775 /* 776 * Function: mcsmsg_cmd 777 * Purpose: Start messading with the MCS. 778 * Parameters: unit - unit 779 * a - args, 0, 1, stop. 780 * Returns: CMD_OK/CMD_FAIL/CMD_USAGE 781 */ 782 { 783 char *c; 784 int ucnum; 785 786 if (!sh_check_attached("mcsmsg", unit)) { 787 return(CMD_FAIL); 788 } 789 790 if (!soc_feature(unit, soc_feature_uc)) { 791 return (CMD_FAIL); 792 } 793 794 if (ARG_CNT(a) < 1) { 795 return(CMD_USAGE); 796 } 797 798 c = ARG_GET(a); 799 if (isint(c)) { 800 ucnum = parse_integer(c); 801 if (ucnum < SOC_INFO(unit).num_ucs) { 802 soc_cmic_uc_msg_uc_start(unit, ucnum); 803 } else { 804 cli_out("%s: Error: uC Num not legal\n", ARG_CMD(a)); 805 return(CMD_USAGE); 806 } 807 808 } else if (sal_strcasecmp(c, "INIT") == 0) { 809 soc_cmic_uc_msg_start(unit); 810 811 } else if (sal_strcasecmp(c, "HALT") == 0) { 812 soc_cmic_uc_msg_shutdown_halt(unit); 813 814 } else if (sal_strcasecmp(c, "STOP") == 0) { 815 if (ARG_CNT(a) < 1) { 816 return(CMD_USAGE); 817 } 818 c = ARG_GET(a); 819 ucnum = parse_integer(c); 820 if (ucnum < SOC_INFO(unit).num_ucs) { 821 soc_cmic_uc_msg_uc_shutdown_halt(unit, ucnum); 822 } else { 823 cli_out("%s: Error: uC Num not legal\n", ARG_CMD(a)); 824 return(CMD_USAGE); 825 } 826 } else { 827 cli_out("%s: Error: Invalid parameter\n", ARG_CMD(a)); 828 return(CMD_USAGE); 829 } 830 831 return (CMD_OK); 832 833 } 834 835 char mcscmd_usage[] = 836 "Parameters: <ucnum> <cmd>\n\t" 837 "Execute cmd on uC\n\t" 838 "ucnum = ucnum to start comminicating with (must start first).\n\t" 839 "cmd = <stats reset>.\n"; 840 841 /* 842 * Function: mcsmsg_cmd 843 * Purpose: Start messading with the MCS. 844 * Parameters: unit - unit 845 * a - args, 0, 1, stop. 846 * Returns: CMD_OK/CMD_FAIL/CMD_USAGE 847 */ 848 cmd_result_t 849 mcscmd_cmd(int unit, args_t *a) 850 { 851 char *c; 852 int uC; 853 854 if (!sh_check_attached("mcsmsg", unit)) { 855 return CMD_FAIL; 856 } 857 858 if (!soc_feature(unit, soc_feature_uc)) { 859 return CMD_FAIL; 860 } 861 862 863 if (ARG_CNT(a) < 1) { 864 return CMD_USAGE; 865 } 866 867 c = ARG_GET(a); 868 if (isint(c)) { 869 uC = parse_integer(c); 870 if (uC >= SOC_INFO(unit).num_ucs) { 871 cli_out("%s: Error: uC Num not legal\n", ARG_CMD(a)); 872 return CMD_USAGE; 873 } 874 } else { 875 cli_out("Error: uC Num not specified\n"); 876 return CMD_USAGE; 877 } 878 879 if (ARG_CNT(a) == 2) { 880 c = ARG_GET(a); 881 if (sal_strcasecmp(c, "STATS") == 0) { 882 c = ARG_GET(a); 883 if (sal_strcasecmp(c, "RESET") == 0) { 884 if (soc_uc_stats_reset(unit, uC) != SOC_E_NONE) { 885 cli_out("Error: stats reset cmd fail\n"); 886 } 887 return CMD_OK; 888 } 889 } else if (sal_strcasecmp(c, "CONSOLE") == 0) { 890 c = ARG_GET(a); 891 if (sal_strcasecmp(c, "ON") == 0) { 892 if (soc_uc_console_log(unit, uC, 1) != SOC_E_NONE) { 893 cli_out("Error: console log ON cmd fail\n"); 894 } 895 return CMD_OK; 896 } else if(sal_strcasecmp(c, "OFF") == 0) { 897 if (soc_uc_console_log(unit, uC, 0) != SOC_E_NONE) { 898 cli_out("Error: console log OFF cmd fail\n"); 899 } 900 return CMD_OK; 901 } 902 } 903 } 904 905 /* Only stats reset supported for now */ 906 return CMD_USAGE; 907 } 908 909 void mcs_core_status(int unit, int uC, uint32 base) 910 { 911 int i; 912 uint32 cpsr; 913 char *version; 914 uint16 dev_id; 915 uint8 rev_id; 916 uint32 regVal; 917 918 soc_cm_get_id(unit, &dev_id, &rev_id); 919 920 /* Skip getting status of Firmware for Core-1 in Dagger2 */ 921 if ((dev_id == BCM56233_DEVICE_ID) && (uC == 1)) { 922 return; 923 } 924 925 /* CPSR is at offset 0x60 from start of TCM */ 926 /* Core 0's TCM is at a PCI address of 0x100000, Core 1's is at 0x200000 */ 927 cpsr = soc_uc_mem_read(unit, base + 0x60); 928 cli_out("uC %d status: %s\n", uC, (cpsr) ? "Fault" : "Ok"); 929 if (uC < MAX_UCS) 930 sal_memcpy(fwInfo[uC].status, 931 (cpsr) ? "Fault" : "Ok", 932 (cpsr) ? sizeof("Fault") : sizeof("Ok")); 933 if (cpsr) { 934 regVal = soc_uc_mem_read(unit, base + 0x64); 935 cli_out("\tcpsr\t0x%08x\n", cpsr); 936 cli_out("\ttype\t0x%08x\n", regVal); 937 if (uC < MAX_UCS) { 938 fwInfo[uC].cpsr = cpsr; 939 fwInfo[uC].type = regVal; 940 } 941 942 for (i = 0; i < 16; ++i) { 943 regVal = soc_uc_mem_read(unit, base + 0x20 + i*4); 944 cli_out("\tr%d\t0x%08x\n", 945 i, regVal); 946 if (uC < MAX_UCS) 947 fwInfo[uC].armReg[i] = regVal; 948 } 949 } 950 else { 951 version = soc_uc_firmware_version(unit, uC); 952 if (version) { 953 cli_out("version: %s\n", version); 954 if (uC < MAX_UCS) 955 sal_memcpy(fwInfo[uC].fw_version, version, 100); 956 soc_cm_sfree(unit, version); 957 } 958 } 959 } 960 961 #if defined(BCM_MONTEREY_SUPPORT) && defined(INCLUDE_GDPLL) 962 extern int _bcm_esw_gdpll_m7_status (int unit, uint8 *pBuff); 963 #endif 964 965 char mcsstatus_usage[] = 966 "Prints fault status of microcontrollers\n\t\t" 967 #ifndef COMPILER_STRING_CONST_LIMIT 968 "Parameters: [Quick=true|false] [TimeOutUs=<val>]\n\t\t" 969 "Quick = Call Ping function instead of FW Ver.(false)\n\t\t" 970 "TimeOutUs = Ping Timeout in uSecs. Used only in Quick mode. (1Sec)\n" 971 #endif 972 ; 973 974 cmd_result_t 975 mcsstatus_cmd(int unit, args_t *a) 976 /* 977 * Function: mcsstatus_cmd 978 * Purpose: Show fault status of MCS 979 * Parameters: unit - unit 980 * a - args (none) 981 * Returns: CMD_OK/CMD_FAIL/CMD_USAGE 982 */ 983 { 984 int quick = 0, uc_num = 0, rv = 0, to = 0; 985 parse_table_t pt; 986 char *c; 987 #if defined(BCM_MONTEREY_SUPPORT) && defined(INCLUDE_GDPLL) 988 uint8 *version = NULL; 989 uint8 buffer[20/*DPLL_FW_VERSION_SIZE*/]; 990 #endif 991 992 if (!sh_check_attached("mcsmsg", unit)) { 993 return(CMD_FAIL); 994 } 995 996 if (!soc_feature(unit, soc_feature_uc)) { 997 return (CMD_FAIL); 998 } 999 1000 if (ARG_CNT(a) > 0) { 1001 /* Just peek into the argument without consuming it 1002 * In case it is not an integer, it is needed for the parse table. 1003 */ 1004 c = ARG_CUR(a); 1005 if (isint(c)) { 1006 uint32 addr = parse_integer(c); 1007 cli_out("%08x: %08x\n", addr, soc_uc_mem_read(unit, addr)); 1008 ARG_DISCARD(a); 1009 return(CMD_OK); 1010 } 1011 1012 parse_table_init(unit, &pt); 1013 parse_table_add(&pt, "Quick", PQ_DFL|PQ_BOOL, 1014 0, &quick, NULL); 1015 parse_table_add(&pt, "TimeOutUs", PQ_DFL|PQ_INT, 1016 (void *)(1*1000*1000), &to, NULL); 1017 if (!parseEndOk(a, &pt, &rv)) { 1018 if (CMD_OK != rv) { 1019 return rv; 1020 } 1021 } 1022 } 1023 1024 if (quick) { 1025 /* Just Ping */ 1026 for(uc_num = 0; uc_num < SOC_INFO(unit).num_ucs; uc_num++) { 1027 rv = soc_uc_ping(unit, uc_num, (sal_usecs_t)to); 1028 cli_out("uC %d status: ", uc_num); 1029 switch(rv) { 1030 case SOC_E_UNAVAIL: 1031 cli_out("No uC / MCS support\n"); 1032 break; 1033 case SOC_E_PARAM: 1034 cli_out("uC Invalid for this chip\n"); 1035 break; 1036 case SOC_E_DISABLED: 1037 cli_out("ARM core is in reset\n"); 1038 break; 1039 case SOC_E_INIT: 1040 cli_out("uKernel messaging is not initialized\n"); 1041 break; 1042 case SOC_E_TIMEOUT: 1043 cli_out("uKernel not responding\n"); 1044 break; 1045 case SOC_E_NONE: 1046 cli_out("OK\n"); 1047 break; 1048 default: 1049 cli_out("Unknown Error\n"); 1050 break; 1051 } 1052 } 1053 return CMD_OK; 1054 } 1055 1056 for(uc_num=0; uc_num < MAX_UCS; uc_num++) { 1057 if (uc_num < SOC_INFO(unit).num_ucs) { 1058 fwInfo[uc_num].status[0] = '\0'; 1059 fwInfo[uc_num].fw_version[0] = '\0'; 1060 } 1061 } 1062 1063 /* If a fault happens, the register dump will include a non-zero CPSR */ 1064 1065 if (soc_feature(unit, soc_feature_iproc)) { 1066 1067 #if defined(BCM_UC_MHOST_SUPPORT) 1068 if (soc_feature(unit, soc_feature_uc_mhost)) { 1069 1070 int uc, addr; 1071 1072 /* iProc mHost: vectors and exception registers are in ATCM */ 1073 for(uc=0; uc<SOC_INFO(unit).num_ucs; uc++) { 1074 #if defined(BCM_MONTEREY_SUPPORT) && defined(INCLUDE_GDPLL) 1075 version = &buffer[0]; 1076 if ((SOC_IS_MONTEREY(unit) && (uc == 2))) { 1077 rv = _bcm_esw_gdpll_m7_status(unit, buffer); 1078 if (rv == BCM_E_NONE) { 1079 version = &buffer[0]; 1080 cli_out("uC 2 status: Ok\n"); 1081 cli_out("version: %.6s %.5s %s\n", version, version+6, version+11); 1082 } else { 1083 cli_out("uC 2 status: RESET\n"); 1084 } 1085 continue; 1086 } 1087 #endif 1088 if (soc_uc_in_reset(unit, uc)) { 1089 cli_out("uC %d status: RESET\n", uc); 1090 if (uc < MAX_UCS) 1091 sal_memcpy(fwInfo[uc].status, "RESET", sizeof("RESET")); 1092 } else { 1093 addr = 0x01000000 + 0x00100000 * uc; 1094 #ifdef BCM_SABER2_SUPPORT 1095 if (SOC_IS_SABER2(unit)) { 1096 if (uc == 2) { 1097 addr = 0x01160000; 1098 } 1099 } 1100 #endif 1101 #if defined(BCM_TRIDENT3_SUPPORT) || defined(BCM_TOMAHAWK2_SUPPORT) || defined(BCM_TOMAHAWK3_SUPPORT) 1102 if (SOC_IS_TRIDENT3(unit) || SOC_IS_TOMAHAWK2(unit) || SOC_IS_TOMAHAWK3(unit) || SOC_IS_MAVERICK2(unit)) { 1103 addr = 0x01100000 + 0x00060000 * uc; 1104 } 1105 #endif 1106 #if defined(BCM_JERICHO_2_SUPPORT) 1107 if (SOC_IS_JERICHO_2_ONLY(unit)) { 1108 addr = 0x01100000 + 0x00060000 * uc; 1109 } 1110 #endif 1111 #ifdef BCM_APACHE_SUPPORT 1112 if (SOC_IS_APACHE(unit)) { 1113 addr = 0x01100000 + 0x00060000 * uc; 1114 } 1115 #endif 1116 mcs_core_status(unit, uc, addr); 1117 } 1118 } 1119 1120 return CMD_OK; 1121 } 1122 #endif 1123 1124 /* iProc - L2Cache + SRAM for now. */ 1125 if (soc_uc_in_reset(unit, 0)) { 1126 cli_out("uC 0 status: RESET\n"); 1127 sal_memcpy(fwInfo[0].status, "RESET", sizeof("RESET")); 1128 } else { 1129 #if defined(BCM_HURRICANE2_SUPPORT) || defined(BCM_HURRICANE3_SUPPORT) 1130 if (SOC_IS_HURRICANE2(unit) || SOC_IS_HURRICANE3(unit)) { 1131 mcs_core_status(unit, 0, 0x00004000); 1132 } else 1133 #endif /* BCM_HURRICANE2_SUPPORT || BCM_HURRICANE3_SUPPORT */ 1134 1135 mcs_core_status(unit, 0, 0x1b004000); 1136 } 1137 if (SOC_INFO(unit).num_ucs > 1) { 1138 if (soc_uc_in_reset(unit, 1)) { 1139 cli_out("uC 1 status: RESET\n"); 1140 sal_memcpy(fwInfo[1].status, "RESET", sizeof("RESET")); 1141 } 1142 else { 1143 mcs_core_status(unit, 1, 0x1b034000); 1144 } 1145 } 1146 } 1147 else { 1148 /* CMICm with TCMs */ 1149 if (soc_uc_in_reset(unit, 0)) { 1150 cli_out("uC 0 status: RESET\n"); 1151 sal_memcpy(fwInfo[0].status, "RESET", sizeof("RESET")); 1152 } 1153 else { 1154 mcs_core_status(unit, 0, 0x100000); 1155 } 1156 if (soc_uc_in_reset(unit, 1)) { 1157 cli_out("uC 1 status: RESET\n"); 1158 sal_memcpy(fwInfo[1].status, "RESET", sizeof("RESET")); 1159 } 1160 else { 1161 mcs_core_status(unit, 1, 0x200000); 1162 } 1163 } 1164 1165 return CMD_OK; 1166 } 1167 1168 1169 char mcstimestamp_usage[] = 1170 "Parameters: [event_id] [ENable|DISable|CHanGe]\n\t" 1171 "Display or configure timestamps captured by UC\n\t" 1172 "event_id = timestamp event index. If empty, all will print.\n\t" 1173 "ENable = enable the specified timestamp event\n\t" 1174 "DISable = disable specified timestamp event, unless used by firmware\n\t" 1175 "CHanGe = poll specified timestamp event for a change before displaying\n"; 1176 1177 cmd_result_t 1178 mcstimestamp_cmd(int unit, args_t *a) 1179 { 1180 char uint64_decimal_string[27]; 1181 int rv, i; 1182 int min_event_id = 0; 1183 int max_event_id = (soc_feature(unit, soc_feature_iproc)) ? (MOS_MSG_MAX_TS_EVENTS-1)/*18*/ : 12; 1184 1185 char *arg = ARG_GET(a); 1186 uint64 diff; 1187 int poll_for_change = 0; 1188 1189 if (!sh_check_attached("mcsmsg", unit)) { 1190 return(CMD_FAIL); 1191 } 1192 1193 if (!soc_feature(unit, soc_feature_uc)) { 1194 return (CMD_FAIL); 1195 } 1196 1197 if (arg) { 1198 int event_id; 1199 1200 if (!isint(arg)) { 1201 return CMD_USAGE; 1202 } 1203 event_id = parse_integer(arg); 1204 1205 arg = ARG_GET(a); 1206 if (arg) { 1207 if (parse_cmp("ENable", arg, 0)) { 1208 if (SOC_FAILURE(soc_cmic_uc_msg_timestamp_enable(unit, event_id))) { 1209 return CMD_FAIL; 1210 } else { 1211 return CMD_OK; 1212 } 1213 } 1214 if (parse_cmp("DISable", arg, 0)) { 1215 if (SOC_FAILURE(soc_cmic_uc_msg_timestamp_disable(unit, event_id))) { 1216 return CMD_FAIL; 1217 } else { 1218 return CMD_OK; 1219 } 1220 } 1221 if (parse_cmp("CHanGe", arg, 0)) { 1222 poll_for_change = 1; 1223 } else { 1224 return CMD_USAGE; 1225 } 1226 } 1227 1228 /* only a single integer argument */ 1229 min_event_id = event_id; 1230 max_event_id = event_id; 1231 } 1232 1233 cli_out(" # Last Timestamp Prev Timestamp <difference> Equivalent TS1 Equivalent Full Time\n"); 1234 1235 for (i = min_event_id; i <= max_event_id; ++i) { 1236 soc_cmic_uc_ts_data_t ts_data; 1237 1238 rv = soc_cmic_uc_msg_timestamp_get(unit, i, &ts_data); 1239 if (poll_for_change) { 1240 soc_cmic_uc_ts_data_t ts_data_orig = ts_data; 1241 int iter = 0; 1242 const int max_iter = 100000; 1243 while (rv == SOC_E_NONE && COMPILER_64_EQ(ts_data.hwts,ts_data_orig.hwts) && ++iter < max_iter) { 1244 rv = soc_cmic_uc_msg_timestamp_get(unit, i, &ts_data); 1245 } 1246 if (iter == max_iter) { 1247 cli_out("Timed out waiting for change in timestamp\n"); 1248 } 1249 } 1250 if (SOC_FAILURE(rv)) { 1251 cli_out("soc_cmic_uc_msg_timestamp_get failed: %s (%d)\n", soc_errmsg(rv), rv); 1252 } else { 1253 diff = ts_data.hwts; 1254 COMPILER_64_SUB_64(diff, ts_data.prev_hwts); 1255 1256 format_uint64_decimal(uint64_decimal_string, ts_data.time.seconds, 0); 1257 1258 cli_out("%2d: %08x:%08x %08x:%08x <%10u> %08x:%08x %s.%09u\n", 1259 i, 1260 (unsigned)COMPILER_64_HI(ts_data.hwts), (unsigned)COMPILER_64_LO(ts_data.hwts), 1261 (unsigned)COMPILER_64_HI(ts_data.prev_hwts), (unsigned)COMPILER_64_LO(ts_data.prev_hwts), 1262 (unsigned)COMPILER_64_LO(diff), 1263 (unsigned)COMPILER_64_HI(ts_data.hwts_ts1), (unsigned)COMPILER_64_LO(ts_data.hwts_ts1), 1264 uint64_decimal_string, (unsigned)ts_data.time.nanoseconds); 1265 } 1266 } 1267 1268 return CMD_OK; 1269 } 1270 1271 1272 #endif /* CMICM support */