cmicx_link.c (25501B)
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 * Purpose: CMICx link scan module 8 */ 9 #include <sal/core/boot.h> 10 #include <sal/core/libc.h> 11 #include <sal/core/sync.h> 12 #include <shared/alloc.h> 13 #include <shared/bsl.h> 14 15 #if defined (BCM_ESW_SUPPORT) || defined(BCM_DNXF_SUPPORT) || defined(BCM_DNX_SUPPORT) 16 #include <soc/drv.h> 17 #include <soc/cm.h> 18 #include <soc/cmic.h> 19 #ifdef BCM_CMICX_SUPPORT 20 #include <shared/cmicfw/iproc_mbox.h> 21 #include <shared/cmicfw/iproc_m0ssq.h> 22 #include <shared/cmicfw/iproc_fwconfig.h> 23 #include <shared/cmicfw/cmicx_link_defs.h> 24 #include <shared/cmicfw/cmicx_link.h> 25 #include <shared/cmicfw/m0_ver.h> 26 27 static soc_iproc_m0ssq_shmem_t *ls_shmem = NULL; 28 29 static uint32 soc_iproc_sysreg_base_get(int unit) 30 { 31 if (SOC_IS_HELIX5(unit)) { 32 return IPROC_MDIO_SYS_BASE_HX5; 33 } else { 34 return IPROC_MDIO_SYS_BASE; 35 } 36 } 37 38 uint32 soc_cmicx_miim_phy_reg_read(int unit, int index) 39 { 40 uint32 base, val; 41 uint32 offset = MIIM_PHY_LINK_STATUS0_OFFSET + (index * 4); 42 43 base = soc_iproc_sysreg_base_get(unit); 44 soc_iproc_getreg(unit, (base + offset), &val); 45 46 return val; 47 } 48 49 void soc_cmicx_miim_phy_reg_write(int unit, int index, uint32 data) 50 { 51 uint32 base; 52 uint32 offset = MIIM_PHY_LINK_STATUS0_OFFSET + (index * 4); 53 54 base = soc_iproc_sysreg_base_get(unit); 55 soc_iproc_setreg(unit, (base + offset), data); 56 } 57 58 59 int soc_iproc_linkscan_process_message(soc_iproc_mbox_info_t *chan, soc_iproc_mbox_msg_t *msg); 60 61 /* 62 * Function: 63 * _soc_iproc_l2p_pbmp_update 64 * Purpose: 65 * Convert given port bitmap from logical to physical port numbering 66 * Parameters: 67 * unit number 68 * port bitmap based on logical port numbering 69 * port bitmap converted to physical port numbering 70 * Returns: 71 * none 72 */ 73 STATIC 74 void _soc_iproc_l2p_pbmp_update(int unit, soc_pbmp_t logical_pbmp, ls_phy_pbmp_t *phy_pbmp) 75 { 76 soc_port_t port; 77 int phy_port = 0; 78 soc_info_t *si; 79 80 si = &SOC_INFO(unit); 81 82 SOC_PBMP_ITER(logical_pbmp, port) { 83 phy_port = si->port_l2p_mapping[port]; 84 LS_PHY_PBMP_PORT_ADD(*phy_pbmp, phy_port); 85 } 86 87 return; 88 } 89 90 /* 91 * Function: 92 * _soc_iproc_p2l_pbmp_update 93 * Purpose: 94 * Convert given port bitmap from physical to logical port numbering 95 * Parameters: 96 * unit number 97 * port bitmap based on physical port numbering 98 * port bitmap converted to logical port numbering 99 * Returns: 100 * none 101 */ 102 STATIC 103 void _soc_iproc_p2l_pbmp_update(int unit, ls_phy_pbmp_t phy_pbmp, soc_pbmp_t *logical_pbmp) 104 { 105 soc_port_t phy_port; 106 int port = 0; 107 soc_info_t *si; 108 109 si = &SOC_INFO(unit); 110 111 LS_PHY_PBMP_ITER(phy_pbmp, phy_port) { 112 port = si->port_p2l_mapping[phy_port]; 113 SOC_PBMP_PORT_ADD(*logical_pbmp, port); 114 } 115 116 return; 117 } 118 119 #if (defined (BCM_DNXF_SUPPORT) || defined (BCM_DNX_SUPPORT)) 120 /* 121 * Function: 122 * _soc_iproc_add_cpu_port_to_pbmp 123 * Purpose: 124 * Add cpu port(bit 0)to given port bitmap and adjust rest of ports accordingly 125 * This function is needed since port bitmap returned by FW taking into account 126 * cpu port at bit 0 which is required by XGS SDK code, but not required by 127 * DNX SDK code. So for DNX device, the function must be needed. 128 * Parameters: 129 * unit number 130 * pointer to port bitmap containing incoming port bitmap 131 * port bitmap to be modified to contain cpu port(bit 0) 132 * 133 * Returns: 134 * none 135 */ 136 STATIC 137 void _soc_iproc_add_cpu_port_to_pbmp(int unit, uint32 *data, ls_phy_pbmp_t *phy_pbmp) 138 { 139 uint32 tmp1 = 0, tmp2 = 0, idx = 0; 140 141 /* For 1st word, save bit 31 before left shift to add cpu port */ 142 tmp1 = (data[idx] & 0x80000000) >> 31; 143 LS_PHY_PBMP_WORD_SET(*phy_pbmp, 0, (data[idx] << 1)); 144 145 for(idx = 1; idx < LS_PHY_PBMP_WORD_MAX; idx++) { 146 /* Set saved bit 31 from previous to bit 0 of next word */ 147 tmp2 = (data[idx] << 1) | tmp1; 148 /* Add updated word to pbmp to be returned */ 149 LS_PHY_PBMP_WORD_SET(*phy_pbmp, idx, tmp2); 150 /* Save bit 31 from current word to be used in next iteration */ 151 tmp1 = (data[idx] & 0x80000000) >> 31; 152 } 153 154 return; 155 } 156 157 /* 158 * Function: 159 * _soc_iproc_remove_cpu_port_from_pbmp 160 * Purpose: 161 * Add cpu port(bit 0)to given port bitmap and adjust rest of ports accordingly 162 * This function is needed since port bitmap returned by FW taking into account 163 * cpu port at bit 0 which is required by XGS SDK code, but not required by 164 * DNX SDK code. So for DNX device, the function must be needed. 165 * Parameters: 166 * unit number 167 * pointer to message data containing incoming port bitmap 168 * port bitmap to be modified to contain cpu port 169 * Returns: 170 * none 171 */ 172 STATIC 173 void _soc_iproc_remove_cpu_port_from_pbmp(int unit, ls_phy_pbmp_t logical_pbmp, uint32 *data) 174 { 175 uint32 tmp = 0, idx = 0; 176 177 for(idx = 0; idx < (LS_PHY_PBMP_WORD_MAX - 1); idx++) { 178 /* Shift out last bit in current word */ 179 data[idx] = (LS_PHY_PBMP_WORD_GET(logical_pbmp, idx) >> 1); 180 /* Get bit 0 from next word and move it to bit 31 of previous */ 181 tmp = LS_PHY_PBMP_WORD_GET(logical_pbmp, (idx + 1)); 182 tmp &= 0x1; 183 tmp <<= 31; 184 data[idx] |= tmp; 185 } 186 187 data[idx] = (LS_PHY_PBMP_WORD_GET(logical_pbmp, idx) >> 1); 188 189 return; 190 } 191 #endif 192 193 /* 194 * Function: 195 * _soc_iproc_optimized_cpu_port_to_pbmp_add 196 * Purpose: 197 * Add cpu port to given port bitmap and adjust rest of ports accordingly 198 * This function is needed since port bitmap returned by FW does not take 199 * into account cpu port at bit 0 which is required by rest of SDK code 200 * CPU port is not tracked by HW linkscan FW. 201 * Parameters: 202 * unit number 203 * port bitmap to be modified to contain cpu port 204 * Returns: 205 * none 206 */ 207 STATIC 208 void _soc_iproc_optimized_cpu_port_to_pbmp_add(int unit, ls_phy_pbmp_t *dev_pbmp) 209 { 210 uint32 tmp1 = 0, tmp2 = 0, idx = 0; 211 uint32 reg1, reg2; 212 213 /* DNX doesn't use CPU port at bit0, no need to shift. */ 214 if (SOC_IS_DNX(unit) || SOC_IS_DNXF(unit)) { 215 for(idx = 0; idx < LS_PHY_PBMP_WORD_MAX; idx++) { 216 reg1 = soc_cmicx_miim_phy_reg_read(unit, idx); 217 LS_PHY_PBMP_WORD_SET(*dev_pbmp, idx, reg1); 218 } 219 } else { 220 reg1 = soc_cmicx_miim_phy_reg_read(unit, idx); 221 222 /* For 1st word, save bit 31 before left shift to add cpu port */ 223 tmp1 = (reg1 & 0x80000000) >> 31; 224 LS_PHY_PBMP_WORD_SET(*dev_pbmp, 0, (reg1 << 1)); 225 226 for(idx = 1; idx < LS_PHY_PBMP_WORD_MAX; idx++) { 227 /* Set saved bit 31 from previous to bit 0 of next word */ 228 reg2 = soc_cmicx_miim_phy_reg_read(unit, idx); 229 tmp2 = (reg2 << 1) | tmp1; 230 /* Add updated word to pbmp to be returned */ 231 LS_PHY_PBMP_WORD_SET(*dev_pbmp, idx, tmp2); 232 /* Save bit 31 from current word to be used in next iteration */ 233 reg1 = soc_cmicx_miim_phy_reg_read(unit, idx); 234 tmp1 = (reg1 & 0x80000000) >> 31; 235 } 236 } 237 return; 238 } 239 /* 240 * Function: 241 * soc_hx5_war_is_enable 242 * Purpose: 243 * This function is only for HX5. It will check 244 * if HX5HW-2279 is applicable for a given TSC core. 245 * Assume that port flexing won't change PMQ mode, 246 * since PMQ qsgmii mode is not support flexing. 247 * Parameters: 248 * unit number 249 * core Core number 250 * > 0, Initial WAR enable cache. 251 * Returns: 252 * 1 if core need WAR. 253 */ 254 static int 255 soc_hx5_war_is_enable(int unit, int core) { 256 257 uint32 qmode = 0; 258 uint32 otp_qmode = 0; 259 static uint32 hx5_war_en[SOC_MAX_NUM_DEVICES] = {0}; 260 static uint32 hx5_war_en_valid[SOC_MAX_NUM_DEVICES] = {0}; 261 262 if (core < 0) { 263 hx5_war_en_valid[unit] = 0; 264 } else if (core > 2) { 265 return 0; 266 } 267 268 if (hx5_war_en_valid[unit]) { 269 return ((hx5_war_en[unit] & (1 << core)) != 0); 270 } 271 272 /* Read PMQ current mode */ 273 if (READ_TOP_MISC_GENERIC_CONTROLr(unit, &qmode) < 0) { 274 return 0; 275 }; 276 277 /* Read OTP (QSGMII_ENABLE) */ 278 READ_DMU_PCU_OTP_CONFIG_8r(unit, &otp_qmode); 279 280 otp_qmode = (otp_qmode >> 25); 281 otp_qmode = (otp_qmode & 0x7); 282 qmode = qmode & 0x7; 283 284 /* 285 * if OTP (QSGMII_ENABLE) is not equal to PMQ current mode. 286 * Then set "war enable" as 1 287 */ 288 hx5_war_en[unit] = (otp_qmode ^ qmode); 289 hx5_war_en_valid[unit] = 1; 290 291 if (core < 0) { 292 return (hx5_war_en[unit] != 0); 293 } else { 294 return ((hx5_war_en[unit] & (1 << core)) != 0); 295 } 296 297 } 298 299 300 /* 301 * Function: 302 * _soc_hx5_optimized_cpu_port_to_pbmp_add 303 * Purpose: 304 * This function is only for HELIX5 with the same purpose with 305 * This function is needed since port bitmap returned by FW does not take 306 * into account cpu port at bit 0 which is required by rest of SDK code 307 * CPU port is not tracked by HW linkscan FW. 308 * Parameters: 309 * unit number 310 * port bitmap to be modified to contain cpu port 311 * Returns: 312 * none 313 */ 314 STATIC 315 void _soc_hx5_optimized_cpu_port_to_pbmp_add(int unit, ls_phy_pbmp_t *dev_pbmp) 316 { 317 uint32 tmp1 = 0, tmp2 = 0, idx = 0; 318 uint32 reg1, reg2; 319 pbmp_t lpbmp; 320 soc_port_t phy_port; 321 int port = 0; 322 soc_info_t *si; 323 link_status_entry_t link_status; 324 325 si = &SOC_INFO(unit); 326 327 READ_MIIM_INT_PHY_LINK_RAW_STATUSr(unit, idx, ®1); 328 329 /* For 1st word, save bit 31 before left shift to add cpu port */ 330 tmp1 = (reg1 & 0x80000000) >> 31; 331 LS_PHY_PBMP_WORD_SET(*dev_pbmp, 0, (reg1 << 1)); 332 333 for(idx = 1; idx < SOC_REG_NUMELS(unit, MIIM_INT_PHY_LINK_RAW_STATUSr); idx++) { 334 335 /* Set saved bit 31 from previous to bit 0 of next word */ 336 READ_MIIM_INT_PHY_LINK_RAW_STATUSr(unit, idx, ®2); 337 tmp2 = (reg2 << 1) | tmp1; 338 339 /* Add updated word to pbmp to be returned */ 340 LS_PHY_PBMP_WORD_SET(*dev_pbmp, idx, tmp2); 341 342 /* Save bit 31 from current word to be used in next iteration */ 343 READ_MIIM_INT_PHY_LINK_RAW_STATUSr(unit, idx, ®1); 344 tmp1 = (reg1 & 0x80000000) >> 31; 345 } 346 347 SOC_PBMP_CLEAR(lpbmp); 348 if (SOC_FAILURE(READ_LINK_STATUSm(unit, IPIPE_BLOCK(unit), 0, &link_status))) { 349 return; 350 }; 351 sal_memcpy(&lpbmp, &link_status, sizeof(link_status)); 352 353 /* WAR for HX5 */ 354 for (phy_port = 1; phy_port <= 48; phy_port++) 355 { 356 if (soc_hx5_war_is_enable(unit, (phy_port-1)/16)) 357 { 358 port = si->port_p2l_mapping[phy_port]; 359 if (port > 0) { 360 if (PBMP_MEMBER(lpbmp, port)) 361 { 362 LS_PHY_PBMP_PORT_ADD(*dev_pbmp, phy_port); 363 } else { 364 LS_PHY_PBMP_PORT_REMOVE(*dev_pbmp, phy_port); 365 } 366 } 367 } 368 } 369 370 return; 371 } 372 /* 373 * Function: 374 * soc_cmicx_linkscan_hw_link_cache_get 375 * Purpose: 376 * Get the current HW link status from linkscan cached copy 377 * Parameters: 378 * unit number 379 * Returns: 380 * SOC_E_NONE 381 */ 382 int soc_cmicx_linkscan_hw_link_cache_get(int unit, soc_pbmp_t *hw_link) 383 { 384 soc_control_t *soc = SOC_CONTROL(unit); 385 int idx; 386 387 for(idx = 0; idx < _SHR_PBMP_WORD_MAX; idx++) { 388 SOC_PBMP_WORD_SET(*hw_link, idx, SOC_PBMP_WORD_GET(soc->cmicx_link_stat, idx)); 389 } 390 391 return SOC_E_NONE; 392 } 393 394 /* 395 * Function: 396 * soc_iproc_link_status_update 397 * Purpose: 398 * Notify the link status change update from Cortex-M0 to linkscan thread 399 * Parameters: 400 * unit number 401 * Linkscan message from cortex-M0 402 * contain_cpu_bit indicate the message include cpu port bit. 403 * Returns: 404 * SOC_E_NONE 405 */ 406 int soc_iproc_link_status_update(int unit, soc_iproc_mbox_msg_t *msg, int contain_cpu_bit) 407 { 408 soc_control_t *soc = SOC_CONTROL(unit); 409 ls_phy_pbmp_t phy_pbmp; 410 #if (defined (BCM_DNXF_SUPPORT) || defined (BCM_DNX_SUPPORT)) 411 ls_phy_pbmp_t updated_phy_pbm; 412 #endif 413 int idx = 0; 414 415 /* Clear phy pbmp */ 416 LS_PHY_PBMP_CLEAR(phy_pbmp); 417 418 /* Copy message payload */ 419 for (idx = 0; idx < LS_PHY_PBMP_WORD_MAX; idx++) { 420 LS_PHY_PBMP_WORD_SET(phy_pbmp, idx, msg->data[idx]); 421 } 422 #if (defined (BCM_DNXF_SUPPORT) || defined (BCM_DNX_SUPPORT)) 423 if (SOC_IS_DNX(unit) || SOC_IS_DNXF(unit)) { 424 /* 425 * DNX need to remove CPU port at bit0. 426 * If it is in hw-config response, 427 * CPU port bit0 are not included in msg 428 */ 429 430 if (contain_cpu_bit) 431 { 432 LS_PHY_PBMP_CLEAR(updated_phy_pbm); 433 _soc_iproc_remove_cpu_port_from_pbmp(unit, phy_pbmp, updated_phy_pbm.pbits); 434 for(idx = 0; idx < LS_PHY_PBMP_WORD_MAX; idx++) { 435 LS_PHY_PBMP_WORD_SET(phy_pbmp, idx, LS_PHY_PBMP_WORD_GET(updated_phy_pbm, idx)); 436 } 437 } 438 LS_PHY_PBMP_CLEAR(soc->cmicx_link_stat); 439 } 440 #endif 441 /* Convert physical pbmp to logical pbmp */ 442 _soc_iproc_p2l_pbmp_update(unit, phy_pbmp, &soc->cmicx_link_stat); 443 444 #if defined (BCM_ESW_SUPPORT) 445 if (SOC_IS_ESW(unit)) { 446 /* Inform linkscan thread */ 447 cmicx_esw_linkscan_hw_interrupt(unit); 448 } 449 #endif 450 451 #if (defined (BCM_DNXF_SUPPORT) || defined (BCM_DNX_SUPPORT)) 452 if (SOC_IS_DNXF(unit) || SOC_IS_DNX(unit)) { 453 /* Inform linkscan thread */ 454 cmicx_common_linkscan_hw_interrupt(unit); 455 } 456 #endif 457 458 return SOC_E_NONE; 459 } 460 461 /* 462 * Function: 463 * soc_iproc_linkscan_process_message 464 * Purpose: 465 * Linkscan application handler to handle messages in running state. 466 * Parameters: 467 * unit number 468 * Iproc mbox info 469 * Linkscan message from cortex-M0 470 * Returns: 471 * SOC_E_xxx 472 */ 473 int soc_iproc_linkscan_process_message(soc_iproc_mbox_info_t *chan, soc_iproc_mbox_msg_t *msg) 474 { 475 int rv = 0; 476 477 if (NULL == msg) { 478 return SOC_E_PARAM; 479 } 480 481 switch(msg->id) { 482 case LS_LINK_STATUS_CHANGE: 483 484 return soc_iproc_link_status_update(chan->unit, msg, 1); 485 default: 486 LOG_ERROR(BSL_LS_SOC_M0, (BSL_META_U(chan->unit, "Invalid M0 message id\n"))); 487 rv = IPROC_MBOX_ERR_INVCMD; 488 break; 489 } 490 491 return rv; 492 } 493 494 /* 495 * Function: 496 * soc_iproc_linkscan_msg_handler 497 * Purpose: 498 * Linkscan message handler to handle messages from Cortex-M0 linkscan application. 499 * Parameters: 500 * Registered parameter 501 * Returns: 502 * SOC_E_xxx 503 */ 504 int soc_iproc_linkscan_msg_handler(void *param) 505 { 506 int rv = 0, respidx; 507 soc_iproc_mbox_msg_t *msg; 508 soc_iproc_mbox_info_t *rxchan = (soc_iproc_mbox_info_t *)param; 509 510 if (rxchan == NULL) 511 return SOC_E_PARAM; 512 513 while(!rv) { 514 respidx = soc_iproc_data_recv(rxchan, &msg); 515 if (respidx < 0) { 516 rv = respidx; 517 break; 518 } 519 520 if ((!IS_IPROC_RESP_READY(msg)) & (!IS_ASYNC_IPROC_STATUS(msg))) { 521 soc_iproc_free(msg); 522 break; 523 } else { 524 rv = soc_iproc_linkscan_process_message(rxchan, msg); 525 LOG_VERBOSE(BSL_LS_SOC_M0, (BSL_META_U(rxchan->unit, " Msg processed %d\n"), msg->id)); 526 soc_iproc_free(msg); 527 } 528 } 529 530 return rv; 531 } 532 533 534 /* 535 * Function: 536 * soc_cmicx_link_fw_config_init 537 * Purpose: 538 * Initialize linkscan firmware config. 539 * Parameters: 540 * unit number 541 * Returns: 542 * SOC_E_xxx 543 */ 544 int 545 soc_cmicx_link_fw_config_init(int unit) { 546 547 FWLINKSCAN_CTRLr_t ctrl; 548 549 /* Get shared memory of firmware linkscan. */ 550 SOC_IF_ERROR_RETURN(soc_iproc_m0ssq_shmem_get(unit, "linkscan", &ls_shmem)); 551 552 /* Clear shared memory of firmware linkscan as zero. */ 553 SOC_IF_ERROR_RETURN(soc_iproc_m0ssq_shmem_clear(ls_shmem)); 554 555 /* Pause firmware linkscan. */ 556 FWLINKSCAN_CTRLr_CLR(ctrl); 557 FWLINKSCAN_CTRLr_PAUSEf_SET(ctrl, 1); 558 SOC_IF_ERROR_RETURN(WRITE_FWLINKSCAN_CTRLr(ls_shmem, ctrl)); 559 560 return SOC_E_NONE; 561 } 562 563 /* 564 * Function: 565 * soc_cmicx_linkscan_hw_init 566 * Purpose: 567 * Initialize linkscan mbox and handler. 568 * Parameters: 569 * unit number 570 * Returns: 571 * SOC_E_xxx 572 */ 573 int soc_cmicx_linkscan_hw_init(int unit) 574 { 575 int rv = 0; 576 soc_control_t *soc = SOC_CONTROL(unit); 577 578 if (!soc->iproc_m0ls_init_done) { 579 580 /* Allocate mailbox. */ 581 SOC_IF_ERROR_RETURN(soc->ls_mbox_id = soc_iproc_mbox_alloc(unit, U0_LINKSCAN_APP)); 582 soc->ls_txmbox= &soc->iproc_mbox_info[soc->ls_mbox_id][IPROC_MBOX_TYPE_TX]; 583 soc->ls_rxmbox= &soc->iproc_mbox_info[soc->ls_mbox_id][IPROC_MBOX_TYPE_RX]; 584 rv = soc_iproc_mbox_handler_register(unit, soc->ls_mbox_id, soc_iproc_linkscan_msg_handler, (void *) soc->ls_rxmbox); 585 if (rv < 0) { 586 LOG_ERROR(BSL_LS_SOC_M0, (BSL_META_U(unit, "Linkscan Mbox handler register failed\n"))); 587 soc_iproc_mbox_free(unit, soc->ls_mbox_id); 588 return rv; 589 } 590 591 soc->iproc_m0ls_init_done = 1; 592 } 593 594 return rv; 595 } 596 597 /* 598 * Function: 599 * soc_cmicx_linkscan_hw_deinit 600 * Purpose: 601 * Cleanup linkscan mbox and handler. 602 * Parameters: 603 * unit number 604 * Returns: 605 * SOC_E_xxx 606 */ 607 int soc_cmicx_linkscan_hw_deinit(int unit) 608 { 609 int rv = 0; 610 soc_control_t *soc = SOC_CONTROL(unit); 611 612 if (soc->iproc_m0ls_init_done) { 613 soc_iproc_mbox_free(unit, soc->ls_mbox_id); 614 soc->iproc_m0ls_init_done = 0; 615 } 616 617 return rv; 618 } 619 620 /* Max time for firmware to complete linkscan one time. (200ms) */ 621 #define LINKSCAN_TIME_MAX (200000) 622 623 /* 624 * Function: 625 * soc_cmicx_linkscan_pause 626 * Purpose: 627 * Pause firmware linkscan. 628 * Parameters: 629 * unit number 630 * Returns: 631 * SOC_E_xxx 632 */ 633 int soc_cmicx_linkscan_pause(int unit) 634 { 635 FWLINKSCAN_STATUSr_t status; 636 FWLINKSCAN_CTRLr_t ctrl; 637 int run; 638 soc_timeout_t to; 639 640 LOG_VERBOSE(BSL_LS_SOC_M0, (BSL_META_U(unit, "M0 Linkscan pause\n"))); 641 642 SOC_IF_ERROR_RETURN(READ_FWLINKSCAN_CTRLr(ls_shmem, &ctrl)); 643 644 /* if firmware linkscan is paused then return. */ 645 if (FWLINKSCAN_CTRLr_PAUSEf_GET(ctrl) != 0) { 646 return SOC_E_NONE; 647 } 648 649 /* Pause firmware linkscan. */ 650 FWLINKSCAN_CTRLr_PAUSEf_SET(ctrl, 1); 651 SOC_IF_ERROR_RETURN(WRITE_FWLINKSCAN_CTRLr(ls_shmem, ctrl)); 652 653 /* Init timeout object with LINKSCAN_TIME_MAX, polling period 100usec. */ 654 soc_timeout_init(&to, LINKSCAN_TIME_MAX, 10); 655 656 /* Ensure firmware being paused. */ 657 do { 658 659 /* Check if firmware linkscan is running. */ 660 SOC_IF_ERROR_RETURN(READ_FWLINKSCAN_STATUSr(ls_shmem, &status)); 661 run = FWLINKSCAN_STATUSr_RUNf_GET(status); 662 if (run == 0) { 663 return SOC_E_NONE; 664 } 665 666 } while (!soc_timeout_check(&to)); 667 668 return SOC_E_TIMEOUT; 669 } 670 671 /* 672 * Function: 673 * soc_cmicx_linkscan_continue 674 * Purpose: 675 * Continue/start firmware linkscan. 676 * Parameters: 677 * unit number 678 * Returns: 679 * SOC_E_xxx 680 */ 681 int soc_cmicx_linkscan_continue(int unit) 682 { 683 FWLINKSCAN_CTRLr_t ctrl; 684 685 LOG_VERBOSE(BSL_LS_SOC_M0, (BSL_META_U(unit, "M0 Linkscan continue\n"))); 686 687 SOC_IF_ERROR_RETURN(READ_FWLINKSCAN_CTRLr(ls_shmem, &ctrl)); 688 689 /* if firmware linkscan is not paused then return. */ 690 if (FWLINKSCAN_CTRLr_PAUSEf_GET(ctrl) == 0) { 691 return SOC_E_NONE; 692 } 693 694 /* Continue/clear pause of firmware linkscan. */ 695 FWLINKSCAN_CTRLr_PAUSEf_SET(ctrl, 0); 696 SOC_IF_ERROR_RETURN(WRITE_FWLINKSCAN_CTRLr(ls_shmem, ctrl)); 697 698 return SOC_E_NONE; 699 700 } 701 702 /* 703 * Function: 704 * soc_cmicx_linkscan_heartbeat 705 * Purpose: 706 * Send LS_HW_HEARTBEAT message to Cortex-M0 linkscan application. 707 * Parameters: 708 * unit number 709 * Returns: 710 * SOC_E_XXX 711 */ 712 int soc_cmicx_linkscan_heartbeat(int unit, soc_ls_heartbeat_t *ls_heartbeat) 713 { 714 soc_iproc_mbox_msg_t *msg, *resp; 715 int rv; 716 717 if (!SOC_CONTROL(unit)->iproc_mbox_init_done) { 718 LOG_VERBOSE(BSL_LS_SOC_M0, (BSL_META_U(unit, "Mbox init not done\n"))); 719 return SOC_E_NONE; 720 } 721 722 LOG_VERBOSE(BSL_LS_SOC_M0, (BSL_META_U(unit, "M0 Linkscan heartbeat\n"))); 723 724 sal_memset(ls_heartbeat, 0, sizeof(soc_ls_heartbeat_t)); 725 726 ls_heartbeat->host_fw_version = (HOST_FW_VER_MAJOR << 16 | HOST_FW_VER_MINOR); 727 728 msg = soc_iproc_alloc(sizeof(soc_iproc_mbox_msg_t) + sizeof(soc_ls_heartbeat_t)); 729 if (msg == NULL) 730 return SOC_E_MEMORY; 731 732 resp = soc_iproc_alloc(sizeof(soc_iproc_mbox_msg_t) + sizeof(soc_ls_heartbeat_t)); 733 if (resp == NULL) { 734 soc_iproc_free(msg); 735 return SOC_E_MEMORY; 736 } 737 738 msg->id = LS_HW_HEARTBEAT; 739 msg->flags = IPROC_SYNC_MSG | IPROC_RESP_REQUIRED; 740 msg->size = sizeof(soc_ls_heartbeat_t) / sizeof(uint32); 741 if (sizeof(soc_ls_heartbeat_t) % sizeof(uint32)) { 742 msg->size++; 743 } 744 745 /* Copy message data */ 746 sal_memcpy((void *)msg->data, (void *)ls_heartbeat, sizeof(soc_ls_heartbeat_t)); 747 748 rv = soc_iproc_data_send_wait(SOC_CONTROL(unit)->ls_txmbox, msg, resp); 749 if (rv == IPROC_MSG_SUCCESS) { 750 if (IS_IPROC_RESP_READY(resp)) { 751 if (IS_IPROC_RESP_SUCCESS(resp)) { 752 /* Copy response data */ 753 sal_memcpy((void *)ls_heartbeat, (void *)resp->data, sizeof(soc_ls_heartbeat_t)); 754 rv = SOC_E_NONE; 755 } else { 756 rv = resp->data[0]; 757 } 758 } 759 } 760 761 soc_iproc_free(msg); 762 soc_iproc_free(resp); 763 764 return rv; 765 } 766 767 /* 768 * Function: 769 * soc_cmicx_linkscan_hw_link_get 770 * Purpose: 771 * Obtain actual device link status from miim registers 772 * Parameters: 773 * unit number 774 * Returns: 775 * SOC_E_xxx 776 */ 777 int soc_cmicx_linkscan_hw_link_get(int unit, soc_pbmp_t *hw_link) 778 { 779 int rv; 780 ls_phy_pbmp_t phy_hw_pbmp; 781 782 LOG_VERBOSE(BSL_LS_SOC_M0, (BSL_META_U(unit, "M0 Linkscan hw link get\n"))); 783 784 if (SOC_IS_HELIX5(unit)) { 785 /* Add CPU port to port bitmap since M0 FW responds without it */ 786 _soc_hx5_optimized_cpu_port_to_pbmp_add(unit, &phy_hw_pbmp); 787 } else { 788 /* Add CPU port to port bitmap since M0 FW responds without it */ 789 _soc_iproc_optimized_cpu_port_to_pbmp_add(unit, &phy_hw_pbmp); 790 } 791 792 /* Convert physical to logical port numbering */ 793 _soc_iproc_p2l_pbmp_update(unit, phy_hw_pbmp, hw_link); 794 795 rv = SOC_E_NONE; 796 return rv; 797 } 798 799 /* 800 * Function: 801 * soc_cmicx_linkscan_config 802 * Purpose: 803 * Send LS_HW_CONFIG message to Cortex-M0 linkscan application. 804 * Parameters: 805 * unit number 806 * hw_mii_pbm - Port bit map of ports to scan with MIIM registers 807 * Returns: 808 * SOC_E_XXX 809 */ 810 int soc_cmicx_linkscan_config(int unit, soc_pbmp_t *hw_mii_pbm) 811 { 812 soc_iproc_mbox_msg_t *msg, *resp; 813 int rv; 814 soc_pbmp_t empty_pbmp; 815 ls_phy_pbmp_t phy_mii_pbm; 816 #if (defined (BCM_DNXF_SUPPORT) || defined (BCM_DNX_SUPPORT)) 817 ls_phy_pbmp_t updated_phy_pbm; 818 #endif 819 int idx = 0; 820 821 LOG_VERBOSE(BSL_LS_SOC_M0, (BSL_META_U(unit, "M0 Linkscan config\n"))); 822 823 if (SOC_IS_HELIX5(unit)) { 824 /* Check HX5 WAR enable then cache the result. */ 825 soc_hx5_war_is_enable(unit, -1); 826 } 827 828 if (!SOC_CONTROL(unit)->iproc_mbox_init_done) { 829 LOG_VERBOSE(BSL_LS_SOC_M0, (BSL_META_U(unit, "Mbox init not done\n"))); 830 return SOC_E_NONE; 831 } 832 833 SOC_PBMP_CLEAR(empty_pbmp); 834 if (SOC_PBMP_EQ(*hw_mii_pbm, empty_pbmp)) { 835 LOG_VERBOSE(BSL_LS_SOC_M0, (BSL_META_U(unit, "HW pbmp is empty..skip\n"))); 836 return SOC_E_NONE; 837 } 838 839 msg = soc_iproc_alloc(sizeof(soc_iproc_mbox_msg_t) + sizeof(ls_phy_pbmp_t)); 840 if (msg == NULL) { 841 LOG_ERROR(BSL_LS_SOC_M0, (BSL_META_U(unit, "HW Linkscan Mbox msg alloc failed\n"))); 842 return SOC_E_MEMORY; 843 } 844 845 resp = soc_iproc_alloc(sizeof(soc_iproc_mbox_msg_t) + sizeof(ls_phy_pbmp_t)); 846 if (resp == NULL) { 847 LOG_ERROR(BSL_LS_SOC_M0, (BSL_META_U(unit, "HW Linkscan Mbox resp alloc failed\n"))); 848 soc_iproc_free(msg); 849 return SOC_E_MEMORY; 850 } 851 852 msg->id = LS_HW_CONFIG; 853 msg->flags = IPROC_SYNC_MSG | IPROC_RESP_REQUIRED; 854 msg->size = sizeof(ls_phy_pbmp_t) / sizeof(uint32); 855 if (sizeof(ls_phy_pbmp_t) % sizeof(uint32)) { 856 msg->size++; 857 } 858 859 LS_PHY_PBMP_CLEAR(phy_mii_pbm); 860 861 /* Convert incoming logical pbmp to physical pbmp */ 862 _soc_iproc_l2p_pbmp_update(unit, *hw_mii_pbm, &phy_mii_pbm); 863 864 #if (defined (BCM_DNXF_SUPPORT) || defined (BCM_DNX_SUPPORT)) 865 /* DNX need to add CPU port at bit0. */ 866 if (SOC_IS_DNX(unit) || SOC_IS_DNXF(unit)) { 867 LS_PHY_PBMP_CLEAR(updated_phy_pbm); 868 _soc_iproc_add_cpu_port_to_pbmp(unit, phy_mii_pbm.pbits, &updated_phy_pbm); 869 for(idx = 0; idx < LS_PHY_PBMP_WORD_MAX; idx++) { 870 LS_PHY_PBMP_WORD_SET(phy_mii_pbm, idx, LS_PHY_PBMP_WORD_GET(updated_phy_pbm, idx)); 871 } 872 } 873 #endif 874 /* Copy message payload */ 875 for (idx = 0; idx < LS_PHY_PBMP_WORD_MAX; idx++) { 876 msg->data[idx] = LS_PHY_PBMP_WORD_GET(phy_mii_pbm, idx); 877 } 878 879 /* Send message to M0 */ 880 rv = soc_iproc_data_send_wait(SOC_CONTROL(unit)->ls_txmbox, msg, resp); 881 if (rv == IPROC_MSG_SUCCESS) { 882 if (IS_IPROC_RESP_READY(resp)) { 883 if (IS_IPROC_RESP_SUCCESS(resp)) { 884 rv = SOC_E_NONE; 885 /* Update linkscan thread with link status for configured port */ 886 887 soc_iproc_link_status_update(unit, resp, 0); 888 } else { 889 rv = resp->data[0]; 890 } 891 } 892 } 893 894 soc_iproc_free(msg); 895 soc_iproc_free(resp); 896 897 return rv; 898 } 899 #endif /*BCM_CMICX_SUPPORT*/ 900 #endif /*BCM_ESW_SUPPORT*/