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 */