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

mbox.c (28153B)


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