mbox.c (28153B)
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 * Shared Memory Mailbox infrastruction - SHM mbox communications & debug 8 * logging 9 */ 10 11 #include <shared/bsl.h> 12 13 #include <bcm_int/common/mbox.h> 14 15 #include <soc/drv.h> 16 #include <soc/uc_msg.h> 17 #include <shared/bsl.h> 18 #include <sal/core/libc.h> 19 #include <sal/core/dpc.h> 20 21 #include <bcm/types.h> 22 #include <bcm/error.h> 23 24 #define MBOX_STATUS_LOCK_TIME (1000) 25 26 #define _BCM_MBOX_HEXDUMP_LINE_WIDTH_OCTETS (100) 27 28 #if defined(BCM_CMICM_SUPPORT) 29 #define _BCM_MBOX_LOCAL_DEBUGBUFSIZE (1024) 30 static _bcm_bs_internal_comm_info_t mbox_info; 31 32 static char local_debugbuf[_BCM_MBOX_LOCAL_DEBUGBUFSIZE]; 33 static int local_head = 0; 34 35 static char output_debugbuf[_BCM_MBOX_LOCAL_DEBUGBUFSIZE * 2]; 36 static int local_tail = 0; 37 #endif /* BCM_CMICM_SUPPORT */ 38 39 static uint32 _cmicm_debug_flags = 0; 40 /* Global variables */ 41 uint32 bs_firmware_version = BS_MIN_UC_VERSION; 42 43 #if defined(BCM_CMICM_SUPPORT) 44 STATIC void _bcm_mbox_rx_thread(void *arg); 45 46 STATIC void _bcm_mbox_debug_poll(void* owner, void* time_as_ptr, 47 void *unit_as_ptr, void *unused_2, 48 void* unused_3); 49 #endif /* BCM_CMICM_SUPPORT */ 50 51 int 52 _bcm_mbox_status_read(int unit, int idx, uint32 *status) 53 { 54 int rv = BCM_E_UNAVAIL; 55 #if defined(BCM_CMICM_SUPPORT) 56 rv = sal_mutex_take(mbox_info.unit_state[unit].status_access_lock, 57 MBOX_STATUS_LOCK_TIME); 58 if (rv != BCM_E_NONE) { 59 LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit, 60 "Failed to get mbox status lock"))); 61 return BCM_E_UNAVAIL; 62 } 63 soc_cm_sinval(unit, (void*)&mbox_info.unit_state[unit].mboxes->status[idx], 64 sizeof(mbox_info.unit_state[unit].mboxes->status[0])); 65 *status = soc_htonl(mbox_info.unit_state[unit].mboxes->status[idx]); 66 sal_mutex_give(mbox_info.unit_state[unit].status_access_lock); 67 #endif /* BCM_CMICM_SUPPORT */ 68 69 return rv; 70 } 71 72 int 73 _bcm_mbox_status_write(int unit, int idx, uint32 status) 74 { 75 int rv = BCM_E_UNAVAIL; 76 #if defined(BCM_CMICM_SUPPORT) 77 rv = sal_mutex_take(mbox_info.unit_state[unit].status_access_lock, 78 MBOX_STATUS_LOCK_TIME); 79 if (rv != BCM_E_NONE) { 80 LOG_ERROR(BSL_LS_BCM_COMMON, (BSL_META_U(unit, 81 "Failed to get mbox status lock"))); 82 return BCM_E_UNAVAIL; 83 } 84 mbox_info.unit_state[unit].mboxes->status[idx] = soc_htonl(status); 85 soc_cm_sflush(unit, (void*)&mbox_info.unit_state[unit].mboxes->status[idx], 86 sizeof(mbox_info.unit_state[unit].mboxes->status[0])); 87 sal_mutex_give(mbox_info.unit_state[unit].status_access_lock); 88 #endif /* BCM_CMICM_SUPPORT */ 89 90 return rv; 91 } 92 /* ************************************ Transport *****************************/ 93 94 /* 95 * Function: 96 * _bcm_mbox_bs_wb_prep 97 * Purpose: 98 * Send the WarmBoot message to Host. 99 * Parameters: 100 * Unit- Unit to send the warmboot message 101 * Returns: 102 * BCM_E_XXX 103 * Notes: 104 */ 105 int 106 _bcm_mbox_bs_wb_prep(int unit) 107 { 108 #if defined(BCM_CMICM_SUPPORT) 109 int timeout_usec = 1900000; 110 int c; 111 int rv = BCM_E_NONE; 112 mos_msg_data_t wb_msg; 113 114 /* If the mbox_comm_init is not done then no need to intimate about warmboot 115 * to BS-FW 116 */ 117 if (!mbox_info.unit_state) { 118 LOG_VERBOSE(BSL_LS_BCM_COMMON, (BSL_META_U(unit, 119 "MBOX not initialised \n"))); 120 return BCM_E_NONE; 121 } 122 123 wb_msg.s.mclass = MOS_MSG_CLASS_BS; 124 wb_msg.s.subclass = MOS_MSG_SUBCLASS_MBOX_WB_PREP; 125 126 c = mbox_info.unit_state[unit].core_num; 127 128 if (BCM_FAILURE(rv = soc_cmic_uc_msg_send(unit, c, 129 &wb_msg, timeout_usec))) { 130 LOG_ERROR(BSL_LS_BCM_COMMON, 131 (BSL_META_U(unit, 132 "soc_cmic_uc_msg_send failed for warmboot message\n"))); 133 rv = BCM_E_UNAVAIL; 134 } 135 136 /* Response/handshaking from Broadsync-FW */ 137 if (BCM_E_NONE == rv) { 138 139 /* Read the response from the FW */ 140 mos_msg_data_t rcv; 141 142 rv = soc_cmic_uc_msg_receive(unit, c, MOS_MSG_CLASS_BS, 143 &rcv, timeout_usec); 144 if (SOC_E_NONE != rv) { 145 LOG_ERROR(BSL_LS_BCM_COMMON, 146 (BSL_META_U(unit, 147 "soc_cmic_uc_msg_receive failed for warmboot ack\n"))); 148 rv = BCM_E_UNAVAIL; 149 } 150 151 /* The length value is just for proper handshaking!! */ 152 if (0xF0F0 != rcv.s.len) { 153 LOG_ERROR(BSL_LS_BCM_COMMON, 154 (BSL_META_U(unit, 155 "_bcm_mbox_bs_wb_prep: wrong length from FW\n"))); 156 rv = BCM_E_UNAVAIL; 157 } 158 else { 159 LOG_VERBOSE(BSL_LS_BCM_COMMON, 160 (BSL_META_U(unit, "_bcm_mbox_bs_wb_prep: FW done with WB prep\n"))); 161 } 162 } 163 164 return rv; 165 #else /* BCM_CMICM_SUPPORT */ 166 return BCM_E_UNAVAIL; 167 #endif /* BCM_CMICM_SUPPORT */ 168 } 169 170 /* 171 * Function: 172 * _bcm_mbox_bs_cosq_port_set 173 * Purpose: 174 * Send the cosq port (to be used in PTCH) to firmware. 175 * Parameters: 176 * Unit- Unit to send the warmboot message 177 * Returns: 178 * BCM_E_XXX 179 * Notes: 180 */ 181 int _bcm_mbox_bs_cosq_port_set(int unit) 182 { 183 #if defined(BCM_CMICM_SUPPORT) 184 int timeout_usec = 1900000; 185 int c; 186 int rv = BCM_E_NONE; 187 int cosq_port=0; 188 mos_msg_data_t msg; 189 190 if (!mbox_info.unit_state) { 191 LOG_VERBOSE(BSL_LS_BCM_COMMON, (BSL_META_U(unit, 192 "MBOX not initialised \n"))); 193 return BCM_E_NONE; 194 } 195 196 /* Read the config property custom_feature_ptp_cosq_port */ 197 cosq_port = soc_property_suffix_num_get(unit, -1, spn_CUSTOM_FEATURE, "ptp_cosq_port", 0); 198 199 if (!cosq_port) { 200 LOG_ERROR(BSL_LS_BCM_COMMON, 201 (BSL_META_U(unit, 202 "Error: bs get cosq port failed.\n"))); 203 return BCM_E_RESOURCE; 204 } 205 206 msg.s.mclass = MOS_MSG_CLASS_BS; 207 msg.s.subclass = MOS_MSG_SUBCLASS_PTP_COSQ_PORT; 208 msg.s.len = 0; 209 msg.s.data = bcm_htonl(cosq_port); 210 211 c = mbox_info.unit_state[unit].core_num; 212 213 if (BCM_FAILURE(rv = soc_cmic_uc_msg_send(unit, c, &msg, timeout_usec))) { 214 LOG_ERROR(BSL_LS_BCM_COMMON, 215 (BSL_META_U(unit, 216 "soc_cmic_uc_msg_send failed for cosq port set\n"))); 217 rv = BCM_E_UNAVAIL; 218 } 219 220 return rv; 221 #else /* BCM_CMICM_SUPPORT */ 222 return BCM_E_UNAVAIL; 223 #endif /* BCM_CMICM_SUPPORT */ 224 225 } 226 227 #if defined(BCM_CMICM_SUPPORT) 228 /* Callback from MCS messaging layer: called before and after uC shutdown */ 229 int _bcm_bs_deinit_callback(int unit, 230 int uC, 231 soc_cmic_uc_shutdown_stage_t stage, 232 void *user_data) 233 { 234 if (stage == SOC_CMIC_UC_SHUTDOWN_NOHALT) { 235 _bcm_mbox_bs_wb_prep(unit); 236 } 237 238 return BCM_E_NONE; 239 } 240 #endif /* BCM_CMICM_SUPPORT */ 241 242 int 243 _bcm_mbox_comm_init(int unit, int appl_type) 244 { 245 #if defined(BCM_CMICM_SUPPORT) 246 int rv = BCM_E_NONE; 247 int timeout_usec = 1900000; 248 int max_num_cores = 2; 249 int result; 250 int c; 251 int i; 252 sal_thread_t thread_id; 253 254 /* Init the system if this is the first time in */ 255 if (mbox_info.unit_state == NULL) { 256 mbox_info.unit_state = soc_cm_salloc(unit, 257 sizeof(_bcm_bs_internal_stack_state_t) * 258 BCM_MAX_NUM_UNITS, 259 "mbox_info_unit_state"); 260 if (!mbox_info.unit_state) { 261 LOG_ERROR(BSL_LS_BCM_COMMON, 262 (BSL_META_U(unit, 263 "MBOX unit_state no memory\n"))); 264 return BCM_E_MEMORY; 265 } 266 267 mbox_info.comm_available = sal_sem_create("BCM BS comms", 268 sal_sem_BINARY, 0); 269 if (mbox_info.comm_available == NULL) { 270 soc_cm_sfree(unit, mbox_info.unit_state); 271 mbox_info.unit_state = NULL; 272 LOG_ERROR(BSL_LS_BCM_COMMON, 273 (BSL_META_U(unit, "BCM BS comms semaphore create failed\n"))); 274 return BCM_E_MEMORY; 275 } 276 sal_memset(mbox_info.unit_state, 0, 277 sizeof(_bcm_bs_internal_stack_state_t) * BCM_MAX_NUM_UNITS); 278 rv = sal_sem_give(mbox_info.comm_available); 279 if (BCM_FAILURE(rv)) { 280 LOG_VERBOSE(BSL_LS_BCM_COMMON, 281 (BSL_META_U(unit, "sal_sem_give failed\n"))); 282 return BCM_E_INTERNAL; 283 } 284 } 285 286 /* Init the unit if this is the first time for the unit */ 287 if (mbox_info.unit_state[unit].mboxes == NULL) { 288 /* allocate space for mboxes */ 289 mbox_info.unit_state[unit].mboxes = 290 soc_cm_salloc(unit, sizeof(_bcm_bs_internal_stack_mboxes_t), "bs msg"); 291 292 if (!mbox_info.unit_state[unit].mboxes) { 293 LOG_ERROR(BSL_LS_BCM_COMMON, 294 (BSL_META_U(unit, 295 "MBOX mboxes no memory\n"))); 296 return BCM_E_MEMORY; 297 } 298 299 /* clear state of message mboxes */ 300 mbox_info.unit_state[unit].mboxes->num_buffers = 301 soc_ntohl(_BCM_MBOX_MAX_BUFFERS); 302 for (i = 0; i < _BCM_MBOX_MAX_BUFFERS; ++i) { 303 mbox_info.unit_state[unit].mboxes->status[i] = 304 soc_htonl(_BCM_MBOX_MS_EMPTY); 305 } 306 soc_cm_sflush(unit, (void*)&mbox_info.unit_state[unit].mboxes->status, 307 _BCM_MBOX_MAX_BUFFERS * 308 sizeof(mbox_info.unit_state[unit].mboxes->status[0])); 309 310 311 312 /* allocate space for debug log */ 313 /* size is the size of the structure without the placeholder space for 314 * debug->buf, plus the real space for it 315 */ 316 mbox_info.unit_state[unit].log = 317 soc_cm_salloc(unit, 318 sizeof(_bcm_bs_internal_stack_log_t) 319 - sizeof(mbox_info.unit_state[unit].log->buf) 320 + _BCM_MBOX_MAX_LOG, "bs log"); 321 if (!mbox_info.unit_state[unit].log) { 322 soc_cm_sfree(unit, mbox_info.unit_state[unit].mboxes); 323 mbox_info.unit_state[unit].mboxes = NULL; 324 LOG_ERROR(BSL_LS_BCM_COMMON, 325 (BSL_META_U(unit, "MBOX log no memory\n"))); 326 return BCM_E_MEMORY; 327 } 328 329 mbox_info.unit_state[unit].status_access_lock = 330 sal_mutex_create("CMICM_status"); 331 if (mbox_info.unit_state[unit].status_access_lock == NULL) { 332 soc_cm_sfree(unit, mbox_info.unit_state[unit].mboxes); 333 mbox_info.unit_state[unit].mboxes = NULL; 334 soc_cm_sfree(unit, mbox_info.unit_state[unit].log); 335 LOG_ERROR(BSL_LS_BCM_COMMON, 336 (BSL_META_U(unit, "CMICM_status mutex create failed\n"))); 337 return BCM_E_MEMORY; 338 } 339 340 mbox_info.unit_state[unit].response_ready = 341 sal_sem_create("CMICM_resp", sal_sem_BINARY, 0); 342 if (mbox_info.unit_state[unit].response_ready == NULL) { 343 soc_cm_sfree(unit, mbox_info.unit_state[unit].mboxes); 344 mbox_info.unit_state[unit].mboxes = NULL; 345 soc_cm_sfree(unit, mbox_info.unit_state[unit].log); 346 sal_mutex_destroy(mbox_info.unit_state[unit].status_access_lock); 347 LOG_ERROR(BSL_LS_BCM_COMMON, 348 (BSL_META_U(unit, "CMICM_resp semaphore create failed\n"))); 349 return BCM_E_MEMORY; 350 } 351 thread_id = sal_thread_create("CMICM Rx", SAL_THREAD_STKSZ, 352 soc_property_get(unit, spn_UC_MSG_THREAD_PRI, 50) + 1, 353 _bcm_mbox_rx_thread, INT_TO_PTR(unit)); 354 if (thread_id == SAL_THREAD_ERROR) { 355 soc_cm_sfree(unit, mbox_info.unit_state[unit].mboxes); 356 mbox_info.unit_state[unit].mboxes = NULL; 357 soc_cm_sfree(unit, mbox_info.unit_state[unit].log); 358 sal_mutex_destroy(mbox_info.unit_state[unit].status_access_lock); 359 sal_sem_destroy(mbox_info.unit_state[unit].response_ready); 360 LOG_ERROR(BSL_LS_BCM_COMMON, 361 (BSL_META_U(unit, "CMICM Rx thread create failed\n"))); 362 return BCM_E_INTERNAL; 363 } 364 365 /* initialize debug */ 366 mbox_info.unit_state[unit].log->size = soc_htonl(_BCM_MBOX_MAX_LOG); 367 mbox_info.unit_state[unit].log->head = 0; 368 mbox_info.unit_state[unit].log->tail = 0; 369 370 /* set up the network-byte-order pointers so that CMICm can access 371 * the shared memory 372 */ 373 mbox_info.unit_state[unit].mbox_ptr = 374 soc_htonl(soc_cm_l2p(unit, (void*)mbox_info.unit_state[unit].mboxes)); 375 mbox_info.unit_state[unit].log_ptr = 376 soc_htonl(soc_cm_l2p(unit, (void*)mbox_info.unit_state[unit].log)); 377 378 _bcm_mbox_debug_poll(INT_TO_PTR(&_bcm_mbox_debug_poll), 379 INT_TO_PTR(soc_property_get(unit, spn_BS_POLL_INTERVAL, 1000)), 380 INT_TO_PTR(unit), 0, 0); 381 } 382 383 /* Allow BS application on uC to get initialized on every call */ 384 rv = BCM_E_UNAVAIL; 385 for (c = max_num_cores - 1; c >= 0; c--) { 386 /* LOG_CLI((BSL_META_U(unit, 387 "Trying BS on core %d\n"), c)); */ 388 result = soc_cmic_uc_appl_init(unit, c, 389 MOS_MSG_CLASS_BS, timeout_usec, 390 BS_SDK_VERSION, 391 BS_MIN_UC_VERSION, 392 _bcm_bs_deinit_callback, NULL); 393 394 if (SOC_E_NONE == result){ 395 /* uKernel communcations started successfully, so run the init */ 396 /* Note: the length of this message is unused, and can be 397 * overloaded */ 398 mos_msg_data_t start_msg; 399 start_msg.s.mclass = MOS_MSG_CLASS_BS; 400 start_msg.s.subclass = MOS_MSG_SUBCLASS_MBOX_CONFIG; 401 _shr_uint16_write((uint8*)(&(start_msg.s.len)), (uint16) appl_type); 402 403 start_msg.s.data = bcm_htonl(soc_cm_l2p(unit, 404 (void*)&mbox_info.unit_state[unit])); 405 406 if (BCM_FAILURE(rv = soc_cmic_uc_msg_send(unit, c, 407 &start_msg, 408 timeout_usec))) { 409 LOG_ERROR(BSL_LS_BCM_COMMON, 410 (BSL_META_U(unit, "soc_cmic_uc_msg_send failed\n"))); 411 } 412 413 mbox_info.unit_state[unit].core_num = c; 414 415 /* Configure custom_feature_ptp_cosq_port required for DNX platforms */ 416 if (SOC_IS_JERICHO(unit)) { 417 _bcm_mbox_bs_cosq_port_set(unit); 418 } 419 break; 420 } 421 422 /* LOG_CLI((BSL_META_U(unit, 423 "No response on core %d\n"), c)); */ 424 } 425 426 if (BCM_FAILURE(rv)) { 427 LOG_ERROR(BSL_LS_BCM_COMMON, 428 (BSL_META_U(unit, "No response from CMICm core(s)\n"))); 429 return rv; 430 } 431 432 return rv; 433 434 #else /* BCM_CMICM_SUPPORT */ 435 return BCM_E_UNAVAIL; 436 #endif /* BCM_CMICM_SUPPORT */ 437 } 438 439 440 int 441 _bcm_mbox_tx( 442 int unit, 443 uint32 node_num, 444 _bcm_mbox_transport_type_t transport, 445 uint8 *message, 446 int message_len) 447 { 448 #if defined(BCM_CMICM_SUPPORT) 449 int rv = BCM_E_NONE; 450 451 mos_msg_data_t uc_msg; 452 453 int wait_iter = 0; 454 uint32 status = _BCM_MBOX_MS_ERR; 455 uint32 status_out = _BCM_MBOX_MS_EMPTY; 456 457 /* LOG_CLI((BSL_META_U(unit, 458 "cmic_tx Len:%d\n"), message_len)); */ 459 460 if (_bcm_mbox_status_read(unit, 0, &status) != BCM_E_NONE || 461 status != _BCM_MBOX_MS_EMPTY) { 462 LOG_VERBOSE(BSL_LS_BCM_COMMON, 463 (BSL_META_U(unit, 464 "Contention\n"))); 465 } 466 467 /* wait for to-TOP buffer to be free, if it is not already */ 468 while ((_bcm_mbox_status_read(unit, 0, &status) != BCM_E_NONE || 469 status != _BCM_MBOX_MS_EMPTY) && wait_iter < 100000) { 470 ++wait_iter; 471 sal_usleep(1); 472 } 473 474 if (status != _BCM_MBOX_MS_EMPTY) { 475 LOG_ERROR(BSL_LS_BCM_COMMON, 476 (BSL_META_U(unit, 477 "TOP message buffer in use on Tx, re-pinging\n"))); 478 rv = soc_cmic_uc_msg_send(unit, mbox_info.unit_state[unit].core_num, 479 &uc_msg, 1000000); 480 return BCM_E_FAIL; 481 } 482 483 /* load the mailbox */ 484 sal_memcpy((uint8 *)mbox_info.unit_state[unit].mboxes->mbox[0].data, 485 message, message_len); 486 mbox_info.unit_state[unit].mboxes->mbox[0].data_len = 487 soc_htonl(message_len); 488 mbox_info.unit_state[unit].mboxes->mbox[0].node_num = node_num; 489 490 /* finish mbox load by setting status */ 491 switch (transport) { 492 case _BCM_MBOX_MESSAGE: 493 status_out = _BCM_MBOX_MS_CMD; 494 break; 495 case _BCM_MBOX_TUNNEL_TO: 496 status_out = _BCM_MBOX_MS_TUNNEL_TO; 497 break; 498 case _BCM_MBOX_TUNNEL_OUT: 499 status_out = _BCM_MBOX_MS_TUNNEL_OUT; 500 break; 501 default: 502 LOG_VERBOSE(BSL_LS_BCM_COMMON, 503 (BSL_META_U(unit, 504 "mbox_tx failed: Unknown transport type\n"))); 505 } 506 507 soc_cm_sflush(unit, (void*)&mbox_info.unit_state[unit].mboxes->mbox[0], 508 sizeof(mbox_info.unit_state[unit].mboxes->mbox[0])); 509 _bcm_mbox_status_write(unit, 0, status_out); 510 511 /* Send a notification to the CMICm */ 512 sal_memset(&uc_msg, 0, sizeof(uc_msg)); 513 uc_msg.s.mclass = MOS_MSG_CLASS_BS; 514 uc_msg.s.subclass = MOS_MSG_SUBCLASS_MBOX_CMDRESP; 515 uc_msg.s.len = message_len; 516 uc_msg.s.data = 0; 517 518 rv = soc_cmic_uc_msg_send(unit, mbox_info.unit_state[unit].core_num, 519 &uc_msg, 1000000); 520 return rv; 521 522 #else /* BCM_CMICM_SUPPORT */ 523 return BCM_E_UNAVAIL; 524 #endif /* BCM_CMICM_SUPPORT */ 525 } 526 527 528 int 529 _bcm_mbox_tx_completion( 530 int unit, 531 uint32 node_num) 532 { 533 #if defined(BCM_CMICM_SUPPORT) 534 int iter; 535 uint32 status = _BCM_MBOX_MS_ERR; 536 537 for (iter = 0; iter < 10000; ++iter) { 538 if (_bcm_mbox_status_read(unit, 0, &status) == BCM_E_NONE && 539 status == _BCM_MBOX_MS_EMPTY) { 540 /* sal_strcpy(holding_thread_name, "none"); */ 541 return BCM_E_NONE; 542 } 543 sal_usleep(1); 544 } 545 546 LOG_VERBOSE(BSL_LS_BCM_COMMON, 547 (BSL_META_U(unit, 548 "Failed async Tx to ToP. No clear\n"))); 549 return BCM_E_TIMEOUT; 550 #else /* BCM_CMICM_SUPPORT */ 551 return BCM_E_UNAVAIL; 552 #endif /* BCM_CMICM_SUPPORT */ 553 } 554 555 556 int 557 _bcm_mbox_rx_response_free(int unit, uint8 *resp_data) 558 { 559 #if defined(BCM_CMICM_SUPPORT) 560 unsigned i; 561 562 for (i = 0; i < _BCM_MBOX_MAX_BUFFERS; ++i) { 563 if (mbox_info.unit_state[unit].mboxes->mbox[i].data == resp_data) { 564 _bcm_mbox_status_write(unit, i, _BCM_MBOX_MS_EMPTY); 565 566 return BCM_E_NONE; 567 } 568 } 569 570 LOG_CLI((BSL_META_U(unit, 571 "Invalid CMICM rx response free (%p)\n"), (void *)resp_data)); 572 573 return BCM_E_NOT_FOUND; 574 #else /* BCM_CMICM_SUPPORT */ 575 return BCM_E_UNAVAIL; 576 #endif /* BCM_CMICM_SUPPORT */ 577 } 578 579 /* 580 * Function: 581 * _bcm_ptp_rx_response_get 582 * Purpose: 583 * Get Rx response data for a PTP clock. 584 * Parameters: 585 * unit - (IN) Unit number. 586 * ptp_id - (IN) PTP stack ID. 587 * clock_num - (IN) PTP clock number. 588 * usec - (IN) Semaphore timeout (usec). 589 * data - (OUT) Response data. 590 * data_len - (OUT) Response data size (octets). 591 * Returns: 592 * BCM_E_XXX 593 * Notes: 594 */ 595 int 596 _bcm_mbox_rx_response_get( 597 int unit, 598 int node_num, 599 int usec, 600 uint8 **data, 601 int *data_len) 602 { 603 #if defined(BCM_CMICM_SUPPORT) 604 int rv = BCM_E_UNAVAIL; 605 int spl; 606 sal_usecs_t expiration_time = sal_time_usecs() + usec; 607 608 /* LOG_CLI((BSL_META_U(unit, 609 "cmic_rx_get\n"))); */ 610 611 rv = BCM_E_FAIL; 612 /* ptp_printf("Await resp @ %d\n", (int)sal_time_usecs()); */ 613 614 while (BCM_FAILURE(rv) && (int32) (sal_time_usecs() - expiration_time) < 0) { 615 rv = sal_sem_take(mbox_info.unit_state[unit].response_ready, usec); 616 } 617 618 if (BCM_FAILURE(rv)) { 619 LOG_VERBOSE(BSL_LS_BCM_COMMON, 620 (BSL_META_U(unit, "sal_sem_take failed\n"))); 621 return rv; 622 } 623 624 /* Lock. */ 625 spl = sal_splhi(); 626 627 *data = mbox_info.unit_state[unit].response_data; 628 *data_len = mbox_info.unit_state[unit].response_len; 629 630 mbox_info.unit_state[unit].response_data = 0; 631 632 /* Unlock. */ 633 sal_spl(spl); 634 635 return rv; 636 637 #else /* BCM_CMICM_SUPPORT */ 638 return BCM_E_UNAVAIL; 639 #endif /* BCM_CMICM_SUPPORT */ 640 } 641 642 643 #if defined(BCM_CMICM_SUPPORT) 644 645 STATIC 646 void 647 _bcm_mbox_rx_thread(void *arg) 648 { 649 int rv = 0; 650 651 int unit = PTR_TO_INT(arg); 652 653 while (1) { 654 int mbox; 655 656 657 /* The uc_msg is just a signal that there is a message somewhere to get, 658 * so look through all mboxes 659 */ 660 /* 661 Note: on some SAL implementations, a short usleep is done by doing a 662 'yield' within a loop, rather than a true 'sleep'. If no other tasks are 663 using the CPU, this will effectively be a busy-wait, as the yield will 664 immediately return. This can make it appear that the PTP Rx thread is 665 using a lot of CPU, though this is only because no other task is in a 666 running state. To avoid this appearance of CPU load, the value can be 667 increased to larger than 20000us=20ms. 668 */ 669 sal_usleep(20000); 670 671 for (mbox = 0; mbox < _BCM_MBOX_MAX_BUFFERS; ++mbox) { 672 uint32 status; 673 674 if (_bcm_mbox_status_read(unit, mbox, &status) != BCM_E_NONE) { 675 continue; 676 } 677 678 switch (status) { 679 case _BCM_MBOX_MS_TUNNEL_IN: 680 break; 681 682 case _BCM_MBOX_MS_EVENT: 683 break; 684 685 case _BCM_MBOX_MS_RESP: 686 { 687 soc_cm_sinval(unit, 688 (void*)&mbox_info.unit_state[unit].mboxes->mbox[mbox], 689 sizeof(mbox_info.unit_state[unit].mboxes->mbox[mbox])); 690 mbox_info.unit_state[unit].response_data = 691 (uint8*)mbox_info.unit_state[unit].mboxes->mbox[mbox].data; 692 mbox_info.unit_state[unit].response_len = soc_ntohl( 693 mbox_info.unit_state[unit].mboxes->mbox[mbox].data_len); 694 695 rv = sal_sem_give(mbox_info.unit_state[unit].response_ready); 696 if (BCM_FAILURE(rv)) { 697 LOG_VERBOSE(BSL_LS_BCM_COMMON, 698 (BSL_META_U(unit, "sal_sem_give failed\n"))); 699 } 700 } 701 break; 702 } 703 } 704 } 705 } 706 707 #endif /* BCM_CMICM_SUPPORT */ 708 709 710 int 711 _bcm_mbox_txrx( 712 int unit, 713 uint32 node_num, 714 _bcm_mbox_transport_type_t transport, 715 uint8 *out_data, 716 int out_len, 717 uint8 *in_data, 718 int *in_len) 719 { 720 #if defined(BCM_CMICM_SUPPORT) 721 int rv; 722 uint8 *response_data; 723 int response_len; 724 725 /* LOG_CLI((BSL_META_U(unit, 726 "cmic_txrx tx Len:%d\n"), out_len)); */ 727 728 int max_response_len = (in_len) ? *in_len : 0; 729 if (in_len) { 730 *in_len = 0; 731 } 732 733 rv = sal_sem_take(mbox_info.comm_available, _BCM_MBOX_RESPONSE_TIMEOUT_US); 734 if (BCM_FAILURE(rv)) { 735 LOG_VERBOSE(BSL_LS_BCM_COMMON, 736 (BSL_META_U(unit, 737 "mbox_txrx failed: sal_sem_take\n"))); 738 return rv; 739 } 740 741 rv = _bcm_mbox_tx(unit, node_num, _BCM_MBOX_MESSAGE, out_data, out_len); 742 743 if (rv != BCM_E_NONE) { 744 LOG_VERBOSE(BSL_LS_BCM_COMMON, 745 (BSL_META_U(unit, 746 "mbox_txrx failed: Tx error\n"))); 747 goto release_mgmt_lock; 748 } 749 750 /* 751 * Get rx buffer, either from rx callback or from cmicm wait task 752 * NOTICE: This call will return an rx response buffer that we will need to 753 * release by notifying the Rx section 754 */ 755 rv = _bcm_mbox_rx_response_get(unit, node_num, _BCM_MBOX_RESPONSE_TIMEOUT_US, 756 &response_data, &response_len); 757 if (BCM_FAILURE(rv)) { 758 LOG_VERBOSE(BSL_LS_BCM_COMMON, 759 (BSL_META_U(unit, 760 "mbox_txrx failed: No response\n"))); 761 goto release_mgmt_lock; 762 } 763 764 765 if (in_data && in_len) { 766 if (response_len > max_response_len) { 767 response_len = max_response_len; 768 } 769 770 *in_len = response_len; 771 sal_memcpy(in_data, response_data, response_len); 772 } 773 774 /* LOG_CLI((BSL_META_U(unit, 775 "cmic_txrx rx Len:%d\n"), *in_len)); */ 776 777 rv = BCM_E_NONE; 778 779 /* dispose_of_resp: */ 780 _bcm_mbox_rx_response_free(unit, response_data); 781 782 release_mgmt_lock: 783 rv = sal_sem_give(mbox_info.comm_available); 784 if (BCM_FAILURE(rv)) { 785 LOG_VERBOSE(BSL_LS_BCM_COMMON, 786 (BSL_META_U(unit, 787 "mbox_txrx failed: sal_sem_give\n"))); 788 } 789 790 return rv; 791 792 #else /* BCM_CMICM_SUPPORT */ 793 return BCM_E_UNAVAIL; 794 #endif /* BCM_CMICM_SUPPORT */ 795 } 796 797 #if defined(BCM_CMICM_SUPPORT) 798 /* Dump anything new in the debug buffers. 799 * owner: The owner if this is being called as a DPC. 800 * time_as_ptr: Recurrence time if a follow-up DPC to this func should 801 * be scheduled. 802 * unit_as_ptr: unit 803 */ 804 STATIC void 805 _bcm_mbox_debug_poll(void* owner, void* time_as_ptr, void *unit_as_ptr, 806 void *unused_2, void* unused_3) 807 { 808 int callback_time = (int)(size_t)time_as_ptr; 809 int out_idx = 0; 810 811 /* output the local debug first */ 812 while (local_tail != local_head) { 813 char c = local_debugbuf[local_tail++]; 814 815 if (c) { 816 output_debugbuf[out_idx++] = c; 817 } 818 819 if (local_tail == _BCM_MBOX_LOCAL_DEBUGBUFSIZE) { 820 local_tail = 0; 821 } 822 } 823 824 /* CMICM shared-mem output */ 825 { 826 int unit = (int)(size_t)unit_as_ptr; 827 uint32 head, size; 828 if ((SOC_CONTROL(unit) != NULL ) && 829 (soc_feature(unit, soc_feature_cmicm) || 830 soc_feature(unit, soc_feature_iproc))) { 831 /* head is written in externally, so will be in network byte order 832 * tail is local, so we'll keep it in local endianness 833 * size is read externally, so is also network byte order 834 */ 835 head = soc_htonl(mbox_info.unit_state[unit].log->head); 836 size = soc_htonl(mbox_info.unit_state[unit].log->size); 837 838 while (mbox_info.unit_state[unit].log->tail != head) { 839 char c = 840 mbox_info.unit_state[unit].log->buf[mbox_info.unit_state[unit].log->tail++]; 841 if (c) { 842 output_debugbuf[out_idx++] = c; 843 } 844 if (mbox_info.unit_state[unit].log->tail == size) { 845 mbox_info.unit_state[unit].log->tail = 0; 846 } 847 } 848 } 849 } 850 851 852 if (out_idx) { 853 output_debugbuf[out_idx] = 0; 854 if (_cmicm_debug_flags) { 855 LOG_CLI((BSL_META("%s"), output_debugbuf)); 856 } 857 } 858 859 if (callback_time) { 860 sal_dpc_time(callback_time, &_bcm_mbox_debug_poll, 861 0, time_as_ptr, unit_as_ptr, 0, 0); 862 } 863 } 864 865 #endif /* BCM_CMICM_SUPPORT */ 866 int 867 _bcm_mbox_debug_flag_set(uint32 flags) 868 { 869 _cmicm_debug_flags = flags; 870 871 return BCM_E_NONE; 872 } 873 874 875 int 876 _bcm_mbox_debug_flag_get(uint32 *flags) 877 { 878 *flags = _cmicm_debug_flags; 879 880 return BCM_E_NONE; 881 }