schan.c (33122B)
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 * S-Channel (internal command bus) support 8 */ 9 10 #include <shared/bsl.h> 11 #include <sal/core/libc.h> 12 #include <sal/core/boot.h> 13 #include <sal/core/dpc.h> 14 15 #include <soc/debug.h> 16 #include <soc/cm.h> 17 #include <soc/drv.h> 18 #include <soc/drv.h> 19 #include <soc/hwstate/hw_log.h> 20 #include <soc/error.h> 21 #include <soc/cmic.h> 22 #ifdef BCM_CMICM_SUPPORT 23 #include <soc/cmicm.h> 24 #endif 25 #include <soc/schanmsg_internal.h> 26 27 #if defined (BCM_DNX_SUPPORT) || defined (BCM_DNXF_SUPPORT) 28 #include <soc/dnxc/dnxc_ha.h> 29 #endif 30 31 #ifdef BCM_DNX_SUPPORT 32 #include <soc/dnx/dnx_err_recovery_manager.h> 33 #endif 34 35 #if defined(PLISIM) && defined(PLISIM_DIRECT_SCHAN) 36 /* Back door into the simulation to perform direct SCHANNEL operations */ 37 extern uint32 plibde_schan_op(int unit, schan_msg_t* msg, int, int); 38 #endif 39 40 #ifdef _SER_TIME_STAMP 41 sal_usecs_t ser_time_1; 42 #endif 43 44 #define IS_WRITE_ALLOWED_DURING_WB(unit) \ 45 (SOC_CONTROL(unit)->schan_wb_thread_id == sal_thread_self()) 46 47 soc_cmic_schan_control_t soc_schan_control[SOC_MAX_NUM_DEVICES]; 48 49 STATIC soc_cmic_schan_drv_t _soc_schan_drv[SOC_MAX_NUM_DEVICES]; 50 51 52 /* 53 * S-Chanel operation names 54 */ 55 56 STATIC char *_soc_schan_op_names[] = { 57 "UNKNOWN_OPCODE", 58 "BP_WARN_STATUS", /* 0x01 */ 59 "BP_DISCARD_STATUS", /* 0x02 */ 60 "COS_QSTAT_NOTIFY", /* 0x03 */ 61 "HOL_STAT_NOTIFY", /* 0x04 */ 62 "", /* 0x05 */ 63 "", /* 0x06 */ 64 "READ_MEM_CMD", /* 0x07 */ 65 "READ_MEM_ACK", /* 0x08 */ 66 "WRITE_MEM_CMD", /* 0x09 */ 67 "WRITE_MEM_ACK", /* 0x0a */ 68 "READ_REG_CMD", /* 0x0b */ 69 "READ_REG_ACK", /* 0x0c */ 70 "WRITE_REG_CMD", /* 0x0d */ 71 "WRITE_REG_ACK", /* 0x0e */ 72 "ARL_INSERT_CMD", /* 0x0f */ 73 "ARL_INSERT_DONE", /* 0x10 */ 74 "ARL_DELETE_CMD", /* 0x11 */ 75 "ARL_DELETE_DONE", /* 0x12 */ 76 "LINKSTAT_NOTIFY", /* 0x13 */ 77 "MEM_FAIL_NOTIFY", /* 0x14 */ 78 "INIT_CFAP", /* 0x15 */ 79 "", /* 0x16 */ 80 "ENTER_DEBUG_MODE", /* 0x17 */ 81 "EXIT_DEBUG_MODE", /* 0x18 */ 82 "ARL_LOOKUP_CMD", /* 0x19 */ 83 "L3_INSERT_CMD", /* 0x1a */ 84 "L3_INSERT_DONE", /* 0x1b */ 85 "L3_DELETE_CMD", /* 0x1c */ 86 "L3_DELETE_DONE", /* 0x1d */ 87 "L3_LOOKUP_CMD", /* 0x1e */ 88 "UNKNOWN_OPCODE", /* 0x1f */ 89 "L2_LOOKUP_CMD_MSG", /* 0x20 */ 90 "L2_LOOKUP_ACK_MSG", /* 0x21 */ 91 "L3X2_LOOKUP_CMD_MSG", /* 0x22 */ 92 "L3X2_LOOKUP_ACK_MSG", /* 0x23 */ 93 "TABLE_INSERT_CMD_MSG", /* 0x24 */ 94 "TABLE_INSERT_DONE_MSG", /* 0x25 */ 95 "TABLE_DELETE_CMD_MSG", /* 0x26 */ 96 "TABLE_DELETE_DONE_MSG", /* 0x27 */ 97 "TABLE_LOOKUP_CMD_MSG", /* 0x28 */ 98 "TABLE_LOOKUP_DONE_MSG", /* 0x29 */ 99 "FIFO_POP_CMD_MSG", /* 0x2a */ 100 "FIFO_POP_DONE_MSG", /* 0x2b */ 101 "FIFO_PUSH_CMD_MSG", /* 0x2c */ 102 "FIFO_PUSH_DONE_MSG", /* 0x2d */ 103 }; 104 105 char * 106 soc_schan_op_name(int op) 107 { 108 if (op < 0 || op >= COUNTOF(_soc_schan_op_names)) { 109 op = 0; 110 } 111 112 return _soc_schan_op_names[op]; 113 } 114 115 #if defined(BCM_TRIUMPH_SUPPORT) 116 STATIC char *_soc_schan_gen_resp_type_names[] = { 117 "FOUND", /* 0 */ 118 "NOT_FOUND", /* 1 */ 119 "FULL", /* 2 */ 120 "INSERTED", /* 3 */ 121 "REPLACED", /* 4 */ 122 "DELETED", /* 5 */ 123 "ENTRY_IS_OLD", /* 6 */ 124 "CLEARED_VALID", /* 7 */ 125 "L2_FIFO_FULL", /* 8 */ 126 "MAC_LIMIT_THRE", /* 9 */ 127 "MAC_LIMIT_DEL", /* 10 */ 128 "L2_STATIC", /* 11 */ 129 "UNKNOWN", /* 12 */ 130 "UNKNOWN", /* 13 */ 131 "UNKNOWN", /* 14 */ 132 "ERROR" /* 15 */ 133 }; 134 135 STATIC char * 136 soc_schan_gen_resp_type_name(int type) 137 { 138 if (type < 0 || type >= COUNTOF(_soc_schan_gen_resp_type_names)) { 139 type = 8; 140 } 141 142 return _soc_schan_gen_resp_type_names[type]; 143 } 144 145 STATIC char *_soc_schan_gen_resp_err_names[] = { 146 "NONE", /* 0 */ 147 "SRAM_P_ERR", /* 1 */ 148 "TCAM_SRCH_ERR", /* 2 */ 149 "MULTIPLE", /* 3 */ 150 "TCAM_RD_ERR", /* 4 */ 151 "MULTIPLE", /* 5 */ 152 "MULTIPLE", /* 6 */ 153 "MULTIPLE", /* 7 */ 154 "TCAM_SEQ_ERR", /* 8 */ 155 "MULTIPLE", /* 9 */ 156 "MULTIPLE", /* 10 */ 157 "MULTIPLE", /* 11 */ 158 "MULTIPLE", /* 12 */ 159 "MULTIPLE", /* 13 */ 160 "MULTIPLE", /* 14 */ 161 "MULTIPLE", /* 15 */ 162 }; 163 164 165 STATIC char * 166 soc_schan_gen_resp_err_name(int err) 167 { 168 if (err < 0 || err >= COUNTOF(_soc_schan_gen_resp_err_names)) { 169 err = 2; 170 } 171 172 return _soc_schan_gen_resp_err_names[err]; 173 } 174 175 #endif /* BCM_TRIUMPH_SUPPORT */ 176 177 /******************************************* 178 * @function soc_schan_header_cmd_set 179 * purpose API to set the command header 180 * 181 * @param handle [in] unit 182 * @param header [out] Populated Command header pointer 183 * @param opcode [in] Opcode 184 * @param dst_blk [in] Block ID 185 * @param acc_type [in] Acc Type 186 * @param data_byte_len [in] Dlen 187 * @param dma, bank_ignore_mask [in] Misc Ctrl/ Status 188 * @returns None 189 * 190 * @end 191 */ 192 void 193 soc_schan_header_cmd_set(int unit, schan_header_t *header, int opcode, 194 int dst_blk, int src_blk, int acc_type, 195 int data_byte_len, int dma, uint32 bank_ignore_mask) 196 { 197 if (soc_feature(unit, soc_feature_sbus_format_v4)) { 198 header->v4.opcode = opcode; 199 header->v4.dst_blk = soc_feature(unit, soc_feature_blkid_extended_format) ? (dst_blk >> 4) : dst_blk; 200 /* input argument src_blk is ignored */ 201 header->v4.acc_type = soc_feature(unit, soc_feature_blkid_extended_format) ? (dst_blk & 0xf)<<1 : acc_type; 202 header->v4.data_byte_len = data_byte_len; 203 header->v4.dma = dma; 204 header->v4.bank_ignore_mask = bank_ignore_mask; 205 } else if (soc_feature(unit, soc_feature_new_sbus_format)) { 206 header->v3.opcode = opcode; 207 header->v3.dst_blk = dst_blk; 208 /* input argument src_blk is ignored */ 209 header->v3.acc_type = acc_type; 210 header->v3.data_byte_len = data_byte_len; 211 header->v3.dma = dma; 212 header->v3.bank_ignore_mask = bank_ignore_mask; 213 } else { 214 header->v2.opcode = opcode; 215 header->v2.dst_blk = dst_blk; 216 header->v2.src_blk = src_blk; 217 /* input argument acc_type is ignored */ 218 header->v2.data_byte_len = data_byte_len; 219 /* input argument dma is ignored */ 220 header->v2.bank_ignore_mask = bank_ignore_mask; 221 } 222 } 223 224 /******************************************* 225 * @function soc_schan_header_cmd_get 226 * purpose API to get the command header 227 * 228 * @param handle [in] unit 229 * @param header [in] Populated Command header pointer 230 * @param opcode [out] Opcode 231 * @param dst_blk [out] Block ID 232 * @param acc_type [out] Acc Type 233 * @param data_byte_len [out] Dlen 234 * @param dma, bank_ignore_mask [out] Misc Ctrl/ Status 235 * @returns None 236 * 237 * @end 238 */ 239 void 240 soc_schan_header_cmd_get(int unit, schan_header_t *header, int *opcode, 241 int *dst_blk, int *src_blk, int *acc_type, 242 int *data_byte_len, int *dma, 243 uint32 *bank_ignore_mask) 244 { 245 if (soc_feature(unit, soc_feature_sbus_format_v4)) { 246 if (opcode != NULL) { 247 *opcode = header->v4.opcode; 248 } 249 if (dst_blk != NULL) { 250 *dst_blk = soc_feature(unit, soc_feature_blkid_extended_format) ? (header->v4.dst_blk << 4) |(header->v4.acc_type>>1) : header->v4.dst_blk; 251 } 252 if (src_blk != NULL) { 253 *src_blk = 0; 254 } 255 if (acc_type != NULL) { 256 *acc_type = (soc_feature(unit, soc_feature_blkid_extended_format)) ? 0 : header->v4.acc_type; 257 } 258 if (data_byte_len != NULL) { 259 *data_byte_len = header->v4.data_byte_len; 260 } 261 if (dma != NULL) { 262 *dma = header->v4.dma; 263 } 264 if (bank_ignore_mask != NULL) { 265 *bank_ignore_mask = header->v4.bank_ignore_mask; 266 } 267 } else if (soc_feature(unit, soc_feature_new_sbus_format)) { 268 if (opcode != NULL) { 269 *opcode = header->v3.opcode; 270 } 271 if (dst_blk != NULL) { 272 *dst_blk = header->v3.dst_blk; 273 } 274 if (src_blk != NULL) { 275 *src_blk = 0; 276 } 277 if (acc_type != NULL) { 278 *acc_type = header->v3.acc_type; 279 } 280 if (data_byte_len != NULL) { 281 *data_byte_len = header->v3.data_byte_len; 282 } 283 if (dma != NULL) { 284 *dma = header->v3.dma; 285 } 286 if (bank_ignore_mask != NULL) { 287 *bank_ignore_mask = header->v3.bank_ignore_mask; 288 } 289 } else { 290 if (opcode != NULL) { 291 *opcode = header->v2.opcode; 292 } 293 if (dst_blk != NULL) { 294 *dst_blk = header->v2.dst_blk; 295 } 296 if (src_blk != NULL) { 297 *src_blk = header->v2.src_blk; 298 } 299 if (acc_type != NULL) { 300 *acc_type = 0; 301 } 302 if (data_byte_len != NULL) { 303 *data_byte_len = header->v2.data_byte_len; 304 } 305 if (dma != NULL) { 306 *dma = 0; 307 } 308 if (bank_ignore_mask != NULL) { 309 *bank_ignore_mask = header->v2.bank_ignore_mask; 310 } 311 } 312 } 313 314 /******************************************* 315 * @function soc_schan_header_status_get 316 * purpose API to get the header status 317 * 318 * @param handle [in] unit 319 * @param header [in] Populated Command header pointer 320 * @param opcode [out] Opcode 321 * @param dst_blk [out] Block ID 322 * @param acc_type [out] Acc Type 323 * @param data_byte_len [out] Dlen 324 * @param err, ecode, nack [out] Misc Ctrl/ Status 325 * @returns None 326 * 327 * @end 328 */ 329 void 330 soc_schan_header_status_get(int unit, schan_header_t *header, int *opcode, 331 int *src_blk, int *data_byte_len, 332 int *err, int *ecode, int *nack) 333 { 334 if (soc_feature(unit, soc_feature_sbus_format_v4)) { 335 *opcode = header->v4.opcode; 336 if (src_blk != NULL) { 337 *src_blk = 0; 338 } 339 if (data_byte_len != NULL) { 340 *data_byte_len = header->v4.data_byte_len; 341 } 342 if (err != NULL) { 343 *err = header->v4.err; 344 } 345 if (ecode != NULL) { 346 *ecode = header->v4.ecode; 347 } 348 if (nack != NULL) { 349 *nack = header->v4.nack; 350 } 351 } else if (soc_feature(unit, soc_feature_new_sbus_format)) { 352 *opcode = header->v3.opcode; 353 if (src_blk != NULL) { 354 *src_blk = 0; 355 } 356 if (data_byte_len != NULL) { 357 *data_byte_len = header->v3.data_byte_len; 358 } 359 if (err != NULL) { 360 *err = header->v3.err; 361 } 362 if (ecode != NULL) { 363 *ecode = header->v3.ecode; 364 } 365 if (nack != NULL) { 366 *nack = header->v3.nack; 367 } 368 } else { 369 *opcode = header->v2.opcode; 370 if (src_blk != NULL) { 371 *src_blk = header->v2.src_blk; 372 } 373 if (data_byte_len != NULL) { 374 *data_byte_len = header->v2.data_byte_len; 375 } 376 if (err != NULL) { 377 *err = header->v2.err; 378 } 379 if (ecode != NULL) { 380 *ecode = header->v2.ecode; 381 } 382 if (nack != NULL) { 383 *nack = header->v2.nack; 384 } 385 } 386 } 387 388 /******************************************* 389 * @function soc_schan_dump 390 * @Purpose Dump an S-Channel message for debugging 391 * 392 * @param unit [in] unit 393 * 394 * @returns SOC_E_NONE 395 * @returns SOC_E_XXX 396 * 397 * @end 398 */ 399 void 400 soc_schan_dump(int unit, schan_msg_t *msg, int dwc) 401 { 402 char buf[128]; 403 int i, j; 404 405 if (soc_feature(unit, soc_feature_sbus_format_v4)) { 406 uint32 dst_blk = msg->header.v4.dst_blk; 407 uint32 acc_type = msg->header.v4.acc_type; 408 uint32 block_id = soc_feature(unit, soc_feature_blkid_extended_format) ? (dst_blk << 4) | (acc_type >> 1) : dst_blk; 409 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 410 (BSL_META_U(unit, 411 " HDR[NACK=%d BANK=%d DMA=%d ECODE=%d ERR=%d " 412 "DLEN=%d ACC=%d DPORT=%d BLOCKID=%d OPC=%d=%s]\n"), 413 msg->header.v4.nack, msg->header.v4.bank_ignore_mask, 414 msg->header.v4.dma, msg->header.v4.ecode, 415 msg->header.v4.err, msg->header.v4.data_byte_len, 416 msg->header.v4.acc_type, msg->header.v4.dst_blk, block_id, 417 msg->header.v4.opcode, 418 soc_schan_op_name(msg->header.v4.opcode))); 419 } else if (soc_feature(unit, soc_feature_new_sbus_format)) { 420 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 421 (BSL_META_U(unit, 422 " HDR[NACK=%d BANK=%d DMA=%d ECODE=%d ERR=%d " 423 "DLEN=%d ACC=%d DPORT=%d OPC=%d=%s]\n"), 424 msg->header.v3.nack, msg->header.v3.bank_ignore_mask, 425 msg->header.v3.dma, msg->header.v3.ecode, 426 msg->header.v3.err, msg->header.v3.data_byte_len, 427 msg->header.v3.acc_type, msg->header.v3.dst_blk, 428 msg->header.v3.opcode, 429 soc_schan_op_name(msg->header.v3.opcode))); 430 } else { 431 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 432 (BSL_META_U(unit, 433 " HDR[NACK=%d BANK=%d DMA=%d ECODE=%d ERR=%d " 434 "DLEN=%d SPORT=%d DPORT=%d OPC=%d=%s]\n"), 435 msg->header.v2.nack, msg->header.v2.bank_ignore_mask, 436 msg->header.v2.dma, msg->header.v2.ecode, 437 msg->header.v2.err, msg->header.v2.data_byte_len, 438 msg->header.v2.src_blk, msg->header.v2.dst_blk, 439 msg->header.v2.opcode, 440 soc_schan_op_name(msg->header.v2.opcode))); 441 } 442 443 #ifdef BCM_TRIUMPH_SUPPORT 444 if (soc_feature(unit, soc_feature_generic_table_ops) && 445 ((msg->header.v2.opcode == TABLE_INSERT_DONE_MSG) || 446 (msg->header.v2.opcode == TABLE_DELETE_DONE_MSG) || 447 (msg->header.v2.opcode == TABLE_LOOKUP_DONE_MSG))) { 448 if (soc_feature(unit, soc_feature_new_sbus_format) && 449 !soc_feature(unit, soc_feature_new_sbus_old_resp) ) { 450 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 451 (BSL_META_U(unit, 452 " RSP[TYPE=%d=%s ERR_INFO=%d=%s " 453 "INDEX=0x%05x]\n"), 454 msg->genresp_v2.response.type, 455 soc_schan_gen_resp_type_name(msg->genresp_v2.response.type), 456 msg->genresp_v2.response.err_info, 457 soc_schan_gen_resp_err_name(msg->genresp_v2.response.err_info), 458 msg->genresp_v2.response.index)); 459 } else { 460 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 461 (BSL_META_U(unit, 462 " RSP[SRC=%d TYPE=%d=%s ERR_INFO=%d=%s " 463 "INDEX=0x%05x]\n"), 464 msg->genresp.response.src, 465 msg->genresp.response.type, 466 soc_schan_gen_resp_type_name(msg->genresp.response.type), 467 msg->genresp.response.err_info, 468 soc_schan_gen_resp_err_name(msg->genresp.response.err_info), 469 msg->genresp.response.index)); 470 } 471 } 472 #endif /* BCM_TRIUMPH_SUPPORT */ 473 474 assert(dwc <= CMIC_SCHAN_WORDS(unit)); 475 476 for (i = 0; i < dwc; i += 4) { 477 buf[0] = 0; 478 479 for (j = i; j < i + 4 && j < dwc; j++) { 480 sal_sprintf(buf + sal_strlen(buf), 481 " DW[%2d]=0x%08x", j, msg->dwords[j]); 482 } 483 484 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 485 (BSL_META_U(unit, " %s\n"), buf)); 486 } 487 } 488 /******************************************* 489 * @function soc_schan_override_enable 490 * @Purpose Enable schan override 491 * 492 * @param unit [in] unit 493 * 494 * @returns SOC_E_NONE 495 * @returns SOC_E_XXX 496 * 497 * @end 498 */ 499 500 #define SOC_SCHAN_WB_TIME_OUT (5000000) /*5 sec*/ 501 int 502 soc_schan_override_enable(int unit) 503 { 504 if (unit < 0 || unit >= SOC_MAX_NUM_DEVICES) { 505 return SOC_E_UNIT; 506 } 507 if (!SOC_HW_ACCESS_DISABLE(unit)) { 508 return SOC_E_NONE; 509 } 510 if (SOC_WARM_BOOT(unit)) { 511 if (sal_mutex_take(SOC_CONTROL(unit)->schan_wb_mutex, 512 SOC_SCHAN_WB_TIME_OUT)) { 513 LOG_ERROR(BSL_LS_SOC_SCHAN, 514 (BSL_META_U(unit, 515 "Failed to take schan_wb_mutex.\n"))); 516 return SOC_E_INTERNAL; 517 } 518 SOC_CONTROL(unit)->schan_wb_thread_id = sal_thread_self(); 519 } 520 521 return SOC_E_NONE; 522 } 523 524 /******************************************* 525 * @function soc_schan_override_disable 526 * @Purpose Disable schan override 527 * 528 * @param unit [in] unit 529 * 530 * @returns SOC_E_NONE 531 * @returns SOC_E_XXX 532 * 533 * @end 534 */ 535 int 536 soc_schan_override_disable(int unit) 537 { 538 if (unit < 0 || unit >= SOC_MAX_NUM_DEVICES) { 539 return SOC_E_UNIT; 540 } 541 if (SOC_CONTROL(unit)->schan_wb_thread_id == sal_thread_self()) { 542 SOC_CONTROL(unit)->schan_wb_thread_id = SAL_THREAD_ERROR; 543 if (sal_mutex_give(SOC_CONTROL(unit)->schan_wb_mutex)) { 544 LOG_ERROR(BSL_LS_SOC_SCHAN, 545 (BSL_META_U(unit, 546 "Failed to release schan_wb_mutex.\n"))); 547 return SOC_E_INTERNAL; 548 } 549 } 550 551 return SOC_E_NONE; 552 } 553 554 /******************************************* 555 * @function soc_schan_op 556 * purpose cmic SCHAN operation 557 * 558 * @param unit [in] unit 559 * @param msg [in] schan_msg_t 560 * @param dwc_write [in] Write messages 561 * @param dwc_write [in] read messages 562 * @param intr [in] use interrupt 563 * 564 * @returns SOC_E_NONE 565 * @returns SOC_E_XXX 566 * 567 * @comments This calls appropriate function based on CMIC type 568 * Writes a message of dwc_write DWORDs from msg to the S-Channel, waits 569 * for the operation to complete, then reads dwc_read DWORDs from the 570 * channel into msg. If there is no return data, use dwc_read = 0. 571 * 572 * On platforms where it is appropriate, the S-Channel is locked during 573 * the operation to prevent multiple tasks trying to use the S-Channel 574 * simultaneously. 575 * 576 * Return value is negative on error, 0 on success. 577 * 578 * If intr is true, this routine goes to sleep until an S-Channel 579 * completion interrupt wakes it up. Otherwise, it polls for the done 580 * bit. NOTE: if schanIntrEnb is false, intr is always overridden to 0. 581 * 582 * Polling is more CPU efficient for most operations since they complete 583 * much faster than the interrupt processing time would take. However, 584 * due to the chip design, some operations such as ARL insert and delete 585 * may have unbounded response time. In this case, the interrupt should 586 * be used. The worst case we have seen is 1 millisec when the switch 587 * is passing max traffic with random addresses at min packet size. 588 * 589 * @end 590 */ 591 int 592 soc_schan_op(int unit, 593 schan_msg_t *msg, 594 int dwc_write, int dwc_read, 595 int intr) 596 { 597 int rv; 598 599 if (_soc_schan_drv[unit].soc_schan_op == NULL) { 600 LOG_FATAL(BSL_LS_SOC_SCHAN, (BSL_META_U(unit, 601 "SOC_SCHAN_OP() function is undefined\n"))); 602 rv = SOC_E_FAIL; 603 } else { 604 rv = _soc_schan_drv[unit].soc_schan_op(unit, msg, dwc_write, dwc_read, intr); 605 } 606 607 return rv; 608 } 609 610 /******************************************* 611 * @function _soc_schan_check_hw_access_disabled 612 * @Purpose return TRUE if hardware access is disabled 613 * 614 * @param unit [in] unit 615 * @param msg [in] pointer to Type <schan_msg_t> 616 * @param dwc_read [out] pointer to status 617 * 618 * @returns TRUE or FALSE 619 * 620 * @comments If hardware access is disabled, this 621 * should return TRUE and set *rv to an error code that 622 * will be passed up to the caller. Otherwise, return FALSE 623 * and do not alter *rv. 624 625 * @end 626 */ 627 STATIC int 628 _soc_schan_check_hw_access_disabled(int unit, schan_msg_t *msg, int *rv) 629 { 630 if (SOC_HW_ACCESS_DISABLE(unit)) { 631 switch (msg->header.v2.opcode) { 632 case WRITE_MEMORY_CMD_MSG: 633 *rv = SOC_E_NONE; 634 return TRUE; 635 case WRITE_REGISTER_CMD_MSG: 636 msg->header.v2.opcode = WRITE_REGISTER_ACK_MSG; 637 *rv = SOC_E_NONE; 638 return TRUE; 639 case ARL_INSERT_CMD_MSG: 640 msg->header.v2.opcode = ARL_INSERT_DONE_MSG; 641 *rv = SOC_E_NONE; 642 return TRUE; 643 case ARL_DELETE_CMD_MSG: 644 msg->header.v2.opcode = ARL_DELETE_DONE_MSG; 645 *rv = SOC_E_NONE; 646 return TRUE; 647 case L3_INSERT_CMD_MSG: 648 msg->header.v2.opcode = L3_INSERT_DONE_MSG; 649 *rv = SOC_E_NONE; 650 return TRUE; 651 case L3_DELETE_CMD_MSG: 652 msg->header.v2.opcode = L3_DELETE_DONE_MSG; 653 *rv = SOC_E_NONE; 654 return TRUE; 655 case INIT_CFAP_MSG: 656 *rv = SOC_E_NONE; 657 return TRUE; 658 case READ_REGISTER_CMD_MSG: 659 if (SOC_IS_DETACHING(unit)) { 660 sal_memset(msg->bytes, 0, 661 sizeof(uint32) * CMIC_SCHAN_WORDS_ALLOC); 662 msg->header.v2.opcode = READ_REGISTER_ACK_MSG; 663 *rv = SOC_E_NONE; 664 return TRUE; 665 } 666 break; 667 case READ_MEMORY_CMD_MSG: 668 if (SOC_IS_DETACHING(unit)) { 669 sal_memset(msg->bytes, 0, 670 sizeof(uint32) * CMIC_SCHAN_WORDS_ALLOC); 671 msg->header.v2.opcode = READ_MEMORY_ACK_MSG; 672 *rv = SOC_E_NONE; 673 return TRUE; 674 } 675 break; 676 case L2_LOOKUP_CMD_MSG: 677 if (SOC_IS_DETACHING(unit)) { 678 msg->header.v2.opcode = L2_LOOKUP_ACK_MSG; 679 *rv = SOC_E_NOT_FOUND; 680 return TRUE; 681 } 682 break; 683 case L3X2_LOOKUP_CMD_MSG: 684 if (SOC_IS_DETACHING(unit)) { 685 msg->header.v2.opcode = L3X2_LOOKUP_ACK_MSG; 686 *rv = SOC_E_NOT_FOUND; 687 return TRUE; 688 } 689 break; 690 case ARL_LOOKUP_CMD_MSG: 691 case L3_LOOKUP_CMD_MSG: 692 if (SOC_IS_DETACHING(unit)) { 693 *rv = SOC_E_NOT_FOUND; 694 return TRUE; 695 } 696 break; 697 case TABLE_INSERT_CMD_MSG: 698 msg->header.v2.opcode = TABLE_INSERT_DONE_MSG; 699 *rv = SOC_E_NONE; 700 return TRUE; 701 case TABLE_DELETE_CMD_MSG: 702 msg->header.v2.opcode = TABLE_DELETE_DONE_MSG; 703 *rv = SOC_E_NONE; 704 return TRUE; 705 case FIFO_POP_CMD_MSG: 706 msg->header.v2.opcode = FIFO_POP_DONE_MSG; 707 *rv = SOC_E_NONE; 708 return TRUE; 709 case FIFO_PUSH_CMD_MSG: 710 msg->header.v2.opcode = FIFO_PUSH_DONE_MSG; 711 *rv = SOC_E_NONE; 712 return TRUE; 713 default: 714 break; 715 } 716 } 717 718 return FALSE; 719 } 720 721 /******************************************* 722 * @function _soc_schan_op_arad_sanity_check 723 * purpose API to perform sanity check for ARAD 724 * 725 * @param unit [in] unit 726 * @param msg [in] pointer to Type <schan_msg_t> 727 * @param dwc_write [in] write 728 * @param dwc_read [in] read 729 * 730 * @returns SOC_E_NONE 731 * @returns SOC_E_XXX 732 * @end 733 */ 734 735 /******************************************* 736 * @function soc_schan_op_sanity_check 737 * purpose API to perform sanity checks 738 * 739 * @param unit [in] unit 740 * @param msg [in] pointer to Type <schan_msg_t> 741 * @param dwc_write [in] write 742 * @param dwc_read [in] read 743 * @param dwc_read [out] pointer to status 744 * 745 * @returns TRUE if the caller should abort the call and return *rv up the stack. 746 * @returns FALSE if the caller should continue as normal. 747 * 748 * @comments First, check that writing is allowed: 749 * If (device is ARAD) and (opcode is not a READ command) and (override flag is off) 750 * Then: writing is not allowed. 751 * 752 * Then, assert sanity checks. 753 * Finally, log the message that schan access is beginning 754 * 755 * @end 756 */ 757 int 758 soc_schan_op_sanity_check(int unit, schan_msg_t *msg, int dwc_write, 759 int dwc_read, int *rv) 760 { 761 *rv = SOC_E_NONE; 762 763 assert(! sal_int_context()); 764 assert(dwc_write <= CMIC_SCHAN_WORDS(unit)); 765 assert(dwc_read <= CMIC_SCHAN_WORDS(unit)); 766 767 /* don't perform check for DNX devices as they undergo different check */ 768 if (!SOC_IS_DNX(unit) && !SOC_IS_DNXF(unit)) { 769 if (_soc_schan_check_hw_access_disabled(unit, msg, rv) == TRUE) { 770 return TRUE; 771 } 772 } 773 774 if (LOG_CHECK(BSL_LS_SOC_SCHAN | BSL_VERBOSE)) { 775 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 776 (BSL_META_U(unit, 777 "S-CHANNEL %s: (unit %d)\n"), 778 soc_schan_op_name(msg->header.v2.opcode), unit)); 779 soc_schan_dump(unit, msg, dwc_write); 780 } 781 782 return FALSE; 783 } 784 785 #if defined(PLISIM) && defined(PLISIM_DIRECT_SCHAN) 786 787 /******************************************* 788 * @function _soc_schan_op_wrapper_plibde 789 * purpose this is called with plisim enabled 790 * 791 * @param unit [in] unit 792 * @param msg [in] schan_msg_t 793 * @param dwc_write [in] Write messages 794 * @param dwc_write [in] read messages 795 * @param intr [in] use interrupt 796 * 797 * @returns SOC_E_NONE 798 * @returns SOC_E_XXX 799 * 800 * @end 801 */ 802 STATIC int 803 _soc_schan_op_wrapper_plibde(int unit, schan_msg_t *msg, int dwc_write, 804 int dwc_read, int intr) 805 { 806 int rv; 807 808 if (soc_schan_op_sanity_check(unit, msg, dwc_write, dwc_read, &rv) == TRUE) { 809 return rv; 810 } 811 /* Back door into the simulation to perform direct SCHANNEL operations */ 812 if (LOG_CHECK(BSL_LS_SOC_SCHAN | BSL_VERBOSE)) { 813 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 814 (BSL_META_U(unit, 815 "S-CHANNEL %s: (unit %d)\n"), 816 soc_schan_op_name(msg->header.v2.opcode), unit)); 817 soc_schan_dump(unit, msg, dwc_write); 818 } 819 820 rv = plibde_schan_op(unit, msg, dwc_write, dwc_read); 821 822 if (LOG_CHECK(BSL_LS_SOC_SCHAN | BSL_VERBOSE)) { 823 soc_schan_dump(unit, msg, dwc_read); 824 } 825 826 return rv; 827 } 828 #endif 829 830 #ifdef INCLUDE_RCPU 831 832 /******************************************* 833 * @function _soc_schan_op_wrapper_rcpu 834 * purpose Called if rcpu schan callback is registered 835 * 836 * @param unit [in] unit 837 * @param msg [in] schan_msg_t 838 * @param dwc_write [in] Write messages 839 * @param dwc_write [in] read messages 840 * @param intr [in] use interrupt 841 * 842 * @returns SOC_E_NONE 843 * @returns SOC_E_XXX 844 * 845 * @end 846 */ 847 STATIC int 848 _soc_schan_op_wrapper_rcpu(int unit, schan_msg_t *msg, int dwc_write, 849 int dwc_read, int intr) 850 { 851 if (SOC_CONTROL(unit)->soc_rcpu_schan_op == NULL) { 852 LOG_ERROR(BSL_LS_SOC_SCHAN, (BSL_META_U(unit, 853 "No soc_rcpu_schan_op callback defined\n"))); 854 return SOC_E_FAIL; 855 } 856 857 return SOC_CONTROL(unit)->soc_rcpu_schan_op(unit, msg, dwc_write, dwc_read); 858 } 859 #endif /* INCLUDE_RCPU */ 860 861 862 /******************************************* 863 * @function soc_schan_timeout_check 864 * @Purpose enable special processing for timeout 865 * 866 * @param unit [in] unit 867 * @param msg [in] pointer to Type <schan_msg_t> 868 * @param dwc_read [out] pointer to status 869 * 870 * @returns TRUE or FALSE 871 * 872 * @end 873 */ 874 int 875 soc_schan_timeout_check(int unit, int *rv, schan_msg_t *msg, int cmc, int ch) 876 { 877 if (*rv != SOC_E_TIMEOUT) { 878 SOC_CONTROL(unit)->stat.schan_op++; 879 return FALSE; 880 } 881 882 if (SOC_IS_TRIUMPH3(unit) && msg->header.v3.opcode == WRITE_REGISTER_CMD_MSG) { 883 if ((msg->writecmd.address == 0x02029700) && 884 (msg->writecmd.header.v3.dst_blk >= 0x8 && msg->writecmd.header.v3.dst_blk <= 0xf)) { 885 *rv = SOC_E_NONE; 886 SOC_CONTROL(unit)->stat.schan_op++; 887 } 888 } else { 889 LOG_WARN(BSL_LS_SOC_SCHAN, 890 (BSL_META_U(unit, 891 "soc_schan_op: operation attempt timed out\n"))); 892 SOC_CONTROL(unit)->stat.err_sc_tmo++; 893 if (_soc_schan_drv[unit].soc_schan_reset != NULL) { 894 _soc_schan_drv[unit].soc_schan_reset(unit, cmc, ch); 895 } 896 return TRUE; 897 } 898 899 return FALSE; 900 } 901 902 /******************************************* 903 * @function _soc_schan_control_init 904 * purpose API to Initialize and SCHAN control 905 * 906 * @param unit [in] unit 907 * 908 * @returns SOC_E_NONE 909 * @returns SOC_E_XXX 910 * 911 * @end 912 */ 913 STATIC int _soc_schan_control_init(int unit) 914 { 915 int rv = SOC_E_NONE; 916 int cmc; 917 918 SOC_SCHAN_CONTROL(unit).schanTimeout = &SOC_CONTROL(unit)->schanTimeout; 919 SOC_SCHAN_CONTROL(unit).schanIntrEnb = &SOC_CONTROL(unit)->schanIntrEnb; 920 for (cmc = 0; cmc <= SOC_CMCS_NUM_MAX; cmc++) { 921 SOC_SCHAN_CONTROL(unit).schanIntr[cmc] = &SOC_CONTROL(unit)->schanIntr[cmc]; 922 SOC_SCHAN_CONTROL(unit).schan_result[cmc] = &SOC_CONTROL(unit)->schan_result[cmc]; 923 } 924 925 return rv; 926 } 927 /******************************************* 928 * @function soc_schan_init 929 * purpose API to Initialize and config SCHAN 930 * 931 * @param unit [in] unit 932 * 933 * @returns SOC_E_NONE 934 * @returns SOC_E_XXX 935 * 936 * @end 937 */ 938 int soc_schan_init(int unit) 939 { 940 int rv = SOC_E_NONE; 941 942 SOC_IF_ERROR_RETURN(_soc_schan_control_init(unit)); 943 944 #if defined(PLISIM) && defined(PLISIM_DIRECT_SCHAN) 945 if ((SAL_BOOT_PLISIM || SAL_BOOT_BCMSIM)) { 946 _soc_schan_drv[unit].soc_schan_op = _soc_schan_op_wrapper_plibde; 947 return rv; 948 } 949 #endif 950 951 #ifdef INCLUDE_RCPU 952 if (SOC_IS_RCPU_ONLY(unit) || SOC_IS_RCPU_UNIT(unit)) { 953 _soc_schan_drv[unit].soc_schan_op = _soc_schan_op_wrapper_rcpu; 954 return rv; 955 } 956 #endif 957 958 #ifdef BCM_CMICX_SUPPORT 959 if (soc_feature(unit, soc_feature_cmicx)) { 960 rv = soc_cmicx_schan_init(unit, &_soc_schan_drv[unit]); 961 return rv; 962 } 963 #endif 964 965 #if defined(BCM_CMICM_SUPPORT) 966 if (soc_feature(unit, soc_feature_cmicm)) { 967 rv = soc_cmicm_schan_init(unit, &_soc_schan_drv[unit]); 968 return rv; 969 } 970 #endif 971 972 973 rv = soc_cmice_schan_init(unit, &_soc_schan_drv[unit]); 974 975 976 return rv; 977 } 978 979 /******************************************* 980 * @function soc_schan_deinit 981 * purpose SDK-7 API to de-Initialize SCHAN 982 * 983 * @param unit [in] unit 984 * 985 * @returns SOC_E_NONE 986 * @returns SOC_E_XXX 987 * 988 * @end 989 */ 990 int soc_schan_deinit(int unit) 991 { 992 int rv = SOC_E_NONE; 993 994 if (_soc_schan_drv[unit].soc_schan_deinit) { 995 rv = _soc_schan_drv[unit].soc_schan_deinit(unit); 996 } 997 998 _soc_schan_drv[unit].soc_schan_deinit = NULL; 999 _soc_schan_drv[unit].soc_schan_op = NULL; 1000 _soc_schan_drv[unit].soc_schan_reset = NULL; 1001 1002 return rv; 1003 } 1004 /* 1005 * Procedures related to PEM block access. 1006 * { 1007 */ 1008 /* 1009 * phy_mem_read 1010 * phy_mem_write 1011 * 1012 * Send/ (rcv) msg to/(from) the S-Channel to carry out PEM operation 1013 * as per '*mem' and '*entry_data'. 1014 * Wait for interrupt to indicate operation to complete. For 'read', 1015 * response data is on '*entry_data'. 1016 * 1017 * Access memory or register depending on the LS 16 bis of mem->mem_address 1018 * (non-zero for 'memory'). 1019 * 1020 * S-Channel is locked during the operation to prevent multiple tasks 1021 * trying to use the S-Channel simultaneously. 1022 * 1023 * Return value is negative on error, 0 (SOC_E_NONE) on success. 1024 * 1025 * NOTE: If SOC_CONTROL(unit)->schanIntrEnb is false, interrupt operation 1026 * is overridden in favour of polling. 1027 * 1028 * NOTE: Within 'header', this procedure uses header.v4 1029 * 1030 * Ensure that a SOC_CONTROL(unit)->schan_op function pointer is defined for this 1031 * unit. If not, an error is flagged. 1032 * 1033 * See also: 1034 * soc_schan_op(), _soc_schan_op_cmicm(), soc_direct_memreg_get(), 1035 * soc_direct_memreg_set(), schan_header_t 1036 */ 1037 int phy_mem_read(int unit, phy_mem_t *mem, void *entry_data) 1038 { 1039 int ret ; 1040 int is_mem ; 1041 uint32 addr, data_longs_to_read ; 1042 uint32 mask = 0xFFFF0000 ; 1043 /* 1044 * Access memory or register depending on the LS 16 bis. 1045 */ 1046 is_mem = ( (mem->mem_address & mask) != 0 ) ? 1 : 0; 1047 /* 1048 * Always request an integer number of longs (expressed in bytes). 1049 */ 1050 data_longs_to_read = BITS2WORDS(mem->mem_width_in_bits) ; 1051 /* 1052 * row_index was removed from phy_mem_t (see SDK-111156). 1053 * Need updated ucode. 1054 */ 1055 addr = mem->mem_address; 1056 1057 ret = soc_direct_memreg_get(unit, mem->block_identifier, addr, data_longs_to_read,is_mem, (uint32 *)entry_data) ; 1058 return (ret) ; 1059 } 1060 int phy_mem_write(int unit, phy_mem_t *mem, void *entry_data) 1061 { 1062 int ret ; 1063 int is_mem ; 1064 uint32 addr, data_longs_to_write ; 1065 uint32 mask = 0xFFFF0000 ; 1066 /* 1067 * Access memory or register depending on the LS 16 bis. 1068 */ 1069 is_mem = ( (mem->mem_address & mask) != 0 ) ? 1 : 0; 1070 /* 1071 * Always request an integer number of longs (expressed in bytes). 1072 */ 1073 data_longs_to_write = BITS2WORDS(mem->mem_width_in_bits) ; 1074 /* 1075 * row_index was removed from phy_mem_t (see SDK-111156). 1076 * Need updated ucode. 1077 */ 1078 addr = mem->mem_address; 1079 ret = soc_direct_memreg_set(unit, mem->block_identifier, addr, data_longs_to_write, is_mem, (uint32 *)entry_data) ; 1080 return (ret) ; 1081 } 1082 1083 /* 1084 * } 1085 */