phymod_symop.c (18203B)
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 * This file contains a set of functions which can be used to parse an 8 * SDK CLI command into a symbolic PHY operation. 9 * 10 * For example usage, please refer to e.g. $SDK/src/appl/diag/port.c. 11 */ 12 13 #include <appl/diag/parse.h> 14 #include <appl/diag/system.h> 15 #include <appl/diag/phymod/phymod_symop.h> 16 17 #include <phymod/phymod_reg.h> 18 #include <shared/bsl.h> 19 20 #include <soc/phy/phyctrl.h> 21 #if defined(PORTMOD_SUPPORT) 22 #include <soc/portmod/portmod.h> 23 #endif 24 25 #if defined(PHYMOD_SUPPORT) 26 27 #define PHY_FIELD_NAME_MAX 80 28 #define PHY_FIELDS_MAX 32 29 30 typedef struct phy_field_s { 31 char name[PHY_FIELD_NAME_MAX + 1]; 32 uint32 val; 33 } phy_field_t; 34 35 typedef struct phy_field_info_s { 36 uint32 regval; /* raw value */ 37 int num_fields; 38 phy_field_t field[PHY_FIELDS_MAX]; 39 } phy_field_info_t; 40 41 typedef struct phy_iter_s { 42 const char *name; 43 const char *found_name; 44 #define PHY_SHELL_SYM_RAW 0x1 /* Do not decode fields */ 45 #define PHY_SHELL_SYM_LIST 0x2 /* List symbol only */ 46 #define PHY_SHELL_SYM_NZ 0x4 /* Skip if reg/field is zero */ 47 #define PHY_SHELL_SYM_RESET 0x8 /* Reset register */ 48 uint32 flags; 49 uint32 addr; 50 int lane; 51 int pll_idx; 52 int count; 53 const phymod_symbols_t *symbols; 54 phymod_phy_access_t *phy_access; 55 phy_field_info_t *finfo; 56 char tmpstr[64]; 57 } phy_iter_t; 58 59 STATIC int 60 _phymod_encode_field(const phymod_symbol_t *symbol, 61 const char **fnames, 62 const char *field, uint32 value, 63 uint32 *and_masks, uint32 *or_masks) 64 { 65 #if PHYMOD_CONFIG_INCLUDE_FIELD_NAMES == 1 66 phymod_field_info_t finfo; 67 uint32 zero_val; 68 69 PHYMOD_SYMBOL_FIELDS_ITER_BEGIN(symbol->fields, finfo, fnames) { 70 71 if (sal_strcasecmp(finfo.name, field)) { 72 continue; 73 } 74 75 zero_val = 0; 76 phymod_field_set(and_masks, finfo.minbit, finfo.maxbit, &zero_val); 77 /* coverity[callee_ptr_arith] */ 78 phymod_field_set(or_masks, finfo.minbit, finfo.maxbit, &value); 79 80 return 0; 81 } PHYMOD_SYMBOL_FIELDS_ITER_END(); 82 83 #endif /* PHYMOD_CONFIG_INCLUDE_FIELD_NAMES */ 84 85 return -1; 86 } 87 88 #if PHYMOD_CONFIG_INCLUDE_FIELD_INFO == 1 89 STATIC int 90 _phymod_print_str(const char *str) 91 { 92 cli_out("%s", str); 93 return 0; 94 } 95 #endif 96 97 STATIC int 98 _phymod_sym_list(const phymod_symbol_t *symbol, uint32 flags, const char **fnames) 99 { 100 uint32 reg_addr; 101 uint32 num_copies; 102 103 cli_out("Name: %s", symbol->name); 104 if (symbol->alias != NULL) { 105 cli_out(" (%s)", symbol->alias); 106 } 107 cli_out("\n"); 108 reg_addr = symbol->addr & 0x00ffffff; 109 switch (PHYMOD_REG_ACCESS_METHOD(symbol->addr)) { 110 case PHYMOD_REG_ACC_AER_IBLK: 111 case PHYMOD_REG_ACC_TSC_IBLK: 112 cli_out("Address: 0x%"PRIx32"", reg_addr & 0xfffff); 113 num_copies = (reg_addr >> 20) & 0xf; 114 if (num_copies == 1) { 115 cli_out(" (1 copy only)"); 116 } else if (num_copies == 2) { 117 cli_out(" (2 copies only)"); 118 } 119 cli_out("\n"); 120 break; 121 case PHYMOD_REG_ACC_RAW: 122 default: 123 cli_out("Address: 0x%"PRIx32"\n", symbol->addr); 124 break; 125 } 126 if (flags & PHY_SHELL_SYM_RAW) { 127 cli_out("\n"); 128 return 0; 129 } 130 #if PHYMOD_CONFIG_INCLUDE_RESET_VALUES == 1 131 cli_out("Reset: 0x%"PRIx32" (%"PRIu32")\n", 132 symbol->resetval, symbol->resetval); 133 #endif 134 #if PHYMOD_CONFIG_INCLUDE_FIELD_INFO == 1 135 if (symbol->fields) { 136 cli_out("Fields: %"PRIu32"\n", 137 phymod_field_info_count(symbol->fields)); 138 phymod_symbol_show_fields(symbol, fnames, NULL, 0, 139 _phymod_print_str, 140 NULL, NULL); 141 } 142 #endif 143 return 0; 144 } 145 146 STATIC int 147 _phymod_sym_iter_count(const phymod_symbol_t *symbol, void *vptr) 148 { 149 phy_iter_t *phy_iter = (phy_iter_t *)vptr; 150 151 return ++(phy_iter->count); 152 } 153 154 STATIC int 155 _phymod_sym_find_hex(const phymod_symbol_t *symbol, void *vptr) 156 { 157 phy_iter_t *phy_iter = (phy_iter_t *)vptr; 158 159 if (phy_iter->symbols == NULL) { 160 return -1; 161 } 162 163 if ((symbol->addr & 0xffff) == phy_iter->addr) { 164 phy_iter->found_name = symbol->name; 165 } 166 return 0; 167 } 168 169 STATIC int 170 _phymod_sym_iter_op(const phymod_symbol_t *symbol, void *vptr) 171 { 172 int rv; 173 uint32 data; 174 uint32 and_mask; 175 uint32 or_mask; 176 uint32 lane_mask; 177 phymod_phy_access_t lpa, *pa; 178 phy_iter_t *phy_iter = (phy_iter_t *)vptr; 179 phy_field_t *fld; 180 uint32 reg_addr; 181 uint32 fdx; 182 char lane_str[16]; 183 char pIdx_str[16]; 184 const char **fnames; 185 186 if (phy_iter->symbols == NULL) { 187 return -1; 188 } 189 fnames = phy_iter->symbols->field_names; 190 191 if (phy_iter->flags & PHY_SHELL_SYM_LIST) { 192 _phymod_sym_list(symbol, phy_iter->flags, fnames); 193 return 0; 194 } 195 196 pa = phy_iter->phy_access; 197 /*There are only two PLL at most in a SerDes core. 198 0 : PLL0 199 1 : PLL1 200 */ 201 if ((phy_iter->pll_idx >= 0) && (phy_iter->pll_idx <= 1)) { 202 pa->access.pll_idx = phy_iter->pll_idx; 203 } 204 if (phy_iter->lane >= 0) { 205 lane_mask = 1 << phy_iter->lane; 206 if (lane_mask != pa->access.lane_mask) { 207 sal_memcpy(&lpa, pa, sizeof(lpa)); 208 209 while ((lane_mask && (lane_mask & 0xFF)) == 0) { 210 lane_mask >>= 8; 211 lpa.access.addr += 8; 212 } 213 lpa.access.lane_mask = lane_mask; 214 pa = &lpa; 215 } 216 } 217 reg_addr = symbol->addr; 218 219 if (phy_iter->flags & PHY_SHELL_SYM_RESET) { 220 #if PHYMOD_CONFIG_INCLUDE_RESET_VALUES == 1 221 if (phymod_phy_reg_write(pa, reg_addr, symbol->resetval) != 0) { 222 cli_out("Error resetting %s\n", symbol->name); 223 return -1; 224 } 225 #endif 226 return 0; 227 } 228 229 if (phy_iter->finfo) { 230 if (phy_iter->finfo->num_fields) { 231 and_mask = ~0; 232 or_mask = 0; 233 for (fdx = 0; fdx < phy_iter->finfo->num_fields; fdx++) { 234 fld = &phy_iter->finfo->field[fdx]; 235 /* coverity[callee_ptr_arith] */ 236 rv = _phymod_encode_field(symbol, fnames, 237 fld->name, fld->val, 238 &and_mask, &or_mask); 239 if (rv < 0) { 240 cli_out("Invalid field: %s\n", fld->name); 241 return -1; 242 } 243 } 244 } else { 245 and_mask = 0; 246 or_mask = phy_iter->finfo->regval; 247 } 248 249 /* Read, update and write PHY register */ 250 if (phymod_phy_reg_read(pa, reg_addr, &data) != 0) { 251 cli_out("Error reading %s\n", symbol->name); 252 return -1; 253 } 254 data &= and_mask; 255 data |= or_mask; 256 if (phymod_phy_reg_write(pa, reg_addr, data) != 0) { 257 cli_out("Error writing %s\n", symbol->name); 258 return -1; 259 } 260 } 261 else { 262 /* Decode PHY register */ 263 if (phymod_phy_reg_read(pa, reg_addr, &data) != 0) { 264 cli_out("Error reading %s\n", symbol->name); 265 return -1; 266 } 267 if (data == 0 && (phy_iter->flags & PHY_SHELL_SYM_NZ)) { 268 return 0; 269 } 270 lane_str[0] = 0; 271 pIdx_str[0] = 0; 272 if (phy_iter->lane >= 0) { 273 sal_sprintf(lane_str, ".%d", phy_iter->lane); 274 if (phy_iter->pll_idx >= 0) { 275 sal_sprintf(pIdx_str, ".%d", phy_iter->pll_idx); 276 } 277 } 278 cli_out("%s%s%s [0x%08"PRIx32"] = 0x%04"PRIx32"\n", 279 symbol->name, lane_str, pIdx_str, reg_addr, data); 280 #if PHYMOD_CONFIG_INCLUDE_FIELD_INFO == 1 281 if (phy_iter->flags & PHY_SHELL_SYM_RAW) { 282 return 0; 283 } 284 if (symbol->fields) { 285 /* coverity[callee_ptr_arith] */ 286 phymod_symbol_show_fields(symbol, fnames, &data, 287 (phy_iter->flags & PHY_SHELL_SYM_NZ), 288 _phymod_print_str, 289 NULL, NULL); 290 } 291 #endif 292 } 293 return 0; 294 } 295 296 297 #define MAX_PHYS_PER_PORT 6 298 299 /* Get PHYMod symbol table and access object from unit/port */ 300 int 301 phymod_sym_info(int unit, int port, int intermediate, phymod_symbols_iter_t *iter, 302 phymod_phy_access_t *pm_acc) 303 { 304 phy_ctrl_t *pc; 305 #ifdef BCM_TOMAHAWK3_SUPPORT 306 int pm_type; 307 int pport; 308 #endif 309 310 if (pm_acc == NULL) { 311 return -1; 312 } 313 #if defined(PORTMOD_SUPPORT) 314 if (soc_feature(unit, soc_feature_portmod)) { 315 int rv, num_phy; 316 phymod_phy_access_t phy_acc[MAX_PHYS_PER_PORT]; 317 portmod_access_get_params_t params; 318 int core_index; 319 phy_iter_t *phy_iter =(phy_iter_t*) iter->vptr; 320 321 portmod_access_get_params_t_init(unit, ¶ms); 322 /* By default we get the access object(s) of outermost PHY */ 323 if (intermediate) { 324 /* Request access object(s) of innermost PHY */ 325 params.phyn = 0; 326 } 327 328 rv = portmod_port_phy_lane_access_get(unit, port, ¶ms, 329 COUNTOF(phy_acc), 330 phy_acc, &num_phy, NULL); 331 332 #ifdef BCM_TOMAHAWK3_SUPPORT 333 pport = SOC_INFO(unit).port_l2p_mapping[port]; 334 rv = SOC_PORTCTRL_FUNCTIONS(unit)->soc_portctrl_pm_type_get(unit, 335 pport, &pm_type); 336 337 if (SOC_FAILURE(rv)) { 338 return rv; 339 } 340 if (pm_type == portmodDispatchTypePm8x50) { 341 core_index = phy_iter->lane / 8; 342 phy_iter->lane %= 8; 343 } else 344 #endif 345 { 346 core_index = phy_iter->lane/4; 347 phy_iter->lane %=4; 348 } 349 if (rv < 0 || core_index >= num_phy) { 350 return -1; 351 } 352 /* Only a single core per port is currently supported */ 353 sal_memcpy(pm_acc, &phy_acc[core_index], sizeof(*pm_acc)); 354 return 0; 355 } 356 #endif 357 if (phy_port_info[unit] == NULL) { 358 return -1; 359 } 360 /* Set up per-port info */ 361 pc = EXT_PHY_SW_STATE(unit, port); 362 if (intermediate || pc == NULL) { 363 pc = INT_PHY_SW_STATE(unit, port); 364 } 365 if (pc == NULL) { 366 return -1; 367 } 368 if (pc->phymod_ctrl.phy[0] == NULL) { 369 return -1; 370 } 371 sal_memcpy(pm_acc, &pc->phymod_ctrl.phy[0]->pm_phy, sizeof(*pm_acc)); 372 373 return 0; 374 } 375 376 /* 377 * Function: 378 * phymod_symop_init 379 * Purpose: 380 * Parse command line for symbolic PHY operation 381 * Parameters: 382 * iter - symbol table iterator structure 383 * a - CLI argument list 384 * Returns: 385 * CMD_OK if no error 386 */ 387 int 388 phymod_symop_init(phymod_symbols_iter_t *iter, args_t *a) 389 { 390 phy_iter_t *phy_iter; 391 phy_field_info_t *finfo = NULL; 392 char *c; 393 const char *name; 394 uint32 flags; 395 int fdx, lane, pll_idx; 396 397 if (iter == NULL) { 398 return CMD_FAIL; 399 } 400 401 phy_iter = sal_alloc(sizeof(phy_iter_t), "phy_iter"); 402 if (phy_iter == NULL) { 403 cli_out("%s: Unable to allocate PHY iterator\n", 404 ARG_CMD(a)); 405 return CMD_FAIL; 406 } 407 408 sal_memset(iter, 0, sizeof(*iter)); 409 sal_memset(phy_iter, 0, sizeof(*phy_iter)); 410 iter->vptr = phy_iter; 411 412 if ((c = ARG_GET(a)) == NULL) { 413 return CMD_USAGE; 414 } 415 name = c; 416 417 /* Check for output flags */ 418 flags = 0; 419 do { 420 if (sal_strcmp(c, "list") == 0) { 421 flags |= PHY_SHELL_SYM_LIST; 422 } else if (sal_strcmp(c, "raw") == 0) { 423 flags |= PHY_SHELL_SYM_RAW; 424 } else if (sal_strcmp(c, "nz") == 0) { 425 flags |= PHY_SHELL_SYM_NZ; 426 } else if (sal_strcmp(c, "reset") == 0) { 427 flags |= PHY_SHELL_SYM_RESET; 428 } else { 429 name = c; 430 break; 431 } 432 } while ((c = ARG_GET(a)) != NULL); 433 434 /* Check for lane-specification, i.e. <regname>.<lane> */ 435 lane = -1; 436 pll_idx = -1; 437 /* coverity[returned_pointer] */ 438 c = sal_strchr(name, '.'); 439 if (c != NULL) { 440 sal_strncpy(phy_iter->tmpstr, name, sizeof(phy_iter->tmpstr)); 441 phy_iter->tmpstr[sizeof(phy_iter->tmpstr)-1] = 0; 442 name = phy_iter->tmpstr; 443 c = sal_strchr(name, '.'); 444 if (c != NULL) { 445 *c++ = 0; 446 lane = sal_ctoi(c, NULL); 447 c = sal_strchr(c, '.'); 448 if (c != NULL) { 449 *c++ = 0; 450 pll_idx = sal_ctoi(c, NULL); 451 } 452 } 453 } 454 455 if ((c = ARG_GET(a)) != NULL) { 456 finfo = sal_alloc(sizeof(phy_field_info_t), "field_info"); 457 if (finfo == NULL) { 458 cli_out("%s: Unable to allocate field info\n", 459 ARG_CMD(a)); 460 return CMD_FAIL; 461 } 462 sal_memset(finfo, 0, sizeof (*finfo)); 463 if (isint(c)) { 464 /* Raw register value */ 465 finfo->regval = parse_integer(c); 466 /* No further parameters expected */ 467 if (ARG_CNT(a) > 0) { 468 cli_out("%s: Unexpected argument %s\n", 469 ARG_CMD(a), ARG_CUR(a)); 470 sal_free(finfo); 471 return CMD_USAGE; 472 } 473 } else { 474 /* Individual fields */ 475 fdx = 0; 476 do { 477 if (finfo->num_fields >= PHY_FIELDS_MAX) { 478 cli_out("%s: Too many fields\n", 479 ARG_CMD(a)); 480 sal_free(finfo); 481 return CMD_FAIL; 482 } 483 sal_strncpy(finfo->field[fdx].name, c, 484 PHY_FIELD_NAME_MAX); 485 c = sal_strchr(finfo->field[fdx].name, '='); 486 if (c == NULL) { 487 cli_out("%s: Invalid field assignment: %s\n", 488 ARG_CMD(a), finfo->field[fdx].name); 489 sal_free(finfo); 490 return CMD_FAIL; 491 } 492 *c++ = 0; 493 finfo->field[fdx].val = parse_integer(c); 494 fdx++; 495 } while ((c = ARG_GET(a)) != NULL); 496 finfo->num_fields = fdx; 497 } 498 } 499 500 iter->name = name; 501 iter->matching_mode = PHYMOD_SYMBOLS_ITER_MODE_EXACT; 502 if (sal_strcmp(iter->name, "*") != 0) { 503 switch (iter->name[0]) { 504 case '^': 505 iter->matching_mode = PHYMOD_SYMBOLS_ITER_MODE_START; 506 iter->name++; 507 break; 508 case '*': 509 iter->matching_mode = PHYMOD_SYMBOLS_ITER_MODE_STRSTR; 510 iter->name++; 511 break; 512 case '@': 513 iter->matching_mode = PHYMOD_SYMBOLS_ITER_MODE_EXACT; 514 iter->name++; 515 break; 516 default: 517 if (flags & PHY_SHELL_SYM_LIST) { 518 iter->matching_mode = PHYMOD_SYMBOLS_ITER_MODE_STRSTR; 519 } 520 break; 521 } 522 } 523 phy_iter->lane = lane; 524 phy_iter->pll_idx = pll_idx; 525 phy_iter->flags = flags; 526 phy_iter->finfo = finfo; 527 528 /* Save for symbol lookup based on register address */ 529 phy_iter->name = iter->name; 530 phy_iter->addr = sal_ctoi(phy_iter->name, NULL); 531 532 return CMD_OK; 533 } 534 535 /* 536 * Function: 537 * phymod_symop_exec 538 * Purpose: 539 * Execute operation on one or more symbols 540 * Parameters: 541 * iter - symbol table iterator structure 542 * symbols - symbol table 543 * pm_acc - PHY access structure 544 * hdr - header string show for register read operations 545 * Returns: 546 * CMD_OK if no error 547 */ 548 int 549 phymod_symop_exec(phymod_symbols_iter_t *iter, const phymod_symbols_t *symbols, 550 phymod_phy_access_t *pm_acc, char *hdr) 551 { 552 phy_iter_t *phy_iter; 553 554 if (iter == NULL || iter->vptr == NULL) { 555 return CMD_FAIL; 556 } 557 phy_iter = (phy_iter_t *)iter->vptr; 558 559 iter->symbols = symbols; 560 phy_iter->symbols = iter->symbols; 561 phy_iter->phy_access = pm_acc; 562 563 if (phy_iter->flags & PHY_SHELL_SYM_LIST) { 564 /* 565 * For symbol listings we force raw mode if multiple 566 * matches are found. 567 */ 568 phy_iter->count = 0; 569 iter->function = _phymod_sym_iter_count; 570 if (phymod_symbols_iter(iter) > 1) { 571 phy_iter->flags |= PHY_SHELL_SYM_RAW; 572 } 573 } 574 575 iter->function = _phymod_sym_iter_op; 576 577 if (phy_iter->finfo == NULL && (phy_iter->flags & PHY_SHELL_SYM_RESET) == 0) { 578 /* Show header only if not writing */ 579 cli_out("%s", hdr ? hdr : ""); 580 } 581 /* If numerical value specified, then look up symbol name */ 582 if (phy_iter->name[0] >= '0' && phy_iter->name[0] <= '9') { 583 iter->function = _phymod_sym_find_hex; 584 iter->name = "*"; 585 phy_iter->found_name = NULL; 586 /* Search for register address */ 587 if (phymod_symbols_iter(iter) == 0 || phy_iter->found_name == NULL) { 588 cli_out("No matching address\n"); 589 return CMD_OK; 590 } 591 iter->name = phy_iter->found_name; 592 /* Restore iterator function */ 593 iter->function = _phymod_sym_iter_op; 594 } 595 /* Iterate over all symbols in symbol table */ 596 if (phymod_symbols_iter(iter) == 0) { 597 cli_out("No matching symbols\n"); 598 } 599 return CMD_OK; 600 } 601 602 /* 603 * Function: 604 * phymod_symop_cleanup 605 * Purpose: 606 * Free resources allocated by phymod_symop_init 607 * Parameters: 608 * iter - symbol table iterator structure 609 * Returns: 610 * CMD_OK if no error 611 */ 612 int 613 phymod_symop_cleanup(phymod_symbols_iter_t *iter) 614 { 615 phy_iter_t *phy_iter; 616 617 if (iter == NULL || iter->vptr == NULL) { 618 return CMD_FAIL; 619 } 620 phy_iter = (phy_iter_t *)iter->vptr; 621 622 if (phy_iter != NULL) { 623 if (phy_iter->finfo != NULL) { 624 sal_free(phy_iter->finfo); 625 } 626 sal_free(phy_iter); 627 } 628 sal_memset(iter, 0, sizeof(*iter)); 629 630 return CMD_OK; 631 } 632 633 #else 634 int phymod_sym_access_not_empty; 635 #endif /* defined(PHYMOD_SUPPORT) */