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

traverse.c (54154B)


      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  * File:        traverse.c
      8  * Purpose:     RLINK traverse server
      9  *
     10  * The RLINK traverse server provides a way for RPC clients to execute
     11  * a BCM traverse API on an RPC server and receive callback data via
     12  * the client's traverse function.
     13  *
     14  * The implementation of this server uses a RLINK based protocol where
     15  * the RPC client issues a request and receives a reply from the
     16  * traverse server.
     17  *
     18  * The traverse server only processes one traverse request at a time.
     19  * The traverse API is executed on the server for the duration of the
     20  * client execution, so any blockable resources that the server
     21  * traverse requests will remain blocked for the entire duration.
     22  *
     23  * If a new traverse request is received while a traverse is
     24  * executing, then that request is queued, and will be executed in order
     25  * with any other outstanding teaverse requests.
     26  *
     27  * Traverse clients may have multiple traverses simultaneously.
     28  *
     29  * RLINK traverse protocol uses a standard RLINK message header
     30  * (msg,type,unit) followed by a client-id and message data
     31  * appropriate for the traverse message type.
     32  *
     33  * <msg><type><unit><c-id><s-id><msg-data>
     34  *
     35  * RLINK MSG: RLINK_MSG_TRAVERSE
     36  *
     37  * RLINK traverse message types
     38  *
     39  *   START  C>S <traverse-id><traverse-arguments>
     40  *   NEXT   C>S <none>
     41  *   QUIT   C>S <error-code><none>
     42  *
     43  *   ERROR  S>C <error-code>
     44  *   MORE   S>C <error-code><cb-count><callback-arguments>
     45  *   DONE   S>C <error-code><cb-count><callback-arguments>
     46  *
     47  * Protocol revision:
     48  *   Delivered protocol message contents are fixed. If there needs to be
     49  *   protocol extensions, then new message types are added.
     50  */
     51 
     52 /* traverse server resources
     53 
     54    server lock
     55    server request queue
     56    server semaphore
     57    server thread
     58 */
     59 
     60 #include <shared/bsl.h>
     61 
     62 #include <assert.h>
     63 #include <sal/core/time.h>
     64 #include <sal/core/sync.h>
     65 #include <sal/core/thread.h>
     66 #include <sal/core/alloc.h>
     67 #include <bcm/types.h>
     68 #include <bcm_int/rpc/pack.h>
     69 #include <bcm_int/rpc/rlink.h>
     70 #include <bcm_int/control.h>
     71 #include <appl/cpudb/cpudb.h>
     72 #include <appl/cputrans/atp.h>
     73 #include "rlink.h"
     74 #include "traverse.h"
     75 #include "traverse_key.h"
     76 
     77 #if !defined(BCM_RXP_DEBUG)
     78 #define bcm_rx_pool_own(b,s)
     79 #endif
     80 
     81 #ifdef	BCM_RPC_SUPPORT
     82 
     83 /* RLINK TRAVERSE OPTIONS
     84 
     85 RLINK_TRAV_THREADED_SERVER
     86 
     87   TRUE:
     88 
     89     Traverse requests are handled by a threaded server that handles
     90     each traverse API call as a co-routine.
     91 
     92   FALSE:
     93   
     94     Traverse requests are handled by calling the traverse API,
     95     buffering the output, and serving this buffer in pieces.
     96 
     97   This is a memory/performance/complexity tradeoff. The threaded
     98   server is more complex, but incurs less memory overhead on the
     99   server. Because the traverse runs in its own thread context, not the
    100   RPC server thread context, calling BCM APIs (via RPC) from within a
    101   remote traverse call to the same unit being traversed can lead to
    102   deadlock if the traverse API holds a lock, and the API being called
    103   over RPC also takes the same lock. There's no good way to know
    104   beforehand if this situation will arise, so it's best to avoid
    105   calling BCM modules recursively in this fashion.
    106 
    107   The non-threaded server required a memory buffer that can
    108   accommodate the *RPC response* for the entire table. This is likely
    109   to be larger than the actual table size. Because the entire traverse
    110   is executed on the remote unit before callbacks are make, the
    111   non-threaded server is not susceptible to deadlock.
    112 
    113 RLINK_TRAVERSE_MAX_REQ_LEN
    114 
    115   This is the maximum size expected for a traverse request. This
    116   typically does not need to change from the defined value.
    117 
    118 RLINK_TRAVERSE_MAX_REPLY_LEN
    119 
    120   This is the maximum size expected for a traverse request. For the
    121   threaded server, this allows a tradeoff between duration and latency;
    122   larger buffers are expected to reduce overall traverse duration due
    123   to communication overhead, at the expense of latency at receiving the
    124   buffers.
    125 
    126 RLINK_TRAVERSE_BUFFER_SIZE
    127 
    128   This is the maximum size expected for a non-threaded traverse
    129   buffer.  Ignored for a threaded server implementation.
    130 
    131 RLINK_TRAV_THREAD_STACK
    132 
    133   Size of the traverse thread stack. Ignored for a non-threaded server
    134   implementation.
    135   
    136 RLINK_TRAV_THREAD_PRIO
    137 
    138   Priority of the traverse thread. Ignored for a non-threaded server
    139   implementation.
    140   
    141 
    142 */
    143 
    144 #ifndef RLINK_TRAV_THREADED_SERVER
    145 #define RLINK_TRAV_THREADED_SERVER 1
    146 #endif
    147 
    148 /*
    149  * Maximum request and reply lengths
    150  */
    151 #ifndef RLINK_TRAVERSE_MAX_REPLY_LEN
    152 #define RLINK_TRAVERSE_MAX_REPLY_LEN 12*1024
    153 #endif
    154 
    155 #ifndef RLINK_TRAVERSE_MAX_REQ_LEN
    156 #define RLINK_TRAVERSE_MAX_REQ_LEN RLINK_TRAVERSE_MAX_REPLY_LEN
    157 #endif
    158 
    159 #define TRAVS_MAGIC 0x54525653
    160 #define TRAVC_MAGIC 0x54525643
    161 
    162 #define ASSERT_TRAVS(s) assert((s)->magic == TRAVS_MAGIC)
    163 #define ASSERT_TRAVC(s) assert((s)->magic == TRAVC_MAGIC)
    164 
    165 typedef struct _rlink_travs_s {
    166     uint32                          magic;      /* magic numbers */
    167     uint32                          c_id;       /* client ID */
    168     uint32                          s_id;       /* server ID */
    169     int                             unit;       /* traverse unit */
    170     _bcm_traverse_handler_t         handler;    /* traverse handler */
    171     uint8                           *msgp;      /* output stream mid-msg ptr */
    172     int                             num;        /* number of replies */
    173     int                             flush;      /* true if flushing cb */
    174     int                             rrv;        /* traverse rv */
    175     sal_usecs_t                     atime;      /* last access time */
    176     bcm_rlink_traverse_data_t       *reply;     /* reply data */
    177     struct _rlink_travs_s           *next;      /* next record */
    178 } _rlink_travs_t;
    179 
    180 #ifndef RLINK_TRAVS_TRANSACTION_TIMEOUT
    181 #define RLINK_TRAVS_TRANSACTION_TIMEOUT -1
    182 #endif
    183 
    184 #ifndef RLINK_TRAVS_LOCK_TIMEOUT
    185 #define RLINK_TRAVS_LOCK_TIMEOUT sal_mutex_FOREVER
    186 #endif
    187 
    188 static _rlink_travs_t   *_rlink_travs_req_current;
    189 int rlink_traverse_transaction_timeout = RLINK_TRAVS_TRANSACTION_TIMEOUT;
    190 
    191 #if RLINK_TRAV_THREADED_SERVER
    192 
    193 static sal_mutex_t      _rlink_travs_lock;
    194 
    195 #define	RLINK_TRAVS_LOCK        sal_mutex_take(_rlink_travs_lock,\
    196                                                RLINK_TRAVS_LOCK_TIMEOUT)
    197 #define	RLINK_TRAVS_UNLOCK      sal_mutex_give(_rlink_travs_lock)
    198 
    199 #ifndef RLINK_TRAV_THREAD_STACK
    200 #define	RLINK_TRAV_THREAD_STACK	SAL_THREAD_STKSZ
    201 #endif
    202 
    203 #ifndef  RLINK_TRAV_THREAD_PRIO
    204 #define	RLINK_TRAV_THREAD_PRIO	50
    205 #endif
    206 
    207 static sal_sem_t        _rlink_travs_sem;
    208 static sal_sem_t        _rlink_travt_sem;
    209 static volatile sal_thread_t    _rlink_travs_thread = SAL_THREAD_ERROR;
    210 static volatile int              _rlink_travs_thread_exit;
    211 
    212 
    213 #ifndef RLINK_TRAVT_SLEEP_TIMEOUT
    214 #define RLINK_TRAVT_SLEEP_TIMEOUT sal_sem_FOREVER
    215 #endif
    216 
    217 #define	RLINK_TRAVT_SLEEP       sal_sem_take(_rlink_travt_sem,\
    218                                              RLINK_TRAVT_SLEEP_TIMEOUT)
    219 #define	RLINK_TRAVT_WAKE        sal_sem_give(_rlink_travt_sem)
    220 
    221 #ifndef RLINK_TRAVS_SLEEP_TIMEOUT
    222 #define RLINK_TRAVS_SLEEP_TIMEOUT sal_sem_FOREVER
    223 #endif
    224 
    225 #define	RLINK_TRAVS_SLEEP       sal_sem_take(_rlink_travs_sem,\
    226                                              RLINK_TRAVS_SLEEP_TIMEOUT)
    227 
    228 #define	RLINK_TRAVS_WAKE        sal_sem_give(_rlink_travs_sem)
    229 
    230 
    231 #else
    232 
    233 /* resources for non-threaded traverse handling */
    234 
    235 #define	RLINK_TRAVS_LOCK
    236 
    237 #define	RLINK_TRAVS_UNLOCK
    238 
    239 
    240 #ifndef RLINK_TRAVERSE_BUFFER_SIZE
    241 #define RLINK_TRAVERSE_BUFFER_SIZE (4*1024*1024)
    242 #endif
    243 
    244 /* needs to come from generated constants */
    245 #define RLINK_TRAVERSE_MIN_REPLY 8
    246 
    247 /* Reply buffer overhead (over-estimate is OK) */
    248 #define RLINK_TRAVERSE_REPLY_OVERHEAD 16
    249 #define RLINK_TRAVERSE_REPLY_LIMIT \
    250         RLINK_TRAVERSE_MAX_REPLY_LEN - RLINK_TRAVERSE_REPLY_OVERHEAD
    251 
    252 typedef struct _rlink_trav_info_s {
    253     int num;
    254     int len;
    255     uint8 *buf;
    256 } _rlink_trav_info_t;
    257 
    258 /* traverse reply buffer */
    259 static uint8 *_rlink_trav_buffer;
    260 
    261 /* size may be set externally prior to initialization */
    262 int rlink_traverse_buffer_size = RLINK_TRAVERSE_BUFFER_SIZE;
    263 
    264 /* traverse reply info buffer current length */
    265 static int _rlink_trav_info_max_length;
    266 static int _rlink_trav_info_length;
    267 static int _rlink_trav_info_offset;
    268 
    269 /* traverse reply info buffer*/
    270 static _rlink_trav_info_t *_rlink_trav_info;
    271 
    272 
    273 #endif /* RLINK_TRAV_THREADED_SERVER */
    274 
    275 /* traverse client resources
    276 
    277    client lock
    278    client semaphore
    279    client queue
    280 */
    281 
    282 typedef enum _rlink_client_state_e {
    283     client_start,
    284     client_run,
    285     client_done
    286 } _rlink_client_state_t;
    287 
    288 typedef struct _rlink_travc_s {
    289     uint32                          magic;      /* struct magic */
    290     uint32                          c_id;       /* client ID */
    291     uint32                          s_id;       /* server ID */
    292     _rlink_client_state_t           state;      /* client state */
    293     sal_sem_t                       sem;        /* client semaphore */
    294     bcm_rlink_traverse_data_t       *data;      /* request/reply data */
    295     int                             rrv;        /* remote error code */
    296     int                             done;       /* server done */
    297     int                             num;        /* number of replies */
    298     struct _rlink_travc_s           *next;      /* next record */
    299 } _rlink_travc_t;
    300 
    301 
    302 static sal_mutex_t      _rlink_travc_lock;
    303 static _rlink_travc_t   *_rlink_travc_req_head;
    304 static _rlink_travc_t   *_rlink_travc_req_tail;
    305 
    306 static uint32 _rlink_traverse_client_id;
    307 static uint32 _rlink_traverse_server_id;
    308 
    309 #ifndef RLINK_TRAVC_LOCK_TIMEOUT
    310 #define RLINK_TRAVC_LOCK_TIMEOUT sal_mutex_FOREVER
    311 #endif
    312 
    313 #define	RLINK_TRAVC_LOCK	sal_mutex_take(_rlink_travc_lock,\
    314                                                RLINK_TRAVC_LOCK_TIMEOUT)
    315 #define	RLINK_TRAVC_UNLOCK	sal_mutex_give(_rlink_travc_lock)
    316 
    317 #ifndef RLINK_TRAVC_SLEEP_TIMEOUT
    318 #define RLINK_TRAVC_SLEEP_TIMEOUT sal_mutex_FOREVER
    319 #endif
    320 
    321 #define	RLINK_TRAVC_SLEEP(t)	sal_sem_take(t->sem, \
    322                                              rlink_traverse_client_timeout)
    323 #define	RLINK_TRAVC_WAKE(t)	sal_sem_give(t->sem)
    324 
    325 int rlink_traverse_client_timeout = RLINK_TRAVC_SLEEP_TIMEOUT;
    326 
    327 /* Client side implementation APIs */
    328 
    329 /* get an ID, make sure it's not zero */
    330 STATIC uint32
    331 _bcm_rlink_traverse_next_id(uint32 *var)
    332 {
    333     uint32 id;
    334 
    335     id = *var;
    336 
    337     if (!++id) {
    338         ++id;
    339     }
    340     *var = id;
    341 
    342     return id;
    343 }
    344 
    345 STATIC void
    346 _bcm_rlink_traverse_server_message_sanity(bcm_rlink_traverse_data_t *req)
    347 {
    348     uint8 *ptr;
    349     rlink_msg_t msg;
    350     rlink_type_t type;
    351     int c_id, s_id, unit;
    352     /* sanity check */
    353     assert(req->tx_buf);
    354     assert(req->tx_ptr);
    355     assert((req->tx_ptr - req->tx_buf) >= 10);
    356     ptr = req->tx_buf;
    357     ptr = bcm_rlink_decode(ptr,&msg,&type,&unit);
    358     BCM_UNPACK_U32(ptr, c_id);
    359     BCM_UNPACK_U32(ptr, s_id);
    360     assert(msg == RLINK_MSG_TRAVERSE);
    361     assert(c_id == req->c_id);
    362     assert(s_id == req->s_id);
    363 }
    364 
    365 /* traverse server send function */
    366 STATIC int
    367 _bcm_rlink_traverse_server_message(int unit, _rlink_travc_t *client,
    368                                    rlink_type_t ty)
    369 {
    370     bcm_rlink_traverse_data_t *req = client->data;
    371     int remunit;
    372     int rv;
    373     cpudb_key_t cpu;
    374     uint8 *tx_buf;
    375     int tx_len;
    376 
    377     ASSERT_TRAVC(client);
    378     _bcm_rlink_traverse_server_message_sanity(req);
    379     atp_rx_free(req->rx_buf, req->rx_pkt);
    380     req->rx_buf = NULL;
    381     req->rx_ptr = NULL;
    382     req->rx_len = 0;
    383 
    384     remunit = BCM_CONTROL(unit)->unit;
    385     cpu = *(cpudb_key_t *)BCM_CONTROL(unit)->drv_control;
    386     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    387                 (BSL_META_U(unit,
    388                             "TRAVERSE server_message %d\n"), ty));
    389     (void)bcm_rlink_encode(req->tx_buf, RLINK_MSG_TRAVERSE, ty, remunit);
    390     tx_len = req->tx_ptr - req->tx_buf;
    391 
    392     _bcm_rlink_traverse_server_message_sanity(req);
    393     tx_buf = req->tx_buf;
    394     req->tx_buf = NULL;
    395     req->tx_ptr = NULL;
    396     req->tx_len = 0;
    397     rv = atp_tx(cpu, RLINK_CLIENT_ID, tx_buf, tx_len, 0, NULL, NULL);
    398     atp_tx_data_free(tx_buf);
    399     if (BCM_SUCCESS(rv)) {
    400         LOG_VERBOSE(BSL_LS_SOC_COMMON,
    401                     (BSL_META_U(unit,
    402                                 "TRAVERSE server_message sleeping %d\n"),
    403                      rlink_traverse_client_timeout));
    404         if (RLINK_TRAVC_SLEEP(client) < 0) {
    405             rv = BCM_E_TIMEOUT;
    406         } else {
    407             /* error if no response received */
    408             if (req->rx_buf == NULL) {
    409                 LOG_VERBOSE(BSL_LS_SOC_COMMON,
    410                             (BSL_META_U(unit,
    411                                         "TRAVERSE server_message not received\n")));
    412                 rv = BCM_E_TIMEOUT;
    413             }
    414         }
    415     }
    416 
    417     return rv;
    418 }
    419 
    420 _bcm_traverse_handler_t
    421 _bcm_rlink_traverse_lookup(uint32 *key)
    422 {
    423     uint32                 key0;
    424     _bcm_traverse_handler_t rtn;
    425     int                     lo, hi, new, i, match;
    426     _bcm_traverse_lookup_t *sarr;
    427 
    428     key0 = key[0];
    429     sarr = _bcm_traverse_lookup;
    430     lo = -1;
    431     hi = BCM_TRAVERSE_LOOKUP_COUNT;
    432     match = 0;
    433     while (hi-lo > 1) {
    434         new = (hi + lo) / 2;
    435         if (sarr[new].key[0] > key0) {
    436             hi = new;
    437         } else if (sarr[new].key[0] < key0) {
    438             lo = new;
    439         } else {
    440             /* key0 is equal, check the rest */
    441             match = 1;
    442             for (i = 1; i < BCM_TRAVERSE_LOOKUP_KEYLEN; i++) {
    443                 if (sarr[new].key[i] > key[i]) {
    444                     hi = new;
    445                     match = 0;
    446                     break;
    447                 } else if (sarr[new].key[i] < key[i]) {
    448                     lo = new;
    449                     match = 0;
    450                     break;
    451                 }
    452             }
    453             if (match) {
    454                 lo = new;
    455                 break;
    456             }
    457         }
    458     }
    459     if (match) {
    460         rtn = sarr[lo].routine;
    461     } else {
    462         rtn = NULL /* _bcm_rlink_traverse_handler_unavail */;
    463     }
    464     return rtn;
    465 }
    466 
    467 /*
    468   Called by a client traverse implementation to start a remote traverse.
    469   Initializes and registers a traverse request record.
    470   Does *not* send any RLINK messages to the RLINK server.
    471       lookup traverse ID
    472       init client record {
    473         allocate client sem
    474         allocate client TX buffer
    475         init reply count
    476         init client ID
    477         init server ID
    478         ...
    479       }
    480       LOCK {
    481         add to client list
    482       }
    483  */
    484 int
    485 bcm_rlink_traverse_request_start(int unit,
    486                                  bcm_rlink_traverse_data_t *req,
    487                                  uint32 *key)
    488 {
    489     int rv = BCM_E_FAIL;
    490     int i;
    491     _rlink_travc_t *trav = NULL;
    492     
    493     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    494                 (BSL_META_U(unit,
    495                             "TRAVERSE request_start\n")));
    496 
    497     trav = sal_alloc(sizeof(*trav),"bcmTRAVC");
    498     if (!trav) {
    499         rv = BCM_E_MEMORY;
    500         goto error;
    501     }
    502     sal_memset(trav, 0, sizeof(*trav));
    503 
    504     trav->sem = sal_sem_create("bcmTRAVC", sal_sem_BINARY, 0);
    505     if (!trav->sem) {
    506         rv = BCM_E_RESOURCE;
    507         goto error;
    508     }
    509 
    510     trav->magic = TRAVC_MAGIC;
    511     trav->state = client_start;
    512     trav->data = req;
    513     trav->rrv = BCM_E_NONE;
    514     req->parent = (void *)trav;
    515     trav->c_id = req->c_id =
    516         _bcm_rlink_traverse_next_id(&_rlink_traverse_client_id);
    517     trav->s_id = req->s_id = 0;
    518     req->rx_buf = NULL;
    519     req->rx_ptr = NULL;
    520     req->rx_len = 0;
    521     req->unit = unit;
    522     req->tx_buf = atp_tx_data_alloc(RLINK_TRAVERSE_MAX_REQ_LEN);
    523     if (!req->tx_buf) {
    524         rv = BCM_E_MEMORY;
    525         goto error;
    526     }
    527     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    528                 (BSL_META_U(unit,
    529                             "TRAVERSE request id:%x:%x\n"),
    530                  req->c_id, req->s_id));
    531     bcm_rx_pool_own(req->tx_buf,(void *)FUNCTION_NAME());
    532     req->tx_len = RLINK_TRAVERSE_MAX_REQ_LEN;
    533 
    534     /* just advance the tx_ptr - actual data rewritten later */
    535     req->tx_ptr = bcm_rlink_encode(req->tx_buf, RLINK_MSG_TRAVERSE, 0, 0);
    536 
    537     /* pack c_id, s_id */
    538     BCM_PACK_U32(req->tx_ptr, req->c_id);
    539     BCM_PACK_U32(req->tx_ptr, req->s_id);
    540 
    541     /* pack t_id */
    542     for (i=0; i<BCM_TRAVERSE_LOOKUP_KEYLEN; i++) {
    543         BCM_PACK_U32(req->tx_ptr, key[i]);
    544     }
    545 
    546     RLINK_TRAVC_LOCK;
    547     {
    548         /* Add traverse request to client list */
    549         if (_rlink_travc_req_tail == NULL) {
    550             _rlink_travc_req_head = _rlink_travc_req_tail = trav;
    551         } else {
    552             _rlink_travc_req_tail->next = trav;
    553             _rlink_travc_req_tail = trav;
    554         }
    555     }
    556     RLINK_TRAVC_UNLOCK;
    557     rv = BCM_E_NONE;
    558     goto done;
    559  error:
    560     if (req->tx_buf) {
    561         atp_tx_data_free(req->tx_buf);
    562         req->tx_buf = NULL;
    563         req->tx_ptr = NULL;
    564         req->tx_len = 0;
    565     }
    566     if (trav) {
    567         if (trav->sem) {
    568             sal_sem_destroy(trav->sem);
    569         }
    570         trav->magic = ~trav->magic;
    571         sal_free(trav);
    572     }
    573  done:
    574     return rv;
    575 }
    576 
    577 /*
    578  *Get a traverse reply. If there are no replies, and the remote
    579  *traverse has not started, or signaled completion, then issue a request
    580  *for traverse data and wait for a response.
    581  *    if no replies
    582  *      if server not complete
    583  *        send server message NEXT
    584  *        wait for server response
    585  *        when  MORE
    586  *          // skip to below
    587  *        when  DONE
    588  *          set server-complete
    589  *        when  ERROR
    590  *          set server-complete
    591  *          set rrv to server-error
    592  *          return false
    593  *        else
    594  *          set server-complete
    595  *          set rrv to internal-error
    596  *          return false
    597  *      else
    598  *        set rrv to BCM_E_NONE
    599  *        return false
    600  *      end
    601  *    end
    602  *    unpack reply
    603  *    return true
    604  *    end
    605  */
    606 
    607 int
    608 bcm_rlink_traverse_reply_get(int unit, bcm_rlink_traverse_data_t *req)
    609 {
    610     _rlink_travc_t *parent = (_rlink_travc_t *)req->parent;
    611     int rv;
    612 
    613     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    614                 (BSL_META_U(unit,
    615                             "TRAVERSE reply_get\n")));
    616     ASSERT_TRAVC(parent);
    617     switch (parent->state) {
    618     case client_start:
    619         /* always send a message when in client_start. */
    620         rv = _bcm_rlink_traverse_server_message(unit, parent,
    621                                                 RLINK_TYPE_START);
    622         if (BCM_FAILURE(rv)) {
    623             /* no response, or client shutting down */
    624             parent->state = client_done;
    625             parent->rrv = BCM_E_FAIL;
    626         }
    627         break;
    628     case client_run:
    629         /* Set s_id for first response */
    630         if (!parent->s_id) {
    631             parent->s_id = req->s_id;
    632         } else {
    633             assert(parent->c_id == req->c_id);
    634             assert(parent->s_id == req->s_id);
    635         }
    636         /* send a message if need more responses and server not done */
    637         if (parent->num == 0) {
    638             if (!parent->done) {
    639                 rv = _bcm_rlink_traverse_server_message(unit, parent,
    640                                                         RLINK_TYPE_NEXT);
    641                 if (BCM_FAILURE(rv)) {
    642                     /* no response, or client shutting down */
    643                     parent->state = client_done;
    644                     parent->rrv = BCM_E_FAIL;
    645                 }
    646             } else {
    647                 /* that's it, then */
    648                 parent->state = client_done;
    649             }
    650         }
    651         break;
    652     case client_done:
    653         /* done - no more messages are sent */
    654         break;
    655     }
    656 
    657     if (parent->state == client_run && parent->num > 0) {
    658         /* one response is extracted at a time */
    659         parent->num--;
    660     }
    661 
    662     assert(parent->state != client_start);
    663     return (parent->state == client_run);
    664 }
    665 
    666 
    667 
    668 /*
    669   Indicate that this request is done. If the traverse server has not
    670   indicated completion, then issue a done message.
    671       if server not complete
    672         send server message QUIT with error code
    673         wait for server response
    674       end
    675       LOCK {
    676         unlink from client list
    677       }
    678       deallocate RX/TX buffer
    679       deallocate sem
    680  */
    681 int
    682 bcm_rlink_traverse_request_done(int unit, int trav_rv,
    683                                 bcm_rlink_traverse_data_t *req)
    684 {
    685     _rlink_travc_t *parent = (_rlink_travc_t *)req->parent;
    686     int rv;
    687 
    688     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    689                 (BSL_META_U(unit,
    690                             "TRAVERSE request_done\n")));
    691     ASSERT_TRAVC(parent);
    692     rv = parent->rrv;
    693     switch (parent->state) {
    694     case client_start:
    695         /* This should never be in client_start. Either
    696            bcm_rlink_traverse_request_start() should have returned an
    697            error, and this routine never reached, or a message
    698            received a a result of bcm_rlink_traverse_reply_get() would have
    699            updated the client state. */
    700         assert(1);
    701         break;
    702     case client_run:
    703         /* If the server is not done, send one last message. There
    704            will be at least one subsequent message from the server,
    705            but it will be effectively ignored. */
    706         if (!parent->done) {
    707             BCM_PACK_U32(req->tx_ptr, trav_rv);
    708             rv = _bcm_rlink_traverse_server_message(unit, parent,
    709                                                     RLINK_TYPE_QUIT);
    710             if (BCM_SUCCESS(rv)) {
    711                 rv = parent->rrv;
    712             }
    713         } else {
    714             /* Server was done, so synthesize the client return value
    715                based on the typical behavior of traverse implementations,
    716                which is to return the last value of the callback */
    717             rv = trav_rv;
    718         }
    719         break;
    720     case client_done:
    721         break;
    722     }
    723     RLINK_TRAVC_LOCK;
    724     {
    725         if (_rlink_travc_req_head == parent) {
    726             _rlink_travc_req_head = parent->next;
    727             if (_rlink_travc_req_tail == parent) {
    728                 _rlink_travc_req_tail = NULL;
    729             }
    730         } else {
    731             _rlink_travc_t *preq;
    732             for (preq = _rlink_travc_req_head; preq; preq = preq->next) {
    733                 if (preq->next == parent) {
    734                     preq->next = parent->next;
    735                     if (_rlink_travc_req_tail == parent) {
    736                         _rlink_travc_req_tail = parent->next;
    737                     }
    738                     break;
    739                 }
    740             }
    741         }
    742     }
    743     RLINK_TRAVC_UNLOCK;
    744 
    745     /* If there are still TX or RX buffers, free them now. */
    746     if (req->rx_buf) {
    747         atp_rx_free(req->rx_buf, req->rx_pkt);
    748     }
    749     if (req->tx_buf) {
    750         atp_tx_data_free(req->tx_buf);
    751     }
    752     sal_sem_destroy(parent->sem);
    753     parent->magic = ~parent->magic;
    754     sal_free(parent);
    755 
    756     return rv;
    757 }
    758 
    759 
    760 
    761 #if RLINK_TRAV_THREADED_SERVER
    762 
    763 /* Threaded Server implementation APIs */
    764 
    765 STATIC int
    766 _bcm_rlink_traverse_client_message(_rlink_travs_t *server, rlink_type_t ty)
    767 {
    768     bcm_rlink_traverse_data_t *req = server->reply;
    769     int rv = BCM_E_NONE;
    770 
    771     assert(server != NULL);
    772     assert(req != NULL);
    773     (void)bcm_rlink_encode(req->tx_buf, RLINK_MSG_TRAVERSE, ty, req->unit);
    774     req->tx_len = req->tx_ptr - req->tx_buf;
    775     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    776                 (BSL_META("TRAVERSE client_message waking travs\n")));
    777 #if 0
    778     if (ty == RLINK_TYPE_MORE) {
    779         /* If MORE, then zero the reply pointer to check if a response
    780            was received. */
    781         server->reply = NULL;
    782     }
    783 #else
    784     /* done with reply */
    785     server->reply = NULL;
    786 #endif
    787     RLINK_TRAVS_WAKE;
    788     if (ty == RLINK_TYPE_MORE) {
    789         int s_rv;
    790 
    791         LOG_VERBOSE(BSL_LS_SOC_COMMON,
    792                     (BSL_META("TRAVERSE client_message sleeping travt\n")));
    793         s_rv = RLINK_TRAVT_SLEEP;
    794         /* If a message was received, then the data pointer has been
    795            updated. */
    796         if (s_rv < 0 ||
    797             server->reply == NULL || server->reply->rx_buf == NULL) {
    798             /* nothing received */
    799             rv = BCM_E_FAIL;
    800         } else {
    801             rv = BCM_E_NONE;
    802         }
    803     }
    804 
    805     return rv;
    806 }
    807 
    808 
    809 /*
    810   Check to see if there's enough room for a reply. If not,
    811   send out current data and wait for a response.
    812 
    813   If there's an error sending out a message, then return that error code.
    814   Normally behaving traverse functions should then exit.
    815  */
    816 int
    817 bcm_rlink_traverse_reply_check(bcm_rlink_traverse_data_t *data, int size)
    818 {
    819     _rlink_travs_t *parent;
    820     int rv = BCM_E_NONE;
    821     
    822     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    823                 (BSL_META("TRAVERSE reply_check%s\n"),
    824                  data ? "" : " - no data"));
    825 
    826     if (data) {
    827         int len;
    828 
    829         parent = (_rlink_travs_t *)data->parent;
    830         ASSERT_TRAVS(parent);
    831         assert(parent->reply == data);
    832         if (!parent->flush) {
    833             len = data->tx_ptr - data->tx_buf;
    834             if ((len + size) > data->tx_len) {
    835                 BCM_PACK_U32(parent->msgp, 0);
    836                 BCM_PACK_U32(parent->msgp, parent->num);
    837                 rv = _bcm_rlink_traverse_client_message(parent,
    838                                                         RLINK_TYPE_MORE);
    839                 parent->num = 0;
    840             }
    841             parent->num++;
    842         } else {
    843             rv = parent->rrv;
    844         }
    845     } else {
    846         rv = BCM_E_FAIL;
    847     }
    848 
    849     return rv;
    850 }
    851 
    852 /*
    853   Flush any outstanding callback data.
    854       if server error code
    855         send ERROR message
    856       else
    857         # edge case: if the last MORE message contained all remaining
    858         # callbacks, there are no new callback to be sent. However,
    859         # the client doesn't know that, so send an empty DONE message
    860         update callback count
    861         send DONE message
    862       end
    863  */
    864 
    865 int
    866 bcm_rlink_traverse_reply_done(bcm_rlink_traverse_data_t *data, int rv)
    867 {
    868     _rlink_travs_t *parent;
    869 
    870     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    871                 (BSL_META("TRAVERSE reply_done%s\n"),
    872                  data ? "" : " - no data"));
    873     if (data) {
    874         /* If there's a pending request from a client */
    875         parent = (_rlink_travs_t *)data->parent;
    876 
    877         if (parent) {
    878             ASSERT_TRAVS(parent);
    879             assert(parent->reply == data);
    880             /* Even when flushing, always send a done message */
    881             BCM_PACK_U32(parent->msgp, rv);
    882             BCM_PACK_U32(parent->msgp, parent->flush ? 0 : parent->num);
    883             (void) _bcm_rlink_traverse_client_message(parent, RLINK_TYPE_DONE);
    884         } else if (BCM_SUCCESS(rv)) {
    885             rv = BCM_E_FAIL;
    886         }
    887     }
    888 
    889     return rv;
    890 }
    891 
    892 int
    893 bcm_rlink_traverse_device_clear(int unit)
    894 {
    895     int rv = BCM_E_NOT_FOUND;
    896 
    897     RLINK_TRAVS_LOCK;
    898     {
    899         if (_rlink_travs_req_current) {
    900             if (unit < 0 || _rlink_travs_req_current->unit == unit) {
    901                 _rlink_travs_req_current->flush = TRUE;
    902                 _rlink_travs_req_current->rrv = BCM_E_FAIL;
    903                 rv = BCM_E_NONE;
    904             }
    905         }
    906     }
    907     RLINK_TRAVS_UNLOCK;
    908 
    909     if (BCM_SUCCESS(rv)) {
    910         LOG_VERBOSE(BSL_LS_SOC_COMMON,
    911                     (BSL_META_U(unit,
    912                                 "TRAVERSE server_clear waking travt\n")));
    913         RLINK_TRAVT_WAKE;
    914     }
    915 
    916     return rv;
    917 }
    918 
    919 /*
    920   Clear any outstanding traverse server messages
    921       LOCK {
    922       throw away all records except head
    923       for server record head
    924         mark shutdown
    925         signal server lock
    926       }
    927  */
    928 int
    929 bcm_rlink_traverse_server_clear(void)
    930 {
    931     return bcm_rlink_traverse_device_clear(-1);
    932 }
    933 
    934 /*
    935  * Traverse server thread
    936  */
    937 STATIC void
    938 _bcm_rlink_travs_thread(void *cookie)
    939 {
    940     _rlink_travs_t *cur = NULL;
    941 
    942     COMPILER_REFERENCE(cookie);
    943 
    944     while (!_rlink_travs_thread_exit) {
    945 
    946 	RLINK_TRAVS_LOCK;
    947         {
    948             /* get a traverse request */
    949             cur =  _rlink_travs_req_current;
    950         }
    951 	RLINK_TRAVS_UNLOCK;
    952 
    953 	/* execute traverse */
    954 	if (cur) {
    955             LOG_VERBOSE(BSL_LS_SOC_COMMON,
    956                         (BSL_META("TRAVERSE begin\n")));
    957 	    cur->handler(&cur->reply);
    958             RLINK_TRAVS_LOCK;
    959             {
    960                 _rlink_travs_req_current = NULL;
    961             }
    962             RLINK_TRAVS_UNLOCK;
    963             LOG_VERBOSE(BSL_LS_SOC_COMMON,
    964                         (BSL_META("TRAVERSE end\n")));
    965             cur->magic = ~cur->magic;
    966             sal_free(cur);
    967             cur = NULL;
    968         } else {
    969             LOG_VERBOSE(BSL_LS_SOC_COMMON,
    970                         (BSL_META("TRAVERSE travs_thread sleeping\n")));
    971             RLINK_TRAVT_SLEEP;
    972         }
    973     }
    974     _rlink_travs_thread = SAL_THREAD_ERROR;
    975     sal_thread_exit(0);
    976 }
    977 
    978 
    979 STATIC int
    980 _bcm_rlink_travs_thread_signal(void)
    981 {
    982     int rv;
    983     
    984     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    985                 (BSL_META("TRAVERSE signal waking travt\n")));
    986     RLINK_TRAVT_WAKE;
    987 
    988     /* wait for traverse server to signal back */
    989     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    990                 (BSL_META("TRAVERSE signal sleeping travs\n")));
    991     rv = RLINK_TRAVS_SLEEP;
    992     LOG_VERBOSE(BSL_LS_SOC_COMMON,
    993                 (BSL_META("TRAVERSE signal woken up travs\n")));
    994 
    995     return rv < 0 ? BCM_E_TIMEOUT : BCM_E_NONE;
    996 }
    997 
    998 STATIC int
    999 _bcm_rlink_traverse_run(_rlink_travs_t *trav)
   1000 {
   1001     COMPILER_REFERENCE(trav);
   1002     return _bcm_rlink_travs_thread_signal();
   1003 }
   1004 
   1005 #else /* !THREADED_SERVER */
   1006 
   1007 STATIC void
   1008 _bcm_rlink_set_current_len(int len)
   1009 {
   1010     if (len > _rlink_trav_info[_rlink_trav_info_offset].len) {
   1011         /* .len may not be entirely accurate, but should be at least an
   1012            overestimate */
   1013         LOG_WARN(BSL_LS_SOC_COMMON,
   1014                  (BSL_META("TRAVERSE set_current_len len=%d actual=%d\n"),
   1015                   _rlink_trav_info[_rlink_trav_info_offset].len, len));
   1016     }
   1017     /* set to calculated length */
   1018     _rlink_trav_info[_rlink_trav_info_offset].len = len;
   1019 }
   1020 
   1021 /*
   1022   If there's no room in the current segment, bump to the next info ptr.
   1023  */
   1024 int
   1025 bcm_rlink_traverse_reply_check(bcm_rlink_traverse_data_t *data, int size)
   1026 {
   1027     int len;
   1028 
   1029     len = data->tx_ptr - _rlink_trav_info[_rlink_trav_info_offset].buf;
   1030     if ((len + size) > RLINK_TRAVERSE_REPLY_LIMIT) {
   1031         _bcm_rlink_set_current_len(len);
   1032 
   1033         /* next segment */
   1034         _rlink_trav_info_offset++;
   1035         assert(_rlink_trav_info_offset < _rlink_trav_info_max_length);
   1036         _rlink_trav_info[_rlink_trav_info_offset].num = 0;
   1037         _rlink_trav_info[_rlink_trav_info_offset].len = 0;
   1038         _rlink_trav_info[_rlink_trav_info_offset].buf = data->tx_ptr;
   1039     }
   1040     
   1041     _rlink_trav_info[_rlink_trav_info_offset].len += size;
   1042     _rlink_trav_info[_rlink_trav_info_offset].num++;
   1043 
   1044     return BCM_E_NONE; /* always pack response */
   1045 }
   1046 
   1047 /*
   1048   Save RV
   1049  */
   1050 int
   1051 bcm_rlink_traverse_reply_done(bcm_rlink_traverse_data_t *data, int rv)
   1052 {
   1053     _rlink_travs_t *parent = (_rlink_travs_t *)data->parent;
   1054     int len;
   1055 
   1056     ASSERT_TRAVS(parent);
   1057     len = data->tx_ptr - _rlink_trav_info[_rlink_trav_info_offset].buf;
   1058     _bcm_rlink_set_current_len(len);
   1059     parent->rrv = rv;
   1060     return BCM_E_NONE;
   1061 }
   1062 
   1063 /*
   1064  */
   1065 int
   1066 bcm_rlink_traverse_server_clear(void)
   1067 {
   1068     RLINK_TRAVS_LOCK;
   1069     {
   1070         _rlink_travs_req_current = NULL;
   1071     }
   1072     RLINK_TRAVS_UNLOCK;
   1073 
   1074     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1075                 (BSL_META("TRAVERSE server_clear\n")));
   1076     return BCM_E_NONE;
   1077 }
   1078 
   1079 
   1080 STATIC int
   1081 _bcm_rlink_trav_done(bcm_rlink_traverse_data_t *data)
   1082 {
   1083     (void)bcm_rlink_encode(data->tx_buf,
   1084                            RLINK_MSG_TRAVERSE,
   1085                            RLINK_TYPE_DONE, data->unit);
   1086     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1087                 (BSL_META("TRAVERSE sync traverse done\n")));
   1088     /* mark done */
   1089     _rlink_trav_info_offset = 0;
   1090     _rlink_trav_info_length = 0;
   1091     bcm_rlink_traverse_server_clear();
   1092 
   1093     return BCM_E_NONE;
   1094 }
   1095 
   1096 
   1097 STATIC int
   1098 _bcm_rlink_trav_send_reply(bcm_rlink_traverse_data_t *data)
   1099 {
   1100     _rlink_travs_t *parent = (_rlink_travs_t *)data->parent;
   1101 
   1102     ASSERT_TRAVS(parent);
   1103     assert(parent->reply == data);
   1104 
   1105     sal_memcpy(data->tx_ptr,
   1106                _rlink_trav_info[_rlink_trav_info_offset].buf,
   1107                _rlink_trav_info[_rlink_trav_info_offset].len);
   1108     data->tx_ptr += _rlink_trav_info[_rlink_trav_info_offset].len;
   1109     BCM_PACK_U32(parent->msgp, 0);
   1110     BCM_PACK_U32(parent->msgp, _rlink_trav_info[_rlink_trav_info_offset].num);
   1111 
   1112     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1113                 (BSL_META("TRAVERSE sync traverse send reply %d/%d\n"),
   1114                  _rlink_trav_info_offset,_rlink_trav_info_length));
   1115     _rlink_trav_info_offset++;
   1116     if (_rlink_trav_info_offset >= _rlink_trav_info_length) {
   1117         _bcm_rlink_trav_done(data);
   1118     }
   1119 
   1120     return BCM_E_NONE;
   1121 }
   1122 
   1123 STATIC int
   1124 _bcm_rlink_traverse_run(_rlink_travs_t *trav)
   1125 {
   1126     bcm_rlink_traverse_data_t reply;
   1127     bcm_rlink_traverse_data_t *replyp = &reply;
   1128     
   1129     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1130                 (BSL_META("TRAVERSE traverse run sync begin\n")));
   1131     assert(_rlink_trav_info);
   1132     assert(_rlink_trav_buffer);
   1133     assert(_rlink_travs_req_current);
   1134 
   1135     /* save original reply info */
   1136     reply = *trav->reply;
   1137 
   1138     /* Use the traverse buffer instead of the reply buffer in a copy
   1139        of the reply structure. This allows all the traverse replies
   1140        to be saved at once. */
   1141     reply.tx_buf = reply.tx_ptr = _rlink_trav_buffer;
   1142 
   1143     /* init response info */
   1144     _rlink_trav_info_offset = 0;
   1145     _rlink_trav_info[_rlink_trav_info_offset].num = 0;
   1146     _rlink_trav_info[_rlink_trav_info_offset].len = 0;
   1147     _rlink_trav_info[_rlink_trav_info_offset].buf = reply.tx_ptr;
   1148 
   1149     /* run traverse */
   1150     trav->handler(&replyp);
   1151 
   1152     /* send first reply */
   1153     _rlink_trav_info_length = _rlink_trav_info_offset+1;
   1154     _rlink_trav_info_offset = 0;
   1155     _bcm_rlink_trav_send_reply(trav->reply);
   1156     LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1157                 (BSL_META("TRAVERSE traverse run sync end\n")));
   1158 
   1159     return BCM_E_NONE;
   1160 }
   1161 
   1162 
   1163 
   1164 #endif /* RLINK_TRAV_THREADED_SERVER */
   1165 
   1166 /* RLINK module interfaces */
   1167 
   1168 
   1169 
   1170 /*
   1171   Clear any outstanding client traverses
   1172         foreach client record
   1173           mark shutdown
   1174           signal client lock
   1175  */
   1176 int
   1177 bcm_rlink_traverse_client_clear(void)
   1178 {
   1179     _rlink_travc_t *trav;
   1180     RLINK_TRAVC_LOCK;
   1181     {
   1182         trav = _rlink_travc_req_head;
   1183         while (trav) {
   1184             trav->state = client_done;
   1185             sal_sem_give(trav->sem);
   1186         }
   1187     }
   1188     RLINK_TRAVC_UNLOCK;
   1189 
   1190     return BCM_E_NONE;
   1191 }
   1192 
   1193 
   1194 /*
   1195   Handle a traverse request
   1196     Client and server sides have slightly different buffer management
   1197     requirements.
   1198 
   1199     For the server:
   1200       allocate TX buffer
   1201       rlink_traverse_message()
   1202       atp_rx_free(rx buffer)
   1203       atp_tx(data_out, len_out_actual)
   1204       atp_tx_free(tx buffer)
   1205       
   1206     For the client:
   1207       allocate TX buffer
   1208       rlink_traverse_message()
   1209         TX and RX free happens in _bcm_rlink_traverse_server_message()
   1210  */
   1211 
   1212 int
   1213 bcm_rlink_traverse_request(rlink_type_t type,
   1214                            cpudb_key_t cpu, bcm_pkt_t *rx_pkt,
   1215                            uint8 *rx_buf, int len)
   1216 {
   1217     uint8 *tx_buf;
   1218     int tx_len = RLINK_TRAVERSE_MAX_REQ_LEN;
   1219     int actual;
   1220     int rv = BCM_E_FAIL;
   1221     int server;
   1222 
   1223     server = (type == RLINK_TYPE_START ||
   1224               type == RLINK_TYPE_NEXT ||
   1225               type == RLINK_TYPE_QUIT);
   1226     tx_buf = atp_tx_data_alloc(tx_len);
   1227     if (tx_buf) {
   1228         bcm_rx_pool_own(tx_buf, (void *)FUNCTION_NAME());
   1229         bcm_rx_pool_own(rx_buf, (void *)FUNCTION_NAME());
   1230         rv = bcm_rlink_traverse_message(rx_pkt,
   1231                                         rx_buf, len, tx_buf, tx_len, &actual);
   1232         if (server) {
   1233             atp_rx_free(rx_buf, rx_pkt);
   1234             if (BCM_SUCCESS(rv)) {
   1235                 assert(actual > 0);
   1236                 LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1237                             (BSL_META("TRAVERSE traverse_request %d\n"),
   1238                              actual));
   1239                 rv = atp_tx(cpu, RLINK_CLIENT_ID, tx_buf, actual, 0,
   1240                             NULL, NULL);
   1241             }
   1242             atp_tx_data_free(tx_buf);
   1243         }
   1244     } else {
   1245         LOG_WARN(BSL_LS_SOC_COMMON,
   1246                  (BSL_META("TRAVERSE traverse_request could not alloc tx\n")));
   1247         atp_rx_free(rx_buf, rx_pkt);
   1248         rv = BCM_E_MEMORY;
   1249     }
   1250 
   1251     return rv;
   1252 }
   1253 
   1254 
   1255 STATIC void
   1256 _bcm_rlink_trav_msg_prep_reply(bcm_rlink_traverse_data_t *data)
   1257 {
   1258     _rlink_travs_t *trav = (_rlink_travs_t *)data->parent;
   1259 
   1260     ASSERT_TRAVS(trav);
   1261     /* prepare MORE message, but could be overwritten by DONE */
   1262     data->tx_ptr = bcm_rlink_encode(data->tx_ptr,
   1263                                     RLINK_MSG_TRAVERSE,
   1264                                     RLINK_TYPE_MORE, data->unit);
   1265     BCM_PACK_U32(data->tx_ptr, data->c_id);
   1266     BCM_PACK_U32(data->tx_ptr, data->s_id);
   1267     /* save the location for error and traverse reply count to be
   1268        filled in later */
   1269     trav->msgp = data->tx_ptr;
   1270     trav->num = 0;
   1271     trav->rrv = BCM_E_NONE;
   1272     /* init return value and reply count to 0,
   1273        will be updated when packet sent */
   1274     BCM_PACK_U32(data->tx_ptr, 0);
   1275     BCM_PACK_U32(data->tx_ptr, 0);
   1276 }
   1277 
   1278 /* handle START message
   1279    received by server from client
   1280       when START
   1281         _rlink_trav_msg_start()
   1282           create server record
   1283           link to server list
   1284           handle stale traverse head
   1285           wake up traverse thread
   1286 
   1287    Need to have queuing and non-queuing versions.
   1288 
   1289           
   1290 */
   1291 
   1292 STATIC void
   1293 _bcm_rlink_trav_prep_error(bcm_rlink_traverse_data_t *data, int rv)
   1294 {
   1295     /* prepare an error response */
   1296     data->tx_ptr = bcm_rlink_encode(data->tx_ptr,
   1297                                     RLINK_MSG_TRAVERSE,
   1298                                     RLINK_TYPE_ERROR, data->unit);
   1299     BCM_PACK_U32(data->tx_ptr, data->c_id);
   1300     BCM_PACK_U32(data->tx_ptr, data->s_id);
   1301     BCM_PACK_U32(data->tx_ptr, rv);
   1302 }
   1303 
   1304 STATIC int
   1305 _bcm_rlink_trav_msg_start(bcm_rlink_traverse_data_t *data)
   1306 {
   1307     int rv = BCM_E_FAIL;
   1308     int i;
   1309     uint32 key[BCM_TRAVERSE_LOOKUP_KEYLEN];
   1310     _rlink_travs_t *trav;
   1311     _bcm_traverse_handler_t handler;
   1312 
   1313     trav = NULL;
   1314     /* unpack t_id */
   1315     for (i=0; i<BCM_TRAVERSE_LOOKUP_KEYLEN; i++) {
   1316         BCM_UNPACK_U32(data->rx_ptr, key[i]);
   1317     }
   1318 
   1319     handler = _bcm_rlink_traverse_lookup(key);
   1320     if (handler == NULL) {
   1321         _bcm_rlink_trav_prep_error(data, BCM_E_NOT_FOUND);
   1322         return BCM_E_NONE;
   1323     }
   1324 
   1325     /* If not queuing requests, then, if the server thread is busy,
   1326        reject the request */
   1327     RLINK_TRAVS_LOCK;
   1328     {
   1329         trav = _rlink_travs_req_current;
   1330     }
   1331     RLINK_TRAVS_UNLOCK;
   1332 
   1333     if (trav) {
   1334         int duration;
   1335         /* If stale transaction timeouts are enabled, check to see if
   1336            trav is stale. If not, return BUSY, otherwise clear it out. */
   1337         duration = SAL_USECS_SUB(sal_time_usecs(), trav->atime);
   1338         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1339                     (BSL_META("TRAVERSE msg_start: cur:%d\n"),
   1340                      duration));
   1341         if (rlink_traverse_transaction_timeout <= 0 ||
   1342             (rlink_traverse_transaction_timeout > 0 &&
   1343              duration > 0 && duration < rlink_traverse_transaction_timeout)) {
   1344             LOG_WARN(BSL_LS_SOC_COMMON,
   1345                      (BSL_META("TRAVERSE msg_start: busy\n")));
   1346             _bcm_rlink_trav_prep_error(data, BCM_E_BUSY);
   1347             return BCM_E_NONE;
   1348         } else {
   1349             LOG_WARN(BSL_LS_SOC_COMMON,
   1350                      (BSL_META("TRAVERSE msg_start: old transaction\n")));
   1351             /* For old transactions, just recycle the old server record.
   1352                Buffered server doesn't need to do anything. */
   1353 #if RLINK_TRAV_THREADED_SERVER
   1354             /* Threaded server needs to quit the current traverse execution
   1355                and wait for it to complete. */
   1356             trav->flush = TRUE;
   1357             trav->rrv = BCM_E_FAIL;
   1358             _bcm_rlink_travs_thread_signal();
   1359 #endif
   1360         }
   1361     } else {
   1362         /* Allocating a server record even for a single threaded or
   1363            non-threaded server will accomodate future multiple
   1364            transaction designs. */
   1365         trav = sal_alloc(sizeof(*trav),"bcmTRAVS");
   1366     }
   1367 
   1368     if (trav) {
   1369         sal_memset(trav, 0, sizeof(*trav));
   1370         trav->magic = TRAVS_MAGIC;
   1371         trav->atime = sal_time_usecs();
   1372         trav->c_id = data->c_id;
   1373         assert(data->s_id == 0);
   1374         trav->s_id = data->s_id =
   1375             _bcm_rlink_traverse_next_id(&_rlink_traverse_server_id);
   1376         trav->handler = handler;
   1377         trav->reply = data;
   1378         trav->reply->parent = (void *)trav;
   1379         _bcm_rlink_trav_msg_prep_reply(trav->reply);
   1380         RLINK_TRAVS_LOCK;
   1381         {
   1382             _rlink_travs_req_current = trav;
   1383         }
   1384         RLINK_TRAVS_UNLOCK;
   1385         rv = _bcm_rlink_traverse_run(trav);
   1386     } else {
   1387         rv = BCM_E_MEMORY;
   1388     }
   1389     return rv;
   1390 }
   1391 
   1392 STATIC int
   1393 _bcm_rlink_travs_get(bcm_rlink_traverse_data_t *data, _rlink_travs_t **tp)
   1394 {
   1395     _rlink_travs_t *trav = NULL;
   1396     int rv = BCM_E_NOT_FOUND;
   1397 
   1398     RLINK_TRAVS_LOCK;
   1399     {
   1400         if (_rlink_travs_req_current != NULL &&
   1401             _rlink_travs_req_current->s_id == data->s_id &&
   1402             _rlink_travs_req_current->c_id == data->c_id) {
   1403             trav = _rlink_travs_req_current;
   1404             rv = BCM_E_NONE;
   1405         }
   1406     }
   1407     RLINK_TRAVS_UNLOCK;
   1408 
   1409     if (BCM_SUCCESS(rv)) {
   1410         /* do some common setup */
   1411         ASSERT_TRAVS(trav);
   1412         data->parent = (void *)trav;
   1413         trav->atime = sal_time_usecs();
   1414         trav->reply = data;
   1415         _bcm_rlink_trav_msg_prep_reply(data);
   1416         *tp = trav;
   1417     } else {
   1418         LOG_ERROR(BSL_LS_SOC_COMMON,
   1419                   (BSL_META("TRAVERSE could not find id %x:%x\n"),
   1420                    data->c_id, data->s_id));
   1421         _bcm_rlink_trav_prep_error(data, BCM_E_NOT_FOUND);
   1422     }
   1423 
   1424     return rv;
   1425 }
   1426 
   1427 
   1428 /* handle NEXT message
   1429    received by server from client
   1430       when NEXT
   1431         _rlink_trav_msg_next()
   1432           if c-id == current-c-id
   1433             update server record
   1434             wake up traverse thread
   1435           else
   1436             error
   1437           end
   1438 
   1439 */
   1440 STATIC int
   1441 _bcm_rlink_trav_msg_next(bcm_rlink_traverse_data_t *data)
   1442 {
   1443     int rv = BCM_E_FAIL;
   1444     _rlink_travs_t *trav;
   1445 
   1446     rv = _bcm_rlink_travs_get(data, &trav);
   1447     if (BCM_SUCCESS(rv)) {
   1448         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1449                     (BSL_META("TRAVERSE msg_next waking travt id=%x:%x\n"),
   1450                      data->c_id, data->s_id));
   1451 #if RLINK_TRAV_THREADED_SERVER
   1452         _bcm_rlink_travs_thread_signal();
   1453 #else
   1454         _bcm_rlink_trav_send_reply(data);
   1455 #endif /* RLINK_TRAV_THREADED_SERVER */
   1456     } else {
   1457         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1458                     (BSL_META("TRAVERSE msg_next id %x:%x not found\n"),
   1459                      data->c_id, data->s_id));
   1460     }
   1461 
   1462     /* travs_get prepares a reply error message */
   1463     return BCM_E_NONE;
   1464 }
   1465 
   1466 
   1467 /* handle QUIT message
   1468    received by server from client
   1469       when QUIT
   1470         _rlink_trav_msg_quit()
   1471           if c-id == current-c-id
   1472             update server record
   1473               set client-quit
   1474             wake up traverse thread
   1475           else
   1476             error
   1477           end
   1478 
   1479 */
   1480 STATIC int
   1481 _bcm_rlink_trav_msg_quit(bcm_rlink_traverse_data_t *data)
   1482 {
   1483     int rv = BCM_E_FAIL;
   1484     _rlink_travs_t *trav;
   1485 
   1486     rv = _bcm_rlink_travs_get(data, &trav);
   1487 
   1488     if (BCM_SUCCESS(rv)) {
   1489         trav->flush = TRUE;
   1490         BCM_UNPACK_U32(data->rx_ptr, trav->rrv);
   1491 
   1492 #if RLINK_TRAV_THREADED_SERVER
   1493         _bcm_rlink_travs_thread_signal();
   1494 #else
   1495         _bcm_rlink_trav_done(data);
   1496 #endif /* RLINK_TRAV_THREADED_SERVER */
   1497     } else {
   1498         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1499                     (BSL_META("TRAVERSE msg_quit id %x:%x not found\n"),
   1500                      data->c_id, data->s_id));
   1501     }
   1502 
   1503     /* travs_get prepares a reply error message */
   1504     return BCM_E_NONE;
   1505 }
   1506 
   1507 STATIC int
   1508 _bcm_rlink_travc_get(bcm_rlink_traverse_data_t *data, _rlink_travc_t **tp)
   1509 {
   1510     int rv = BCM_E_NOT_FOUND;
   1511     _rlink_travc_t *trav;
   1512     RLINK_TRAVC_LOCK;
   1513     {
   1514         for (trav = _rlink_travc_req_head; trav; trav=trav->next) {
   1515             if (trav->c_id == data->c_id) {
   1516                 rv = BCM_E_NONE;
   1517                 break;
   1518             }
   1519         }
   1520     }
   1521     RLINK_TRAVC_UNLOCK;
   1522     if (BCM_SUCCESS(rv)) {
   1523         ASSERT_TRAVC(trav);
   1524         /* update data pointers */
   1525         *trav->data = *data;
   1526         trav->data->parent = (void *)trav;
   1527         *tp = trav;
   1528     } else {
   1529         LOG_ERROR(BSL_LS_SOC_COMMON,
   1530                   (BSL_META("TRAVERSE could not find c_id %x\n"),
   1531                    data->c_id));
   1532     }
   1533 
   1534     return rv;
   1535 }
   1536 
   1537 /* handle ERROR message
   1538    received by client from server
   1539       when ERROR
   1540         _rlink_trav_msg_error()
   1541           if exists c-id
   1542             update client record
   1543             wake up client traverse
   1544           else
   1545             error
   1546           end
   1547 
   1548 */
   1549 STATIC int
   1550 _bcm_rlink_trav_msg_error(bcm_rlink_traverse_data_t *data)
   1551 {
   1552     _rlink_travc_t *trav;
   1553     int rv;
   1554 
   1555     rv = _bcm_rlink_travc_get(data,&trav);
   1556     if (BCM_SUCCESS(rv)) {
   1557 
   1558         BCM_UNPACK_U32(trav->data->rx_ptr, trav->rrv);
   1559         trav->state = client_done;
   1560         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1561                     (BSL_META("TRAVERSE msg_err (%d) waking\n"),
   1562                      trav->rrv));
   1563         RLINK_TRAVC_WAKE(trav);
   1564     }
   1565     return rv;
   1566 }
   1567 
   1568 
   1569 /* handle MORE message
   1570    received by client from server
   1571       when MORE
   1572         _rlink_trav_msg_more()
   1573           if exists c-id
   1574             update client record
   1575             wake up client traverse
   1576           else
   1577             error
   1578           end
   1579 
   1580 */
   1581 STATIC int
   1582 _bcm_rlink_trav_msg_more(bcm_rlink_traverse_data_t *data)
   1583 {
   1584     _rlink_travc_t *trav;
   1585     int rv;
   1586 
   1587     rv = _bcm_rlink_travc_get(data,&trav);
   1588     if (BCM_SUCCESS(rv)) {
   1589 
   1590         /* get return value and number of callback records */
   1591         BCM_UNPACK_U32(trav->data->rx_ptr, trav->rrv);
   1592         BCM_UNPACK_U32(trav->data->rx_ptr, trav->num);
   1593     
   1594         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1595                     (BSL_META("TRAVERSE msg_more (%d) waking\n"),
   1596                      trav->rrv));
   1597         /* Prepare next TX message */
   1598         trav->data->tx_ptr = bcm_rlink_encode(trav->data->tx_buf,
   1599                                               RLINK_MSG_TRAVERSE,
   1600                                               RLINK_TYPE_NEXT, 0);
   1601         BCM_PACK_U32(trav->data->tx_ptr, data->c_id);
   1602         BCM_PACK_U32(trav->data->tx_ptr, data->s_id);
   1603         trav->state = client_run;
   1604         RLINK_TRAVC_WAKE(trav);
   1605     }
   1606     return rv;
   1607 }
   1608 
   1609 
   1610 /* handle DONE message
   1611    received by client from server
   1612       when DONE
   1613         _rlink_trav_msg_done()
   1614           if exists c-id
   1615             update client record
   1616             wake up client traverse
   1617           else
   1618             error
   1619           end
   1620 
   1621 */
   1622 STATIC int
   1623 _bcm_rlink_trav_msg_done(bcm_rlink_traverse_data_t *data)
   1624 {
   1625     _rlink_travc_t *trav;
   1626     int rv;
   1627 
   1628     rv = _bcm_rlink_travc_get(data,&trav);
   1629     if (BCM_SUCCESS(rv)) {
   1630 
   1631         BCM_UNPACK_U32(trav->data->rx_ptr, trav->rrv);
   1632         BCM_UNPACK_U32(trav->data->rx_ptr, trav->num);
   1633         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1634                     (BSL_META("TRAVERSE msg_done (%d) waking\n"),
   1635                      trav->rrv));
   1636         trav->state = trav->num > 0 ? client_run : client_done;
   1637         trav->done = TRUE;
   1638         RLINK_TRAVC_WAKE(trav);
   1639     }
   1640     return rv;
   1641 }
   1642 
   1643 
   1644 /*
   1645   Handle a traverse server request, and receive a response buffer
   1646       decode RLINK header (msg,type,unit)
   1647       decode TRAVERSE c-id
   1648       else
   1649         send ERROR
   1650  */
   1651 int
   1652 bcm_rlink_traverse_message(bcm_pkt_t *rx_pkt,
   1653                            uint8 *data_in, int len_in,
   1654                            uint8 *data_out, int len_out, int *actual)
   1655 {
   1656     rlink_msg_t msg;
   1657     rlink_type_t type;
   1658     int unit;
   1659     bcm_rlink_traverse_data_t data;
   1660     int rv = BCM_E_FAIL;
   1661 
   1662     data.rx_pkt = rx_pkt;
   1663     data.rx_buf = data_in;
   1664     data.rx_ptr = bcm_rlink_decode(data.rx_buf, &msg, &type, &unit);
   1665     data.rx_len = len_in;
   1666     data.tx_buf = data_out;
   1667     data.tx_ptr = data_out;
   1668     data.tx_len = len_out;
   1669     data.unit   = unit;
   1670     data.parent = NULL;
   1671     BCM_UNPACK_U32(data.rx_ptr, data.c_id);
   1672     BCM_UNPACK_U32(data.rx_ptr, data.s_id);
   1673     switch (type) {
   1674     case RLINK_TYPE_START:
   1675         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1676                     (BSL_META_U(unit,
   1677                                 "TRAVERSE START %d (%x:%x)\n"),
   1678                      unit, data.c_id, data.s_id));
   1679         rv = _bcm_rlink_trav_msg_start(&data);
   1680         break;
   1681     case RLINK_TYPE_NEXT:
   1682         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1683                     (BSL_META_U(unit,
   1684                                 "TRAVERSE NEXT %d (%x:%x)\n"),
   1685                      unit, data.c_id, data.s_id));
   1686         rv = _bcm_rlink_trav_msg_next(&data);
   1687         break;
   1688     case RLINK_TYPE_QUIT:
   1689         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1690                     (BSL_META_U(unit,
   1691                                 "TRAVERSE QUIT %d (%x:%x)\n"),
   1692                      unit, data.c_id, data.s_id));
   1693         rv = _bcm_rlink_trav_msg_quit(&data);
   1694         break;
   1695     case RLINK_TYPE_ERROR:
   1696         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1697                     (BSL_META_U(unit,
   1698                                 "TRAVERSE ERROR %d (%x:%x)\n"),
   1699                      unit, data.c_id, data.s_id));
   1700         rv = _bcm_rlink_trav_msg_error(&data);
   1701         break;
   1702     case RLINK_TYPE_MORE:
   1703         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1704                     (BSL_META_U(unit,
   1705                                 "TRAVERSE MORE %d (%x:%x)\n"),
   1706                      unit, data.c_id, data.s_id));
   1707         rv = _bcm_rlink_trav_msg_more(&data);
   1708         break;
   1709     case RLINK_TYPE_DONE:
   1710         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1711                     (BSL_META_U(unit,
   1712                                 "TRAVERSE DONE %d (%x:%x)\n"),
   1713                      unit, data.c_id, data.s_id));
   1714         rv = _bcm_rlink_trav_msg_done(&data);
   1715         break;
   1716     default:
   1717         LOG_VERBOSE(BSL_LS_SOC_COMMON,
   1718                     (BSL_META_U(unit,
   1719                                 "TRAVERSE %d? %d\n"), type, unit));
   1720         rv = BCM_E_NOT_FOUND;
   1721         break;
   1722     }
   1723 
   1724     if (actual) {
   1725         *actual = data.tx_ptr - data.tx_buf;
   1726     }
   1727 
   1728     return rv;
   1729 }
   1730 
   1731 /*
   1732   Initialize RLINK traverse subsystem
   1733  */
   1734 int
   1735 bcm_rlink_traverse_server_init(void)
   1736 {
   1737     int rv;
   1738 
   1739 #if RLINK_TRAV_THREADED_SERVER
   1740     _rlink_travs_lock = sal_mutex_create("bcmTRAVS");
   1741     if (_rlink_travs_lock == NULL) {
   1742         rv = BCM_E_RESOURCE;
   1743         goto error;
   1744     }
   1745 
   1746     _rlink_travs_sem  = sal_sem_create("bcmTRAVS", sal_sem_BINARY, 0);
   1747     if (_rlink_travs_sem == NULL) {
   1748         rv = BCM_E_RESOURCE;
   1749         goto error;
   1750     }
   1751 
   1752     _rlink_travt_sem  = sal_sem_create("bcmTRAVT", sal_sem_BINARY, 0);
   1753     if (_rlink_travt_sem == NULL) {
   1754         rv = BCM_E_RESOURCE;
   1755         goto error;
   1756     }
   1757 
   1758     /* init traverse thread */
   1759     _rlink_travs_thread_exit = FALSE;
   1760     _rlink_travs_thread = sal_thread_create("bcmTRAVS",
   1761                                                RLINK_TRAV_THREAD_STACK,
   1762                                                RLINK_TRAV_THREAD_PRIO,
   1763                                                _bcm_rlink_travs_thread,
   1764                                                NULL);
   1765     if (_rlink_travs_thread == SAL_THREAD_ERROR) {
   1766         rv = BCM_E_RESOURCE;
   1767         goto error;
   1768     }
   1769 #else
   1770     /* non threaded initialization */
   1771     _rlink_trav_buffer = sal_alloc(rlink_traverse_buffer_size, "bcmTRAVS");
   1772     if (_rlink_trav_buffer == NULL) {
   1773         rv = BCM_E_MEMORY;
   1774         goto error;
   1775     }
   1776     /* Calculate the maximum number of buffer pointers needed based on
   1777      the traverse buffer size, traverse reply length and traverse
   1778      reply overhead, rounding up. CPP complains if this calculation is
   1779      done at compile time. */
   1780 
   1781     _rlink_trav_info_max_length = rlink_traverse_buffer_size;
   1782     _rlink_trav_info_max_length /= RLINK_TRAVERSE_REPLY_LIMIT;
   1783     _rlink_trav_info_max_length++;
   1784 
   1785     _rlink_trav_info =
   1786         sal_alloc(_rlink_trav_info_max_length * sizeof(*_rlink_trav_info),
   1787                   "bcmTRAVS");
   1788     if (_rlink_trav_info == NULL) {
   1789         rv = BCM_E_MEMORY;
   1790         goto error;
   1791     }
   1792 #endif /* RLINK_TRAV_THREADED_SERVER */
   1793     rv = BCM_E_NONE;
   1794     goto done;
   1795  error:
   1796     (void)bcm_rlink_traverse_deinit();
   1797  done:
   1798     return rv;
   1799 }
   1800 
   1801 int
   1802 bcm_rlink_traverse_client_init(void)
   1803 {
   1804     int rv = BCM_E_NONE;
   1805 
   1806     /* init locks */
   1807     _rlink_travc_lock = sal_mutex_create("bcmTRAVC");
   1808     if (_rlink_travc_lock == NULL) {
   1809         rv = BCM_E_RESOURCE;
   1810     }
   1811 
   1812     return rv;
   1813 }
   1814 
   1815 int
   1816 bcm_rlink_traverse_init(void)
   1817 {
   1818     int rv;
   1819 
   1820     rv = bcm_rlink_traverse_client_init();
   1821     if (BCM_SUCCESS(rv)) {
   1822         rv = bcm_rlink_traverse_server_init();
   1823         if (BCM_FAILURE(rv)) {
   1824             (void)bcm_rlink_traverse_client_deinit();
   1825         }
   1826     }
   1827 
   1828     return rv;
   1829 }
   1830 
   1831 
   1832 /*
   1833   Deinitialize RLINK traverse subsystem
   1834  */
   1835 int
   1836 bcm_rlink_traverse_server_deinit(void)
   1837 {
   1838 #if RLINK_TRAV_THREADED_SERVER
   1839     /* stop traverse thread */
   1840     if (_rlink_travs_thread != SAL_THREAD_ERROR) {
   1841         _rlink_travs_thread_exit = TRUE;
   1842         sal_sem_give(_rlink_travt_sem);
   1843         sal_thread_yield();
   1844         while (_rlink_travs_thread != SAL_THREAD_ERROR) {
   1845             sal_sem_give(_rlink_travt_sem);
   1846             sal_usleep(10000);
   1847         }
   1848         _rlink_travs_thread_exit = FALSE;
   1849     }
   1850     /* free locks */
   1851     if (_rlink_travs_sem) {
   1852     	sal_sem_destroy(_rlink_travs_sem);
   1853         _rlink_travs_sem = NULL;
   1854     }
   1855     if (_rlink_travt_sem) {
   1856     	sal_sem_destroy(_rlink_travt_sem);
   1857         _rlink_travt_sem = NULL;
   1858     }
   1859     if (_rlink_travs_lock) {
   1860         /* Deal with any outstanding server requests */
   1861         bcm_rlink_traverse_server_clear();
   1862     	sal_mutex_destroy(_rlink_travs_lock);
   1863         _rlink_travs_lock = NULL;
   1864     }
   1865 #else
   1866     if (_rlink_trav_buffer) {
   1867         sal_free(_rlink_trav_buffer);
   1868         _rlink_trav_buffer = NULL;
   1869     }
   1870     if (_rlink_trav_info) {
   1871         sal_free(_rlink_trav_info);
   1872         _rlink_trav_info = NULL;
   1873     }
   1874 #endif /* RLINK_TRAV_THREADED_SERVER */
   1875 
   1876     return BCM_E_NONE;
   1877 }
   1878 
   1879 int
   1880 bcm_rlink_traverse_client_deinit(void)
   1881 {
   1882     if (_rlink_travc_lock) {
   1883         /* Deal with any outstanding client requests */
   1884         bcm_rlink_traverse_client_clear();
   1885     	sal_mutex_destroy(_rlink_travc_lock);
   1886         _rlink_travc_lock = NULL;
   1887     }
   1888 
   1889     return BCM_E_NONE;
   1890 }
   1891 
   1892 
   1893 
   1894 int
   1895 bcm_rlink_traverse_deinit(void)
   1896 {
   1897     (void)bcm_rlink_traverse_client_deinit();
   1898     (void)bcm_rlink_traverse_server_deinit();
   1899     return BCM_E_NONE;
   1900 }
   1901 
   1902 #endif /* BCM_RPC_SUPPORT */