cmicm_schan.c (16650B)
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 * CMICM 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 #include <soc/drv.h> 15 #include <soc/debug.h> 16 #include <soc/cm.h> 17 #include <soc/error.h> 18 #include <soc/cmic.h> 19 #include <soc/schanmsg_internal.h> 20 21 #ifdef BCM_CMICM_SUPPORT 22 #include <soc/cmicm.h> 23 24 #define SOC_CHECK_MULTI_CMC(unit) \ 25 (soc_feature(unit, soc_feature_cmicm_multi_schan_cmc) && \ 26 (SOC_PCI_CMCS_NUM(unit) > 1)) 27 28 typedef struct cmicm_schan_ch_s { 29 sal_spinlock_t lock; 30 int timeout; 31 uint8 ch[CMIC_CMC_NUM_MAX+1]; 32 } cmicm_schan_ch_t; 33 34 35 STATIC cmicm_schan_ch_t _cmicm_schan_ch[SOC_MAX_NUM_DEVICES]; 36 STATIC int _soc_schan_multi_cmc[SOC_MAX_NUM_DEVICES]; 37 38 39 /******************************************* 40 * @function fschan_wait_idle 41 * @Purpose FIFO SCHAN wait function. 42 * 43 * @param unit [in] unit 44 * 45 * @returns SOC_E_NONE 46 * @returns SOC_E_XXX 47 * @end 48 */ 49 int 50 fschan_wait_idle(int unit) 51 { 52 int cmc = SOC_PCI_CMC(unit); 53 soc_timeout_t to; 54 55 soc_timeout_init(&to, SOC_CONTROL(unit)->schanTimeout, 100); 56 do { 57 if (0==(soc_pci_read(unit, CMIC_CMCx_FSCHAN_STATUS_OFFSET(cmc)) & FSCHAN_BUSY)) { 58 return SOC_E_NONE; 59 } 60 } while (!soc_timeout_check(&to)); 61 return SOC_E_TIMEOUT; 62 } 63 64 /******************************************* 65 * @function _soc_cmicm_schan_reset 66 * @Purpose Resets the CMIC S-Channel interface. 67 * 68 * @param unit [in] unit 69 * @param cmc [in] cmc number 0-2 or 3 for common 70 * @param ch [in] channel number 0 71 * 72 * @returns None 73 * @comments This is required when we sent 74 * a message and did not receive a response after the poll count was 75 * exceeded. 76 * @end 77 */ 78 STATIC void 79 _soc_cmicm_schan_reset(int unit, int cmc, int ch) 80 { 81 uint32 val, addr; 82 83 COMPILER_REFERENCE(ch); 84 85 addr = CMIC_COMMON_CMCx_SCHAN_CTRL_OFFSET(cmc); 86 val = soc_pci_read(unit, addr); 87 /* Toggle S-Channel abort bit in CMIC_SCHAN_CTRL register */ 88 soc_pci_write(unit, addr, val | SC_CMCx_SCHAN_ABORT); 89 SDK_CONFIG_MEMORY_BARRIER; 90 soc_pci_write(unit, addr, val); 91 SDK_CONFIG_MEMORY_BARRIER; 92 93 if (SAL_BOOT_QUICKTURN) { 94 /* Give Quickturn at least 2 cycles */ 95 sal_usleep(10 * MILLISECOND_USEC); 96 } 97 } 98 99 100 /******************************************* 101 * @function _soc_cmicm_schan_intr_wait 102 * purpose interrupt wait to complete SCHAN operation 103 * 104 * @param unit [in] unit 105 * @param cmc [in] cmc number 0-2 or 3 for common 106 * 107 * @returns SOC_E_NONE 108 * @returns SOC_E_XXX 109 * 110 * @comments Called by schan_op_* functions. 111 * wait on a schan interrupt. When schan interrupts are disabled, 112 * _soc_cmicm_schan_poll_wait is called instead. 113 114 * @end 115 */ 116 STATIC int 117 _soc_cmicm_schan_intr_wait(int unit, int cmc) 118 { 119 uint32 errAddr; 120 int rv = SOC_E_NONE; 121 122 if (cmc != CMIC_CMC_NUM_MAX) { 123 soc_cmicm_cmcx_intr0_enable(unit, cmc, IRQ_CMCx_SCH_OP_DONE); 124 } else { 125 /* this is for common SCHAN, this is available to all cmcs */ 126 soc_cmicm_cmcx_intr1_enable(unit, (cmc - 1), 127 IRQ_CMCx_COMMON_SCHAN_DONE); 128 } 129 if (sal_sem_take(SOC_CONTROL(unit)->schanIntr[cmc], 130 SOC_CONTROL(unit)->schanTimeout) != 0) { 131 rv = SOC_E_TIMEOUT; 132 } else { 133 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 134 (BSL_META_U(unit, 135 " Interrupt received\n"))); 136 137 if (SOC_CONTROL(unit)->schan_result[cmc] & SC_CMCx_MSG_NAK) { 138 rv = SOC_E_FAIL; 139 } 140 if (soc_feature(unit, soc_feature_schan_hw_timeout)) { 141 if (SOC_CONTROL(unit)->schan_result[cmc] & 142 SC_CMCx_MSG_TIMEOUT_TST) { 143 rv = SOC_E_TIMEOUT; 144 } 145 } 146 147 if (soc_feature(unit, soc_feature_schan_err_check)) { 148 uint32 schan_err, err_bit = 0; 149 150 errAddr = CMIC_COMMON_CMCx_SCHAN_ERR_OFFSET(cmc); 151 schan_err = soc_pci_read(unit, errAddr); 152 err_bit = soc_reg_field_get(unit, CMIC_CMC0_SCHAN_ERRr, schan_err, ERRBITf); 153 154 if (err_bit) { 155 rv = SOC_E_FAIL; 156 LOG_ERROR(BSL_LS_SOC_SCHAN, (BSL_META_U(unit, 157 " ERRBIT received in CMIC_SCHAN_ERR.\n"))); 158 } 159 } 160 } 161 162 if (cmc != CMIC_CMC_NUM_MAX) { 163 soc_cmicm_cmcx_intr0_disable(unit, cmc, IRQ_CMCx_SCH_OP_DONE); 164 } else { 165 /* this is for common SCHAN, this is available to all cmcs */ 166 soc_cmicm_cmcx_intr1_disable(unit, (cmc - 1), 167 IRQ_CMCx_COMMON_SCHAN_DONE); 168 } 169 170 return rv; 171 } 172 173 /******************************************* 174 * @function _soc_cmicm_schan_poll_wait 175 * purpose POLL wait to complete cmicm SCHAN operation 176 * 177 * @param unit [in] unit 178 * @param cmc [in] cmc number 0-2 or 3 for common 179 * @param msg [in] schan_msg_t 180 * 181 * @returns SOC_E_NONE 182 * @returns SOC_E_XXX 183 * 184 * @end 185 * @comments Called by schan_cmicm_schan_op function. 186 * In case interrupts are disabled, wait on a schan response via polling. 187 */ 188 STATIC int 189 _soc_cmicm_schan_poll_wait(int unit, int cmc, schan_msg_t *msg) 190 { 191 uint32 schanCtrl, ctrlAddr, msgAddr, errAddr; 192 int rv = SOC_E_NONE; 193 soc_timeout_t to; 194 195 soc_timeout_init(&to, SOC_CONTROL(unit)->schanTimeout, 100); 196 ctrlAddr = CMIC_COMMON_CMCx_SCHAN_CTRL_OFFSET(cmc); 197 198 while (((schanCtrl = soc_pci_read(unit, ctrlAddr)) & SC_CMCx_MSG_DONE) == 0) { 199 if (soc_timeout_check(&to)) { 200 return SOC_E_TIMEOUT; 201 } 202 } 203 204 if (rv == SOC_E_NONE) { 205 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 206 (BSL_META_U(unit, 207 " Done in %d polls\n"), to.polls)); 208 } 209 210 if (schanCtrl & SC_CMCx_MSG_NAK) { 211 schan_msg_t resp_msg; 212 213 /* This is still the input opcode */ 214 msgAddr = CMIC_COMMON_CMCx_SCHAN_MESSAGEn(cmc, 1); 215 resp_msg.dwords[1] = soc_pci_read(unit, msgAddr); 216 217 rv = SOC_E_FAIL; 218 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 219 (BSL_META_U(unit, 220 " NAK received from SCHAN.\n"))); 221 222 switch (msg->header.v2.opcode) { 223 case TABLE_INSERT_CMD_MSG: 224 case TABLE_DELETE_CMD_MSG: 225 case TABLE_LOOKUP_CMD_MSG: 226 if (resp_msg.genresp.response.type != SCHAN_GEN_RESP_TYPE_ERROR) { 227 /* Not a parity error */ 228 break; 229 } 230 /* Else fallthru */ 231 case READ_MEMORY_CMD_MSG: 232 case READ_REGISTER_CMD_MSG: 233 #if defined(BCM_XGS_SUPPORT) 234 { 235 int dst_blk, opcode; 236 soc_schan_header_cmd_get(unit, &msg->header, &opcode, &dst_blk, 237 NULL, NULL, NULL, NULL, NULL); 238 239 (void)soc_ser_mem_nack(INT_TO_PTR(unit), 240 INT_TO_PTR(msg->gencmd.address), 241 INT_TO_PTR(dst_blk), 242 opcode == READ_REGISTER_CMD_MSG ? INT_TO_PTR(1) : 0, 0); 243 } 244 #endif 245 default: 246 break; 247 } 248 } 249 if ((schanCtrl & SC_CMCx_MSG_SER_CHECK_FAIL) && 250 soc_feature(unit, soc_feature_ser_parity)){ 251 rv = SOC_E_FAIL; 252 LOG_ERROR(BSL_LS_SOC_SCHAN, (BSL_META_U(unit, 253 " SER Parity Check Error.\n"))); 254 255 #if defined(BCM_XGS_SUPPORT) 256 sal_dpc(soc_ser_fail, INT_TO_PTR(unit), 257 INT_TO_PTR(msg->gencmd.address), 0, 0, 0); 258 #endif 259 } 260 261 if (soc_feature(unit, soc_feature_schan_hw_timeout)) { 262 if (schanCtrl & SC_CMCx_MSG_TIMEOUT_TST) { 263 rv = SOC_E_TIMEOUT; 264 } 265 } 266 267 if (soc_feature(unit, soc_feature_schan_err_check)) { 268 uint32 schan_err, err_bit = 0; 269 270 errAddr = CMIC_COMMON_CMCx_SCHAN_ERR_OFFSET(cmc); 271 schan_err = soc_pci_read(unit, errAddr); 272 err_bit = soc_reg_field_get(unit, CMIC_CMC0_SCHAN_ERRr, schan_err, ERRBITf); 273 274 if (err_bit) { 275 rv = SOC_E_FAIL; 276 LOG_ERROR(BSL_LS_SOC_SCHAN, (BSL_META_U(unit, 277 " ERRBIT received in CMIC_SCHAN_ERR.\n"))); 278 } 279 } 280 soc_pci_write(unit, ctrlAddr, SC_CMCx_MSG_CLR); 281 282 return rv; 283 } 284 285 /******************************************* 286 * @function _soc_cmicm_schan_op 287 * purpose cmicm SCHAN operation 288 * 289 * @param unit [in] unit 290 * @param msg [in] schan_msg_t 291 * @param dwc_write [in] Write messages 292 * @param dwc_write [in] read messages 293 * @param intr [in] use interrupt 294 * 295 * @returns SOC_E_NONE 296 * @returns SOC_E_XXX 297 * 298 * @end 299 * @comments This is the basic logic for schan 300 */ 301 302 STATIC int 303 _soc_cmicm_schan_op(int unit, schan_msg_t *msg, int dwc_write, 304 int dwc_read, int intr) 305 { 306 uint32 ctrlAddr, msgAddr; 307 int i, rv; 308 int cmc; 309 310 if (soc_schan_op_sanity_check(unit, msg, dwc_write, dwc_read, &rv) == TRUE) { 311 return rv; 312 } 313 314 #if defined(BCM_SABER2_SUPPORT) 315 if (!(SAL_BOOT_PLISIM || SAL_BOOT_BCMSIM)) { 316 if (SOC_IS_SABER2(unit)) { 317 if (msg->header.v4.dst_blk == SOC_BLOCK_INFO(unit, OAMP_BLOCK(unit)). 318 schan) { 319 if (msg->header.v4.opcode == WRITE_REGISTER_CMD_MSG) { 320 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 321 (BSL_META_U(unit, 322 "OAMP Write Block access OLD :%x \n"), 323 msg->writecmd.address)); 324 msg->writecmd.address = 325 (msg->writecmd.address >> 8) & 0x000003ff; 326 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 327 (BSL_META_U(unit, 328 "NEW :%x \n"), msg->writecmd.address)); 329 } 330 if (msg->header.v4.opcode == READ_REGISTER_CMD_MSG) { 331 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 332 (BSL_META_U(unit, 333 "OAMP READ Block access OLD:%x "), 334 msg->readcmd.address)); 335 msg->readcmd.address = 336 (msg->readcmd.address >> 8) & 0x000003ff; 337 LOG_VERBOSE(BSL_LS_SOC_SCHAN, 338 (BSL_META_U(unit, 339 "New: %x \n"), msg->readcmd.address)); 340 } 341 } 342 } 343 } 344 #endif /* BCM_SABER2_SUPPORT */ 345 346 if (_soc_schan_multi_cmc[unit]){ 347 SOC_IF_ERROR_RETURN(cmicm_schan_ch_get(unit, &cmc)); 348 } else { 349 SCHAN_LOCK(unit); 350 cmc = SOC_PCI_CMC(unit); 351 } 352 353 do { 354 rv = SOC_E_NONE; 355 356 /* Write raw S-Channel Data: dwc_write words */ 357 for (i = 0; i < dwc_write; i++) { 358 msgAddr = CMIC_COMMON_CMCx_SCHAN_MESSAGEn(cmc, i); 359 soc_pci_write(unit, msgAddr, msg->dwords[i]); 360 } 361 362 /* Tell CMIC to start */ 363 ctrlAddr = CMIC_COMMON_CMCx_SCHAN_CTRL_OFFSET(cmc); 364 soc_pci_write(unit, ctrlAddr, SC_CMCx_MSG_START); 365 366 /* Wait for completion using either the interrupt or polling method */ 367 if (intr && SOC_CONTROL(unit)->schanIntrEnb) { 368 rv = _soc_cmicm_schan_intr_wait(unit, cmc); 369 } else { 370 rv = _soc_cmicm_schan_poll_wait(unit, cmc, msg); 371 } 372 373 if (soc_schan_timeout_check(unit, &rv, msg, cmc, 0) == TRUE) { 374 break; 375 } 376 377 /* Read in data from S-Channel buffer space, if any */ 378 for (i = 0; i < dwc_read; i++) { 379 msgAddr = CMIC_COMMON_CMCx_SCHAN_MESSAGEn(cmc, i); 380 msg->dwords[i] = soc_pci_read(unit, msgAddr); 381 } 382 383 if (LOG_CHECK(BSL_LS_SOC_SCHAN | BSL_VERBOSE)) { 384 soc_schan_dump(unit, msg, dwc_read); 385 } 386 387 } while (0); 388 389 if (_soc_schan_multi_cmc[unit]) { 390 cmicm_schan_ch_put(unit, cmc); 391 } else { 392 SCHAN_UNLOCK(unit); 393 } 394 395 if (rv == SOC_E_TIMEOUT) { 396 if (LOG_CHECK(BSL_LS_SOC_SCHAN | BSL_ERROR)) { 397 LOG_ERROR(BSL_LS_SOC_SCHAN, 398 (BSL_META_U(unit, 399 "SchanTimeOut:soc_schan_op operation timed out cmc=%d\n"), cmc)); 400 soc_schan_dump(unit, msg, dwc_write); 401 } 402 } 403 404 return rv; 405 } 406 407 /******************************************* 408 * @function _cmicm_schan_ch_get 409 * purpose get idle schan on cmc 410 * 411 * @param unit [in] unit # 412 * @param *cmc [out] cmc number 0-2 or 3 for common 413 * 414 * @returns SOC_E_BUSY 415 * @returns SOC_E_NONE 416 * 417 * @end 418 */ 419 STATIC int 420 _cmicm_schan_ch_get(int unit, int *cmc) 421 { 422 int rv = SOC_E_BUSY; 423 int i; 424 425 sal_spinlock_lock(_cmicm_schan_ch[unit].lock); 426 for (i = 0; i <= CMIC_CMC_NUM_MAX; i++) { 427 if (_cmicm_schan_ch[unit].ch[i] & 0x01) { 428 rv = SOC_E_NONE; 429 *cmc = i; 430 _cmicm_schan_ch[unit].ch[i] &= ~(0x01); 431 break; 432 } 433 } 434 sal_spinlock_unlock(_cmicm_schan_ch[unit].lock); 435 return rv; 436 } 437 438 /******************************************* 439 * @function cmicm_schan_ch_get 440 * purpose get idle schan on cmc 441 * 442 * @param unit [in] unit # 443 * @param cmc [out] cmc number 0-2 or 3 for common 444 * 445 * @returns SOC_E_BUSY 446 * @returns SOC_E_NONE 447 * 448 * @end 449 */ 450 int cmicm_schan_ch_get(int unit, int *cmc) 451 { 452 int rv; 453 454 soc_timeout_t to; 455 456 soc_timeout_init(&to, _cmicm_schan_ch[unit].timeout, 100); 457 458 do { 459 rv = _cmicm_schan_ch_get(unit, cmc); 460 if (rv == SOC_E_NONE) 461 break; 462 } while (!soc_timeout_check(&to)); 463 return rv; 464 } 465 466 /******************************************* 467 * @function cmicm_schan_ch_try_get 468 * purpose get idle channel on cmc 469 * 470 * @param unit [in] unit # 471 * @param cmc [in] cmc number 0-2 or 3 for common 472 * 473 * @returns SOC_E_BUSY 474 * @returns SOC_E_NONE 475 * 476 * @end 477 */ 478 int cmicm_schan_ch_try_get(int unit, int cmc) 479 { 480 int rv = SOC_E_BUSY; 481 482 soc_timeout_t to; 483 484 soc_timeout_init(&to, _cmicm_schan_ch[unit].timeout, 100); 485 486 sal_spinlock_lock(_cmicm_schan_ch[unit].lock); 487 do { 488 if (_cmicm_schan_ch[unit].ch[cmc] & 0x01) { 489 rv = SOC_E_NONE; 490 _cmicm_schan_ch[unit].ch[cmc] &= ~(0x01); 491 break; 492 } 493 } while (!soc_timeout_check(&to)); 494 sal_spinlock_unlock(_cmicm_schan_ch[unit].lock); 495 496 return rv; 497 } 498 499 /******************************************* 500 * @function cmicm_schan_ch_put 501 * purpose put back the freed channel on cmc 502 * 503 * @param unit [in] unit # 504 * @param cmc [in] cmc number 0-2 or 3 for common 505 * 506 * @returns SOC_E_PARAM 507 * @returns SOC_E_NONE 508 * 509 * @end 510 */ 511 int cmicm_schan_ch_put(int unit, int cmc) 512 { 513 int rv = SOC_E_NONE; 514 515 if ((cmc < 0) || (cmc > CMIC_CMC_NUM_MAX)) { 516 rv = SOC_E_PARAM; 517 return rv; 518 } 519 sal_spinlock_lock(_cmicm_schan_ch[unit].lock); 520 _cmicm_schan_ch[unit].ch[cmc] |= 0x01; 521 sal_spinlock_unlock(_cmicm_schan_ch[unit].lock); 522 523 return rv; 524 } 525 526 /******************************************* 527 * @function cmicm_schan_ch_init 528 * purpose API to Initialize schan channel seletion mechanism 529 * 530 * @param unit [in] unit 531 * @param timeout [in] timeout 532 * 533 * @returns SOC_E_NONE 534 * @returns SOC_E_XXX 535 * 536 * @end 537 */ 538 int cmicm_schan_ch_init(int unit, int timeout) 539 { 540 int rv = SOC_E_NONE; 541 int i; 542 543 _cmicm_schan_ch[unit].lock = sal_spinlock_create("schan Lock"); 544 545 if (_cmicm_schan_ch[unit].lock == NULL) { 546 return SOC_E_MEMORY; 547 } 548 /* Availability of channels */ 549 for (i = 0; i <= CMIC_CMC_NUM_MAX; i++) { 550 _cmicm_schan_ch[unit].ch[i] = 0x01; 551 } 552 return rv; 553 554 } 555 556 /******************************************* 557 * @function _soc_cmicm_schan_deinit 558 * purpose API to de-intialize cmicm SCHAN 559 * 560 * @param unit [in] unit 561 * 562 * @returns SOC_E_NONE 563 * @returns SOC_E_XXX 564 * 565 * @end 566 */ 567 STATIC int 568 _soc_cmicm_schan_deinit(int unit) 569 { 570 int cmc; 571 572 for (cmc = 0; cmc <= CMIC_CMC_NUM_MAX; cmc++) { 573 _soc_cmicm_schan_reset(unit, cmc, 0); 574 } 575 sal_spinlock_destroy(_cmicm_schan_ch[unit].lock); 576 577 return SOC_E_NONE; 578 } 579 580 /******************************************* 581 * @function soc_schan_cmicm_init 582 * purpose API to Initialize cmicm SCHAN 583 * 584 * @param unit [in] unit 585 * @param drv [out] soc_cmic_schan_drv_t pointer 586 * 587 * @returns SOC_E_NONE 588 * @returns SOC_E_XXX 589 * 590 * @end 591 */ 592 int soc_cmicm_schan_init(int unit, soc_cmic_schan_drv_t *drv) 593 { 594 /* Cache multi CMC flag */ 595 sal_memset(_soc_schan_multi_cmc, 0, sizeof(_soc_schan_multi_cmc)); 596 if (SOC_CHECK_MULTI_CMC(unit)) { 597 _soc_schan_multi_cmc[unit] = 1; 598 } 599 drv->soc_schan_deinit = _soc_cmicm_schan_deinit; 600 drv->soc_schan_op = _soc_cmicm_schan_op; 601 drv->soc_schan_reset = _soc_cmicm_schan_reset; 602 603 SOC_IF_ERROR_RETURN(cmicm_schan_ch_init(unit, 604 CMIC_CMCx_SCHAN_CHSELECT_TIMEOUT)); 605 606 return SOC_E_NONE; 607 } 608 609 #endif /* BCM_CMICM_SUPPORT */