openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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 */