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

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, &params);
    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, &params,
    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) */