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

regtest.c (14455B)


      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  * Register Test
      8  *
      9  *
     10  * This module is also used by the main SOC diagnostics register tests,
     11  * fronted by user interface code.
     12  */
     13 
     14 #include <shared/bsl.h>
     15 #include <sal/core/libc.h>
     16 #include <soc/cm.h>
     17 #include <soc/register.h>
     18 #include <soc/debug.h>
     19 #include <soc/drv.h>
     20 #ifdef BCM_TOMAHAWK_SUPPORT
     21 #include <soc/tomahawk.h>
     22 #endif /* BCM_TOMAHAWK_SUPPORT */
     23 
     24 #if defined(BCM_ESW_SUPPORT)
     25 
     26 #if defined(SER_TR_TEST_SUPPORT)
     27 
     28 #define _SER_TEST_REG_SOC_FIELD_NAME(unit, field) \
     29     ((field >= 0)? SOC_FIELD_NAME((unit), (field)) : "INVALIDf")
     30 
     31 
     32 /*
     33  * Function:
     34  *      ser_test_reg_write
     35  * Purpose:
     36  *      write to register without update cache
     37  * Parameters:
     38  *      unit        - (IN) Device Number
     39  *      test_reg   - (IN) contains the current state of the test.
     40  * Returns:
     41  *      An error if one is generated by the ser_test_reg_write, otherwise SOC_E_NONE
     42  */
     43 soc_error_t
     44 ser_test_reg_write(int unit, ser_reg_test_data_t *test_reg)
     45 {
     46     soc_error_t rv = SOC_E_NONE;
     47 
     48     if (SOC_REG_IS_64(unit, test_reg->reg)) {
     49         soc_reg64_field32_set(unit, test_reg->reg, test_reg->reg_buf,
     50                               test_reg->test_field, *test_reg->field_buf);
     51     } else {
     52         soc_reg_field_set(unit, test_reg->reg, ((uint32 *) test_reg->reg_buf),
     53                           test_reg->test_field, *test_reg->field_buf);
     54     }
     55 
     56     rv = soc_reg_set_nocache(unit, test_reg->reg, test_reg->port,
     57                              test_reg->index, *test_reg->reg_buf);
     58 
     59     if (SOC_FAILURE(rv)) {
     60         LOG_ERROR(BSL_LS_SOC_SER,
     61                   (BSL_META_U(unit,
     62                   "unit %d %s port %d reg write error\n"),
     63                    unit, test_reg->reg_name, test_reg->port));
     64     }
     65     return rv;
     66 }
     67 
     68 
     69 /*
     70  * Function:
     71  *      ser_test_reg_read
     72  * Purpose:
     73  *      Read register and update the test data.
     74  * Parameters:
     75  *      unit        - (IN) Device Number
     76  *      test_reg   - (IN & OUT) contains the current state of the test data.
     77  *                    The members reg_buf and field_buf will be modified by this function
     78  * Returns:
     79  *      An error if one is generated by the soc_mem_read, otherwise SOC_E_NONE
     80  */
     81 
     82 soc_error_t
     83 ser_test_reg_read(int unit, ser_reg_test_data_t *test_reg)
     84 {
     85     soc_error_t rv = SOC_E_NONE;
     86     soc_reg_t reg = test_reg->reg;
     87     uint32 data32 = 0;
     88 
     89     rv = soc_reg_get(unit, reg, test_reg->port, test_reg->index, test_reg->reg_buf);
     90     if (SOC_FAILURE(rv)) {
     91         LOG_VERBOSE(BSL_LS_SOC_SER,
     92                   (BSL_META_U(unit,
     93                   "unit %d NACK received for %s port %d:\n\t"),
     94                    unit, SOC_REG_NAME(unit, reg), test_reg->port));
     95     }
     96 
     97     if (SOC_REG_IS_64(unit, reg)) {
     98         *test_reg->field_buf = soc_reg64_field32_get(unit, reg, *test_reg->reg_buf,
     99                                                      test_reg->test_field);
    100     } else {
    101         data32 = COMPILER_64_LO(*test_reg->reg_buf);
    102         *test_reg->field_buf = soc_reg_field_get(unit, reg, data32, test_reg->test_field);
    103     }
    104 
    105     return rv;
    106 }
    107 
    108 
    109 
    110 /*
    111  * Function:
    112  *      soc_ser_create_reg_test_data
    113  * Purpose:
    114  *      Populates and performs data verification on a ser_test_reg_t structure.  This was
    115  *      broken out into a separate function to avoid performing this work an excessive number
    116  *      of times.
    117  * Parameters:
    118  *      unit                 - (IN) Device Number
    119  *      reg_data             - (IN) A pointer to a uint32 array
    120  *      fieldData            - (IN) A pointer to a uint 32 array
    121  *      parity_enable_reg    - (IN) Register which turns on and off parity protection
    122  *      parity_enable_field   - (IN) The field in the parity enable register
    123  *      port                 - (IN) The port for this reg.
    124  *      index             - (IN) The index for this reg.
    125  *      reg_test_data            - (OUT)A pointer to a data structure cotaining SER test date.
    126  * Returns:
    127  *      SOC_E_NONE if the test passes, and error if it does
    128  */
    129 void
    130 soc_ser_create_reg_test_data(int unit, uint32 *reg_data, uint32 *field_data,
    131                              soc_reg_t parity_enable_reg,
    132                              soc_field_t parity_enable_field,
    133                              soc_reg_t reg, soc_field_t test_field,
    134                              soc_port_t port, int index,
    135                              ser_reg_test_data_t *reg_test_data)
    136 {
    137     static soc_field_t field_names[] = {
    138                                         ECCf,
    139                                         EVEN_PARITYf,
    140                                         PARITYf,
    141                                         INVALIDf};
    142     int i, found = 0, field_length = 1, field_num = 0;
    143 #ifdef SOC_REG_NAME
    144     size_t len;
    145 #endif
    146 
    147     sal_memset(reg_test_data, 0 , sizeof(ser_reg_test_data_t));
    148 
    149     reg_test_data->reg = reg;
    150     reg_test_data->parity_enable_reg = parity_enable_reg;
    151     reg_test_data->parity_enable_field = parity_enable_field;
    152     reg_test_data->port = port;
    153     reg_test_data->index = index;
    154     reg_test_data->reg_info = &SOC_REG_INFO(unit, reg_test_data->reg);
    155     reg_test_data->test_field = test_field;
    156 
    157     /* An INVALIDf, 0 passed in for test_field implies we should select
    158      * any valid field. */
    159     if ((test_field == INVALIDf) || (test_field == 0) ||
    160         !SOC_REG_FIELD_VALID(unit, reg_test_data->reg, test_field)
    161        ) {
    162         /* select from preferred list */
    163         for (i = 0; (field_names[i] != INVALIDf); i++) {
    164             if (SOC_REG_FIELD_VALID(unit, reg_test_data->reg, field_names[i])) {
    165                 reg_test_data->test_field = field_names[i];
    166                 found = 1;
    167                 break;
    168             }
    169         }
    170 
    171         /* select first multi-bit field or last 1-bit field */
    172         if (!found && (reg_test_data->reg_info != NULL)) {
    173            field_num = reg_test_data->reg_info->nFields;
    174            for (i = 0; i < field_num; i++) {
    175                reg_test_data->test_field = reg_test_data->reg_info->fields[i].field;
    176                field_length = soc_reg_field_length(unit, reg_test_data->reg,
    177                                                    reg_test_data->test_field);
    178                if (field_length > 1) {
    179                    found = 1;
    180                    break;
    181                }
    182            }
    183         }
    184     }
    185     LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit,
    186                 "unit %d, soc_ser_create_test_reg: error_inject_view: reg %s, test_field %s\n"),
    187                  unit, SOC_REG_NAME(unit, reg_test_data->reg),
    188                  _SER_TEST_REG_SOC_FIELD_NAME(unit, reg_test_data->test_field)));
    189 
    190     reg_test_data->reg_buf = (uint64 *) reg_data;
    191     reg_test_data->field_buf = field_data;
    192 #ifdef SOC_REG_NAME
    193     /* coverity[secure_coding] */
    194     len = sal_strlen(SOC_REG_NAME(unit, reg_test_data->reg));
    195     if(sizeof(reg_test_data->reg_name)- 1 < len)
    196             len = sizeof(reg_test_data->reg_name)- 1;
    197     sal_strncpy(reg_test_data->reg_name, SOC_REG_NAME(unit, reg_test_data->reg), len);
    198     reg_test_data->reg_name[len] = 0;
    199     /* coverity[secure_coding] */
    200     len = sal_strlen(_SER_TEST_REG_SOC_FIELD_NAME(unit, reg_test_data->test_field));
    201     if(sizeof(reg_test_data->field_name)- 1 < len)
    202       len = sizeof(reg_test_data->field_name)- 1;
    203     sal_strncpy(reg_test_data->field_name,
    204                _SER_TEST_REG_SOC_FIELD_NAME(unit, reg_test_data->test_field), len);
    205     reg_test_data->field_name[len] = 0;
    206 #else
    207     sprintf(reg_test_data->mem_name, "Reg ID: %d", reg_test_data->reg);
    208     sprintf(reg_test_data->field_name, "Field ID: %d", reg_test_data->test_field);
    209 #endif
    210 }
    211 
    212 extern int soc_ser_test_long_sleep;
    213 extern int soc_ser_test_long_sleep_time_us;
    214 
    215 soc_error_t
    216 _soc_ser_reg_inject_error(int unit, ser_reg_test_data_t *test_reg)
    217 {
    218     if((test_reg->field_buf[0] & 1) == 1) {
    219         test_reg->field_buf[0] &= 0xFFFFFFFE;
    220     } else {
    221         test_reg->field_buf[0] |= 0x00000001;
    222     }
    223 
    224     test_reg->badData = test_reg->field_buf[0];
    225 
    226     /*Disable writing to cache for fudged data.*/
    227     SOC_IF_ERROR_RETURN(ser_test_reg_write(unit, test_reg));
    228 
    229     return SOC_E_NONE;
    230 }
    231 
    232 /*
    233  * Function:
    234  *      _ser_test_parity_control
    235  * Purpose:
    236  *      Disables/enables parity for the provided register.
    237  * Parameters:
    238  *      unit          - (IN) Device Number
    239  *      test_reg     - (IN) Contains parity registers to set.
    240  *      enable        - (IN) (Bool) enable parity if true, disable if false
    241  *
    242  * Returns:
    243  *      SOC_E_NONE if no errors are encountered while setting parity.
    244  */
    245 soc_error_t
    246 _ser_test_reg_parity_control(int unit, ser_reg_test_data_t *test_reg, int enable)
    247 {
    248     soc_error_t rv = SOC_E_NONE;
    249     rv = soc_reg_field32_modify(unit, test_reg->parity_enable_reg,
    250                                 test_reg->port,
    251                                 test_reg->parity_enable_field, enable);
    252     return rv;
    253 }
    254 
    255 /*
    256  * Function:
    257  *      ser_test_reg
    258  * Purpose:
    259  *      Serform a Software Error Recovery test on one register.
    260  * Parameters:
    261  *      unit                  - (IN) Device Number
    262  *      test_reg            - (IN) Structure which holds the test data and some
    263                                     intermediate results.
    264  *      error_count        - (OUT)Increments if  failed.
    265  * Returns:
    266  *      SOC_E_NONE if the test passes, an error if it does not
    267  */
    268 soc_error_t
    269 ser_test_reg(int unit, ser_reg_test_data_t *test_reg,
    270                int *error_count)
    271 {
    272     int startErrorCount;
    273     soc_error_t rv = SOC_E_NONE;
    274 
    275     startErrorCount = *error_count;
    276 
    277     if (!SOC_REG_IS_VALID(unit, test_reg->reg)) {
    278         LOG_CLI((BSL_META_U(unit,
    279                  "%s is not a valid register for this platform. Skipping.\n"),
    280                  SOC_REG_NAME(unit, test_reg->reg)));
    281         return SOC_E_UNAVAIL;
    282     }
    283 
    284     rv = (ser_test_reg_read(unit, test_reg));
    285     if (SOC_FAILURE(rv)) {
    286         (*error_count)++;
    287         LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit,
    288                     "SER failed. 1st Read got NACK. mem: %s field: %s\n"),
    289                     test_reg->reg_name,
    290                     test_reg->field_name));
    291         return rv;
    292     }
    293 
    294     /*Disable Parity*/
    295     rv = (_ser_test_reg_parity_control(unit, test_reg, 0));
    296     if (SOC_FAILURE(rv)) {
    297         (*error_count)++;
    298         LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit,
    299                     "SER failed. Disable Parity did not work. reg: %s field: %s\n"),
    300                     test_reg->reg_name,
    301                     test_reg->field_name));
    302         return rv;
    303     }
    304 
    305     /*Inject error:*/
    306     rv = (_soc_ser_reg_inject_error(unit, test_reg));
    307 
    308     if (SOC_FAILURE(rv)) {
    309         (*error_count)++;
    310         LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit,
    311                     "SER failed. soc_ser_test_inject_error failed. reg: %s field: %s\n"),
    312                     test_reg->reg_name,
    313                     test_reg->field_name));
    314         return rv;
    315     }
    316 
    317     /*Read back write to ensure value is still fudged.*/
    318     rv = (ser_test_reg_read(unit, test_reg));
    319     if (SOC_FAILURE(rv)) {
    320         (*error_count)++;
    321         LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit,
    322                     "SER failed for could not read the data. reg: %s field: %s\n"),
    323                     test_reg->reg_name,
    324                     test_reg->field_name));
    325         return rv;
    326     }
    327     if (test_reg->badData != test_reg->field_buf[0]) {
    328         LOG_CLI((BSL_META_U(unit,
    329                  "SER failed for Injection Error for reg: %s field: %s\n"),
    330                  test_reg->reg_name,
    331                  test_reg->field_name));
    332         (*error_count)++;
    333         return SOC_E_FAIL;
    334     }
    335 
    336     /*Enable Parity (Even if it was not enabled before*/
    337     rv = (_ser_test_reg_parity_control(unit, test_reg, 1));
    338     if (SOC_FAILURE(rv)) {
    339         (*error_count)++;
    340         LOG_VERBOSE(BSL_LS_SOC_SER, (BSL_META_U(unit,
    341                         "SER failed. Re-enable Parity did not work. reg: %s field: %s\n"),
    342                         test_reg->reg_name,
    343                         test_reg->field_name));
    344         return rv;
    345     }
    346 
    347     if (SAL_BOOT_QUICKTURN) {
    348         sal_usleep(10000); /* Add delay for QT to trigger parity error */
    349     }
    350     /*Read the register in order to trigger the error reporting */
    351     rv = ser_test_reg_read(unit, test_reg);
    352 
    353     sal_usleep(1500000); /*wait for memory and register ops to complete.*/
    354     if (SAL_BOOT_QUICKTURN) {
    355         sal_usleep(10000000);    /* add more delay for Quickturn.*/
    356     } else if (soc_ser_test_long_sleep) {
    357         sal_usleep(soc_ser_test_long_sleep_time_us);
    358     }
    359     /*Read the register once more to compare it to the old value*/
    360     rv = (ser_test_reg_read(unit, test_reg));
    361     if (SOC_FAILURE(rv)) {
    362         (*error_count)++;
    363         LOG_ERROR(BSL_LS_SOC_SER,
    364                   (BSL_META_U(unit,
    365                       "SER failed. Received NACK on 2nd Read "
    366                       "for reg %s \n"),
    367                       test_reg->reg_name));
    368         return rv;
    369     }
    370 
    371     /* reg restore */
    372     if (soc_ser_reg_cache_get(unit, test_reg->reg, REG_PORT_ANY, 0, test_reg->reg_buf)
    373          == SOC_E_NONE) {
    374           if (test_reg->badData == test_reg->field_buf[0]) {
    375             (*error_count)++;
    376             LOG_ERROR(BSL_LS_SOC_SER,
    377                       (BSL_META_U(unit,
    378                        "SER failed to correct reg %s index %d field %s\n"),
    379                        test_reg->reg_name, test_reg->index,
    380                        test_reg->field_name));
    381             return SOC_E_FAIL;
    382           }
    383     } else if (0 != test_reg->field_buf[0]) {
    384         (*error_count)++;
    385         LOG_ERROR(BSL_LS_SOC_SER,
    386                   (BSL_META_U(unit,
    387                    "SER failed to clear reg %s index %d field %s \n"),
    388                    test_reg->reg_name, test_reg->index,
    389                    test_reg->field_name));
    390         return SOC_E_FAIL;
    391     } else {
    392         LOG_VERBOSE(BSL_LS_SOC_SER,
    393                     (BSL_META_U(unit,
    394                      "SER corrected reg %s \n"),
    395                      test_reg->reg_name));
    396     }
    397 
    398     if (startErrorCount != *error_count) {
    399         LOG_CLI((BSL_META_U(unit,
    400                  "SER failed to correct reg %s field: %s %d:%d\n"),
    401                  test_reg->reg_name,
    402                  test_reg->field_name,
    403                  startErrorCount, *error_count));
    404         return SOC_E_FAIL;
    405     }
    406     return SOC_E_NONE;
    407 }
    408 
    409 #endif /* defined (SER_TR_TEST_SUPPORT)*/
    410 #endif /* BCM_ESW_SUPPORT */