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

rcpu.c (20260B)


      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  * Utility routines for RCPU packets encap/decap
      8  */
      9 
     10 #include <sal/core/libc.h>
     11 #include <shared/bsl.h>
     12 #include <soc/util.h>
     13 #include <soc/drv.h>
     14 
     15 #ifdef INCLUDE_RCPU
     16 
     17 #define SOC_RCPU_BENCHMARK     1
     18 #define MAX_RETRY_ATTEMPTS     3
     19 #define SOC_RCPU_F_INITED    0x1
     20 
     21 /* The data length of CMIC request packet */
     22 #define CMIC_REQUEST_DATA_LEN  0x8
     23 
     24 soc_rcpu_control_t   *soc_rcpu_control[SOC_MAX_NUM_DEVICES];
     25 
     26 #define SOC_RCPU_CONTROL(_unit)     soc_rcpu_control[_unit]
     27 #define RCPU_TRANS_PTR_SET(unit)    _rcpu_trans_ptr = CMVEC(unit).rcpu_tp;
     28 
     29 /*
     30  * Data format of CMIC request packet:
     31  * The first word of each pair is an address/operation word.
     32  * The bottom 24 bits of the word are the address in CMIC register space. 
     33  * The top 8 bits encode the operation type and the size of the request:
     34  * ED00 00SS
     35  * 0 bits are reserved and must be zero.
     36  * E is an error bit and must be 0 in a CMIC_REQUEST.
     37  * D is a direction bit (0 means read, 1 means write)
     38  * SS are the size of the operation (00 is reserved, 01 is 1 byte,
     39  *                                   10 is 2 bytes, 11 is 4 bytes)
     40  */
     41 #if defined(LE_HOST)
     42 #define CMIC_REQ_ADDR_OP_SET(ptr, addr, read_op) \
     43         (((uint32 *)(ptr))[0] = (soc_htonl(addr) | 0x3 |  \
     44                                  ((0 == read_op)? (1 << 6) : 0)))
     45 
     46 #define CMIC_REQ_VALUE_SET(ptr, read_op, val) \
     47         (((uint32 *)(ptr))[1] = ((0 == read_op)? soc_htonl(*val): 0))
     48 #else
     49 #define CMIC_REQ_ADDR_OP_SET(ptr, addr, read_op) \
     50         (((uint32 *)(ptr))[0] = (addr | 0x3000000 |  \
     51                                  ((0 == read_op)? (1 << 30): 0)))
     52 
     53 #define CMIC_REQ_VALUE_SET(ptr, read_op, val) \
     54         (((uint32 *)(ptr))[1] = ((0 == read_op)? *val: 0))
     55 #endif
     56 
     57 /***********************************************************
     58  *
     59  * Functions:
     60  *      _soc_rcpu_tp_rx
     61  * Purpose:
     62  *      Main entry for all received RCPU packets.
     63  *      1. Perform decapsulation to find which unit this packet belongs to.
     64  *      2. Handle SCHAN or CMIC reply packets.
     65  *      3. Disptach ToCPU and Interrupt packets.
     66  *
     67  * Parameters:
     68  *      rx_unit     - (IN) Recevie tp unit number
     69  *      pkt         - (IN) Packet buffer where to decap header
     70  *      pkt_len     - (IN) Packet length
     71  *      cookie      - (IN) Callback cookie
     72  * Returns:
     73  *      SOC_E_NONE
     74  *      -1 : Not RCPU packets or error case
     75  * Notes:
     76  *      Assumes buffers are valid and contain enough memory space.
     77  */
     78 STATIC int 
     79 _soc_rcpu_tp_rx(int rx_unit, uint8 *pkt, int pkt_len, void *cookie)
     80 {
     81     int unit;
     82     rcpu_encap_info_t info;
     83 
     84     SOC_IF_ERROR_RETURN(soc_rcpu_decap(pkt, &unit, &info));
     85 
     86     if (NULL == SOC_RCPU_CONTROL(unit)) {
     87         /* Not initialized */
     88         return -1;
     89     }
     90 
     91     if ((SOC_RCPU_OP_SCHAN_REPLY == info.operation) ||
     92         (SOC_RCPU_OP_CMIC_REPLY == info.operation)) {
     93 
     94         if (info.flags & SOC_RCPU_FLAG_BUSY) {
     95             if (LOG_CHECK(BSL_LS_SOC_RCPU | BSL_INFO)) {
     96                 LOG_CLI((BSL_META_U(unit,
     97                                     "****RCPU REPLY BUSY****\n")));
     98             }
     99             /* Let it timeout and retry. */
    100             return -1;
    101         }
    102 
    103         /* 
    104          * Check Fail flag 
    105          *     If FAIL, then set length appropriately
    106          */
    107         if (info.flags & SOC_RCPU_FLAG_FAIL) {
    108             if (LOG_CHECK(BSL_LS_SOC_RCPU | BSL_INFO)) {
    109                 LOG_CLI((BSL_META_U(unit,
    110                                     "****RCPU REPLY FAIL****\n")));
    111                 soc_dma_ether_dump(unit, "RCPU_REP ", pkt, pkt_len, 0);
    112             }
    113             info.datalen = pkt_len - info.cmic_hdr_size;
    114         }
    115 
    116         if (++info.transid == SOC_RCPU_CONTROL(unit)->transid) {
    117             sal_memcpy(SOC_RCPU_CONTROL(unit)->reply_data, 
    118                        pkt + info.cmic_hdr_size,
    119                        info.datalen);
    120             if (SOC_RCPU_CONTROL(unit)->schan_reply) {
    121                 sal_sem_give(SOC_RCPU_CONTROL(unit)->schan_reply);
    122             }
    123         }
    124         return SOC_E_NONE;
    125     }
    126 
    127     /* Handle ToCPU packets */
    128     if (SOC_RCPU_OP_TOCPU_PKT == info.operation) {
    129         if (SOC_RCPU_CONTROL(unit)->tocpu_cb != NULL) {
    130             SOC_RCPU_CONTROL(unit)->tocpu_cb(unit, pkt, pkt_len, &info);
    131         }
    132         return SOC_E_NONE;
    133     }
    134 
    135 #ifdef BCM_CMICM_SUPPORT
    136     /* Handle Remote Interrupt packets */
    137     if (SOC_RCPU_OP_INTR_PKT == info.operation) {
    138         soc_cmicm_rcpu_intr(unit, (soc_rcpu_intr_packet_t *)(pkt + info.cmic_hdr_size));
    139         return SOC_E_NONE;
    140     }
    141 #endif /* BCM_CMICM_SUPPORT */
    142 
    143     return -1;
    144 
    145 }
    146 
    147 /***********************************************************
    148  *
    149  * Functions:
    150  *      soc_rcpu_encap
    151  * Purpose:
    152  *      Encap RCPU CMIC header into the buffer
    153  * 
    154  * Parameters:
    155  *      unit        - (IN) device number
    156  *      buf         - (IN) Buffer where to encap header.
    157  *      info        - (IN) Encap CMIC packet header information.
    158  * Returns:
    159  *      SOC_E_NONE
    160  *      SOC_E_PARAM
    161  * Notes:
    162  *      Assumes buffers are valid and contain enough memory space.
    163  */
    164 int 
    165 soc_rcpu_encap(int unit, uint8 *buf, rcpu_encap_info_t *info)
    166 {
    167     soc_rcpu_cfg_t rcpu_cfg;
    168     rcpu1_cmic_pkt_hdr_t *hdr = (rcpu1_cmic_pkt_hdr_t *)buf;
    169 
    170     if (!SOC_IS_RCPU_ONLY(unit)) {
    171         return SOC_E_PARAM;
    172     }
    173 
    174     SOC_IF_ERROR_RETURN(soc_cm_get_rcpu_cfg(unit, &rcpu_cfg));
    175 
    176     sal_memcpy(hdr->dst_mac, rcpu_cfg.dst_mac, 6);
    177     sal_memcpy(hdr->src_mac, rcpu_cfg.src_mac, 6);
    178     hdr->tpid = soc_htons(rcpu_cfg.tpid);
    179     hdr->vlan = soc_htons(rcpu_cfg.vlan);
    180     hdr->ethertype = soc_htons(rcpu_cfg.ether_type);
    181     hdr->signature = soc_htons(rcpu_cfg.signature);
    182 
    183     hdr->operation = info->operation;
    184     hdr->flags = info->flags;
    185     hdr->transid = soc_htons(info->transid);
    186     hdr->datalen = soc_htons(info->datalen);
    187     hdr->replen = soc_htons(info->replen);
    188     hdr->reserved = 0;
    189 
    190     return SOC_E_NONE;
    191 }
    192 
    193 /***********************************************************
    194  * RCPU CMIC header Decap
    195  *
    196  * Functions:
    197  *      soc_rcpu_decap
    198  * Purpose:
    199  *      Parse input buffer and decide to which device number
    200  *      it should go.
    201  * Parameters:
    202  *      buf   - (IN)  Buffer where to decap message.
    203  *      runit - (OUT) Device unit number to which this message belogs.
    204  *      info  - (OUT) Decap CMIC packet header information.
    205  *
    206  * Returns:
    207  *      SOC_E_NONE
    208  *      SOC_E_NOT_FOUND
    209  * Notes:
    210  *      Assumes pointers are valid and contain enough memory space.
    211  */
    212 int
    213 soc_rcpu_decap(uint8 *buf, int *runit, rcpu_encap_info_t *info)
    214 {
    215     int rv, unit;
    216     soc_rcpu_cfg_t rcpu_cfg;
    217     rcpu1_cmic_pkt_hdr_t *hdr = (rcpu1_cmic_pkt_hdr_t *)buf;
    218 
    219     for (unit = 0; unit < soc_cm_get_num_devices(); unit++) {
    220 
    221         if (!SOC_IS_RCPU_ONLY(unit)) {
    222             continue;
    223         }
    224 
    225         rv = soc_cm_get_rcpu_cfg(unit, &rcpu_cfg);
    226 
    227         if (SOC_E_NONE != rv) {
    228             continue;
    229         }
    230 
    231         if (sal_memcmp(buf+6, rcpu_cfg.dst_mac, 6)) {
    232             continue;
    233         }
    234 
    235         if (rcpu_cfg.tpid != soc_ntohs(hdr->tpid) &&
    236             rcpu_cfg.ether_type != soc_ntohs(hdr->tpid)) {
    237             continue;
    238         }
    239 
    240         info->cmic_hdr_size = sizeof(rcpu1_cmic_pkt_hdr_t);
    241 
    242         if (rcpu_cfg.tpid == soc_ntohs(hdr->tpid)) {
    243             if ((rcpu_cfg.vlan != soc_ntohs(hdr->vlan)) ||
    244                 (rcpu_cfg.ether_type != soc_ntohs(hdr->ethertype))) {
    245                 /* Could be double tagged */
    246                 hdr = (rcpu1_cmic_pkt_hdr_t *)(buf + 4);
    247                 if (rcpu_cfg.ether_type != soc_ntohs(hdr->ethertype)) {
    248                     continue;
    249                 }
    250                 info->cmic_hdr_size += 4;
    251             }
    252         } else {
    253             /* Could have no vlan tag. */
    254             info->cmic_hdr_size -= 4;
    255             hdr = (rcpu1_cmic_pkt_hdr_t *)(buf - 4);
    256         }
    257 
    258         if (rcpu_cfg.signature != soc_ntohs(hdr->signature)) {
    259             continue;
    260         }
    261 
    262         info->operation = hdr->operation;
    263         info->flags = hdr->flags;
    264         info->transid = soc_ntohs(hdr->transid);
    265         info->datalen = soc_ntohs(hdr->datalen);
    266         if (hdr->operation == SOC_RCPU_OP_TOCPU_PKT) {
    267             /* Count dcb size */
    268             info->dcb_size = (SOC_DCB_SIZE(unit) == 64)? 64:32;
    269         } else {
    270             info->dcb_size = 0;
    271         }
    272         *runit = unit;
    273         return SOC_E_NONE;
    274     }
    275     return SOC_E_NOT_FOUND;
    276 }
    277 
    278 /*
    279  * Function:
    280  *      soc_rcpu_init
    281  * Purpose:
    282  *      Initialize RCPU master units before BCM module init so each bcm module
    283  *      can access s-channel registers/tables via RCPU mechanism
    284  * Parameters:
    285  *      unit - (IN) unit number
    286  * Returns:
    287  *      SOC_E_XXX
    288  */
    289 int
    290 soc_rcpu_init(int unit)
    291 {
    292     int                 rv = SOC_E_NONE;
    293     rcpu_trans_ptr_t    *_rcpu_trans_ptr;
    294 
    295     if (!SOC_UNIT_VALID(unit)){
    296         return SOC_E_UNIT;
    297     }
    298 
    299     if (!soc_feature(unit, soc_feature_rcpu_1)) {
    300         return SOC_E_NONE;
    301     }
    302 
    303     if (SOC_RCPU_CONTROL(unit) &&
    304        (SOC_RCPU_CONTROL(unit)->flags & SOC_RCPU_F_INITED)) {
    305         return SOC_E_NONE;
    306     }
    307 
    308     if (SOC_RCPU_CONTROL(unit) == NULL) {
    309         SOC_RCPU_CONTROL(unit) = sal_alloc(sizeof(soc_rcpu_control_t), 
    310                                            "soc_rcpu_control");
    311         if (SOC_RCPU_CONTROL(unit) == NULL) {
    312             return SOC_E_MEMORY;
    313         }
    314         sal_memset(SOC_RCPU_CONTROL(unit), 0, sizeof(soc_rcpu_control_t));
    315 
    316         SOC_RCPU_CONTROL(unit)->lock = sal_mutex_create("rcpu_unit_mutex");
    317         if (SOC_RCPU_CONTROL(unit)->lock == NULL) {
    318             LOG_ERROR(BSL_LS_SOC_RCPU,
    319                       (BSL_META_U(unit,
    320                                   "soc_rcpu_init: Failed to create mutex.\n")));
    321             return SOC_E_MEMORY;
    322         }
    323 
    324         if ((SOC_RCPU_CONTROL(unit)->schan_reply =
    325                 sal_sem_create("RCPU SCHAN", sal_sem_BINARY, 0)) == NULL) {
    326             LOG_ERROR(BSL_LS_SOC_RCPU,
    327                       (BSL_META_U(unit,
    328                                   "soc_rcpu_init: Failed to create semaphore.\n")));
    329             return SOC_E_MEMORY;
    330         }
    331     }
    332 
    333     RCPU_TRANS_PTR_SET(unit);
    334     rv = _rcpu_trans_ptr->rcpu_tp_rx_register(_rcpu_trans_ptr->tp_unit,
    335                                               _soc_rcpu_tp_rx,
    336                                               NULL);
    337 
    338     if (SOC_SUCCESS(rv)) {
    339         _rcpu_trans_ptr->ref_count++;
    340     }
    341 
    342     if (SOC_IS_RCPU_ONLY(unit)) {
    343         soc_rcpu_schan_op_register(unit, soc_rcpu_schan_op);
    344     }
    345 
    346     SOC_RCPU_CONTROL(unit)->flags |= SOC_RCPU_F_INITED;
    347 
    348     return rv;
    349 }
    350 /*
    351  * Function:
    352  *      soc_rcpu_deinit
    353  * Purpose:
    354  *      Deinitialize resources of RCPU master units
    355  * Parameters:
    356  *      unit - (IN) unit number
    357  * Returns:
    358  *      SOC_E_XXX
    359  */
    360 int
    361 soc_rcpu_deinit(int unit)
    362 {
    363     rcpu_trans_ptr_t *_rcpu_trans_ptr;
    364 
    365     if (!SOC_UNIT_VALID(unit)){
    366         return SOC_E_UNIT;
    367     }
    368 
    369     if (!soc_feature(unit, soc_feature_rcpu_1)) {
    370         return SOC_E_NONE;
    371     }
    372 
    373     (void)soc_rcpu_schan_op_unregister(unit);
    374 
    375     if (SOC_RCPU_CONTROL(unit)) {
    376 
    377         RCPU_TRANS_PTR_SET(unit);
    378 
    379         if (_rcpu_trans_ptr->ref_count > 0) {
    380             _rcpu_trans_ptr->ref_count--;
    381             if (0 == _rcpu_trans_ptr->ref_count) {
    382                 _rcpu_trans_ptr->rcpu_tp_rx_unregister(_rcpu_trans_ptr->tp_unit,
    383                                                        _soc_rcpu_tp_rx);
    384             }
    385         }
    386 
    387         if (SOC_RCPU_CONTROL(unit)->lock) {
    388             sal_mutex_destroy(SOC_RCPU_CONTROL(unit)->lock);
    389         }
    390 
    391         if (SOC_RCPU_CONTROL(unit)->schan_reply) {
    392             sal_sem_destroy(SOC_RCPU_CONTROL(unit)->schan_reply);
    393         }
    394 
    395         sal_free(SOC_RCPU_CONTROL(unit));
    396         SOC_RCPU_CONTROL(unit) = NULL;
    397     }
    398 
    399     return SOC_E_NONE;
    400 }
    401 
    402 /*
    403  * Function:
    404  *      soc_rcpu_tocpu_cb_register
    405  * Purpose:
    406  *      Registers ToCPU packet handler
    407  * Parameters:
    408  *      unit - SOC unit #
    409  *      f    - (IN) Function to be called for ToCPU packets
    410  * Returns:
    411  *      SOC_E_XXX
    412  */
    413 int
    414 soc_rcpu_tocpu_cb_register(int unit, rcpu_tocpu_cb_f f)
    415 {
    416     if (!SOC_IS_RCPU_UNIT(unit) && !SOC_IS_RCPU_ONLY(unit)) {
    417         return SOC_E_UNAVAIL;
    418     }
    419 
    420     if (SOC_RCPU_CONTROL(unit) == NULL) {
    421         return SOC_E_INIT;
    422     }
    423 
    424     if (NULL == f) {
    425         return SOC_E_PARAM;
    426     }
    427 
    428     SOC_RCPU_CONTROL(unit)->tocpu_cb = f;
    429 
    430     return SOC_E_NONE;
    431 }
    432 
    433 /*
    434  * Function:
    435  *      soc_rcpu_tocpu_cb_unregister
    436  * Purpose:
    437  *      Unregisters ToCPU packet handler
    438  *
    439  * Parameters:
    440  *      unit - SOC unit #
    441  * Returns:
    442  *      SOC_E_XXX
    443  */
    444 int
    445 soc_rcpu_tocpu_cb_unregister(int unit)
    446 {
    447     if (!SOC_IS_RCPU_UNIT(unit) && !SOC_IS_RCPU_ONLY(unit)) {
    448         return SOC_E_UNAVAIL;
    449     }
    450 
    451     if (SOC_RCPU_CONTROL(unit) == NULL) {
    452         return SOC_E_INIT;
    453     }
    454 
    455     SOC_RCPU_CONTROL(unit)->tocpu_cb = NULL;
    456 
    457     return SOC_E_NONE;
    458 }
    459 /*
    460  * Function:
    461  *      soc_rcpu_schan_op
    462  * Purpose:
    463  *      RCPU version of soc_schan_op function
    464  *
    465  * Returns:
    466  *      SOC_E_XXX
    467  */
    468 int
    469 soc_rcpu_schan_op(int unit, schan_msg_t *msg, int dwc_write, int dwc_read)
    470 {
    471     uint8 *tx_buf;
    472     uint32 *buf_ptr;
    473     int i, rcpu_schan_pkt_len = 0;
    474     int rv = SOC_E_NONE, num_retries;
    475     rcpu_encap_info_t info;
    476 #if defined(SOC_RCPU_BENCHMARK)
    477     sal_usecs_t         time_start = 0;
    478     sal_usecs_t         time_end = 0;
    479 #endif /* SOC_RCPU_BENCHMARK */
    480     rcpu_trans_ptr_t *_rcpu_trans_ptr;
    481 
    482     if (SOC_RCPU_CONTROL(unit) == NULL) {
    483         return SOC_E_INIT;
    484     }
    485 
    486 #if defined(SOC_RCPU_BENCHMARK)
    487     if (LOG_CHECK(BSL_LS_SOC_RCPU | BSL_INFO) &&
    488         LOG_CHECK(BSL_LS_SOC_SCHAN | BSL_INFO)) {
    489         time_start = sal_time_usecs();
    490     }
    491 #endif /* SOC_RCPU_BENCHMARK */
    492 
    493     rcpu_schan_pkt_len = sizeof(rcpu1_cmic_pkt_hdr_t) + 4 * dwc_write;
    494     rcpu_schan_pkt_len = (rcpu_schan_pkt_len < ENET_MIN_PKT_SIZE)? ENET_MIN_PKT_SIZE:rcpu_schan_pkt_len;
    495 
    496     info.datalen = 4 * dwc_write;
    497     info.flags = SOC_RCPU_FLAG_REPLY;
    498     info.operation = SOC_RCPU_OP_SCHAN_REQ;
    499     /* If dwc_read is 0, get a SCHAN_REPLY as an ACK (1 word) */
    500     info.replen = dwc_read ? 4 * dwc_read : 4;
    501 
    502     SCHAN_LOCK(unit);
    503 
    504     info.transid = SOC_RCPU_CONTROL(unit)->transid++;
    505 
    506     RCPU_TRANS_PTR_SET(unit);
    507 
    508     for (num_retries = 0; num_retries < MAX_RETRY_ATTEMPTS; num_retries++) {
    509 
    510         _rcpu_trans_ptr->rcpu_tp_data_alloc(_rcpu_trans_ptr->tp_unit,
    511                                         rcpu_schan_pkt_len,
    512                                         (void*)&tx_buf);
    513 
    514         if (!tx_buf) {
    515             SCHAN_UNLOCK(unit);
    516             return SOC_E_MEMORY;
    517         }
    518 
    519         /* Construct CMIC header */
    520         soc_rcpu_encap(unit, tx_buf, &info);
    521 
    522         buf_ptr = (uint32 *)(tx_buf + sizeof(rcpu1_cmic_pkt_hdr_t));
    523 
    524         for (i = 0; i < dwc_write; i++) {
    525             buf_ptr[i] = soc_htonl(msg->dwords[i]);
    526         }
    527 
    528         _rcpu_trans_ptr->rcpu_tp_tx(_rcpu_trans_ptr->tp_unit,
    529                                     (void*)tx_buf,
    530                                     rcpu_schan_pkt_len,
    531                                     NULL);
    532 
    533         if (sal_sem_take(SOC_RCPU_CONTROL(unit)->schan_reply, 
    534                          SOC_CONTROL(unit)->schanTimeout) == 0) {
    535             uint32 *pdata = (uint32 *)SOC_RCPU_CONTROL(unit)->reply_data;
    536             for (i = 0; i < dwc_read; i++) {
    537                 msg->dwords[i] = soc_ntohl(pdata[i]);
    538             }
    539             rv = SOC_E_NONE;
    540             break;
    541         } else {
    542             rv = SOC_E_TIMEOUT;
    543         }
    544     }
    545 
    546     SCHAN_UNLOCK(unit);
    547 
    548 #if defined(SOC_RCPU_BENCHMARK)
    549     if (LOG_CHECK(BSL_LS_SOC_RCPU | BSL_INFO) &&
    550         LOG_CHECK(BSL_LS_SOC_SCHAN | BSL_INFO)) {
    551         time_end = sal_time_usecs();
    552         LOG_CLI((BSL_META_U(unit,
    553                             "RCPU schan-op (%d, %d) took %d usecs\n"),
    554                  dwc_write, dwc_read, SAL_USECS_SUB(time_end, time_start)));
    555     }
    556 #endif /* SOC_RCPU_BENCHMARK */
    557 
    558     return rv;
    559 }
    560 
    561 #ifdef BCM_CMICM_SUPPORT
    562 /*
    563  * Functions:
    564  *      _soc_rcpu_cmic_op
    565  * Purpose:
    566  *      Handling CMIC request packets
    567  * Parameters:
    568  *      unit    - (IN) device number
    569  *      read_op - (IN) 1 = read operation; 0 = write operation
    570  *      addr    - (IN) CMIC address to access
    571  *      val32   - (IN/OUT) Input for write operation; Output for read operation
    572  *
    573  * Returns:
    574  *      SOC_E_XXXE
    575  */
    576 STATIC int 
    577 _soc_rcpu_cmic_op(int unit, int read_op, uint32 addr, uint32 *val32)
    578 {
    579     uint8  *tx_buf;
    580     uint32 *addr_ptr;
    581     int rcpu_cmic_pkt_len = 0;
    582     int rv = SOC_E_NONE, num_retries;
    583     rcpu_encap_info_t info;
    584 #if defined(SOC_RCPU_BENCHMARK)
    585     sal_usecs_t         time_start = 0;
    586     sal_usecs_t         time_end = 0;
    587 #endif /* SOC_RCPU_BENCHMARK */
    588     rcpu_trans_ptr_t *_rcpu_trans_ptr;
    589 
    590     if (SOC_RCPU_CONTROL(unit) == NULL) {
    591         return SOC_E_INIT;
    592     }
    593 
    594     if (!soc_feature(unit, soc_feature_cmicm)) {
    595         return SOC_E_UNIT;
    596     }
    597 
    598 #if defined(SOC_RCPU_BENCHMARK)
    599     if (LOG_CHECK(BSL_LS_SOC_RCPU | BSL_INFO) &&
    600         LOG_CHECK(BSL_LS_SOC_PCI | BSL_INFO)) {
    601         time_start = sal_time_usecs();
    602     }
    603 #endif /* SOC_RCPU_BENCHMARK */
    604 
    605     /* Use minimum size since the packet length for one operation is 40 bytes. */
    606     rcpu_cmic_pkt_len = ENET_MIN_PKT_SIZE;
    607 
    608     info.datalen = CMIC_REQUEST_DATA_LEN;
    609     info.flags = SOC_RCPU_FLAG_REPLY;
    610     info.operation = SOC_RCPU_OP_CMIC_REQ;
    611     /* Reply length must be the same value as datalen */
    612     info.replen = CMIC_REQUEST_DATA_LEN;
    613 
    614     SCHAN_LOCK(unit);
    615 
    616     info.transid = SOC_RCPU_CONTROL(unit)->transid++;
    617 
    618     RCPU_TRANS_PTR_SET(unit);
    619 
    620     for (num_retries = 0; num_retries < MAX_RETRY_ATTEMPTS; num_retries++) {
    621 
    622         _rcpu_trans_ptr->rcpu_tp_data_alloc(_rcpu_trans_ptr->tp_unit,
    623                                         rcpu_cmic_pkt_len,
    624                                         (void*)&tx_buf);
    625 
    626         if (!tx_buf) {
    627             LOG_ERROR(BSL_LS_SOC_RCPU,
    628                       (BSL_META_U(unit,
    629                                   "rcpu_cmic_read: Failed to allocate memory.\n")));
    630             SCHAN_UNLOCK(unit);
    631             return SOC_E_MEMORY;
    632         }
    633 
    634         /* Construct CMIC header */
    635         rv = soc_rcpu_encap(unit, tx_buf, &info);
    636 
    637         addr_ptr = (uint32 *)(tx_buf + sizeof(rcpu1_cmic_pkt_hdr_t));
    638 
    639         CMIC_REQ_ADDR_OP_SET(addr_ptr, addr, read_op);
    640 
    641         CMIC_REQ_VALUE_SET(addr_ptr, read_op, val32);
    642 
    643         rv = _rcpu_trans_ptr->rcpu_tp_tx(_rcpu_trans_ptr->tp_unit,
    644                                     (void*)tx_buf,
    645                                     rcpu_cmic_pkt_len,
    646                                     NULL);
    647 
    648         if (sal_sem_take(SOC_RCPU_CONTROL(unit)->schan_reply,
    649                          SOC_CONTROL(unit)->schanTimeout) == 0) {
    650             uint32 *pdata = (uint32 *)SOC_RCPU_CONTROL(unit)->reply_data;
    651             *val32 = soc_ntohl(pdata[1]);
    652             rv = SOC_E_NONE;
    653             break;
    654         } else {
    655             rv = SOC_E_TIMEOUT;
    656         }
    657     }
    658 
    659     SCHAN_UNLOCK(unit);
    660 
    661 #if defined(SOC_RCPU_BENCHMARK)
    662     if (LOG_CHECK(BSL_LS_SOC_RCPU | BSL_INFO) &&
    663         LOG_CHECK(BSL_LS_SOC_PCI | BSL_INFO)) {
    664         time_end = sal_time_usecs();
    665         LOG_CLI((BSL_META_U(unit,
    666                             "RCPU cmic-op took %d usecs\n"), 
    667                  SAL_USECS_SUB(time_end, time_start)));
    668     }
    669 #endif /* SOC_RCPU_BENCHMARK */
    670 
    671     return rv;
    672 }
    673 /*
    674  * Functions:
    675  *      _soc_rcpu_cmic_op
    676  * Purpose:
    677  *      RCPU version for CMIC read operation
    678  * Parameters:
    679  *      unit    - (IN) device number
    680  *      addr    - (IN) CMIC address to access
    681  *
    682  * Returns:
    683  *      Register value or zero
    684  */
    685 uint32
    686 soc_rcpu_cmic_read(int unit, uint32 addr)
    687 {
    688     int rv;
    689     uint32 data;
    690 
    691     rv = _soc_rcpu_cmic_op(unit, 1, addr, &data);
    692 
    693     return (SOC_E_NONE == rv)? data : 0;
    694 }
    695 /*
    696  * Functions:
    697  *      soc_rcpu_cmic_write
    698  * Purpose:
    699  *      RCPU version for CMIC write operation
    700  * Parameters:
    701  *      unit    - (IN) device number
    702  *      addr    - (IN) CMIC address to access
    703  *      data    - (IN) Data to write
    704  *
    705  * Returns:
    706  *      SOC_E_XXXE
    707  */
    708 int
    709 soc_rcpu_cmic_write(int unit, uint32 addr, uint32 data)
    710 {
    711     _soc_rcpu_cmic_op(unit, 0, addr, &data);
    712     return 0;
    713 }
    714 #endif /* BCM_CMICM_SUPPORT */
    715 
    716 #endif /* INCLUDE_RCPU */