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

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