uc_msg.c (77591B)
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 8 #include <shared/bsl.h> 9 10 #include <sal/types.h> 11 #include <sal/core/boot.h> 12 #include <sal/core/libc.h> 13 #include <shared/alloc.h> 14 15 #include <soc/drv.h> 16 #include <soc/dcb.h> 17 #include <soc/dcbformats.h> /* only for 5670 crc erratum warning */ 18 #include <soc/pbsmh.h> 19 #include <soc/higig.h> 20 #include <soc/debug.h> 21 #include <soc/cm.h> 22 #include <soc/error.h> 23 #include <soc/property.h> 24 25 #ifdef BCM_CMICX_SUPPORT 26 #include <soc/intr_cmicx.h> 27 #include <soc/mcm/memregs.h> 28 #endif 29 30 #if defined(BCM_CMICM_SUPPORT) || defined(BCM_IPROC_SUPPORT) 31 #include <soc/cmicm.h> 32 #include <soc/shared/mos_intr_common.h> 33 #include <soc/uc_msg.h> 34 #include <soc/uc.h> 35 #include <soc/uc_dbg.h> 36 #include <bcm_int/common/PTP_feature.h> 37 #include <bcm_int/common/Bs_feature.h> 38 #include <bcm_int/common/PTP_feature.h> 39 #if defined(INCLUDE_MPLS_LM_DM) 40 extern uint32 mpls_lm_dm_firmware_version; 41 #endif 42 43 #if defined(INCLUDE_FLOWTRACKER) 44 extern uint32 ft_msg_version; 45 #endif /* INCLUDE_FLOWTRACKER */ 46 47 #if defined(INCLUDE_IFA) 48 extern uint32 ifa_firmware_version; 49 #endif /* INCLUDE_IFA*/ 50 51 #if defined(INCLUDE_TELEMETRY) 52 extern uint32 st_firmware_version; 53 #endif /* INCLUDE_TELEMETRY*/ 54 55 #if defined(INCLUDE_INT) 56 extern uint32 int_firmware_version; 57 #endif /* INCLUDE_INT*/ 58 59 #if defined(INCLUDE_SUM) 60 extern uint32 sum_firmware_version; 61 #endif /* INCLUDE_SUM */ 62 63 #if defined(INCLUDE_UC_ULINK) 64 #include <soc/shared/ulink_pack.h> 65 66 uint8 soc_cmic_ulink_uc_active[CMICM_NUM_UCS]; 67 68 #define UC_ULINK_IS_ACTIVE(uc) \ 69 (soc_cmic_ulink_uc_active[uc]) 70 71 #define UC_ULINK_SET_ACTIVE(uc) \ 72 if((uc) < CMICM_NUM_UCS) { soc_cmic_ulink_uc_active[uc]++; } 73 74 #define UC_ULINK_SET_DEACTIVE(uc) \ 75 if((uc) < CMICM_NUM_UCS) { \ 76 if(soc_cmic_ulink_uc_active[uc] > 0) \ 77 soc_cmic_ulink_uc_active[uc]--; \ 78 }; 79 #endif 80 /* Macro to do 32-bit address calculations for CMICm-based addresses. 81 These are NOT local addresses and can only be accessed over the 82 PCIe or via CMICm-based DMA operations */ 83 84 #define CMICM_ADDR(base, field) \ 85 ((uint32) ((base) + SAL_OFFSETOF(mos_msg_area_t, field))) 86 87 #define CMICM_DATA_WORD0_BASE(base) \ 88 ((uint32) ((base) + SAL_OFFSETOF(mos_msg_area_t,data[0].words[0]))) 89 #define CMICM_DATA_WORD1_BASE(base) \ 90 ((uint32) ((base) + SAL_OFFSETOF(mos_msg_area_t,data[0].words[1]))) 91 #define MOS_MSG_DATA_SIZE sizeof(mos_msg_data_t) 92 93 #define MOS_MSG_TEST_DMA_SIZE (32) 94 95 /* Macros for passing unit + uC numbers to the threads */ 96 #define ENCODE_UNIT_UC(unit, uC) INT_TO_PTR((unit) << 16 | (uC)) 97 #define DECODE_UNIT(val) ((int)(PTR_TO_INT(val) >> 16)) 98 #define DECODE_UC(val) ((int)(PTR_TO_INT(val) & 0xffff)) 99 100 static int soc_cmic_uc_msg_receive_internal(int unit, int uC, uint8 mclass, 101 mos_msg_data_t *msg, int timeout, int is_system); 102 103 /* Internal routine to determine the base address of the msg area */ 104 /* 105 * Function: 106 * _soc_cmic_uc_msg_base 107 * Purpose: 108 * Determine the base address of the msg area 109 * Parameters: 110 * unit - unit number 111 * Returns: 112 * address of the msg area, or NULL 113 */ 114 static uint32 _soc_cmic_uc_msg_base(int unit) 115 { 116 #ifdef BCM_METROLITE_SUPPORT 117 if (SOC_IS_METROLITE(unit)) { 118 return 0x1b07f000; 119 } 120 #endif 121 122 #ifdef BCM_SABER2_SUPPORT 123 if (SOC_IS_SABER2(unit)) { 124 return 0x0207f000; 125 } 126 #endif 127 128 #if defined(BCM_HELIX4_SUPPORT) || defined(BCM_KATANA2_SUPPORT) 129 if (SOC_IS_HELIX4(unit) || SOC_IS_KATANA2(unit)) { 130 return 0x1b07f008; 131 } 132 #endif 133 134 #ifdef BCM_HURRICANE2_SUPPORT 135 if (SOC_IS_HURRICANE2(unit)) { 136 return 0x000f0000; 137 } 138 #endif 139 140 #ifdef BCM_HURRICANE3_SUPPORT 141 if (SOC_IS_HURRICANE3(unit)) { 142 return 0x000f0000; 143 } 144 #endif 145 146 #ifdef BCM_GREYHOUND_SUPPORT 147 if (SOC_IS_GREYHOUND(unit) || SOC_IS_GREYHOUND2(unit)) { 148 return 0x0100f000; 149 } 150 #endif 151 152 #if defined(BCM_APACHE_SUPPORT) || defined(BCM_TOMAHAWK2_SUPPORT) || \ 153 defined(BCM_MONTEREY_SUPPORT) 154 if (SOC_IS_APACHE(unit) || SOC_IS_TOMAHAWK2(unit) || 155 SOC_IS_MONTEREY(unit)) { 156 return 0x0127f000; 157 } 158 #endif 159 160 #ifdef BCM_TOMAHAWK_SUPPORT 161 if (SOC_IS_TOMAHAWK3(unit)) { 162 return 0x012ff000; 163 } else if (SOC_IS_TOMAHAWKX(unit)) { 164 return 0x1b07f000; 165 } 166 #endif 167 168 #if defined(BCM_TRIDENT3_SUPPORT) 169 if (SOC_IS_TRIDENT3(unit)) { 170 return 0x0127f000; 171 } 172 #endif 173 174 #if defined(BCM_JERICHO_2_SUPPORT) 175 if (SOC_IS_JERICHO_2_ONLY(unit)) { 176 return 0x012ff000; 177 } 178 #endif 179 180 #if defined(BCM_MAVERICK2_SUPPORT) 181 if (SOC_IS_MAVERICK2(unit)) { 182 return 0x012ff000; 183 } 184 #endif 185 186 #if defined(BCM_88375) || defined(BCM_88675) || defined(BCM_88470) || defined(BCM_88270) 187 if (SOC_IS_JERICHO(unit)) { 188 return 0x1b07f000; 189 } 190 #endif 191 192 return CMICM_MSG_AREAS; 193 } 194 195 /* Internal routine to read MCS memory */ 196 static int 197 soc_cmic_mcs_read(int unit, uint32 addr) 198 { 199 #if defined(BCM_IPROC_SUPPORT) && defined(BCM_UC_MHOST_SUPPORT) 200 if (soc_feature(unit, soc_feature_uc_mhost)) { 201 return soc_cm_iproc_read(unit, addr); 202 } 203 #endif /* BCM_IPROC_SUPPORT && BCM_UC_MHOST_SUPPORT */ 204 205 return soc_pci_mcs_read(unit, addr); 206 } 207 208 /* Internal routine to write MCS memory */ 209 static int 210 soc_cmic_mcs_write(int unit, uint32 addr, uint32 data) 211 { 212 #if defined(BCM_IPROC_SUPPORT) && defined(BCM_UC_MHOST_SUPPORT) 213 if (soc_feature(unit, soc_feature_uc_mhost)) { 214 soc_cm_iproc_write(unit, addr, data); 215 return SOC_E_NONE; 216 } 217 #endif /* BCM_IPROC_SUPPORT && BCM_UC_MHOST_SUPPORT */ 218 219 return soc_pci_mcs_write(unit, addr, data); 220 } 221 222 /* Static routine to add received message to receive LL 223 *Inserts an element at tail of LL */ 224 static void ll_insert_tail(ll_ctrl_t *p_ll_ctrl, ll_element_t *p_element) 225 { 226 assert(p_element && p_ll_ctrl); 227 228 p_element->p_prev = p_ll_ctrl->p_tail; 229 p_element->p_next = NULL; 230 231 if(p_ll_ctrl->ll_count) { 232 /* LL is not empty */ 233 p_ll_ctrl->p_tail->p_next = p_element; 234 } else { 235 /* LL is empty */ 236 assert(!p_ll_ctrl->p_tail && !p_ll_ctrl->p_head); 237 p_ll_ctrl->p_head = p_element; 238 } 239 240 p_ll_ctrl->ll_count++; 241 p_ll_ctrl->p_tail = p_element; 242 } 243 244 /* Static routine to remove message from receive LL 245 *Removes an element from head of LL */ 246 static ll_element_t* ll_remove_head (ll_ctrl_t *p_ll_ctrl) 247 { 248 ll_element_t* p_el; 249 250 assert(p_ll_ctrl); 251 252 if(p_ll_ctrl->ll_count) { 253 /* list is not empty */ 254 assert(p_ll_ctrl->p_head && p_ll_ctrl->p_tail); 255 256 /* keep the removed head */ 257 p_el = p_ll_ctrl->p_head; 258 259 /*update ll_ctrl*/ 260 p_ll_ctrl->p_head = p_el->p_next; 261 p_ll_ctrl->ll_count--; 262 if(p_ll_ctrl->ll_count) { 263 /* there are still elements in the list */ 264 assert(p_ll_ctrl->p_head); 265 p_ll_ctrl->p_head->p_prev = NULL; 266 } else { 267 /* p_el was the only list element */ 268 assert(p_ll_ctrl->p_tail == p_el && !p_ll_ctrl->p_head); 269 p_ll_ctrl->p_tail = NULL; 270 } 271 272 /* disconnect the removed element from the list */ 273 p_el->p_next = NULL; 274 p_el->p_prev = NULL; 275 276 return p_el; 277 } 278 return NULL; 279 280 } 281 282 /* Internal routine to process a status word */ 283 /* 284 * Function: 285 * _soc_cmic_uc_msg_process_status 286 * Purpose: 287 * Process the uC message status from a uC 288 * Parameters: 289 * unit - unit number 290 * uC - uC number 291 * Returns: 292 * 0 - OK 293 * 1 - uC reset 294 */ 295 296 int _soc_cmic_uc_msg_process_status(int unit, int uC) { 297 soc_control_t *soc = SOC_CONTROL(unit); 298 299 uint32 msg_base = _soc_cmic_uc_msg_base(unit); 300 uint32 area_in = MSG_AREA_ARM_TO_HOST(msg_base, uC); 301 uint32 area_out = MSG_AREA_HOST_TO_ARM(msg_base, uC); 302 303 /* Snapshot the status from the uC memory */ 304 mos_msg_host_status_t cur_status_in; 305 306 int out_status = 0; /* Set when new out status */ 307 int i; 308 mos_msg_ll_node_t *msg_node = NULL; 309 310 cur_status_in = soc_cmic_mcs_read(unit, CMICM_ADDR(area_in, status)); 311 312 if (MOS_MSG_STATUS_STATE(cur_status_in) == MOS_MSG_RESET_STATE) { /* Got a reset */ 313 return (1); /* Restart init */ 314 } 315 316 sal_mutex_take(soc->uc_msg_control, sal_sem_FOREVER); 317 318 /* Process the ACKS */ 319 for (i = MOS_MSG_STATUS_ACK_INDEX(soc->uc_msg_prev_status_in[uC]); 320 i != MOS_MSG_STATUS_ACK_INDEX(cur_status_in); 321 i = MOS_MSG_INCR(i)) { 322 323 /* See if any thread is waiting for an ack */ 324 if (soc->uc_msg_ack_sems[uC][i] != NULL) { 325 if (soc->uc_msg_ack_data[uC][i] != NULL) { 326 *soc->uc_msg_ack_data[uC][i] = 327 MOS_MSG_ACK_BIT(cur_status_in, i); 328 } 329 sal_sem_give(soc->uc_msg_ack_sems[uC][i]); 330 soc->uc_msg_ack_sems[uC][i] = NULL; 331 soc->uc_msg_ack_data[uC][i] = NULL; 332 } 333 334 /* Give back one for each ACK received */ 335 sal_sem_give(soc->uc_msg_send_queue_sems[uC]); 336 337 } 338 339 /* Process the messages */ 340 for (i = MOS_MSG_STATUS_SENT_INDEX(soc->uc_msg_prev_status_in[uC]); 341 i != MOS_MSG_STATUS_SENT_INDEX(cur_status_in); i = MOS_MSG_INCR(i)) { 342 343 /* Read the message data in in 2 32-bit chunks */ 344 mos_msg_data_t msg; 345 msg.words[0] = soc_cmic_mcs_read(unit,CMICM_DATA_WORD0_BASE(area_in) + 346 MOS_MSG_DATA_SIZE * i); 347 msg.words[1] = soc_cmic_mcs_read(unit,CMICM_DATA_WORD1_BASE(area_in) + 348 MOS_MSG_DATA_SIZE * i); 349 350 LOG_VERBOSE(BSL_LS_SOC_COMMON, 351 (BSL_META_U(unit, 352 "UC%d: msg recv 0x%08x 0x%08x\n"), 353 uC, msg.words[0], msg.words[1])); 354 355 /* swap to host endian */ 356 msg.words[0] = soc_ntohl(msg.words[0]); 357 msg.words[1] = soc_ntohl(msg.words[1]); 358 359 LOG_VERBOSE(BSL_LS_SOC_COMMON, 360 (BSL_META_U(unit, 361 "UC%d: msg recv mclass 0x%02x sclass 0x%02x len 0x%04x data 0x%08x\n"), 362 uC, msg.s.mclass, msg.s.subclass, 363 msg.s.len, msg.s.data)); 364 if (msg.s.mclass > MAX_MOS_MSG_CLASS) { 365 MOS_MSG_ACK_BIT_CLEAR(soc->uc_msg_prev_status_out[uC], i); 366 } else if ((msg.s.mclass == MOS_MSG_CLASS_SYSTEM) && 367 (msg.s.subclass == MOS_MSG_SUBCLASS_SYSTEM_PING)) { 368 /* Special case - PING just gets an ACK */ 369 MOS_MSG_ACK_BIT_SET(soc->uc_msg_prev_status_out[uC], i); 370 } else { 371 if (((soc->uc_msg_rcvd_ll[uC][msg.s.mclass]).ll_count) < MOS_MSG_EVENT_QUEUE_SIZE) { 372 /* Enqueue the message in respective LL */ 373 msg_node = (mos_msg_ll_node_t *)sal_alloc(sizeof(mos_msg_ll_node_t), "UC Msg Node"); 374 if (msg_node != NULL) { 375 MOS_MSG_ACK_BIT_SET(soc->uc_msg_prev_status_out[uC], i); 376 msg_node->msg_data.words[0] = msg.words[0]; 377 msg_node->msg_data.words[1] = msg.words[1]; 378 ll_insert_tail(&(soc->uc_msg_rcvd_ll[uC][msg.s.mclass]), (ll_element_t *)msg_node); 379 380 /* Kick the waiter */ 381 sal_sem_give(soc->uc_msg_rcv_sems[uC][msg.s.mclass]); 382 383 } else { 384 /* Malloc failed, no room for the message - NACK it */ 385 MOS_MSG_ACK_BIT_CLEAR(soc->uc_msg_prev_status_out[uC], i); 386 LOG_ERROR(BSL_LS_SOC_COMMON, 387 (BSL_META_U(unit, 388 "Could not malloc, Sending NACK, Msg Class - %d\n"), msg.s.mclass)); 389 } 390 } else { 391 MOS_MSG_ACK_BIT_CLEAR(soc->uc_msg_prev_status_out[uC], i); 392 LOG_VERBOSE(BSL_LS_SOC_COMMON, 393 (BSL_META_U(unit, 394 "More than 1000 nodes in LL for Msg Class - %d\n"), msg.s.mclass)); 395 } 396 } 397 398 LOG_VERBOSE(BSL_LS_SOC_COMMON, 399 (BSL_META_U(unit, 400 "UC%d: Ack slot %d 0x%08x 0x%08x\n"), 401 uC, i, msg.words[0], msg.words[1])); 402 out_status = 1; 403 } 404 405 /* Update the status out with the final index */ 406 MOS_MSG_STATUS_ACK_INDEX_W(soc->uc_msg_prev_status_out[uC], i); 407 408 /* Remember previous status for next time */ 409 soc->uc_msg_prev_status_in[uC] = cur_status_in; 410 411 if (out_status) { 412 /* We have determined the new status out - write it and notify 413 the other uC by writing the word once here and 414 interrupting the uC*/ 415 soc_cmic_mcs_write(unit, CMICM_ADDR(area_out, status), 416 soc->uc_msg_prev_status_out[uC]); 417 /* coverity[result_independent_of_operands] */ 418 #ifdef BCM_CMICX_SUPPORT 419 if (soc_feature(unit, soc_feature_cmicx)) { 420 CMICX_SW_INTR_SET(unit, CMICM_SW_INTR_UC(uC)); 421 } else 422 #endif 423 { 424 CMIC_CMC_SW_INTR_SET(unit, CMICM_SW_INTR_UC(uC)); 425 } 426 } 427 428 sal_mutex_give(soc->uc_msg_control); 429 430 return (0); 431 } 432 433 /* 434 * Function: 435 * soc_cmic_uc_msg_active_wait 436 * Purpose: 437 * To wait for the message system to becone active 438 * Parameters: 439 * unit - unit number 440 * uC - microcontroller number 441 * Returns: 442 * SOC_E_NONE - Handshake complete, msg active 443 * SOC_E_UNAVAIL - system shut down 444 */ 445 446 int 447 soc_cmic_uc_msg_active_wait(int unit, uint32 uC) { 448 soc_control_t *soc = SOC_CONTROL(unit); 449 450 if ((soc == NULL) || ((soc->swIntrActive & (1 << uC)) == 0) || 451 (soc->uc_msg_active[uC] == NULL)) { 452 return (SOC_E_UNAVAIL); 453 } 454 455 /* Wait for the semaphore to be available */ 456 if (!sal_sem_take(soc->uc_msg_active[uC], 10000000)) { 457 sal_sem_give(soc->uc_msg_active[uC]); 458 } 459 460 return (SOC_E_NONE); 461 } 462 463 /* 464 * Function: 465 * _soc_cmic_uc_msg_system_thread 466 * Purpose: 467 * Thread to system messages 468 * Parameters: 469 * unit - unit number 470 * Returns: 471 * Nothing 472 */ 473 474 void 475 _soc_cmic_uc_msg_system_thread(void *unit_vp) { 476 int unit = DECODE_UNIT(unit_vp); 477 int uC = DECODE_UC(unit_vp); 478 soc_control_t *soc = SOC_CONTROL(unit); 479 mos_msg_data_t rcv, send; 480 uint8 *endian_buf = NULL; 481 482 if (soc == NULL) { 483 return; 484 } 485 486 while (1) { 487 while (soc_cmic_uc_msg_receive_internal(unit, uC, MOS_MSG_CLASS_SYSTEM, 488 &rcv, sal_sem_FOREVER, 1) != SOC_E_NONE) { 489 if (soc_cmic_uc_msg_active_wait(unit, uC) != SOC_E_NONE) { 490 if (endian_buf) { 491 /* Free the buffer if it was previously allocated */ 492 soc_cm_sfree(unit, endian_buf); 493 endian_buf = NULL; 494 } 495 496 /*Let the receive thread kick in and exit*/ 497 sal_thread_yield(); 498 499 /* wait 0.5sec until all threads exit*/ 500 sal_udelay(500000); 501 502 /* Clear the swIntr, after exiting all threads*/ 503 sal_mutex_take(soc->uc_msg_control, sal_sem_FOREVER); 504 if (soc->swIntr[CMICM_SW_INTR_UC(uC)] != NULL) { 505 sal_sem_destroy(soc->swIntr[CMICM_SW_INTR_UC(uC)]); 506 soc->swIntr[CMICM_SW_INTR_UC(uC)] = NULL; 507 } 508 sal_mutex_give(soc->uc_msg_control); 509 510 /* Down and not coming back up - exit thread */ 511 LOG_CLI((BSL_META_U(unit, 512 "System thread exiting\n"))); 513 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, \ 514 "%s", "System thread exiting\n")); 515 return; 516 } 517 } 518 519 if (endian_buf) { 520 /* Free the buffer if it was previously allocated */ 521 soc_cm_sfree(unit, endian_buf); 522 endian_buf = NULL; 523 } 524 525 if (rcv.s.subclass == MOS_MSG_SUBCLASS_SYSTEM_LOG) { 526 527 } else if (rcv.s.subclass == MOS_MSG_SUBCLASS_SYSTEM_INFO) { 528 int send_rv = SOC_E_INTERNAL; 529 if (rcv.s.len == 0) { 530 /* For older firmware that does not process SYSTEM_DMA_ENDIAN, 531 * send endianness swapping based on tested combinations: 532 */ 533 int big_pio, big_packet, big_other; 534 535 send.s.mclass = MOS_MSG_CLASS_SYSTEM; 536 send.s.subclass = MOS_MSG_SUBCLASS_SYSTEM_INFO_REPLY; 537 send.s.data = ~0; 538 539 if (soc_feature(unit, soc_feature_iproc)) { 540 soc_cm_get_endian(unit, &big_pio, &big_packet, &big_other); 541 if (!big_other) { 542 send.s.data = 0; 543 } 544 } 545 546 LOG_VERBOSE(BSL_LS_SOC_COMMON, 547 (BSL_META_U(unit, "SYSTEM INFO REPLY (%08x)\n"), 548 (unsigned)send.s.data)); 549 550 send_rv = soc_cmic_uc_msg_send(unit, uC, &send, 551 soc->uc_msg_send_timeout); 552 553 } else if (rcv.s.len == soc_htons(1)) { 554 /* Tell Firmware to pull local data to determine endianness */ 555 send.s.mclass = MOS_MSG_CLASS_SYSTEM; 556 send.s.subclass = MOS_MSG_SUBCLASS_SYSTEM_DMA_ENDIAN; 557 send.s.len = 0; 558 endian_buf = soc_cm_salloc(unit, MOS_MSG_TEST_DMA_SIZE, 559 "uKernel DMA"); 560 561 endian_buf[0] = 1; 562 endian_buf[1] = 2; 563 endian_buf[2] = 3; 564 endian_buf[3] = 4; 565 soc_cm_sflush(unit, endian_buf, MOS_MSG_TEST_DMA_SIZE); 566 send.s.data = soc_htonl(soc_cm_l2p(unit, endian_buf)); 567 send_rv = soc_cmic_uc_msg_send(unit, uC, &send, 568 soc->uc_msg_send_timeout); 569 } 570 if (send_rv == SOC_E_NONE) { 571 /* Indicate to waiters that we are up */ 572 sal_sem_give(soc->uc_msg_active[uC]); 573 } 574 575 } else if (rcv.s.subclass == MOS_MSG_SUBCLASS_SYSTEM_STATS) { 576 /* TBD - drop for now */ 577 578 } else if (rcv.s.subclass == MOS_MSG_SUBCLASS_SYSTEM_CONSOLE_IN) { 579 /* TBD - drop for now */ 580 581 } else if (rcv.s.subclass == MOS_MSG_SUBCLASS_SYSTEM_CONSOLE_OUT) { 582 LOG_CLI((BSL_META_U(unit, 583 "%c"), rcv.s.data & 0x0ff)); 584 #if defined (INCLUDE_UC_ULINK) 585 } else if (rcv.s.subclass == MOS_MSG_SUBCLASS_SYSTEM_LINK_REQ) { 586 LOG_DEBUG(BSL_LS_SOC_COMMON, 587 (BSL_META_U(unit, "SYSTEM ULINK REQ from UC (%d)\n"), 588 uC)); 589 UC_ULINK_SET_ACTIVE(uC); 590 591 soc_cmic_uc_pkd_link_notify(unit); 592 #endif 593 } else if (rcv.s.subclass == MOS_MSG_SUBCLASS_SYSTEM_EXCEPTION) { 594 LOG_CLI((BSL_META_U(unit, "uC-%d Exception\n"), uC)); 595 /* Exception Type : 596 * 0 - Reset Reentry 597 * 1 - Undefined Instruction 598 * 2 - SWI 599 * 3 - Prefetch Abort 600 * 4 - Data Abort 601 */ 602 LOG_CLI((BSL_META_U(unit, "Type : 0x%08x\n"), soc_uc_mem_read(unit, soc_uc_addr_to_pcie(unit, uC, 0x64)))); 603 /* Data Fault Status Register */ 604 LOG_CLI((BSL_META_U(unit, "DFSR : 0x%08x\n"), soc_uc_mem_read(unit, soc_uc_addr_to_pcie(unit, uC, 0x68)))); 605 /* Data Fault Address Register */ 606 LOG_CLI((BSL_META_U(unit, "DFAR : 0x%08x\n"), soc_uc_mem_read(unit, soc_uc_addr_to_pcie(unit, uC, 0x6c)))); 607 /* Instruction Fault Status Register */ 608 LOG_CLI((BSL_META_U(unit, "IFSR : 0x%08x\n"), soc_uc_mem_read(unit, soc_uc_addr_to_pcie(unit, uC, 0x70)))); 609 /* Instruction Fault Address Register */ 610 LOG_CLI((BSL_META_U(unit, "IFAR : 0x%08x\n"), soc_uc_mem_read(unit, soc_uc_addr_to_pcie(unit, uC, 0x74)))); 611 } 612 } 613 } 614 615 /* 616 * Function: 617 * _soc_cmic_uc_msg_thread 618 * Purpose: 619 * Thread to handle comminucations with UCs (ARMs) 620 * Parameters: 621 * unit - unit number 622 * Returns: 623 * Nothing 624 */ 625 626 void 627 _soc_cmic_uc_msg_thread(void *unit_vp) { 628 int unit = DECODE_UNIT(unit_vp); 629 int uC = DECODE_UC(unit_vp); 630 soc_control_t *soc = SOC_CONTROL(unit); 631 int i; 632 int uC_intr; 633 634 uint32 msg_base; 635 uint32 area_in; 636 uint32 area_out; 637 638 mos_msg_host_status_t cur_status_in; 639 sal_sem_t tsem; 640 mos_msg_ll_node_t *msg_node; 641 642 /* Use the message control mutex to pick a UC */ 643 sal_mutex_take(soc->uc_msg_control, sal_sem_FOREVER); 644 645 /* This uC is ready to start */ 646 uC_intr = CMICM_SW_INTR_UC(uC); 647 soc->swIntr[uC_intr] = sal_sem_create("SW interrupt", 648 sal_sem_BINARY, 0); 649 if (soc->swIntr[CMICM_SW_INTR_UC(uC)] == NULL) { 650 LOG_ERROR(BSL_LS_SOC_COMMON, 651 (BSL_META_U(unit, 652 "soc_cmic_uc_msg_thread: failed (swIntr) %d\n"), uC)); 653 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 654 "soc_cmic_uc_msg_thread: failed (swIntr) %d\n", uC)); 655 sal_mutex_give(soc->uc_msg_control); 656 return; 657 } 658 659 #ifdef BCM_CMICM_SUPPORT 660 if (soc_feature(unit, soc_feature_cmicm)) { 661 soc_cmicm_intr0_enable(unit, IRQ_CMCx_SW_INTR(uC_intr)); 662 } 663 #endif 664 665 #ifdef BCM_CMICX_SUPPORT 666 if (soc_feature(unit, soc_feature_cmicx)) { 667 soc_cmic_intr_enable(unit, SW_PROG_INTR); 668 } 669 #endif 670 671 sal_mutex_give(soc->uc_msg_control); 672 673 /* These are addresses in the uC SRAM and not directly addressible 674 from the SDK - they are addesses for PCI operations */ 675 msg_base = _soc_cmic_uc_msg_base(unit); 676 area_in = MSG_AREA_ARM_TO_HOST(msg_base, uC); 677 area_out = MSG_AREA_HOST_TO_ARM(msg_base, uC); 678 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 679 "uC: %d msg_area_in: %p msg_area_out: %p\n", 680 uC, area_in, area_out)); 681 682 /* While not killed off */ 683 while (1) { 684 /* We must write the IN status area to zero. This is becuase 685 the ECC for the SRAM where it lives might not be initialized 686 and the resulting ECC error would cause a PCIe error which 687 would cause the SDK to crash. Zero is safe in this protocol 688 since we will not consider that a reset or init state */ 689 soc_cmic_mcs_write(unit, CMICM_ADDR(area_in, status), 0); 690 691 soc->uc_msg_prev_status_out[uC] = 0; 692 693 /* Handshake protocol: 694 695 Master (SDK host): 696 (restart or receive RESET state) 697 RESET STATE 698 Wait for INIT state 699 INIT state 700 Wait for READY state 701 READY state 702 703 Slave (uC) 704 (retart or recieve RESET state) 705 RESET state 706 Wait for RESET state 707 INIT state 708 Wait for INIT state 709 READY sate 710 711 */ 712 713 714 /* Phase 1 of init handshake (wait for INIT/RESET state) */ 715 while (1) { 716 cur_status_in = soc_cmic_mcs_read(unit, CMICM_ADDR(area_in, status)); 717 if (MOS_MSG_STATUS_STATE(cur_status_in) == MOS_MSG_INIT_STATE) { 718 /* Our partner is the subordinate so we go to 719 INIT state when we see him go to INIT state */ 720 break; 721 } 722 723 /* Set the status and write it out. We do that inside the 724 loop in the first phase to avoid a race where the uKernel 725 is clearing memory to clear ECC errors and the first write 726 is lost. This is not needed after the first phase since 727 we see the uKernel msg area change state. */ 728 LOG_VERBOSE(BSL_LS_SOC_COMMON, 729 (BSL_META_U(unit, 730 "UC%d messaging system: reset\n"), uC)); 731 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 732 "UC%d messaging system: reset\n", uC)); 733 soc->uc_msg_prev_status_out[uC] = MOS_MSG_RESET_STATE; 734 soc_cmic_mcs_write(unit, CMICM_ADDR(area_out, status), 735 soc->uc_msg_prev_status_out[uC]); 736 #ifdef BCM_CMICX_SUPPORT 737 if (soc_feature(unit, soc_feature_cmicx)) { 738 CMICX_SW_INTR_SET(unit, uC_intr); 739 } else 740 #endif 741 { 742 CMIC_CMC_SW_INTR_SET(unit, uC_intr); /* Wake up call */ 743 } 744 745 if (sal_sem_take(soc->swIntr[uC_intr], sal_sem_FOREVER)) { 746 goto thread_stop; 747 } 748 #ifdef BCM_CMICX_SUPPORT 749 if (soc_feature(unit, soc_feature_cmicx)) { 750 soc_cmic_intr_enable(unit, SW_PROG_INTR); 751 } 752 #endif 753 if ((soc->swIntrActive & (1 << uC)) == 0) { /* If exit signaled */ 754 goto thread_stop; 755 } 756 } 757 758 /* Proceed to INIT state */ 759 LOG_VERBOSE(BSL_LS_SOC_COMMON, 760 (BSL_META_U(unit, 761 "UC%d messaging system: init\n"), uC)); 762 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 763 "UC%d messaging system: init\n", uC)); 764 MOS_MSG_STATUS_STATE_W(soc->uc_msg_prev_status_out[uC], MOS_MSG_INIT_STATE); 765 soc_cmic_mcs_write(unit, CMICM_ADDR(area_out, status), 766 soc->uc_msg_prev_status_out[uC]); 767 #ifdef BCM_CMICX_SUPPORT 768 if (soc_feature(unit, soc_feature_cmicx)) { 769 CMICX_SW_INTR_SET(unit, uC_intr); 770 } else 771 #endif 772 { 773 CMIC_CMC_SW_INTR_SET(unit, uC_intr); /* Wake up call */ 774 } 775 776 /* Phase 2 of init handshake (wait for READY/INIT state */ 777 while (1) { 778 /* Get the status once */ 779 cur_status_in = soc_cmic_mcs_read(unit, CMICM_ADDR(area_in, status)); 780 if (MOS_MSG_STATUS_STATE(cur_status_in) == MOS_MSG_READY_STATE) { 781 /* Our partner is the subordinate so we go to 782 READY state when we see him go to READY state */ 783 break; 784 } else if (MOS_MSG_STATUS_STATE(cur_status_in) == MOS_MSG_RESET_STATE) { 785 /* The subordinate has requested another 786 reset. process_msg_status will detect this 787 and we will go to the top of the loop */ 788 break; 789 } 790 791 if (sal_sem_take(soc->swIntr[uC_intr], sal_sem_FOREVER)) { 792 goto thread_stop; 793 } 794 #ifdef BCM_CMICX_SUPPORT 795 if (soc_feature(unit, soc_feature_cmicx)) { 796 soc_cmic_intr_enable(unit, SW_PROG_INTR); 797 } 798 #endif 799 if ((soc->swIntrActive & (1 << uC)) == 0) { /* If exit signaled */ 800 goto thread_stop; 801 } 802 } 803 804 /* Go to the ready state */ 805 LOG_VERBOSE(BSL_LS_SOC_COMMON, 806 (BSL_META_U(unit, 807 "UC%d messaging system: ready\n"), uC)); 808 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 809 "UC%d messaging system: ready\n", uC)); 810 MOS_MSG_STATUS_STATE_W(soc->uc_msg_prev_status_out[uC], MOS_MSG_READY_STATE); 811 soc_cmic_mcs_write(unit, CMICM_ADDR(area_out, status), 812 soc->uc_msg_prev_status_out[uC]); 813 soc->uc_msg_prev_status_in[uC] = cur_status_in; 814 #ifdef BCM_CMICX_SUPPORT 815 if (soc_feature(unit, soc_feature_cmicx)) { 816 CMICX_SW_INTR_SET(unit, uC_intr); 817 } else 818 #endif 819 { 820 CMIC_CMC_SW_INTR_SET(unit, uC_intr); /* Wake up call */ 821 } 822 823 LOG_CLI((BSL_META_U(unit, 824 "UC%d messaging system: up\n"), uC)); 825 826 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 827 "UC%d messaging system: up\n", uC)); 828 829 /* Give one count for each slot (all free to start) */ 830 for (i = 0; i < NUM_MOS_MSG_SLOTS; i++) { 831 sal_sem_give(soc->uc_msg_send_queue_sems[uC]); 832 } 833 834 835 /* Start normal processing */ 836 while (1) { 837 if (_soc_cmic_uc_msg_process_status(unit, uC)) { 838 break; /* Received reset */ 839 } 840 if (sal_sem_take(soc->swIntr[uC_intr], sal_sem_FOREVER)) { 841 goto thread_stop; 842 } 843 #ifdef BCM_CMICX_SUPPORT 844 if (soc_feature(unit, soc_feature_cmicx)) { 845 soc_cmic_intr_enable(unit, SW_PROG_INTR); 846 } 847 #endif 848 if ((soc->swIntrActive & (1 << uC)) == 0) { 849 /* If exit signaled */ 850 goto thread_stop; 851 } 852 } 853 854 LOG_CLI((BSL_META_U(unit, 855 "UC messaging back to reset\n"))); 856 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 857 "%s", "UC messaging back to reset\n")); 858 859 /* Connection failed - go back to reset */ 860 861 if ((soc->swIntrActive & (1 << uC)) == 0) { 862 /* If exit signaled */ 863 goto thread_stop; 864 } 865 866 sal_sem_take(soc->uc_msg_active[uC], 0); /* Get or timeout */ 867 868 /* Take all of the slots */ 869 for (i = 0; i < NUM_MOS_MSG_SLOTS; i++) { 870 /* These will timeout immedaitely */ 871 sal_sem_take(soc->uc_msg_send_queue_sems[uC], 0); 872 } 873 874 /*Clear receive LL and set Semaphore count to 0*/ 875 sal_mutex_take(soc->uc_msg_control, sal_sem_FOREVER); 876 for (i = 0; i <= MAX_MOS_MSG_CLASS; i++) { 877 while( soc->uc_msg_rcvd_ll[uC][i].ll_count ){ 878 msg_node = (mos_msg_ll_node_t *)ll_remove_head(&(soc->uc_msg_rcvd_ll[uC][i])); 879 if (msg_node != NULL){ 880 sal_free(msg_node); 881 } 882 /*Decrement the counting semaphore count to be in sync with LL*/ 883 sal_sem_take(soc->uc_msg_rcv_sems[uC][i], 10000000); 884 }; 885 886 /* Kick the waiter */ 887 sal_sem_give(soc->uc_msg_rcv_sems[uC][i]); 888 } 889 sal_mutex_give(soc->uc_msg_control); 890 /*Let the receive thread kick in and exit*/ 891 sal_thread_yield(); 892 893 for (i = 0; i < NUM_MOS_MSG_SLOTS; i++) { 894 if (soc->uc_msg_ack_sems[uC][i] != NULL) { 895 /* Kick the waiter */ 896 tsem = soc->uc_msg_ack_sems[uC][i]; 897 898 soc->uc_msg_ack_sems[uC][i] = NULL; 899 sal_sem_give(tsem); 900 } 901 } 902 903 } /* end while (1) */ 904 905 thread_stop: 906 907 LOG_CLI((BSL_META_U(unit, 908 "UC msg thread dies %x\n"), uC)); 909 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 910 "UC msg thread dies %x\n", uC)); 911 912 sal_sem_take(soc->uc_msg_active[uC], 0); 913 914 /* NAK all of the current messages */ 915 for (i = 0; i < NUM_MOS_MSG_SLOTS; i++) { 916 if (soc->uc_msg_ack_sems[uC][i] != NULL) { 917 tsem = soc->uc_msg_ack_sems[uC][i]; 918 919 soc->uc_msg_ack_sems[uC][i] = NULL; 920 sal_sem_give(tsem); 921 } 922 } 923 924 925 /* Init the rest of our structures */ 926 if (soc->uc_msg_send_queue_sems[uC] != NULL) { 927 sal_sem_destroy(soc->uc_msg_send_queue_sems[uC]); 928 soc->uc_msg_send_queue_sems[uC] = NULL; 929 } 930 931 /*Clear receive LL and set Semaphore count to 0*/ 932 sal_mutex_take(soc->uc_msg_control, sal_sem_FOREVER); 933 for (i = 0; i <= MAX_MOS_MSG_CLASS; i++) { 934 while( soc->uc_msg_rcvd_ll[uC][i].ll_count ) { 935 msg_node = (mos_msg_ll_node_t *)ll_remove_head(&(soc->uc_msg_rcvd_ll[uC][i])); 936 if (msg_node != NULL) { 937 sal_free(msg_node); 938 } 939 /*Decrement the counting semaphore count to be in sync with LL*/ 940 sal_sem_take(soc->uc_msg_rcv_sems[uC][i], 10000000); 941 }; 942 943 /* Kick the waiter */ 944 sal_sem_give(soc->uc_msg_rcv_sems[uC][i]); 945 } 946 sal_mutex_give(soc->uc_msg_control); 947 /* This print statement is required for this function 948 to get some microseconds delay to exit cleanly */ 949 LOG_CLI((BSL_META_U(unit,"Exit Clean\n"))); 950 } 951 952 /* 953 * Function: 954 * soc_cmic_sw_intr 955 * Purpose: 956 * Process a S/W generated interrupt from one of the ARMs 957 * Parameters: 958 * s - pointer to socket structure. 959 * rupt_num - sw itnerrupt number 960 * Returns: 961 * Nothing 962 * Notes: 963 * INTERRUPT LEVEL ROUTINE 964 */ 965 966 void 967 soc_cmic_sw_intr(int unit, uint32 rupt_num) 968 { 969 soc_control_t *soc = SOC_CONTROL(unit); 970 int cmc = SOC_PCI_CMC(unit); 971 972 LOG_VERBOSE(BSL_LS_SOC_COMMON, 973 (BSL_META_U(unit, 974 "SW Intr %d\n"), rupt_num)); 975 soc_cmic_ucdebug_sw_intr_count_inc(unit, rupt_num); 976 977 /* Clear the interrupt source */ 978 soc_pci_write(unit, CMIC_CMCx_SW_INTR_CONFIG_OFFSET(cmc), rupt_num); 979 980 /* Re-enable interrupts (including this one) */ 981 #ifdef BCM_CMICM_SUPPORT 982 if (soc_feature(unit, soc_feature_cmicm)) { 983 (void)soc_cmicm_intr0_enable(unit, 0); 984 } 985 #endif 986 987 if (soc->swIntr[rupt_num]) { 988 sal_sem_give(soc->swIntr[rupt_num]); 989 } 990 } 991 992 993 /* 994 * Function: 995 * soc_cmic_uc_msg_init 996 * Purpose: 997 * Do nothing - threads started elsewhere 998 * Parameters: 999 * unit - unit number 1000 * Returns: 1001 * Nothing 1002 */ 1003 1004 void 1005 soc_cmic_uc_msg_init(int unit) { 1006 COMPILER_REFERENCE(unit); 1007 } 1008 1009 #ifdef BCM_CMICX_SUPPORT 1010 1011 /* 1012 * Function: 1013 * soc_cmicx_sw_intr 1014 * Purpose: 1015 * Process a S/W generated interrupt from one of the ARMs 1016 * Parameters: 1017 * para - unused for time being 1018 * Returns: 1019 * Nothing 1020 * Notes: 1021 * INTERRUPT LEVEL ROUTINE 1022 */ 1023 1024 void 1025 soc_cmicx_sw_intr(int unit, void *data) 1026 { 1027 soc_control_t *soc = SOC_CONTROL(unit); 1028 uint32 mhost_0_intr_val = 0, mHost0_val = 0; 1029 uint32 mhost_1_intr_val = 0, mHost1_val = 0; 1030 uint32 m0_u0_sw_prg_intr = 0, u0_val = 0; 1031 uint32 m0_u1_sw_prg_intr = 0, u1_val = 0; 1032 uint32 m0_u2_sw_prg_intr = 0, u2_val = 0; 1033 uint32 m0_u3_sw_prg_intr = 0, u3_val = 0; 1034 1035 1036 /* By pass mHost interrupt if chip doesn't support mHost */ 1037 if (SOC_REG_IS_VALID(unit, ICFG_MHOST0_SW_PROG_INTRr)) { 1038 READ_ICFG_MHOST0_SW_PROG_INTRr(unit, &mhost_0_intr_val); 1039 /* Bit-0 = PCIe Host */ 1040 mHost0_val = mhost_0_intr_val & 1; 1041 } 1042 if (SOC_REG_IS_VALID(unit, ICFG_MHOST1_SW_PROG_INTRr)) { 1043 READ_ICFG_MHOST1_SW_PROG_INTRr(unit, &mhost_1_intr_val); 1044 /* Bit-0 = PCIe Host */ 1045 mHost1_val = mhost_1_intr_val & 1; 1046 } 1047 1048 /* Read Cortex M0 SW PROG INTR */ 1049 READ_ICFG_CORTEXM0_U0_SW_PROG_INTRr(unit, &u0_val); 1050 READ_ICFG_CORTEXM0_U1_SW_PROG_INTRr(unit, &u1_val); 1051 READ_ICFG_CORTEXM0_U2_SW_PROG_INTRr(unit, &u2_val); 1052 READ_ICFG_CORTEXM0_U3_SW_PROG_INTRr(unit, &u3_val); 1053 /* Bit-0 = PCIe Host */ 1054 m0_u0_sw_prg_intr = u0_val & 1; 1055 m0_u1_sw_prg_intr = u1_val & 1; 1056 m0_u2_sw_prg_intr = u2_val & 1; 1057 m0_u3_sw_prg_intr = u3_val & 1; 1058 1059 /* Clear Interrupts */ 1060 if (mHost0_val) 1061 { 1062 mhost_0_intr_val &= ~(1 << 0); 1063 WRITE_ICFG_MHOST0_SW_PROG_INTRr(unit, mhost_0_intr_val); 1064 } 1065 if (mHost1_val) 1066 { 1067 mhost_1_intr_val &= ~(1 << 0); 1068 WRITE_ICFG_MHOST1_SW_PROG_INTRr(unit, mhost_1_intr_val); 1069 } 1070 1071 if (m0_u0_sw_prg_intr) { 1072 u0_val &= ~(1 << 0); 1073 WRITE_ICFG_CORTEXM0_U0_SW_PROG_INTRr(unit, u0_val); 1074 } 1075 if (m0_u1_sw_prg_intr) { 1076 u1_val &= ~(1 << 0); 1077 WRITE_ICFG_CORTEXM0_U1_SW_PROG_INTRr(unit, u1_val); 1078 } 1079 if (m0_u2_sw_prg_intr) { 1080 u2_val &= ~(1 << 0); 1081 WRITE_ICFG_CORTEXM0_U2_SW_PROG_INTRr(unit, u2_val); 1082 } 1083 if (m0_u3_sw_prg_intr) { 1084 u3_val &= ~(1 << 0); 1085 WRITE_ICFG_CORTEXM0_U3_SW_PROG_INTRr(unit, u3_val); 1086 } 1087 1088 soc->stat.uc_sw_prg_intr++; 1089 1090 if (mHost0_val) 1091 { 1092 if (soc->swIntr[CMICM_SW_INTR_UC(0)]) { 1093 sal_sem_give(soc->swIntr[CMICM_SW_INTR_UC(0)]); 1094 } 1095 } 1096 if (mHost1_val) 1097 { 1098 if (soc->swIntr[CMICM_SW_INTR_UC(1)]) { 1099 sal_sem_give(soc->swIntr[CMICM_SW_INTR_UC(1)]); 1100 } 1101 } 1102 if (m0_u0_sw_prg_intr) { 1103 soc->stat.m0_u0_sw_intr++; 1104 if (soc->iproc_m0ssq_ctrl[0].event_sema) { 1105 sal_sem_give(soc->iproc_m0ssq_ctrl[0].event_sema); 1106 } 1107 } 1108 if (m0_u1_sw_prg_intr) { 1109 soc->stat.m0_u1_sw_intr++; 1110 if (soc->iproc_m0ssq_ctrl[1].event_sema) { 1111 sal_sem_give(soc->iproc_m0ssq_ctrl[1].event_sema); 1112 } 1113 } 1114 if (m0_u2_sw_prg_intr) { 1115 soc->stat.m0_u2_sw_intr++; 1116 if (soc->iproc_m0ssq_ctrl[2].event_sema) { 1117 sal_sem_give(soc->iproc_m0ssq_ctrl[2].event_sema); 1118 } 1119 } 1120 if (m0_u3_sw_prg_intr) { 1121 soc->stat.m0_u3_sw_intr++; 1122 if (soc->iproc_m0ssq_ctrl[3].event_sema) { 1123 sal_sem_give(soc->iproc_m0ssq_ctrl[3].event_sema); 1124 } 1125 } 1126 } 1127 1128 /* 1129 * Function: 1130 * soc_cmicx_uc_msg_init 1131 * Purpose: 1132 * Initialize uC messaging 1133 * Parameters: 1134 * unit - unit number 1135 * Returns: 1136 * standard SOC_E_XXX 1137 */ 1138 1139 int 1140 soc_cmicx_uc_msg_init(int unit) { 1141 soc_cmic_intr_handler_t *handle; 1142 int rv = SOC_E_NONE; 1143 1144 /* Register interrupts */ 1145 handle = sal_alloc(sizeof(soc_cmic_intr_handler_t), "sw_interrupt"); 1146 if (handle == NULL) { 1147 return SOC_E_MEMORY; 1148 } 1149 1150 handle->num = SW_PROG_INTR; 1151 handle->intr_fn = soc_cmicx_sw_intr; 1152 handle->intr_data = (void *)0; 1153 1154 rv = soc_cmic_intr_register(unit, handle, 1); 1155 1156 sal_free(handle); 1157 1158 return rv; 1159 } 1160 #endif /* BCM_CMICX_SUPPORT */ 1161 1162 /* 1163 * Function: 1164 * soc_cmic_uc_msg_start 1165 * Purpose: 1166 * Start communication sessions with the UCs 1167 * Parameters: 1168 * unit - unit number 1169 * Returns: 1170 * SOC_E_xxx 1171 */ 1172 1173 int 1174 soc_cmic_uc_msg_start(int unit) { 1175 soc_control_t *soc = SOC_CONTROL(unit); 1176 int i; 1177 1178 if ((soc == NULL) || (soc->uc_msg_control != NULL)) { 1179 return (SOC_E_INIT); 1180 } 1181 1182 soc->swIntrActive = 0; 1183 soc->uc_msg_control = NULL; 1184 1185 /* Get a few properties for efficiency */ 1186 soc->uc_msg_queue_timeout = 1187 soc_property_get(unit, spn_UC_MSG_QUEUE_TIMEOUT, 20000000); 1188 soc->uc_msg_ctl_timeout = 1189 soc_property_get(unit, spn_UC_MSG_CTL_TIMEOUT, 1000000); 1190 soc->uc_msg_send_timeout = 1191 soc_property_get(unit, spn_UC_MSG_SEND_TIMEOUT, 10000000); 1192 soc->uc_msg_send_retry_delay = 1193 soc_property_get(unit, spn_UC_MSG_SEND_RETRY_DELAY, 100); 1194 1195 /* Init a few fields so that the threads can sort themselves out */ 1196 soc->uc_msg_control = sal_mutex_create("Msgctrl"); 1197 for (i = 0; i < COUNTOF(soc->swIntr); i++) { 1198 soc->swIntr[i] = NULL; 1199 } 1200 1201 for (i = 0; i < COUNTOF(soc->uc_msg_active); i++) { 1202 /* Init the active sem and hold it */ 1203 soc->uc_msg_active[i] = sal_sem_create("msgActive", 1204 sal_sem_BINARY, 0); 1205 } 1206 1207 /* Init things for the system msg threads */ 1208 soc->uc_msg_system_control = sal_mutex_create("SysMsgCtrl"); 1209 soc->uc_msg_system_count = 0; 1210 1211 return (SOC_E_NONE); 1212 } 1213 1214 1215 /* 1216 * Function: 1217 * soc_cmic_uc_msg_stop 1218 * Purpose: 1219 * Stop communication sessions with the UCs 1220 * Parameters: 1221 * unit - unit number 1222 * Returns: 1223 * SOC_E_xxx 1224 */ 1225 1226 int 1227 soc_cmic_uc_msg_stop(int unit) { 1228 soc_control_t *soc = SOC_CONTROL(unit); 1229 int uC; 1230 1231 if (soc == NULL) { 1232 return (SOC_E_INIT); /* Already shut down */ 1233 } 1234 1235 /* Kill all of the msg threads */ 1236 for (uC = 0; uC < COUNTOF(soc->uc_msg_active); uC++) { 1237 soc_cmic_uc_msg_uc_stop(unit, uC); 1238 1239 /* Destroy the semaphore. Threads using it must be quiecsed */ 1240 if (soc->uc_msg_active[uC] != NULL) { 1241 sal_sem_destroy(soc->uc_msg_active[uC]); 1242 soc->uc_msg_active[uC] = NULL; 1243 } 1244 } 1245 1246 /* Destroy control mutex */ 1247 if (soc->uc_msg_control != NULL) { 1248 sal_mutex_destroy(soc->uc_msg_control); 1249 soc->uc_msg_control = NULL; 1250 } 1251 1252 /* Destroy system control mutex */ 1253 if (soc->uc_msg_system_control != NULL) { 1254 sal_mutex_destroy(soc->uc_msg_system_control); 1255 soc->uc_msg_system_control = NULL; 1256 } 1257 1258 1259 return (SOC_E_NONE); 1260 } 1261 1262 /* 1263 * Function: 1264 * soc_cmic_uc_msg_uc_start 1265 * Purpose: 1266 * Start communicating with one of the uCs 1267 * Parameters: 1268 * unit - unit number 1269 * uC - uC number 1270 * Returns: 1271 * SOC_E_xxxx 1272 */ 1273 1274 int 1275 soc_cmic_uc_msg_uc_start(int unit, int uC) { 1276 char prop_buff[20]; 1277 soc_control_t *soc = SOC_CONTROL(unit); 1278 int i; 1279 sal_thread_t thread_id_uc_msg; 1280 sal_thread_t thread_id_uc_system_msg; 1281 1282 1283 sal_sprintf(prop_buff, "uc_msg_ctrl_%i", uC); 1284 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, "uc_msg_ctrl_%i\n", uC)); 1285 if (soc_property_get(unit, prop_buff, 1) == 0) { 1286 return (SOC_E_UNAVAIL); 1287 } 1288 1289 /* Check for the master control for this uC */ 1290 if ((soc == NULL) || ((soc->swIntrActive & (1 << uC)) != 0)) { 1291 return (SOC_E_BUSY); 1292 } 1293 1294 sal_mutex_take(soc->uc_msg_control, sal_sem_FOREVER); 1295 1296 /* Init some data structures */ 1297 soc->uc_msg_send_queue_sems[uC] = 1298 sal_sem_create("uC msg queue", sal_sem_COUNTING, 0); 1299 if (soc->uc_msg_send_queue_sems[uC] == NULL) { 1300 LOG_ERROR(BSL_LS_SOC_COMMON, 1301 (BSL_META_U(unit, 1302 "soc_cmic_uc_msg_thread: failed (uC msg) %d\n"), uC)); 1303 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 1304 "soc_cmic_uc_msg_thread: failed (uC msg) %d\n", uC)); 1305 sal_mutex_give(soc->uc_msg_control); 1306 return (SOC_E_MEMORY); 1307 } 1308 1309 /* Initialize receive LL, Create receive semaphores,*/ 1310 for (i = 0; i <= MAX_MOS_MSG_CLASS; i++) { 1311 soc->uc_msg_rcvd_ll[uC][i].p_head = NULL; 1312 soc->uc_msg_rcvd_ll[uC][i].p_tail = NULL; 1313 soc->uc_msg_rcvd_ll[uC][i].ll_count = 0; 1314 soc->uc_msg_rcv_sems[uC][i] = sal_sem_create("us_msg_rcv", sal_sem_COUNTING, 0); 1315 soc->uc_msg_appl_cb[uC][i] = NULL; 1316 soc->uc_msg_appl_cb_data[uC][i] = NULL; 1317 } 1318 1319 /* Clear Ack Semaphores and data*/ 1320 for (i = 0; i < NUM_MOS_MSG_SLOTS; i++) { 1321 soc->uc_msg_ack_sems[uC][i] = NULL; 1322 soc->uc_msg_ack_data[uC][i] = NULL; 1323 } 1324 1325 soc->swIntrActive |= 1 << uC; /* This uC is active */ 1326 thread_id_uc_msg = sal_thread_create("uC msg", SAL_THREAD_STKSZ, 1327 soc_property_get(unit, spn_UC_MSG_THREAD_PRI, 95), 1328 _soc_cmic_uc_msg_thread, ENCODE_UNIT_UC(unit, uC)); 1329 if (thread_id_uc_msg == SAL_THREAD_ERROR) { 1330 LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "uC msg thread create failed\n"))); 1331 sal_mutex_give(soc->uc_msg_control); 1332 return SOC_E_INTERNAL; 1333 } 1334 thread_id_uc_system_msg = sal_thread_create("uC system msg", SAL_THREAD_STKSZ, 1335 soc_property_get(unit, spn_UC_MSG_THREAD_PRI, 100), 1336 _soc_cmic_uc_msg_system_thread, ENCODE_UNIT_UC(unit, uC)); 1337 if (thread_id_uc_system_msg == SAL_THREAD_ERROR) { 1338 LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META_U(unit, "uC msg thread create failed\n"))); 1339 sal_thread_destroy(thread_id_uc_msg); 1340 sal_mutex_give(soc->uc_msg_control); 1341 return SOC_E_INTERNAL; 1342 } 1343 1344 sal_mutex_give(soc->uc_msg_control); 1345 1346 if (soc_cmic_uc_msg_active_wait(unit, uC) != SOC_E_NONE) { 1347 /* Down and not coming back up */ 1348 return (SOC_E_UNAVAIL); 1349 } 1350 1351 return (SOC_E_NONE); 1352 } 1353 1354 /* 1355 * Function: 1356 * soc_cmic_uc_msg_uc_stop 1357 * Purpose: 1358 * Stop communicating with one of the uCs 1359 * Parameters: 1360 * unit - unit number 1361 * uC - uC number 1362 * Returns: 1363 * SOC_E_xxx 1364 */ 1365 1366 int 1367 soc_cmic_uc_msg_uc_stop(int unit, int uC) { 1368 soc_control_t *soc = SOC_CONTROL(unit); 1369 int i; 1370 1371 /* Check for the master control for this uC */ 1372 if ((soc == NULL) || ((soc->swIntrActive & (1 << uC)) == 0)) { 1373 return (SOC_E_INIT); 1374 } 1375 1376 sal_mutex_take(soc->uc_msg_control, sal_sem_FOREVER); 1377 soc->swIntrActive &= ~(1 << uC); /* This uC is inactive */ 1378 1379 if (soc->swIntr[CMICM_SW_INTR_UC(uC)] != NULL) { 1380 sal_sem_give(soc->swIntr[CMICM_SW_INTR_UC(uC)]); /* Kick msg thread */ 1381 1382 } 1383 1384 while (1) { 1385 if (soc->swIntr[CMICM_SW_INTR_UC(uC)] == NULL) { 1386 break; /* It is shut down */ 1387 } 1388 sal_mutex_give(soc->uc_msg_control); 1389 sal_thread_yield(); 1390 sal_mutex_take(soc->uc_msg_control, sal_sem_FOREVER); 1391 } 1392 1393 /*Destroy receive semaphores*/ 1394 for (i = 0; i <= MAX_MOS_MSG_CLASS; i++) { 1395 if (soc->uc_msg_rcv_sems[uC][i] != NULL) { 1396 sal_sem_give(soc->uc_msg_rcv_sems[uC][i]); 1397 sal_thread_yield(); 1398 sal_sem_destroy(soc->uc_msg_rcv_sems[uC][i]); 1399 soc->uc_msg_rcv_sems[uC][i] = NULL; 1400 } 1401 } 1402 1403 sal_mutex_give(soc->uc_msg_control); 1404 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 1405 "soc_cmic_uc_msg_uc_stop() called uC: %d\n", uC)); 1406 1407 return (SOC_E_NONE); 1408 1409 } 1410 1411 /* 1412 * Function: 1413 * soc_cmic_uc_msg_apps_notify 1414 * Purpose: 1415 * Notify applications about shutdown, etc 1416 * Parameters: 1417 * unit - unit number 1418 * Returns: 1419 * SOC_E_xxx 1420 */ 1421 1422 int 1423 soc_cmic_uc_msg_apps_notify(int unit, soc_cmic_uc_shutdown_stage_t notification) { 1424 soc_control_t *soc = SOC_CONTROL(unit); 1425 int uC, appl; 1426 1427 if (soc == NULL) { 1428 return (SOC_E_INIT); 1429 } 1430 1431 /* Notify registered applications */ 1432 for (uC = 0; uC < COUNTOF(soc->uc_msg_active); uC++) { 1433 for (appl = 0; appl <= MAX_MOS_MSG_CLASS; ++appl) { 1434 if (soc->uc_msg_appl_cb[uC][appl]) { 1435 (soc->uc_msg_appl_cb[uC][appl])(unit, uC, notification, 1436 soc->uc_msg_appl_cb_data[uC][appl]); 1437 } 1438 } 1439 } 1440 1441 return SOC_E_NONE; 1442 } 1443 1444 /* 1445 * Function: 1446 * soc_cmic_uc_msg_uc_apps_notify 1447 * Purpose: 1448 * Notify applications about shutdown, etc 1449 * Parameters: 1450 * unit - unit number 1451 * Returns: 1452 * SOC_E_xxx 1453 */ 1454 1455 int 1456 soc_cmic_uc_msg_uc_apps_notify(int unit, soc_cmic_uc_shutdown_stage_t notification, int uC) { 1457 soc_control_t *soc = SOC_CONTROL(unit); 1458 int appl; 1459 1460 if (soc == NULL) { 1461 return (SOC_E_INIT); 1462 } 1463 1464 /* Notify registered applications */ 1465 for (appl = 0; appl <= MAX_MOS_MSG_CLASS; ++appl) { 1466 if (soc->uc_msg_appl_cb[uC][appl]) { 1467 (soc->uc_msg_appl_cb[uC][appl])(unit, uC, notification, 1468 soc->uc_msg_appl_cb_data[uC][appl]); 1469 } 1470 } 1471 return SOC_E_NONE; 1472 } 1473 1474 /* 1475 * Function: 1476 * soc_cmic_uc_msg_uc_shutdown 1477 * Purpose: 1478 * Shutdown messaging, notifying applications. Optionally halt uCs 1479 * Parameters: 1480 * unit - unit number 1481 * Returns: 1482 * SOC_E_xxx 1483 */ 1484 1485 int 1486 soc_cmic_uc_msg_shutdown_halt(int unit) { 1487 soc_control_t *soc = SOC_CONTROL(unit); 1488 int uC; 1489 int rv; 1490 1491 if (soc == NULL) { 1492 return (SOC_E_INIT); 1493 } 1494 1495 soc_cmic_uc_msg_apps_notify(unit, SOC_CMIC_UC_SHUTDOWN_STARTING); 1496 1497 if (soc->swIntrActive != 0) { /* Shut down messaging if it has been setup */ 1498 if ((rv = soc_cmic_uc_msg_stop(unit)) != SOC_E_NONE) { 1499 LOG_ERROR(BSL_LS_SOC_COMMON, 1500 (BSL_META_U(unit, 1501 "soc_cmic_uc_msg_stop: failed rv=%d\n"), rv)); 1502 1503 } 1504 } 1505 1506 /* Halt each uC */ 1507 for (uC = 0; uC < COUNTOF(soc->uc_msg_active); uC++) { 1508 soc_uc_reset(unit, uC); 1509 } 1510 1511 /* notify registered applications that their core is halted */ 1512 soc_cmic_uc_msg_apps_notify(unit, SOC_CMIC_UC_SHUTDOWN_HALTED); 1513 1514 return SOC_E_NONE; 1515 } 1516 1517 /* 1518 * Function: 1519 * soc_cmic_uc_msg_uc_shutdown_halt 1520 * Purpose: 1521 * Shutdown messaging, notifying applications. Optionally halt uCs 1522 * Parameters: 1523 * unit - unit number 1524 * Returns: 1525 * SOC_E_xxx 1526 */ 1527 1528 int 1529 soc_cmic_uc_msg_uc_shutdown_halt(int unit, int uC) { 1530 soc_control_t *soc = SOC_CONTROL(unit); 1531 int rv; 1532 1533 if (soc == NULL) { 1534 return (SOC_E_INIT); 1535 } 1536 1537 soc_cmic_uc_msg_uc_apps_notify(unit, SOC_CMIC_UC_SHUTDOWN_STARTING, uC); 1538 1539 if (soc->swIntrActive != 0) { /* Shut down messaging if it has been setup */ 1540 if ((rv = soc_cmic_uc_msg_uc_stop(unit, uC)) != SOC_E_NONE) { 1541 LOG_ERROR(BSL_LS_SOC_COMMON, 1542 (BSL_META_U(unit, 1543 "soc_cmic_uc_msg_uc_stop: failed rv=%d\n"), rv)); 1544 } 1545 } 1546 1547 /* Halt uC */ 1548 soc_uc_reset(unit, uC); 1549 1550 /* notify registered applications that their core is halted */ 1551 soc_cmic_uc_msg_uc_apps_notify(unit, SOC_CMIC_UC_SHUTDOWN_HALTED, uC); 1552 1553 return SOC_E_NONE; 1554 } 1555 1556 /* Function: 1557 * soc_cmic_uc_msg_send 1558 * Purpose: 1559 * Send a message to another processor and retry until an ack 1560 * Parameters: 1561 * unit - unit number 1562 * uC - uC number 1563 * msg - the 64-bit message to send 1564 * timeout - time to wait in usecs or zero (no wait) 1565 * Returns: 1566 * SOC_E_NONE = message ACK'd (agent received msg) 1567 * SOC_E_xxx - message NAK'd (no agent or buffer space full or timeout) 1568 */ 1569 int soc_cmic_uc_msg_send(int unit, int uC, mos_msg_data_t *msg, 1570 sal_usecs_t timeout) { 1571 soc_control_t *soc = SOC_CONTROL(unit); 1572 int32 msg_base; 1573 int rc; 1574 uint8 ack; 1575 int index; 1576 sal_sem_t ack_sem; 1577 uint32 area_out; 1578 mos_msg_data_t omsg; 1579 /* Figure out when to give up */ 1580 sal_usecs_t start_time = sal_time_usecs(); 1581 sal_usecs_t end_time, time_elapsed; 1582 1583 if ((soc == NULL) || ((soc->swIntrActive & (1 << uC)) == 0)) { 1584 return SOC_E_INIT; 1585 } 1586 1587 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 1588 "uC: %d msg->s.mclass: %d msg->s.subclass: %d msg->s.len :%d msg->s.addr: 0x%x\n", 1589 uC, msg->s.mclass, msg->s.subclass, msg->s.len, msg->s.data)); 1590 1591 1592 ack_sem = sal_sem_create("uc_msg_send", 1, 0); 1593 1594 msg_base = _soc_cmic_uc_msg_base(unit); 1595 1596 while (1) { /* Retry loop */ 1597 1598 rc = SOC_E_NONE; 1599 1600 /* Wait for a semaphore indicating a free slot */ 1601 if (sal_sem_take(soc->uc_msg_send_queue_sems[uC], soc->uc_msg_queue_timeout) == -1) { 1602 rc = SOC_E_TIMEOUT; 1603 break; 1604 } 1605 1606 /* Block others for a bit */ 1607 if (sal_mutex_take(soc->uc_msg_control, soc->uc_msg_ctl_timeout) == 0) { 1608 if (MOS_MSG_STATUS_STATE(soc->uc_msg_prev_status_out[uC]) != 1609 MOS_MSG_READY_STATE) { 1610 sal_mutex_give(soc->uc_msg_control); 1611 rc = SOC_E_INIT; 1612 break; 1613 } 1614 1615 assert(MOS_MSG_INCR(MOS_MSG_STATUS_SENT_INDEX(soc->uc_msg_prev_status_out[uC])) != 1616 MOS_MSG_STATUS_ACK_INDEX(soc->uc_msg_prev_status_in[uC])); 1617 1618 /* Room for the message - update the local status copy */ 1619 index = MOS_MSG_STATUS_SENT_INDEX(soc->uc_msg_prev_status_out[uC]); 1620 MOS_MSG_STATUS_SENT_INDEX_W(soc->uc_msg_prev_status_out[uC], 1621 MOS_MSG_INCR(index)); 1622 1623 soc->uc_msg_ack_data[uC][index] = &ack; 1624 soc->uc_msg_ack_sems[uC][index] = ack_sem; 1625 1626 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1627 (BSL_META_U(unit, 1628 "UC%d: msg send mclass 0x%02x sclass 0x%02x len 0x%04x data 0x%08x\n"), 1629 uC, msg->s.mclass, msg->s.subclass, 1630 msg->s.len, msg->s.data)); 1631 omsg.words[0] = soc_htonl(msg->words[0]); 1632 omsg.words[1] = soc_htonl(msg->words[1]); 1633 1634 /* Update the outbound area that contains the new message */ 1635 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1636 (BSL_META_U(unit, 1637 "UC%d: send slot %d 0x%08x 0x%08x\n"), 1638 uC, index, omsg.words[0], omsg.words[1])); 1639 area_out = MSG_AREA_HOST_TO_ARM(msg_base, uC); 1640 soc_cmic_mcs_write(unit, CMICM_DATA_WORD0_BASE(area_out) + 1641 MOS_MSG_DATA_SIZE * index, 1642 omsg.words[0]); 1643 soc_cmic_mcs_write(unit, CMICM_DATA_WORD1_BASE(area_out) + 1644 MOS_MSG_DATA_SIZE *index, 1645 omsg.words[1]); 1646 1647 soc_cmic_mcs_write(unit, CMICM_ADDR(area_out,status), 1648 soc->uc_msg_prev_status_out[uC]); 1649 1650 /* coverity[result_independent_of_operands] */ 1651 #ifdef BCM_CMICX_SUPPORT 1652 if (soc_feature(unit, soc_feature_cmicx)) { 1653 CMICX_SW_INTR_SET(unit, CMICM_SW_INTR_UC(uC)); 1654 } else 1655 #endif 1656 { 1657 CMIC_CMC_SW_INTR_SET(unit, CMICM_SW_INTR_UC(uC)); 1658 } 1659 1660 /* Return the global message control mutex */ 1661 sal_mutex_give(soc->uc_msg_control); 1662 1663 /* Wait for the ACK semaphore to be posted indicating that 1664 a response has been received */ 1665 if (sal_sem_take(ack_sem, soc->uc_msg_send_timeout)) { 1666 soc->uc_msg_ack_data[uC][index] = NULL; 1667 soc->uc_msg_ack_sems[uC][index] = NULL; 1668 rc = SOC_E_TIMEOUT; 1669 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1670 (BSL_META_U(unit, "uC:%d sal_sem_take failed\n"), uC)); 1671 break; 1672 } 1673 1674 if (ack == 1) { 1675 rc = SOC_E_NONE; 1676 break; /* Message received OK */ 1677 } 1678 1679 end_time = sal_time_usecs(); 1680 if (end_time > start_time) { 1681 time_elapsed = end_time - start_time; 1682 } else { 1683 time_elapsed = SAL_USECS_TIMESTAMP_ROLLOVER - start_time + end_time; 1684 } 1685 1686 if (time_elapsed >= timeout) { 1687 soc->uc_msg_ack_data[uC][index] = NULL; 1688 soc->uc_msg_ack_sems[uC][index] = NULL; 1689 rc = SOC_E_TIMEOUT; 1690 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1691 (BSL_META_U(unit, "uC:%d time out\n"), uC)); 1692 break; /* Timeout */ 1693 } 1694 1695 sal_usleep(soc->uc_msg_send_retry_delay); 1696 } 1697 1698 } 1699 1700 sal_sem_destroy(ack_sem); 1701 1702 return (rc); 1703 } 1704 1705 /* 1706 * Function 1707 * soc_cmic_uc_msg_receive_internal 1708 * Purpose: 1709 * Wait for a message of a given type from a uC, possibly before messaging is fully up 1710 * Parameters: 1711 * unit - unit number 1712 * uC - uC number 1713 * mclass - the message class 1714 * msg - pointer to buffer for message (64 bits) 1715 * is_system - true if this receive is done by system thread, so no wait on messaging being up 1716 * Returns: 1717 * SOC_E_NONE = message ACK'd (agent received msg) 1718 * SOC_E_xxx - message NAK'd (no agent or buffer space full or timeout) 1719 */ 1720 static int soc_cmic_uc_msg_receive_internal(int unit, int uC, uint8 mclass, 1721 mos_msg_data_t *msg, int timeout, int is_system) 1722 { 1723 soc_control_t *soc = SOC_CONTROL(unit); 1724 int rc = SOC_E_NONE; 1725 mos_msg_ll_node_t *msg_node; 1726 1727 if ((soc == NULL) || ((soc->swIntrActive & (1 << uC)) == 0)) { 1728 return SOC_E_INIT; 1729 } 1730 1731 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1732 (BSL_META_U(unit, 1733 "UC%d msg wait mclass %d\n"), 1734 uC, mclass)); 1735 1736 /* Wait/Check if msg available to be received */ 1737 if ( !soc->uc_msg_rcv_sems[uC][mclass] || sal_sem_take(soc->uc_msg_rcv_sems[uC][mclass], timeout) ) { 1738 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1739 (BSL_META_U(unit, 1740 "UC%d semtake - uc_msg_rcv_sems failed\n"), uC)); 1741 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 1742 "%s: msg wait mclass %d uC: %d: semtake - uc_msg_rcv_sems failed\n", 1743 FUNCTION_NAME(), mclass, uC)); 1744 return SOC_E_TIMEOUT; 1745 } 1746 1747 /* System messages must be exchanged in order to bring up messaging */ 1748 /* So only wait for messaging to be up if this is not a system message */ 1749 if (!is_system && soc_cmic_uc_msg_active_wait(unit, uC) != SOC_E_NONE) { 1750 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 1751 "%s: msg wait mclass %d uC: %d: uc message thread is not active\n", 1752 FUNCTION_NAME(), mclass, uC)); 1753 return SOC_E_INIT; 1754 } 1755 1756 /* Block others for a bit */ 1757 if (sal_mutex_take(soc->uc_msg_control, soc->uc_msg_ctl_timeout)) { 1758 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1759 (BSL_META_U(unit, 1760 "UC%d semtake - uc_msg_control timed out\n"), uC)); 1761 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 1762 "%s: msg wait mclass %d uC: %d: semtake - uc_msg_control timed out\n", 1763 FUNCTION_NAME(), mclass, uC)); 1764 return SOC_E_TIMEOUT; 1765 } 1766 1767 /* Remove the message from Receive LL head*/ 1768 msg_node = (mos_msg_ll_node_t *)ll_remove_head(&(soc->uc_msg_rcvd_ll[uC][mclass])); 1769 if (msg_node != NULL){ 1770 msg->words[0] = msg_node->msg_data.words[0]; 1771 msg->words[1] = msg_node->msg_data.words[1]; 1772 sal_free(msg_node); 1773 } else { 1774 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1775 (BSL_META_U(unit, 1776 "UC%d NULL node returned from LL\n"), uC)); 1777 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 1778 "%s: msg wait mclass %d uC: %d: NULL node returned from LL\n", 1779 FUNCTION_NAME(), mclass, uC)); 1780 1781 /* Check the uc_msg_control mutex availability, to avoid runtime error */ 1782 if (soc->uc_msg_control != NULL) { 1783 sal_mutex_give(soc->uc_msg_control); 1784 } 1785 return SOC_E_INTERNAL; 1786 } 1787 1788 /* Return the global message control mutex */ 1789 sal_mutex_give(soc->uc_msg_control); 1790 1791 if ((rc == SOC_E_NONE) && (msg->s.mclass != mclass)) { 1792 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1793 (BSL_META_U(unit, 1794 "UC%d Reply from wrong mclass\n"), uC)); 1795 SOC_CMIC_UCDBG_LOG_ADD((unit, _bcmCmicUcDbgLogHostUcMsg, 1796 "%s: msg wait mclass %d uC: %d: Reply from wrong mclass\n", 1797 FUNCTION_NAME(), mclass, uC)); 1798 rc = SOC_E_INTERNAL; /* Reply from wrong mclass */ 1799 } 1800 1801 return (rc); 1802 } 1803 1804 1805 /* 1806 * Function 1807 * soc_cmic_uc_msg_receive 1808 * Purpose: 1809 * Wait for a message of a given type from a uC 1810 * Parameters: 1811 * unit - unit number 1812 * uC - uC number 1813 * mclass - the message class 1814 * msg - pointer to buffer for message (64 bits) 1815 * Returns: 1816 * SOC_E_NONE = message ACK'd (agent received msg) 1817 * SOC_E_xxx - message NAK'd (no agent or buffer space full or timeout) 1818 */ 1819 int soc_cmic_uc_msg_receive(int unit, int uC, uint8 mclass, 1820 mos_msg_data_t *msg, int timeout) 1821 { 1822 /* Do the receive, but not as the system messaging thread */ 1823 return soc_cmic_uc_msg_receive_internal(unit, uC, mclass, msg, timeout, 0); 1824 } 1825 1826 1827 /* Function: 1828 * soc_cmic_uc_msg_receive_cancel 1829 * Purpose: 1830 * Cancel wait to receive an application message 1831 * Parameters: 1832 * unit - unit number 1833 * uC - uC number 1834 * msg_class - application message class 1835 * Returns: 1836 * SOC_E_NONE = Waiters kicked or none waiting 1837 * SOC_E_UNAVAIL = Feature not available 1838 */ 1839 int soc_cmic_uc_msg_receive_cancel(int unit, int uC, int msg_class) 1840 { 1841 soc_control_t *soc = SOC_CONTROL(unit); 1842 mos_msg_ll_node_t *msg_node; 1843 1844 if (!soc_feature(unit, soc_feature_uc)) { 1845 return (SOC_E_UNAVAIL); 1846 } 1847 1848 if ((soc == NULL) || ((soc->swIntrActive & (1 << uC)) == 0) || 1849 (soc->uc_msg_active[uC] == NULL)) { 1850 return (SOC_E_NONE); 1851 } 1852 1853 /* Block others for a bit */ 1854 if (sal_mutex_take(soc->uc_msg_control, soc->uc_msg_ctl_timeout)) { 1855 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1856 (BSL_META_U(unit, 1857 "UC%d semtake - uc_msg_control timed out\n"), uC)); 1858 return SOC_E_INTERNAL; 1859 } 1860 1861 /*Clear receive LL and set Semaphore count to 0*/ 1862 while( soc->uc_msg_rcvd_ll[uC][msg_class].ll_count ) { 1863 msg_node = (mos_msg_ll_node_t *)ll_remove_head(&(soc->uc_msg_rcvd_ll[uC][msg_class])); 1864 if (msg_node != NULL) { 1865 sal_free(msg_node); 1866 } 1867 /*Decrement the counting semaphore count to be in sync with LL*/ 1868 sal_sem_take(soc->uc_msg_rcv_sems[uC][msg_class], 10000000); 1869 }; 1870 1871 /* Kick the waiter */ 1872 sal_sem_give( soc->uc_msg_rcv_sems[uC][msg_class] ); 1873 1874 sal_mutex_give(soc->uc_msg_control); 1875 return (SOC_E_NONE); 1876 } 1877 1878 /* Function: 1879 * soc_cmic_uc_msg_send_receive 1880 * Purpose: 1881 * Send a message to another processor and wait for a reply 1882 * Parameters: 1883 * unit - unit number 1884 * uC - uC number 1885 * send - the 64-bit message to send 1886 * reply - the 64-bit reply 1887 * timeout - time to wait for reply 1888 * Returns: 1889 * SOC_E_NONE = message ACK'd (agent received msg) 1890 * SOC_E_xxx - message NAK'd (no agent or buffer space full or timeout) 1891 */ 1892 int soc_cmic_uc_msg_send_receive(int unit, int uC, mos_msg_data_t *send, 1893 mos_msg_data_t *reply, sal_usecs_t timeout) { 1894 int rc; 1895 1896 sal_usecs_t start = sal_time_usecs(); 1897 sal_usecs_t now, time_elapsed; 1898 1899 rc = soc_cmic_uc_msg_send(unit, uC, send, timeout); 1900 if (rc != SOC_E_NONE) { /* send failed */ 1901 return rc; 1902 } 1903 1904 now = sal_time_usecs(); 1905 /* Check for time rollover and adjust the timeout accordingly */ 1906 if (now > start) { 1907 time_elapsed = now - start; 1908 } else { 1909 time_elapsed = SAL_USECS_TIMESTAMP_ROLLOVER - start + now; 1910 } 1911 1912 if (timeout <= time_elapsed) { 1913 rc = SOC_E_TIMEOUT; 1914 LOG_VERBOSE(BSL_LS_SOC_COMMON, 1915 (BSL_META_U(unit, "UC%d time out\n"), uC)); 1916 } else if (rc == SOC_E_NONE) { /* If ack'd */ 1917 timeout -= time_elapsed; 1918 rc = soc_cmic_uc_msg_receive(unit, uC, send->s.mclass, reply, timeout); 1919 } 1920 1921 return (rc); 1922 } 1923 #if defined (INCLUDE_UC_ULINK) 1924 1925 uint8 *cmic_uc_link_dma_buffer; 1926 1927 int soc_cmic_uc_pkd_link_notify(int unit) 1928 { 1929 mos_msg_data_t send; 1930 int uc, rv = SOC_E_NONE; 1931 int word; 1932 int word_max; 1933 soc_ulink_pbm_msg_t ulink_msg; 1934 soc_info_t *si; 1935 soc_persist_t *sop; 1936 uint8 *buffer; 1937 int data_len; 1938 1939 sop = SOC_PERSIST(unit); 1940 si = &SOC_INFO(unit); 1941 1942 if( cmic_uc_link_dma_buffer == NULL) { 1943 cmic_uc_link_dma_buffer = soc_cm_salloc(unit, UC_LINK_DMA_BUFFER_LEN, 1944 "uC_LINK_BUFFER"); 1945 if(cmic_uc_link_dma_buffer == NULL) { 1946 return (BCM_E_MEMORY); 1947 } 1948 } 1949 buffer = cmic_uc_link_dma_buffer; 1950 1951 sal_memset(buffer, 0, UC_LINK_DMA_BUFFER_LEN); 1952 sal_memset(&ulink_msg, 0, sizeof(soc_ulink_pbm_msg_t)); 1953 sal_memset(&send, 0, sizeof(send)); 1954 1955 word_max = (si->port_addr_max + _SHR_PBMP_WORD_WIDTH) / _SHR_PBMP_WORD_WIDTH; 1956 word_max = (word_max <= UL_PBMP_WORD_MAX) ? word_max : UL_PBMP_WORD_MAX; 1957 1958 for(word = 0; word < word_max; word++) { 1959 ulink_msg.pbits[word] = sop->lc_pbm_link.pbits[word]; 1960 } 1961 ulink_msg.words = word_max; 1962 ulink_msg.flags = 0; 1963 buffer = shr_ulink_pbm_pack(buffer, &ulink_msg); 1964 1965 data_len = buffer - cmic_uc_link_dma_buffer; 1966 buffer = cmic_uc_link_dma_buffer; 1967 1968 LOG_INFO(BSL_LS_SOC_COMMON, 1969 (BSL_META_U(unit, 1970 "msg len %d si maxport %d, mywordmax %d,PBM maxword %d,sopbmp 0x%x\n" 1971 "active uc %d,%d,%d, max sizeof msg %d\n"), 1972 data_len, si->port_addr_max, 1973 word_max, _SHR_PBMP_WORD_MAX, sop->lc_pbm_link.pbits[0], 1974 UC_ULINK_IS_ACTIVE(0),UC_ULINK_IS_ACTIVE(1),UC_ULINK_IS_ACTIVE(CMICM_NUM_UCS-1), 1975 UC_LINK_DMA_BUFFER_LEN)); 1976 1977 send.s.mclass = MOS_MSG_CLASS_SYSTEM; 1978 send.s.subclass = MOS_MSG_SUBCLASS_SYSTEM_LINK; 1979 send.s.len = bcm_htons(data_len); 1980 send.s.data = bcm_htonl(soc_cm_l2p(unit, buffer)); 1981 1982 for(uc = 0; uc < SOC_INFO(unit).num_ucs; uc++) { 1983 if ((!soc_uc_in_reset(unit, uc)) && UC_ULINK_IS_ACTIVE(uc)) { 1984 1985 soc_cm_sflush(unit, buffer, data_len); 1986 soc_cm_sinval(unit, buffer, UC_LINK_DMA_BUFFER_LEN); 1987 1988 if (soc_cmic_uc_msg_active_wait(unit, uc) != SOC_E_NONE) { 1989 /* Down and not coming back up */ 1990 return (SOC_E_UNAVAIL); 1991 } 1992 /* Timeout in usec */ 1993 rv = soc_cmic_uc_msg_send(unit, uc, &send, 1000000); 1994 if (rv < 0) { 1995 LOG_INFO(BSL_LS_SOC_COMMON, 1996 (BSL_META_U(unit, "Uc %d, pbmp 0x%x word %d, rv %d\n"), 1997 uc, sop->lc_pbm_link.pbits[word], word, rv)); 1998 break; 1999 } 2000 } 2001 } 2002 return rv; 2003 } 2004 2005 #endif 2006 2007 2008 /* Function: 2009 * soc_cmic_uc_appl_init 2010 * Purpose: 2011 * Try to initialze an application on a UC 2012 * Parameters: 2013 * unit - unit number 2014 * uC - uC number 2015 * msg_class - application message class 2016 * timeout - time to wait for reply 2017 * version_info - version of the SDK-based application. The 2018 * contents of this are application dependent. 2019 * Common uses include passing a pointer to an 2020 * area to be DMA'd to the Uc, or passing a 2021 * simple version number. 2022 * min_appl_version - min version for the remote app 2023 * Returns: 2024 * SOC_E_NONE = message ACK'd (agent received msg) 2025 * SOC_E_UNAVAIL = Cannot init this app on this uC 2026 * SOC_E_CONFIG = Appl started but app is < min version 2027 */ 2028 int soc_cmic_uc_appl_init(int unit, int uC, int msg_class, 2029 sal_usecs_t timeout, uint32 version_info, 2030 uint32 min_appl_version, 2031 soc_cmic_uc_appl_cb_t *shutdown_cb, void *cb_data) 2032 { 2033 soc_control_t *soc = SOC_CONTROL(unit); 2034 mos_msg_data_t send, rcv; 2035 int rc; 2036 2037 if (!soc_feature(unit, soc_feature_uc)) { 2038 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2039 (BSL_META_U(unit, "feature unsupport\n"))); 2040 return (SOC_E_UNAVAIL); 2041 } 2042 2043 if (soc_cmic_uc_msg_active_wait(unit, uC) != SOC_E_NONE) { 2044 /* Down and not coming back up */ 2045 return (SOC_E_UNAVAIL); 2046 } 2047 2048 send.s.mclass = MOS_MSG_CLASS_SYSTEM; 2049 send.s.subclass = MOS_MSG_SUBCLASS_SYSTEM_APPL_INIT; 2050 send.s.len = soc_htons(msg_class); 2051 send.s.data = soc_htonl(version_info); 2052 2053 rc = soc_cmic_uc_msg_send(unit, uC, &send, timeout); 2054 if (rc != SOC_E_NONE) { 2055 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2056 (BSL_META_U(unit, "UC%d soc_cmic_uc_msg_send failed\n"), uC)); 2057 return(SOC_E_FAIL); 2058 } 2059 2060 rc = soc_cmic_uc_msg_receive(unit, uC, msg_class, &rcv, timeout); 2061 2062 if (rc != SOC_E_NONE) { 2063 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2064 (BSL_META_U(unit, "UC%d soc_cmic_uc_msg_receive failed\n"), uC)); 2065 return (SOC_E_UNAVAIL); 2066 } 2067 if (rcv.s.len != 0) { 2068 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2069 (BSL_META_U(unit, "UC%d soc_cmic_uc_msg_receive length != 0\n"), uC)); 2070 return (SOC_E_UNAVAIL); 2071 } 2072 2073 if (soc_ntohl(rcv.s.data) < min_appl_version) { 2074 LOG_VERBOSE(BSL_LS_SOC_COMMON, 2075 (BSL_META_U(unit, "UC%d appl version\n"), uC)); 2076 return (SOC_E_CONFIG); 2077 } 2078 2079 soc->uc_msg_appl_cb[uC][msg_class] = shutdown_cb; 2080 soc->uc_msg_appl_cb_data[uC][msg_class] = cb_data; 2081 #if defined(INCLUDE_PTP) 2082 if(MOS_MSG_CLASS_1588 == msg_class) { 2083 ptp_firmware_version = soc_ntohl(rcv.s.data); 2084 } 2085 #endif 2086 /* BS Msg Class */ 2087 if(MOS_MSG_CLASS_BS == msg_class) { 2088 bs_firmware_version = soc_ntohl(rcv.s.data); 2089 } 2090 #if defined(INCLUDE_BFD) 2091 if(msg_class == MOS_MSG_CLASS_BFD) { 2092 bfd_firmware_version = soc_ntohl(rcv.s.data); 2093 } 2094 #endif 2095 2096 #if defined(INCLUDE_BHH) 2097 if(msg_class == MOS_MSG_CLASS_BHH) { 2098 bhh_firmware_version = soc_ntohl(rcv.s.data); 2099 } 2100 #endif 2101 2102 #if defined(INCLUDE_ETH_LM_DM) 2103 if(msg_class == MOS_MSG_CLASS_ETH_LM_DM) { 2104 eth_lm_dm_firmware_version = soc_ntohl(rcv.s.data); 2105 } 2106 #endif 2107 #if defined(INCLUDE_MPLS_LM_DM) 2108 if(msg_class == MOS_MSG_CLASS_MPLS_LM_DM) { 2109 mpls_lm_dm_firmware_version = soc_ntohl(rcv.s.data); 2110 } 2111 #endif 2112 #if defined(INCLUDE_FLOWTRACKER) 2113 if(msg_class == MOS_MSG_CLASS_FT) { 2114 ft_msg_version = soc_ntohl(rcv.s.data); 2115 } 2116 #endif /* INCLUDE_FLOWTRACKER */ 2117 #if defined(INCLUDE_IFA) 2118 if(msg_class == MOS_MSG_CLASS_IFA) { 2119 ifa_firmware_version = soc_ntohl(rcv.s.data); 2120 } 2121 #endif /* INCLUDE_IFA */ 2122 #if defined(INCLUDE_TELEMETRY) 2123 if(msg_class == MOS_MSG_CLASS_ST) { 2124 st_firmware_version = soc_ntohl(rcv.s.data); 2125 } 2126 #endif /* INCLUDE_TELEMETRY */ 2127 #if defined(INCLUDE_INT) 2128 if(msg_class == MOS_MSG_CLASS_INT) { 2129 int_firmware_version = soc_ntohl(rcv.s.data); 2130 } 2131 #endif /* INCLUDE_INT */ 2132 #if defined(INCLUDE_SUM) 2133 if(msg_class == MOS_MSG_CLASS_SUM) { 2134 sum_firmware_version = soc_ntohl(rcv.s.data); 2135 } 2136 #endif /* INCLUDE_SUM */ 2137 return (SOC_E_NONE); 2138 } 2139 2140 /* Routine to determine the base address of the BroadSync Register cache on KT2 */ 2141 uint32 soc_cmic_bs_reg_cache(int unit, int bs_num) 2142 { 2143 uint32 msg_end = MSG_AREA_END(_soc_cmic_uc_msg_base(unit)); 2144 return msg_end + bs_num * sizeof(mos_msg_bs_reg_cache_t); 2145 } 2146 2147 2148 /* Internal routine to determine the base address of the timestamp data area */ 2149 uint32 soc_cmic_timestamp_base(int unit) 2150 { 2151 uint32 msg_end = MSG_AREA_END(_soc_cmic_uc_msg_base(unit)); 2152 if (SOC_IS_KATANA2(unit)) { 2153 /* KT2 has two BS register caches after the msg area, so skip over them */ 2154 return msg_end + 2 * sizeof(mos_msg_bs_reg_cache_t); 2155 } else { 2156 return msg_end; 2157 } 2158 } 2159 2160 2161 static uint64 uc_mem_read_64(int unit, unsigned addr) 2162 { 2163 uint32 hi = soc_uc_mem_read(unit, addr); 2164 uint32 lo = soc_uc_mem_read(unit, addr + 4); 2165 uint64 ret; 2166 2167 COMPILER_64_SET(ret, hi,lo); 2168 return ret; 2169 } 2170 2171 /* 2172 * Function: 2173 * soc_cmic_uc_msg_timestamp_get 2174 * Purpose: 2175 * Get most two most recent timestamps from a given source, and corresponding firmware time 2176 * Parameters: 2177 * unit - (IN) Unit number. 2178 * event_id - (IN) Index of desired timestamp event 2179 * ts_data - (OUT) Timestamp data 2180 * Returns: 2181 * SOC_E_PARAM - event_id is out of bounds 2182 * SOC_E_TIMEOUT - unable to read consistent timestamp data before timeout 2183 */ 2184 int 2185 soc_cmic_uc_msg_timestamp_get( 2186 int unit, 2187 int event_id, 2188 soc_cmic_uc_ts_data_t *ts_data) 2189 { 2190 uint64 read_ts[2] = {COMPILER_64_INIT(0,0)}; /* event timestamps as read from shared memory */ 2191 uint64 read_prev_ts[2] = {COMPILER_64_INIT(0,0)}; /* the preceeding ts of the same event */ 2192 uint64 read_ts0[2] = {COMPILER_64_INIT(0,0)}; /* TS0 corresponding to PTP time */ 2193 uint64 read_ts1[2] = {COMPILER_64_INIT(0,0)}; /* TS1 corresponding to PTP time */ 2194 soc_cmic_uc_time_t read_full_time[2] = {{COMPILER_64_INIT(0,0)}}; 2195 int32 event_ts_minus_ts0_nsec; 2196 int rv = SOC_E_NONE; 2197 uint32 timestamp_base = soc_cmic_timestamp_base(unit); 2198 const int max_iter = 100; 2199 int iter = 0; 2200 2201 if (event_id >= MOS_MSG_MAX_TS_EVENTS) { 2202 return SOC_E_PARAM; 2203 } 2204 2205 do { 2206 read_ts[1] = read_ts[0]; 2207 read_prev_ts[1] = read_prev_ts[0]; 2208 read_ts0[1] = read_ts0[0]; 2209 read_ts1[1] = read_ts1[0]; 2210 read_full_time[1] = read_full_time[0]; 2211 2212 /* Get from CMICM / IPROC shared memory */ 2213 read_full_time[0].seconds = uc_mem_read_64(unit, timestamp_base + 4); 2214 read_full_time[0].nanoseconds = soc_uc_mem_read(unit, timestamp_base + 12); 2215 2216 read_ts0[0] = uc_mem_read_64(unit, timestamp_base + 16); 2217 read_ts1[0] = uc_mem_read_64(unit, timestamp_base + 24); 2218 2219 read_ts[0] = uc_mem_read_64(unit, timestamp_base + 32 + 8 * event_id); 2220 read_prev_ts[0] = uc_mem_read_64(unit, timestamp_base + 32 + 8 * MOS_MSG_MAX_TS_EVENTS + 8 * event_id); 2221 2222 /* repeat until everything we care about comes out the same way twice */ 2223 /* to ensure that we didn't race the firmware updating the same data */ 2224 } while ((COMPILER_64_NE(read_full_time[0].seconds, read_full_time[1].seconds) || 2225 read_full_time[0].nanoseconds != read_full_time[1].nanoseconds || 2226 COMPILER_64_NE(read_ts[0], read_ts[1]) || 2227 COMPILER_64_NE(read_prev_ts[0], read_prev_ts[1]) || 2228 COMPILER_64_NE(read_ts1[0], read_ts1[1]) || 2229 COMPILER_64_NE(read_ts0[0], read_ts0[1])) && 2230 ++iter < max_iter); 2231 2232 if (iter == max_iter) { 2233 rv = SOC_E_TIMEOUT; 2234 /* don't exit- populate the fields with whatever we read, in case it is useful */ 2235 } 2236 2237 ts_data->hwts = read_ts[0]; 2238 ts_data->prev_hwts = read_prev_ts[0]; 2239 2240 /* ts_minus_ts0_nsec = (read_ts - read_ts0) */ 2241 event_ts_minus_ts0_nsec = COMPILER_64_LO(read_ts[0]) - COMPILER_64_LO(read_ts0[0]); 2242 2243 /* ts0/ts1/full timestamps are all for the same time. So, find offset from event timestamp 2244 * (made with timestamper0) from ts0, to compute event time in ts1 / full domains 2245 */ 2246 2247 /* Start with hwts_ts1 = read_ts1. Adjusted below by (ts - ts0) */ 2248 COMPILER_64_COPY(ts_data->hwts_ts1, read_ts1[0]); 2249 2250 /* Start with the time corresponding to ts0. Adjusted below by (ts - ts0) */ 2251 COMPILER_64_COPY(ts_data->time.seconds, read_full_time[0].seconds); 2252 ts_data->time.nanoseconds = read_full_time[0].nanoseconds; 2253 2254 if (event_ts_minus_ts0_nsec > 0) { 2255 /* Adjusting hwts_ts1 by (ts - ts0) */ 2256 COMPILER_64_ADD_32(ts_data->hwts_ts1, event_ts_minus_ts0_nsec); 2257 2258 /* Adjusting time by (ts - ts0) */ 2259 ts_data->time.nanoseconds += event_ts_minus_ts0_nsec; 2260 if (ts_data->time.nanoseconds > 1000000000) { 2261 ts_data->time.nanoseconds -= 1000000000; 2262 COMPILER_64_ADD_32(ts_data->time.seconds, 1); 2263 } 2264 } else { 2265 /* Adjusting hwts_ts1 by (ts - ts0) */ 2266 COMPILER_64_SUB_32(ts_data->hwts_ts1, -event_ts_minus_ts0_nsec); 2267 2268 /* Adjusting time by (ts - ts0) */ 2269 if (ts_data->time.nanoseconds < -event_ts_minus_ts0_nsec) { 2270 ts_data->time.nanoseconds += (1000000000 + event_ts_minus_ts0_nsec); 2271 COMPILER_64_SUB_32(ts_data->time.seconds, 1); 2272 } else { 2273 ts_data->time.nanoseconds += event_ts_minus_ts0_nsec; 2274 } 2275 } 2276 return rv; 2277 } 2278 2279 2280 /* 2281 * Function: 2282 * soc_cmic_uc_msg_timestamp_enable 2283 * Purpose: 2284 * Enable a specified timestamp event 2285 * Parameters: 2286 * unit - (IN) Unit number. 2287 * event_id - (IN) Index of desired timestamp event 2288 * Returns: 2289 * SOC_E_PARAM - event_id is out of bounds 2290 * Note: CPU-initiated capture is one-shot. All other events are simply enabled 2291 */ 2292 int 2293 soc_cmic_uc_msg_timestamp_enable( 2294 int unit, 2295 int event_id) 2296 { 2297 uint32 timestamp_base = soc_cmic_timestamp_base(unit); 2298 uint32 capture_reg; 2299 2300 capture_reg = soc_uc_mem_read(unit, timestamp_base); 2301 2302 if (soc_feature(unit, soc_feature_iproc)) { 2303 /* IPROC */ 2304 /* if (event_id > 18) { */ 2305 if (event_id >= MOS_MSG_MAX_TS_EVENTS) { 2306 return SOC_E_PARAM; 2307 } 2308 capture_reg |= (1 << event_id); 2309 } else { 2310 /* CMICM */ 2311 if (event_id > 12) { 2312 return SOC_E_PARAM; 2313 } 2314 capture_reg |= (1 << (event_id + 16)); 2315 } 2316 soc_uc_mem_write(unit, timestamp_base, capture_reg); 2317 2318 return SOC_E_NONE; 2319 } 2320 2321 2322 /* 2323 * Function: 2324 * soc_cmic_uc_msg_timestamp_disable 2325 * Purpose: 2326 * Disable a specified timestamp event, unless used by firmware 2327 * Parameters: 2328 * unit - (IN) Unit number. 2329 * event_id - (IN) Index of desired timestamp event 2330 * Returns: 2331 * SOC_E_PARAM - event_id is out of bounds 2332 */ 2333 int 2334 soc_cmic_uc_msg_timestamp_disable( 2335 int unit, 2336 int event_id) 2337 { 2338 uint32 timestamp_base = soc_cmic_timestamp_base(unit); 2339 uint32 capture_reg; 2340 2341 capture_reg = soc_uc_mem_read(unit, timestamp_base); 2342 2343 if (soc_feature(unit, soc_feature_iproc)) { 2344 /* IPROC */ 2345 /* if (event_id > 18) { */ 2346 if (event_id >= MOS_MSG_MAX_TS_EVENTS) { 2347 return SOC_E_PARAM; 2348 } 2349 capture_reg &= ~(1 << event_id); 2350 } else { 2351 /* CMICM */ 2352 if (event_id > 12) { 2353 return SOC_E_PARAM; 2354 } 2355 capture_reg &= ~(1 << (event_id + 16)); 2356 } 2357 2358 soc_uc_mem_write(unit, timestamp_base, capture_reg); 2359 2360 return SOC_E_NONE; 2361 } 2362 #else 2363 int uc_msg_c_file_not_empty; 2364 #endif /* CMICM or IPROC Support */