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