soc_async.c (27182B)
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: soc_async.c 8 * Purpose: This file implements the async frame work 9 * used by various soc cimicx modules. Async framework 10 * facilitates the message queuing and call back notification 11 * mechanism is multi threaded environment. 12 */ 13 14 #include <shared/bsl.h> 15 #include <sal/core/time.h> 16 #include <sal/core/sync.h> 17 #include <sal/core/thread.h> 18 #include <sal/core/boot.h> 19 #include <sal/core/libc.h> 20 #include <shared/alloc.h> 21 #include <soc/soc_async.h> 22 #include <soc/util.h> 23 24 #ifdef BCM_SOC_ASYNC_SUPPORT 25 26 /* This structure is associated of the thread safe queue management. 27 * Each queue will be represented by structure pointer. 28 */ 29 typedef struct { 30 int head; 31 int tail; 32 int count; 33 int size; 34 sal_spinlock_t lock; 35 soc_async_msg_t **msg_q; 36 }soc_async_queue_t; 37 38 typedef enum { 39 s_stop = 0, 40 s_start, 41 s_wait, 42 s_run, 43 s_exit 44 } thread_state_t; 45 46 typedef enum { 47 c_stop = 0, 48 c_start, 49 c_exit 50 } thread_cmd_t; 51 52 typedef struct { 53 sal_thread_t pid; 54 sal_sem_t wait_event; 55 thread_state_t state; 56 }async_thread_t; 57 58 59 /* This structure is associated with the async thread. */ 60 typedef struct { 61 int unit; 62 soc_async_p_type type; 63 soc_async_queue_t queue; 64 int threads; 65 thread_cmd_t cmd; 66 sal_spinlock_t lock; 67 int count; 68 sal_sem_t stop_sem; 69 async_thread_t *async_threads; 70 } soc_async_proc_t; 71 72 /******************************************* 73 * @function _async_queue_create 74 * purpose Create async message que 75 * 76 * @param size [in] size of the queue 77 * @param q [in] pointer to soc_async_queue_t 78 79 * @returns SOC_E_NONE 80 * @returns SOC_E_MEMORY 81 * 82 * @end 83 */ 84 STATIC int 85 _async_queue_create(int size, soc_async_queue_t *q) 86 { 87 q->msg_q = sal_alloc(sizeof(soc_async_msg_t *)*size, "Message Q"); 88 89 if (q->msg_q == NULL) { 90 return SOC_E_MEMORY; 91 } 92 93 q->lock = sal_spinlock_create("Msg Lock"); 94 95 if (q->lock == NULL) { 96 sal_free(q->msg_q); 97 q->msg_q = NULL; 98 return SOC_E_MEMORY; 99 } 100 101 q->size = size; 102 q->tail = q->head = 0; 103 104 return SOC_E_NONE; 105 } 106 107 /******************************************* 108 * @function _async_proc_cmd_set 109 * purpose Set the proc command 110 * 111 * @param proc [in] pointer to soc_async_proc_t 112 * 113 * @returns None 114 * 115 * @end 116 */ 117 STATIC void 118 _async_proc_cmd_set(soc_async_proc_t *proc, thread_cmd_t cmd) 119 { 120 sal_spinlock_lock(proc->lock); 121 proc->cmd = cmd; 122 sal_spinlock_unlock(proc->lock); 123 } 124 125 /******************************************* 126 * @function _async_proc_cmd_get 127 * purpose Get the proc command 128 * 129 * @param proc [in] pointer to soc_async_proc_t 130 * 131 * @returns None 132 * 133 * @end 134 */ 135 STATIC thread_cmd_t 136 _async_proc_cmd_get(soc_async_proc_t *proc) 137 { 138 thread_cmd_t cmd; 139 140 sal_spinlock_lock(proc->lock); 141 cmd = proc->cmd; 142 sal_spinlock_unlock(proc->lock); 143 144 return cmd; 145 } 146 147 /******************************************* 148 * @function _async_proc_count_inc 149 * purpose increment message count in process. 150 * 151 * @param proc [in] pointer to soc_async_proc_t 152 * 153 * @returns None 154 * 155 * @end 156 */ 157 STATIC void 158 _async_proc_count_inc(soc_async_proc_t *proc) 159 { 160 sal_spinlock_lock(proc->lock); 161 proc->count++; 162 sal_spinlock_unlock(proc->lock); 163 } 164 165 /******************************************* 166 * @function _async_proc_count_dec 167 * purpose decrement message count in process. 168 * 169 * @param proc [in] pointer to soc_async_proc_t 170 * 171 * @returns None 172 * 173 * @end 174 */ 175 STATIC void 176 _async_proc_count_dec(soc_async_proc_t *proc) 177 { 178 thread_cmd_t cmd; 179 180 sal_spinlock_lock(proc->lock); 181 if (proc->count > 0) { 182 proc->count--; 183 } 184 sal_spinlock_unlock(proc->lock); 185 186 cmd = _async_proc_cmd_get(proc); 187 if ((cmd == c_stop) && (proc->count == 0)) { 188 LOG_VERBOSE(BSL_LS_SOC_COMMON, 189 (BSL_META_U(proc->unit, 190 "Wake Proc count\n"))); 191 sal_sem_give(proc->stop_sem); 192 } 193 194 } 195 196 /******************************************* 197 * @function _async_queue_destroy 198 * purpose Destroy the message 199 * 200 * @param q [in] pointer to soc_async_queue_t 201 * 202 * @returns SOC_E_NONE 203 * 204 * @end 205 */ 206 STATIC int 207 _async_queue_destroy(soc_async_queue_t *q) 208 { 209 if (q->lock) { 210 sal_spinlock_destroy(q->lock); 211 q->lock = NULL; 212 } 213 214 if(q->msg_q) { 215 sal_free(q->msg_q); 216 q->msg_q = NULL; 217 } 218 219 return SOC_E_NONE; 220 } 221 222 /******************************************* 223 * @function async_thread_func 224 * purpose Process the messages 225 * 226 * @param handle [in] Async handle of type soc_async_handle_t 227 * 228 * @returns None 229 * As DMA engines has multiple channels. In Async processing 230 * it is possible to utilize the channels in parallel so that 231 * total through put can be improved. 232 * So there is question that how many thread should be used. 233 * Because if there are more threads than a substential amount of 234 * time is spend in switching back and forth which will effect 235 * the throughput in neagtive way. On the other hand if number of 236 * threads are less than required than channels will be sitting 237 * idle even if messages are waiting to be processed. 238 * It looks like the tradeoff can be achieved if number of threads 239 * are 50% of available channels and each thread if shecdule and if 240 * request are in queue get 1st messages program DMA to start processing, 241 * get another message if present and program DMA to start and go back to 242 * wait for completrtion of the first utilizing the hardware processing 243 * time to program . In the mean time the 1st message is more likely to 244 * be done and callback function can be called ASAP. 245 * This ping pong scheme seem to be optimum because if suppose we program 246 * sequecne of messages then 1st request callback function will be waiting 247 * even if it is done, 248 * 249 * @end 250 */ 251 STATIC void 252 _async_thread_msg_proc(soc_async_handle_t handle) 253 { 254 soc_async_proc_t *proc = (soc_async_proc_t *)handle; 255 soc_async_msg_t *msg[2]; 256 int count, rv[2]; 257 int id = 0; 258 int state = 1; 259 int n = 0; 260 261 rv[0] = rv[1] = SOC_E_FAIL; 262 msg[0] = msg[1] = NULL; 263 while (1) { 264 switch (state) { 265 case 1: 266 soc_async_msg_count(handle, &count); 267 if (count) { 268 /* Get the message 1 */ 269 rv[id] = soc_async_msg_dequeue(handle, &msg[id]); 270 if (rv[id] == SOC_E_NONE) { 271 if (msg[id]->type == proc->type) { 272 /* process the message */ 273 if (msg[id]->proc_f != NULL) { 274 n++; 275 _async_proc_count_inc(handle); 276 rv[id] = msg[id]->proc_f(msg[id]->unit, 277 msg[id]->data, msg[id]->cookie); 278 id ^= 1; 279 state = 2; 280 } else { 281 /* Callback for notifcaition */ 282 if (msg[id]->cb_f != NULL) { 283 msg[id]->cb_f(msg[id]->unit, 284 msg[id]->data, msg[id]->cookie, SOC_E_UNAVAIL); 285 } 286 soc_async_msg_free(handle, msg[id]); 287 msg[id] = NULL; 288 } 289 } else { 290 soc_async_msg_free(handle, msg[id]); 291 } 292 } else { 293 state = 4; 294 } 295 } else { 296 state = 4; 297 } 298 299 break; 300 /* Get message 2 */ 301 case 2: 302 soc_async_msg_count(handle, &count); 303 if (count) { 304 rv[id] = soc_async_msg_dequeue(handle, &msg[id]); 305 if (rv[id] == SOC_E_NONE) { 306 if (msg[id]->type == proc->type) { 307 /* process the message */ 308 if (msg[id]->proc_f != NULL) { 309 n++; 310 _async_proc_count_inc(handle); 311 rv[id] = msg[id]->proc_f(msg[id]->unit, 312 msg[id]->data, msg[id]->cookie); 313 } else { 314 /* Callback for notifcaition */ 315 if (msg[id]->cb_f != NULL) { 316 msg[id]->cb_f(msg[id]->unit, 317 msg[id]->data, msg[id]->cookie, SOC_E_UNAVAIL); 318 soc_async_msg_free(handle, msg[id]); 319 msg[id] = NULL; 320 } 321 } 322 state = 3; 323 } else { 324 soc_async_msg_free(handle, msg[id]); 325 msg[id] = NULL; 326 } 327 } 328 } 329 if (n > 0) { 330 state = 3; 331 } else { 332 state = 4; 333 } 334 id ^= 1; 335 break; 336 337 case 3: 338 /* Complete message 1 */ 339 if (rv[id] == SOC_E_NONE) { 340 /* Wait for the processing to complete */ 341 if (msg[id]->wait_f != NULL) { 342 rv[id] = msg[id]->wait_f(msg[id]->unit, msg[id]->data, 343 msg[id]->cookie); 344 } 345 } 346 /* Callback for notifcaition */ 347 if (msg[id]->cb_f != NULL) { 348 msg[id]->cb_f(msg[id]->unit, 349 msg[id]->data, msg[id]->cookie, rv[id]); 350 } 351 soc_async_msg_free(handle, msg[id]); 352 msg[id] = NULL; 353 n--; 354 _async_proc_count_dec(handle); 355 if (n > 0) { 356 state = 2; 357 } else { 358 state = 4; 359 } 360 break; 361 362 default: 363 364 return; 365 } 366 } 367 368 } 369 370 /******************************************* 371 * @function async_thread_func 372 * purpose This is async thread fucntion to handle messages 373 * 374 * @param handle [in] Async handle of type soc_async_handle_t 375 * 376 * @returns None 377 * 378 * @end 379 */ 380 STATIC void 381 async_thread_func(soc_async_handle_t handle) 382 { 383 soc_async_proc_t *proc = (soc_async_proc_t *)handle; 384 int id = proc->threads; 385 async_thread_t *async_threads = &proc->async_threads[id - 1]; 386 thread_cmd_t cmd; 387 388 LOG_VERBOSE(BSL_LS_SOC_COMMON, 389 (BSL_META_U(proc->unit, 390 "id [%d] type [%d] started\n"), 391 id, proc->type)); 392 393 while(async_threads->state != s_exit) { 394 cmd = _async_proc_cmd_get(proc); 395 switch(async_threads->state) { 396 397 case s_stop: 398 if (cmd == c_exit) { 399 async_threads->state = s_exit; 400 } else if (cmd == c_start) { 401 async_threads->state = s_start; 402 } else { 403 /* Yield to delay */ 404 LOG_VERBOSE(BSL_LS_SOC_COMMON, 405 (BSL_META_U(proc->unit, 406 "Yield for stop\n"))); 407 sal_thread_yield(); 408 } 409 break; 410 case s_start: 411 if (cmd == c_exit) { 412 async_threads->state = s_exit; 413 } else if (cmd == c_stop) { 414 async_threads->state = s_stop; 415 } else { 416 async_threads->state = s_wait; 417 } 418 break; 419 case s_wait: 420 if (cmd == c_exit) { 421 async_threads->state = s_exit; 422 } else if (cmd == c_stop) { 423 async_threads->state = s_stop; 424 } else { 425 int count; 426 soc_async_msg_count(handle, &count); 427 if (count == 0) { 428 (void)sal_sem_take(async_threads->wait_event, 429 sal_sem_FOREVER); 430 } 431 async_threads->state = s_run; 432 } 433 break; 434 case s_run: 435 if (cmd == c_exit) { 436 async_threads->state = s_exit; 437 } else if (cmd == c_stop) { 438 async_threads->state = s_stop; 439 } else { 440 _async_thread_msg_proc(handle); 441 async_threads->state = s_wait; 442 } 443 break; 444 default: 445 LOG_VERBOSE(BSL_LS_SOC_COMMON, 446 (BSL_META_U(proc->unit, 447 "id [%d] Non Option\n"), id)); 448 break; 449 } 450 } 451 452 LOG_VERBOSE(BSL_LS_SOC_COMMON, 453 (BSL_META_U(proc->unit, 454 "id [%d] Terminated\n"), id)); 455 async_threads->pid = SAL_THREAD_ERROR; 456 sal_thread_exit(0); 457 458 } 459 460 /******************************************* 461 * @function _async_thread_destroy 462 * purpose Destroy the async threads 463 * 464 * @param proc [in] pointer to soc_async_proc_t 465 * 466 * @returns SOC_E_NONE 467 * 468 * @end 469 */ 470 STATIC int 471 _async_thread_destroy(soc_async_proc_t *proc) 472 { 473 soc_timeout_t to; 474 int i; 475 async_thread_t *async_threads = proc->async_threads; 476 477 if ((proc->threads == 0) || (async_threads == NULL)) { 478 return SOC_E_NONE; 479 } 480 481 /* Give thread a few seconds to wake up and exit */ 482 soc_timeout_init(&to, 50 * 1000000, 0); 483 _async_proc_cmd_set(proc, c_exit); 484 485 for (i = 0 ; i < proc->threads; i++) { 486 /* Wake up thread so it will check the exit flag */ 487 while (async_threads[i].pid != SAL_THREAD_ERROR) { 488 sal_sem_give(async_threads[i].wait_event); 489 if (soc_timeout_check(&to)) { 490 LOG_ERROR(BSL_LS_SOC_COMMON, 491 (BSL_META_U(proc->unit, 492 "thread will not exit\n"))); 493 break; 494 } 495 /* Delay for some time */ 496 sal_usleep(200); 497 } 498 if (async_threads[i].wait_event) { 499 sal_sem_destroy(async_threads[i].wait_event); 500 async_threads[i].wait_event = NULL; 501 } 502 } 503 504 if (proc->lock) { 505 sal_spinlock_destroy(proc->lock); 506 proc->lock = NULL; 507 } 508 509 if (proc->stop_sem) { 510 sal_sem_destroy(proc->stop_sem); 511 proc->stop_sem = NULL; 512 } 513 514 return SOC_E_NONE; 515 } 516 517 /******************************************* 518 * @function _async_thread_create 519 * purpose Create the async threads 520 * 521 * @param proc [in] pointer to soc_async_proc_t 522 * @param threads [in] number of threads 523 * @returns SOC_E_NONE 524 * 525 * @end 526 */ 527 528 STATIC int 529 _async_thread_create(soc_async_proc_t *proc, soc_async_prop_t *prop) 530 { 531 async_thread_t *async_threads = NULL; 532 int rv = SOC_E_NONE; 533 int i; 534 535 /* Create Async processing threads */ 536 async_threads = 537 sal_alloc(prop->threads * sizeof(async_thread_t), 538 "Async thread"); 539 540 if (async_threads == NULL) { 541 return SOC_E_MEMORY; 542 } 543 544 do { 545 proc->lock = sal_spinlock_create("Proc Lock"); 546 547 if (proc->lock == NULL) { 548 rv = SOC_E_MEMORY; 549 break; 550 } 551 552 proc->stop_sem = sal_sem_create("stop wait", sal_sem_BINARY, 0); 553 554 if (proc->stop_sem == NULL) { 555 rv = SOC_E_MEMORY; 556 break; 557 } 558 559 proc->async_threads = async_threads; 560 proc->cmd = c_start; 561 sal_memset(async_threads, 0, prop->threads * sizeof(async_thread_t)); 562 for (i = 0 ; i < prop->threads; i++) { 563 proc->threads = i + 1; 564 async_threads[i].wait_event = 565 sal_sem_create("Msg event", sal_sem_BINARY, 0); 566 567 if (async_threads[i].wait_event == NULL) { 568 rv = SOC_E_MEMORY; 569 break; 570 } 571 async_threads[i].state = s_stop; 572 async_threads[i].pid = sal_thread_create("Async thread", 573 SAL_THREAD_STKSZ, 574 prop->prio, 575 async_thread_func, 576 proc); 577 if (async_threads[i].pid == SAL_THREAD_ERROR) { 578 rv = SOC_E_FAIL; 579 break; 580 } 581 /* Let the thread started */ 582 sal_thread_yield(); 583 584 } 585 if (rv != SOC_E_NONE) { 586 break; 587 } else { 588 return rv; 589 } 590 } while(0); 591 592 (void)_async_thread_destroy(proc); 593 sal_free(async_threads); 594 proc->async_threads = NULL; 595 proc->threads = 0; 596 597 return rv; 598 599 } 600 601 /******************************************* 602 * @function _async_thread_wake 603 * purpose wake up async threads 604 * 605 * @param proc [in] pointer to soc_async_proc_t 606 * 607 * @returns SOC_E_NONE 608 * 609 * @end 610 */ 611 STATIC int 612 _async_thread_wake(soc_async_proc_t *proc) 613 { 614 int i, j; 615 int count; 616 async_thread_t *async_threads = proc->async_threads; 617 618 soc_async_msg_count(proc, &count); 619 /* Unblock the threads to process message */ 620 /* One thread will process 2 messages simulteneously */ 621 count = (count > 2 * proc->threads) ? \ 622 2 * proc->threads : count; 623 count = (count > 1) ? (count >> 1) : count; 624 for (i = 0, j = 0; (i < count) && (j < proc->threads); j++) { 625 if (async_threads[j].state == s_wait) { 626 sal_sem_give(async_threads[j].wait_event); 627 i++; 628 } 629 } 630 /* Let's yield for processing */ 631 sal_thread_yield(); 632 633 return SOC_E_NONE; 634 635 } 636 637 /******************************************* 638 * @function soc_async_proc_deinit 639 * purpose Deinit async proc. 640 * 641 * @param handle [in] Async handle of type soc_async_handle_t 642 * 643 * @returns SOC_E_NONE 644 * @returns SOC_E_XXX 645 * 646 * @comments The function will destroy message queues and processing 647 * threads, unbind associated channels and free resources. 648 * 649 * @end 650 */ 651 int soc_async_proc_deinit(soc_async_handle_t handle) 652 { 653 int rv = SOC_E_NONE; 654 soc_async_proc_t *proc = (soc_async_proc_t *)handle; 655 656 if (!handle) { 657 return SOC_E_PARAM; 658 } 659 660 soc_async_flush_queue(handle); 661 662 rv = _async_thread_destroy(proc); 663 sal_free(proc->async_threads); 664 proc->async_threads = NULL; 665 proc->threads = 0; 666 667 if (rv != SOC_E_NONE) 668 return rv; 669 LOG_VERBOSE(BSL_LS_SOC_COMMON, 670 (BSL_META_U(proc->unit, 671 "Async threads Destroyed\n"))); 672 673 LOG_VERBOSE(BSL_LS_SOC_COMMON, 674 (BSL_META_U(proc->unit, 675 "Message queue flushed\n"))); 676 677 rv = _async_queue_destroy(&proc->queue); 678 679 LOG_VERBOSE(BSL_LS_SOC_COMMON, 680 (BSL_META_U(proc->unit, 681 "Async proc Destroy Success\n"))); 682 683 sal_free(proc); 684 685 return rv; 686 } 687 688 /******************************************* 689 * @function soc_async_proc_init 690 * @purpose Initialize the async proc. 691 * 692 * @param unit [in] unit number 693 * @param prop [in] property of <soc_async_prop_t> 694 * 695 * @returns SOC_E_NONE 696 * @returns SOC_E_XXX 697 * 698 * @comments The function will allocate resources , create thread safe 699 * queues and processing threads. This will return handle to caller 700 * 701 * @end 702 */ 703 int soc_async_proc_init( 704 int unit, 705 soc_async_prop_t *prop, 706 soc_async_handle_t *handle) 707 { 708 int rv = SOC_E_NONE; 709 soc_async_proc_t *proc; 710 711 if (!prop) { 712 return SOC_E_PARAM; 713 } 714 if((prop->q_size == 0) || (prop->threads == 0)) { 715 return SOC_E_PARAM; 716 } 717 718 LOG_VERBOSE(BSL_LS_SOC_COMMON, 719 (BSL_META_U(unit, 720 "type = %d, size = %u, threads =%d\n"), 721 prop->type, (unsigned int)prop->q_size, prop->threads)); 722 723 proc = sal_alloc(sizeof(*proc), "Async PROC"); 724 725 if (proc == NULL) { 726 return SOC_E_MEMORY; 727 } 728 729 sal_memset(proc, 0, sizeof(*proc)); 730 proc->unit = unit; 731 proc->type = prop->type; 732 733 /* Initialize message queue */ 734 rv = _async_queue_create(prop->q_size, &proc->queue); 735 736 if (rv != SOC_E_NONE) { 737 goto error; 738 } 739 740 rv = _async_thread_create(proc, prop); 741 742 if (rv != SOC_E_NONE) { 743 goto error; 744 } 745 746 *handle = (soc_async_handle_t)proc; 747 748 LOG_VERBOSE(BSL_LS_SOC_COMMON, 749 (BSL_META_U(unit, 750 "Async proc type[%d] create Success\n"), 751 prop->type)); 752 753 return SOC_E_NONE; 754 error: 755 756 LOG_ERROR(BSL_LS_SOC_COMMON, 757 (BSL_META_U(unit, 758 "Error in initialize Async thread.\n"))); 759 soc_async_proc_deinit(proc); 760 return rv; 761 } 762 763 /******************************************* 764 * @function soc_async_msg_alloc 765 * purpose Allocate the message 766 * 767 * @param handle [in] Async handle of type soc_async_handle_t 768 * @param msg [in] pointer to pointer of message 769 770 * @returns SOC_E_NONE 771 * @returns SOC_E_MEMORY 772 * 773 * @end 774 */ 775 int soc_async_msg_alloc( 776 soc_async_handle_t handle, 777 soc_async_msg_t **msg) 778 { 779 780 /* If required, to optimize the peformance application 781 * specific allocation method can be implemented 782 */ 783 *msg = sal_alloc(sizeof(soc_async_msg_t), "Async MSG"); 784 785 if (*msg == NULL) { 786 return SOC_E_MEMORY; 787 } 788 return SOC_E_NONE; 789 } 790 791 /******************************************* 792 * @function soc_async_msg_free 793 * purpose Free the previously allocated the message 794 * 795 * @param handle [in] Async handle of type soc_async_handle_t 796 * @param msg [in] pointer of message 797 * @returns SOC_E_NONE 798 * @returns SOC_E_PARAM 799 * 800 * @end 801 */ 802 int soc_async_msg_free( 803 soc_async_handle_t handle, 804 soc_async_msg_t *msg) 805 { 806 if (msg == NULL) { 807 return SOC_E_PARAM; 808 } 809 sal_free(msg); 810 return SOC_E_NONE; 811 } 812 813 /******************************************* 814 * @function soc_async_msg_queue 815 * purpose Queue the message 816 * 817 * @param handle [in] Async handle of type soc_async_handle_t 818 * @param msg [in] message pointer 819 820 * @returns SOC_E_NONE 821 * @returns SOC_E_XXX 822 * 823 * @comments This will queue the message "soc_async_msg_t" and 824 trigger the event so that associated thread is unblocked, 825 dequeue and process the message. 826 * 827 * @end 828 */ 829 int soc_async_msg_queue( 830 soc_async_handle_t handle, 831 soc_async_msg_t *msg) 832 { 833 soc_async_proc_t *proc = (soc_async_proc_t *)handle; 834 soc_async_queue_t *q = &proc->queue; 835 int count; 836 thread_cmd_t cmd; 837 838 cmd = _async_proc_cmd_get(proc); 839 if((cmd == c_exit) || (cmd == c_stop)) { 840 return SOC_E_UNAVAIL; 841 } 842 843 sal_spinlock_lock(q->lock); 844 count = q->tail - q->head; 845 if ((count == -1) || (count == q->size - 1)) { 846 sal_spinlock_unlock(q->lock); 847 return SOC_E_MEMORY; 848 } 849 q->msg_q[q->tail] = msg; 850 q->count++; 851 q->tail = (q->tail + 1) % q->size; 852 count = q->count; 853 sal_spinlock_unlock(q->lock); 854 855 LOG_VERBOSE(BSL_LS_SOC_COMMON, 856 (BSL_META_U(proc->unit, 857 "Messages = %d\n"), 858 count)); 859 860 _async_thread_wake(proc); 861 862 return SOC_E_NONE; 863 } 864 865 /******************************************* 866 * @function soc_async_msg_dequeue 867 * purpose Dequeue the message 868 * 869 * @param handle [in] Async handle of type soc_async_handle_t 870 * @param msg [out] message pointer to get the message 871 872 * @returns SOC_E_NONE 873 * @returns SOC_E_XXX 874 * 875 * @comments The processing Threads will call this function to 876 * dequeue the message from the thread safe message queue to 877 * process it further. 878 * 879 * @end 880 */ 881 int soc_async_msg_dequeue( 882 soc_async_handle_t handle, 883 soc_async_msg_t **msg) 884 { 885 soc_async_proc_t *proc = (soc_async_proc_t *)handle; 886 soc_async_queue_t *q = &proc->queue; 887 int count; 888 thread_cmd_t cmd; 889 890 cmd = _async_proc_cmd_get(proc); 891 if(cmd == c_exit) { 892 return SOC_E_UNAVAIL; 893 } 894 895 sal_spinlock_lock(q->lock); 896 897 if (q->tail == q->head) { 898 sal_spinlock_unlock(q->lock); 899 return SOC_E_MEMORY; 900 } 901 *msg = q->msg_q[q->head]; 902 q->head = (q->head + 1) % q->size; 903 q->count--; 904 count = q->count; 905 sal_spinlock_unlock(q->lock); 906 LOG_VERBOSE(BSL_LS_SOC_COMMON, 907 (BSL_META_U(proc->unit, 908 "Messages = %d \n"), count)); 909 910 return SOC_E_NONE; 911 } 912 913 914 /******************************************* 915 * @function soc_async_flush_queue 916 * purpose Flush the message queue 917 * 918 * @param handle [in] Async handle of type soc_async_handle_t 919 * 920 * @returns SOC_E_NONE 921 * @returns SOC_E_XXX 922 * 923 * @comments Delete all the messages in the queue and make it empty. 924 * 925 * @end 926 */ 927 int soc_async_flush_queue(soc_async_handle_t handle) 928 { 929 int i, count; 930 soc_async_msg_t *msg; 931 soc_async_proc_t *proc = (soc_async_proc_t *)handle; 932 int rv; 933 934 soc_async_msg_stop(handle); 935 soc_async_msg_count(handle, &count); 936 LOG_VERBOSE(BSL_LS_SOC_COMMON, 937 (BSL_META_U(proc->unit, 938 "[%d] Messages to Flush\n"), count)); 939 940 for ( i = 0 ; i < count ; i++) { 941 rv = soc_async_msg_dequeue(handle, &msg); 942 if (SOC_SUCCESS(rv)) { 943 soc_async_msg_free(handle, msg); 944 } 945 } 946 soc_async_msg_start(handle); 947 return SOC_E_NONE; 948 } 949 950 /******************************************* 951 * @function soc_async_msg_count 952 * purpose Get the number of messages in the queue 953 * 954 * @param handle [in] Async handle of type soc_async_handle_t 955 * @param count [out] returns message count 956 * 957 * @returns SOC_E_NONE 958 * 959 * @comments Delete all the messages in the queue and make it empty. 960 * 961 * @end 962 */ 963 int soc_async_msg_count(soc_async_handle_t handle, int *count) 964 { 965 soc_async_queue_t *q = &((soc_async_proc_t *)handle)->queue; 966 967 sal_spinlock_lock(q->lock); 968 *count = q->count; 969 sal_spinlock_unlock(q->lock); 970 971 return SOC_E_NONE; 972 } 973 974 /******************************************* 975 * @function soc_async_msg_start 976 * purpose start the message queue processing 977 * 978 * @param handle [in] Async handle of type soc_async_handle_t 979 * 980 * @returns SOC_E_NONE 981 * 982 * @end 983 */ 984 int soc_async_msg_start(soc_async_handle_t handle) 985 { 986 soc_async_proc_t *proc = (soc_async_proc_t *)handle; 987 int count = 0; 988 989 soc_async_msg_count(handle, &count); 990 _async_proc_cmd_set(proc, c_start); 991 if (count > 0) { 992 _async_thread_wake(proc); 993 } 994 995 return SOC_E_NONE; 996 } 997 998 /******************************************* 999 * @function soc_async_msg_stop 1000 * purpose Stop the message queue processing 1001 * 1002 * @param handle [in] Async handle of type soc_async_handle_t 1003 * 1004 * @returns SOC_E_NONE 1005 * 1006 * @end 1007 */ 1008 int soc_async_msg_stop(soc_async_handle_t handle) 1009 { 1010 soc_async_proc_t *proc = (soc_async_proc_t *)handle; 1011 int count = 0; 1012 1013 _async_proc_cmd_set(proc, c_stop); 1014 1015 sal_spinlock_lock(proc->lock); 1016 count = proc->count; 1017 sal_spinlock_unlock(proc->lock); 1018 1019 if (count > 0) { 1020 LOG_ERROR(BSL_LS_SOC_COMMON, 1021 (BSL_META_U(proc->unit, 1022 "[%d] Wait Proc count\n"), count)); 1023 (void)sal_sem_take(proc->stop_sem, sal_sem_FOREVER); 1024 } 1025 1026 return SOC_E_NONE; 1027 } 1028 1029 1030 1031 #endif /* BCM_SOC_ASYNC_SUPPORT */ 1032