O-RAN E Maintenance Release contribution for ODULOW
[o-du/phy.git] / fapi_5g / source / framework / wls / fapi2phy / nr5g_fapi_fapi2phy_wls.c
1 /******************************************************************************
2 *
3 *   Copyright (c) 2019 Intel.
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 *
17 *******************************************************************************/
18
19 /**
20  * @file This file has Shared Memory interface functions between FAPI and PHY
21  * @defgroup nr5g_fapi_source_framework_wls_fapi2phy_group
22  **/
23
24 #include "nr5g_fapi_std.h"
25 #include "nr5g_fapi_common_types.h"
26 #include "nr5g_fapi_internal.h"
27 #include "nr5g_fapi_wls.h"
28 #include "nr5g_fapi_fapi2phy_wls.h"
29 #include "nr5g_fapi_log.h"
30 #include "nr5g_fapi_urllc_thread.h"
31
32 static uint32_t g_to_free_send_list_cnt[TO_FREE_SIZE] = { 0 };
33 static uint64_t g_to_free_send_list[TO_FREE_SIZE][TOTAL_FREE_BLOCKS] = { {0L} };
34 static uint32_t g_to_free_recv_list_cnt[TO_FREE_SIZE] = { 0 };
35 static uint64_t g_to_free_recv_list[TO_FREE_SIZE][TOTAL_FREE_BLOCKS] = { {0L} };
36
37 static uint32_t g_to_free_send_list_cnt_urllc[TO_FREE_SIZE_URLLC] = { 0 };
38 static uint64_t g_to_free_send_list_urllc[TO_FREE_SIZE_URLLC][TOTAL_FREE_BLOCKS] = { {0L} };
39
40 //------------------------------------------------------------------------------
41 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
42  *
43  *  @param data Pointer to validate
44  *
45  *  @return  TRUE If pointer is within valid shared WLS memory region
46  *           FALSE If pointer is out of valid shared WLS memory region
47  *
48  *  @description
49  *  This function validates pointer's in WLS shared memory region
50  *
51 **/
52 //------------------------------------------------------------------------------
53 uint8_t nr5g_fapi_fapi2phy_is_valid_wls_ptr(
54     void *data)
55 {
56     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
57     if ((unsigned long)data >= (unsigned long)p_wls_ctx->pPartitionMemBase &&
58         (unsigned long)data < ((unsigned long)p_wls_ctx->pPartitionMemBase +
59             p_wls_ctx->nPartitionMemSize)) {
60         return TRUE;
61     } else {
62         return FALSE;
63     }
64 }
65
66 //------------------------------------------------------------------------------
67 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
68  *
69  *  @param void
70  *
71  *  @return  A pointer to WLS_HANDLE stucture
72  *
73  *  @description
74  *  This function returns the WLS instance
75  *
76 **/
77 //------------------------------------------------------------------------------
78 static inline WLS_HANDLE nr5g_fapi_fapi2phy_wls_instance(
79     )
80 {
81     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
82     return p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST];
83 }
84
85 //----------------------------------------------------------------------------------
86 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
87  *
88  *  @param[out]   data Location where First API from L1 is stored
89  *
90  *  @return  Size of Message sent from L1
91  *
92  *  @description
93  *  This function queries the APIs sent from L1 to L2 and gets the first pointer
94  *  to the linked list
95  *
96 **/
97 //----------------------------------------------------------------------------------
98 inline uint64_t *nr5g_fapi_fapi2phy_wls_get(
99     uint32_t * msg_size,
100     uint16_t * msg_type,
101     uint16_t * flags)
102 {
103     uint64_t *data = NULL;
104     WLS_HANDLE h_wls;
105     uint32_t ms = 0;
106     uint16_t mt = 0, f = 0;
107
108     h_wls = nr5g_fapi_fapi2phy_wls_instance();
109     data = (uint64_t *) WLS_Get(h_wls, &ms, &mt, &f);
110     *msg_size = ms, *msg_type = mt, *flags = f;
111     NR5G_FAPI_LOG(TRACE_LOG, ("[FAPI2PHY WLS][GET] %p size: %d "
112             "type: %x flags: %x", data, *msg_size, *msg_type, *flags));
113
114     return data;
115 }
116
117 //----------------------------------------------------------------------------------
118 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
119  *
120  *  @param[in]   p_msg Pointer to API block that needs to be sent to L1
121  *  @param[in]   msg_size Size of Message
122  *  @param[in]   msg_id Message Id
123  *  @param[in]   flags Special flags needed for WLS
124  *
125  *  @return  0 if SUCCESS
126  *
127  *  @description
128  *  This function adds a block of API from L2 to L1 which will be sent later
129  *
130 **/
131 //----------------------------------------------------------------------------------
132 inline uint8_t nr5g_fapi_fapi2phy_wls_put(
133     uint64_t p_msg,
134     uint32_t msg_size,
135     uint16_t msg_type,
136     uint16_t flags)
137 {
138     int ret = SUCCESS;
139     WLS_HANDLE h_phy_wls = nr5g_fapi_fapi2phy_wls_instance();
140     uint64_t pa = nr5g_fapi_wls_va_to_pa(h_phy_wls, (void *)p_msg);
141     NR5G_FAPI_LOG(TRACE_LOG, ("[FAPI2PHY WLS][PUT] %ld size: %d "
142             "type: %x flags: %x", pa, msg_size, msg_type, flags));
143     ret = WLS_Put(h_phy_wls, pa, msg_size, msg_type, flags);
144
145     return ret;
146 }
147
148 //----------------------------------------------------------------------------------
149 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
150  *
151  *  @param   void
152  *
153  *  @return  Number of blocks of APIs received
154  *
155  *  @description
156  *  This functions waits in a infinite loop for L1 to send a list of APIs to MAC. This is called
157  *  during runtime when L2 sends a API to L1 and then waits for response back.
158  *
159 **/
160 //----------------------------------------------------------------------------------
161 inline uint32_t nr5g_fapi_fapi2phy_wls_wait(
162     )
163 {
164     int ret = SUCCESS;
165 //    NR5G_FAPI_LOG(TRACE_LOG, ("Waiting for L1 to respond in WLS Wait"));
166     ret = WLS_Wait(nr5g_fapi_fapi2phy_wls_instance());
167     return ret;
168 }
169
170 //------------------------------------------------------------------------------
171 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
172  *
173  *  @param[out]   data Location where First API from L1 is stored
174  *
175  *  @return  Size of Message sent from L1
176  *
177  *  @description
178  *  This function checks if this is the last message in this tti.
179  *
180 **/
181 //------------------------------------------------------------------------------
182 static inline uint8_t is_msg_present(
183     uint16_t flags)
184 {
185     return (!((flags & WLS_TF_FIN) || (flags == 0)));
186 }
187
188 //----------------------------------------------------------------------------------
189 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
190  *
191  *  @param[out]   data Location where First API from L1 is stored
192  *
193  *  @return  Size of Message sent from L1
194  *
195  *  @description
196  *  This function queries the APIs sent from L1 to L2 and gets the first pointer
197  *  to the linked list
198  *
199 **/
200 //----------------------------------------------------------------------------------
201 PMAC2PHY_QUEUE_EL nr5g_fapi_fapi2phy_wls_recv(
202     )
203 {
204     uint16_t msg_type = 0;
205     uint16_t flags = 0;
206     uint32_t msg_size = 0;
207     uint32_t num_elms = 0;
208     uint64_t *p_msg = NULL;
209     static uint32_t g_free_recv_idx = 0;
210     PMAC2PHY_QUEUE_EL p_qelm_list = NULL, p_urllc_qelm_list = NULL;
211     PMAC2PHY_QUEUE_EL p_qelm = NULL;
212     PMAC2PHY_QUEUE_EL p_tail_qelm = NULL, p_urllc_tail_qelm = NULL;
213     uint64_t start_tick = 0;
214
215     num_elms = nr5g_fapi_fapi2phy_wls_wait();
216     if (!num_elms)
217         return p_qelm_list;
218
219     start_tick = __rdtsc();
220
221     do {
222         p_msg = nr5g_fapi_fapi2phy_wls_get(&msg_size, &msg_type, &flags);
223         if (p_msg) {
224             WLS_HANDLE h_wls = nr5g_fapi_fapi2phy_wls_instance();
225             p_qelm = (PMAC2PHY_QUEUE_EL)
226                 nr5g_fapi_wls_pa_to_va(h_wls, (uint64_t) p_msg);
227             if (nr5g_fapi_fapi2phy_is_valid_wls_ptr(p_qelm) == FALSE) {
228                 printf("Error: Invalid Ptr\n");
229                 continue;
230             }
231             p_qelm->pNext = NULL;
232
233             if (flags & WLS_TF_URLLC)
234             {
235                 if (p_urllc_qelm_list) {
236                     p_urllc_tail_qelm->pNext = p_qelm;
237                     p_urllc_tail_qelm = p_qelm;
238                 } else {
239                     p_urllc_qelm_list = p_qelm;
240                     p_urllc_tail_qelm = p_qelm;
241                 }
242             } else {
243             if (p_qelm_list) {
244                 p_tail_qelm->pNext = p_qelm;
245                 p_tail_qelm = p_qelm;
246             } else {
247                 p_qelm_list = p_qelm;
248                 p_tail_qelm = p_qelm;
249             }
250         }
251
252         }
253         num_elms--;
254     } while (num_elms && is_msg_present(flags));
255
256     if (p_urllc_qelm_list) {
257         wls_fapi_add_recv_apis_to_free(p_urllc_qelm_list, g_free_recv_idx);
258         g_free_recv_idx++;
259         if (g_free_recv_idx >= TO_FREE_SIZE) {
260             g_free_recv_idx = 0;
261         }
262         // Free 10 TTIs Later
263         wls_fapi_free_recv_free_list(g_free_recv_idx);
264
265         wls_fapi_add_blocks_to_ul();
266         nr5g_fapi_urllc_thread_callback(NR5G_FAPI_URLLC_MSG_DIR_PHY2MAC, (void *) p_urllc_qelm_list);
267     }
268
269     if (p_qelm_list) {
270         wls_fapi_add_recv_apis_to_free(p_qelm_list, g_free_recv_idx);
271         g_free_recv_idx++;
272         if (g_free_recv_idx >= TO_FREE_SIZE) {
273             g_free_recv_idx = 0;
274         }
275         // Free 10 TTIs Later
276         wls_fapi_free_recv_free_list(g_free_recv_idx);
277
278         wls_fapi_add_blocks_to_ul();
279     }
280     tick_total_wls_get_per_tti_ul += __rdtsc() - start_tick;
281
282     return p_qelm_list;
283 }
284
285 //------------------------------------------------------------------------------
286 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
287  *
288  *  @param[in]    p_msg_header Pointer to the TxSDuReq Message block
289  *  @param[out]   n_zbc_blocks Number of ZBC blocks
290  *
291  *  @return  1 if this block is a TxSduReq message. 0 else.
292  *
293  *  @description
294  *  This function checks if a block is a TxSduReq messages and counts the number
295  *  of ZBC blocks in this API
296  *
297 **/
298 //------------------------------------------------------------------------------
299 int nr5g_fapi_fapi2phy_is_sdu_zbc_block(
300     void *p_msg,
301     int *num_zbc_blocks)
302 {
303     PL1L2MessageHdr p_msg_header = (PL1L2MessageHdr) p_msg;
304     *num_zbc_blocks = 0;
305
306     if (p_msg_header->nMessageType == MSG_TYPE_PHY_TX_REQ) {
307         PTXRequestStruct p_dl_sdu_req = (PTXRequestStruct) p_msg_header;
308         PDLPDUDataStruct p_dl_pdu_data = (PDLPDUDataStruct) (p_dl_sdu_req + 1);
309         uint32_t i;
310         for (i = 0; i < p_dl_sdu_req->nPDU; i++) {
311             *num_zbc_blocks += (p_dl_pdu_data->nPduLen1 ? 1 : 0);
312             *num_zbc_blocks += (p_dl_pdu_data->nPduLen2 ? 1 : 0);
313             p_dl_pdu_data++;
314         }
315
316         if (*num_zbc_blocks) {
317             return 1;
318         }
319     }
320
321     return 0;
322 }
323
324 //----------------------------------------------------------------------------------
325 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
326  *
327  *  @param[in]   p_msg_header Pointer to the TxSduReq Message block
328  *  @param[in]   flags Special flags needed for WLS
329  *  @param[in]   n_zbc_blocks Number of ZBC blocks in list
330  *
331  *  @return  0 if SUCCESS
332  *
333  *  @description
334  *  This function adds all the ZBC blocks in a TXSDU Message and prepares them to
335  *  be sent to the L1
336  *
337 **/
338 //------------------------------------------------------------------------------
339 uint32_t nr5g_fapi_fapi2phy_send_zbc_blocks(
340     void *p_msg,
341     uint16_t flags)
342 {
343     PL1L2MessageHdr p_msg_header = (PL1L2MessageHdr) p_msg;
344     PTXRequestStruct p_dl_sdu_req = (PTXRequestStruct) p_msg_header;
345     PDLPDUDataStruct p_dl_pdu_data = (PDLPDUDataStruct) (p_dl_sdu_req + 1);
346     uint32_t i, j, is_last, is_last1, msg_type;
347     uint16_t list_flags = flags;
348     uint16_t flags_urllc = (flags & WLS_TF_URLLC) ? WLS_TF_URLLC : 0;
349
350     for (i = 0; i < p_dl_sdu_req->nPDU; i++) {
351         is_last = (i == (p_dl_sdu_req->nPDU - 1));
352         for (j = 0; j < MAX_DL_PER_UE_CODEWORD_NUM; j++) {
353             uint32_t pdu_len;
354             uint8_t *p_payload;
355             p_payload = NULL;
356             msg_type = 0;
357             if (j == 0) {
358                 pdu_len = p_dl_pdu_data->nPduLen1;
359                 p_payload = p_dl_pdu_data->pPayload1;
360                 msg_type = MSG_PHY_ZBC_BLOCK0_REQ;
361             } else {
362                 pdu_len = p_dl_pdu_data->nPduLen2;
363                 p_payload = p_dl_pdu_data->pPayload2;
364                 msg_type = MSG_PHY_ZBC_BLOCK1_REQ;
365             }
366
367             if (p_payload) {
368                 is_last1 = (((j == 0) && (p_dl_pdu_data->pPayload2 == 0)) ||
369                     (j == (MAX_DL_PER_UE_CODEWORD_NUM - 1)));
370                 if ((list_flags & WLS_TF_FIN) && is_last && is_last1) {
371                     flags = WLS_SG_LAST | flags_urllc;
372                 } else {
373                     flags = WLS_SG_NEXT | flags_urllc;
374                 }
375
376                 WLS_HANDLE h_phy_wls = nr5g_fapi_fapi2phy_wls_instance();
377                 if (WLS_Put(h_phy_wls, (uint64_t) p_payload, pdu_len, msg_type,
378                         flags) != SUCCESS) {
379                     printf("Error ZBC block 0x%016lx\n", (uint64_t) p_payload);
380                     return FAILURE;
381                 }
382             }
383         }
384         p_dl_pdu_data++;
385     }
386
387     return SUCCESS;
388 }
389
390 //------------------------------------------------------------------------------
391 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
392  *
393  *  @param[in]      A pointer to the phy instance
394  *  @param[in]      A data Pointer to the Linked list header
395  *
396  *  @return         0 if SUCCESS
397  *
398  *  @description    This function sends a list of APIs to the L1 via WLS
399  *
400 **/
401 //------------------------------------------------------------------------------
402 uint8_t nr5g_fapi_fapi2phy_wls_send(
403     void *data,
404     bool is_urllc)
405 {
406     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
407     PMAC2PHY_QUEUE_EL p_curr_msg = NULL;
408     PL1L2MessageHdr p_msg_header;
409     uint16_t flags = 0;
410     uint16_t flags_urllc = (is_urllc ? WLS_TF_URLLC : 0);
411     uint8_t ret = SUCCESS;
412     int n_zbc_blocks = 0, is_zbc = 0, count = 0;
413     static uint32_t g_free_send_idx = 0;
414     static uint32_t g_free_send_idx_urllc = 0;
415
416     p_curr_msg = (PMAC2PHY_QUEUE_EL) data;
417     is_urllc ? wls_fapi_add_send_apis_to_free_urllc(p_curr_msg, g_free_send_idx_urllc)
418              : wls_fapi_add_send_apis_to_free(p_curr_msg, g_free_send_idx);
419
420     if (pthread_mutex_lock((pthread_mutex_t *) & p_wls_ctx->fapi2phy_lock_send)) {
421         NR5G_FAPI_LOG(ERROR_LOG, ("unable to lock send pthread mutex"));
422         return FAILURE;
423     }
424
425     if (p_curr_msg->pNext) {
426         flags = WLS_SG_FIRST | flags_urllc;
427         while (p_curr_msg) {
428             // only batch mode
429             count++;
430             p_msg_header = (PL1L2MessageHdr) (p_curr_msg + 1);
431             if (p_curr_msg->pNext) {    // FIRST/NEXT list element
432                 if (SUCCESS != nr5g_fapi_fapi2phy_wls_put((uint64_t) p_curr_msg,
433                         p_curr_msg->nMessageLen + sizeof(MAC2PHY_QUEUE_EL),
434                         p_msg_header->nMessageType, flags)) {
435                     if (pthread_mutex_unlock((pthread_mutex_t *) &
436                             p_wls_ctx->fapi2phy_lock_send)) {
437                         NR5G_FAPI_LOG(ERROR_LOG,
438                             ("unable to unlock send pthread mutex"));
439                     }
440                     return FAILURE;
441                 }
442
443                 if (nr5g_fapi_fapi2phy_is_sdu_zbc_block(p_msg_header, &n_zbc_blocks)) { // ZBC blocks
444                     if (nr5g_fapi_fapi2phy_send_zbc_blocks(p_msg_header,
445                             flags) != SUCCESS) {
446                         if (pthread_mutex_unlock((pthread_mutex_t *) &
447                                 p_wls_ctx->fapi2phy_lock_send)) {
448                             NR5G_FAPI_LOG(ERROR_LOG,
449                                 ("unable to unlock send pthread mutex"));
450                         }
451                         return FAILURE;
452                     }
453                 }
454                 p_curr_msg = p_curr_msg->pNext;
455             } else {            /* p_curr_msg->Next */
456                 // LAST
457                 flags = WLS_SG_LAST | flags_urllc;
458                 is_zbc = 0;
459                 if (nr5g_fapi_fapi2phy_is_sdu_zbc_block(p_msg_header,
460                         &n_zbc_blocks)) {
461                     flags = WLS_SG_NEXT | flags_urllc;
462                     is_zbc = 1;
463                 }
464                 if (nr5g_fapi_fapi2phy_wls_put((uint64_t) p_curr_msg,
465                         p_curr_msg->nMessageLen + sizeof(MAC2PHY_QUEUE_EL),
466                         p_msg_header->nMessageType, flags) != SUCCESS) {
467                     printf("Error\n");
468                     if (pthread_mutex_unlock((pthread_mutex_t *) &
469                             p_wls_ctx->fapi2phy_lock_send)) {
470                         NR5G_FAPI_LOG(ERROR_LOG,
471                             ("unable to unlock send pthread mutex"));
472                     }
473                     return FAILURE;
474                 }
475
476                 if (is_zbc) {   // ZBC blocks
477                     if (nr5g_fapi_fapi2phy_send_zbc_blocks(p_msg_header,
478                             WLS_SG_LAST | flags_urllc) != SUCCESS) {
479                         printf("Error\n");
480                         if (pthread_mutex_unlock((pthread_mutex_t *) &
481                                 p_wls_ctx->fapi2phy_lock_send)) {
482                             NR5G_FAPI_LOG(ERROR_LOG,
483                                 ("unable to unlock send pthread mutex"));
484                         }
485                         return FAILURE;
486                     }
487                 }
488                 p_curr_msg = NULL;
489             }                   /* p_curr_msg->Next */
490             flags = WLS_SG_NEXT | flags_urllc;
491         }
492     } else {                    // one block
493         count++;
494         if (nr5g_fapi_fapi2phy_is_sdu_zbc_block(p_curr_msg, &n_zbc_blocks)) {
495             printf("Error ZBC block cannot be only one in the list\n");
496             if (pthread_mutex_unlock((pthread_mutex_t *) &
497                     p_wls_ctx->fapi2phy_lock_send)) {
498                 NR5G_FAPI_LOG(ERROR_LOG,
499                     ("unable to unlock send pthread mutex"));
500             }
501             return FAILURE;
502         }
503
504         if (SUCCESS != nr5g_fapi_fapi2phy_wls_put((uint64_t) p_curr_msg,
505                 p_curr_msg->nMessageLen + sizeof(MAC2PHY_QUEUE_EL),
506                 p_curr_msg->nMessageType, flags)) {
507             printf("Error\n");
508             if (pthread_mutex_unlock((pthread_mutex_t *) &
509                     p_wls_ctx->fapi2phy_lock_send)) {
510                 NR5G_FAPI_LOG(ERROR_LOG,
511                     ("unable to unlock send pthread mutex"));
512             }
513             return FAILURE;
514         }
515     }
516
517     if (count > 1) {
518         if(is_urllc) {
519             g_free_send_idx_urllc++;
520             if (g_free_send_idx_urllc >= TO_FREE_SIZE_URLLC)
521                 g_free_send_idx_urllc = 0;
522         } else {
523         g_free_send_idx++;
524         if (g_free_send_idx >= TO_FREE_SIZE)
525             g_free_send_idx = 0;
526         }
527
528         // Free some TTIs Later
529         is_urllc ? wls_fapi_free_send_free_list_urllc(g_free_send_idx_urllc)
530                  : wls_fapi_free_send_free_list(g_free_send_idx);
531     }
532
533     if (pthread_mutex_unlock((pthread_mutex_t *) &
534             p_wls_ctx->fapi2phy_lock_send)) {
535         NR5G_FAPI_LOG(ERROR_LOG, ("unable to unlock send pthread mutex"));
536         return FAILURE;
537     }
538     return ret;
539 }
540
541 //------------------------------------------------------------------------------
542 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
543  *
544  *  @param[in]      pListElem Pointer to List element header
545  *  @param[in]      idx Subframe Number
546  *
547  *  @return         Number of blocks freed
548  *
549  *  @description    This function Frees all the blocks in a List Element Linked
550  *                  List coming from L1 by storing them into an array to be 
551  *                  freed at a later point in time.
552 **/
553 //------------------------------------------------------------------------------
554 uint8_t get_stats_location(
555     uint8_t msg_type)
556 {
557     uint8_t loc;
558     switch (msg_type) {
559         case MSG_TYPE_PHY_CONFIG_REQ:
560             loc = MEM_STAT_CONFIG_REQ;
561             break;
562         case MSG_TYPE_PHY_START_REQ:
563             loc = MEM_STAT_START_REQ;
564             break;
565         case MSG_TYPE_PHY_STOP_REQ:
566             loc = MEM_STAT_STOP_REQ;
567             break;
568         case MSG_TYPE_PHY_SHUTDOWN_REQ:
569             loc = MEM_STAT_SHUTDOWN_REQ;
570             break;
571         case MSG_TYPE_PHY_DL_CONFIG_REQ:
572             loc = MEM_STAT_DL_CONFIG_REQ;
573             break;
574         case MSG_TYPE_PHY_UL_CONFIG_REQ:
575             loc = MEM_STAT_UL_CONFIG_REQ;
576             break;
577         case MSG_TYPE_PHY_UL_DCI_REQ:
578             loc = MEM_STAT_UL_DCI_REQ;
579             break;
580         case MSG_TYPE_PHY_TX_REQ:
581             loc = MEM_STAT_TX_REQ;
582             break;
583         case MSG_TYPE_PHY_DL_IQ_SAMPLES:
584             loc = MEM_STAT_DL_IQ_SAMPLES;
585             break;
586         case MSG_TYPE_PHY_UL_IQ_SAMPLES:
587             loc = MEM_STAT_UL_IQ_SAMPLES;
588             break;
589         default:
590             loc = MEM_STAT_DEFAULT;
591     }
592
593     return loc;
594 }
595
596 //------------------------------------------------------------------------------
597 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
598  *
599  *  @param[in]      pListElem Pointer to List element header
600  *  @param[in]      idx Subframe Number
601  *
602  *  @return         Number of blocks freed
603  *
604  *  @description    This function Frees all the blocks in a List Element Linked
605  *                  List coming from L1 by storing them into an array to be 
606  *                  freed at a later point in time.
607 **/
608 //------------------------------------------------------------------------------
609 void wls_fapi_add_recv_apis_to_free(
610     PMAC2PHY_QUEUE_EL pListElem,
611     uint32_t idx)
612 {
613     PMAC2PHY_QUEUE_EL pNextMsg = NULL;
614     L1L2MessageHdr *p_msg_header = NULL;
615     PRXULSCHIndicationStruct p_phy_rx_ulsch_ind = NULL;
616     PULSCHPDUDataStruct p_ulsch_pdu = NULL;
617     uint8_t *ptr = NULL;
618     uint32_t count;
619     uint8_t i;
620
621     WLS_HANDLE h_wls;
622     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
623     h_wls = p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST];
624
625     count = g_to_free_recv_list_cnt[idx];
626     pNextMsg = pListElem;
627     while (pNextMsg) {
628         if (count >= TOTAL_FREE_BLOCKS) {
629             NR5G_FAPI_LOG(ERROR_LOG, ("%s: Reached max capacity of free list.\n"
630                     "\t\t\t\tlist index: %d list count: %d max list count: %d",
631                     __func__, idx, count, TOTAL_FREE_BLOCKS));
632             return;
633         }
634
635         g_to_free_recv_list[idx][count++] = (uint64_t) pNextMsg;
636         p_msg_header = (PL1L2MessageHdr) (pNextMsg + 1);
637         if (p_msg_header->nMessageType == MSG_TYPE_PHY_RX_ULSCH_IND) {
638             p_phy_rx_ulsch_ind = (PRXULSCHIndicationStruct) p_msg_header;
639             for (i = 0u; i < p_phy_rx_ulsch_ind->nUlsch; i++) {
640                 p_ulsch_pdu = &(p_phy_rx_ulsch_ind->sULSCHPDUDataStruct[i]);
641                 if(p_ulsch_pdu->nPduLen > 0) {
642                     ptr = (uint8_t *) nr5g_fapi_wls_pa_to_va(h_wls,
643                         (uint64_t) p_ulsch_pdu->pPayload);
644
645                 if (ptr) {
646                     g_to_free_recv_list[idx][count++] = (uint64_t) ptr;
647                 }
648                 } else {
649                     NR5G_FAPI_LOG(DEBUG_LOG, ("%s: Payload for"
650                         "MSG_TYPE_PHY_RX_ULSCH_IND ulsch pdu (%u/%u) is NULL."
651                         "Skip adding to free list.",
652                          __func__, i, p_phy_rx_ulsch_ind->nUlsch));
653                 }
654             }
655         }
656         pNextMsg = pNextMsg->pNext;
657     }
658
659     g_to_free_recv_list[idx][count] = 0L;
660     g_to_free_recv_list_cnt[idx] = count;
661
662     NR5G_FAPI_LOG(DEBUG_LOG, ("To Free %d\n", count));
663 }
664
665 //------------------------------------------------------------------------------
666 /** @ingroup nr5g_fapi_source_framework_wls_lib_group 
667  *
668  *  @param[in]      idx subframe Number
669  *
670  *  @return         Number of blocks freed
671  *
672  *  @description    This function frees all blocks that have been added to the 
673  *                  free array
674 **/
675 //------------------------------------------------------------------------------
676 void wls_fapi_free_recv_free_list(
677     uint32_t idx)
678 {
679     PMAC2PHY_QUEUE_EL pNextMsg = NULL;
680     int count = 0;
681
682     if (idx >= TO_FREE_SIZE) {
683         NR5G_FAPI_LOG(ERROR_LOG, ("%s: list index: %d\n", __func__, idx));
684         return;
685     }
686
687     pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_recv_list[idx][count];
688     while (pNextMsg) {
689         wls_fapi_free_buffer(pNextMsg, MIN_UL_BUF_LOCATIONS);
690         g_to_free_recv_list[idx][count++] = 0L;
691         if (g_to_free_recv_list[idx][count])
692             pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_recv_list[idx][count];
693         else
694             pNextMsg = 0L;
695     }
696
697     NR5G_FAPI_LOG(DEBUG_LOG, ("Free %d\n", count));
698     g_to_free_recv_list_cnt[idx] = 0;
699
700     return;
701 }
702
703 //------------------------------------------------------------------------------
704 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
705  *
706  *  @param[in]      pListElem Pointer to List element header
707  *  @param[in]      idx Subframe Number
708  *
709  *  @return         Number of blocks freed
710  *
711  *  @description    This function Frees all the blocks in a List Element Linked
712  *                  List coming from L1 by storing them into an array to be 
713  *                  freed at a later point in time.
714 **/
715 //------------------------------------------------------------------------------
716 void wls_fapi_add_send_apis_to_free(
717     PMAC2PHY_QUEUE_EL pListElem,
718     uint32_t idx)
719 {
720     PMAC2PHY_QUEUE_EL pNextMsg = NULL;
721     uint32_t count;
722
723     count = g_to_free_send_list_cnt[idx];
724     pNextMsg = pListElem;
725     while (pNextMsg) {
726         if (count >= TOTAL_FREE_BLOCKS) {
727             NR5G_FAPI_LOG(ERROR_LOG, ("%s: Reached max capacity of free list.\n"
728                     "\t\t\t\tlist index: %d list count: %d max list count: %d",
729                     __func__, idx, count, TOTAL_FREE_BLOCKS));
730             return;
731         }
732
733         g_to_free_send_list[idx][count++] = (uint64_t) pNextMsg;
734         pNextMsg = pNextMsg->pNext;
735     }
736
737     g_to_free_send_list[idx][count] = 0L;
738     g_to_free_send_list_cnt[idx] = count;
739
740     NR5G_FAPI_LOG(DEBUG_LOG, ("To Free %d\n", count));
741 }
742
743 //------------------------------------------------------------------------------
744 /** @ingroup nr5g_fapi_source_framework_wls_lib_group 
745  *
746  *  @param[in]      idx subframe Number
747  *
748  *  @return         Number of blocks freed
749  *
750  *  @description    This function frees all blocks that have been added to the 
751  *                  free array
752 **/
753 //------------------------------------------------------------------------------
754 void wls_fapi_free_send_free_list(
755     uint32_t idx)
756 {
757     PMAC2PHY_QUEUE_EL pNextMsg = NULL;
758     L1L2MessageHdr *p_msg_header = NULL;
759     int count = 0, loc = 0;
760
761     if (idx >= TO_FREE_SIZE) {
762         NR5G_FAPI_LOG(ERROR_LOG, ("%s: list index: %d\n", __func__, idx));
763         return;
764     }
765
766     pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_send_list[idx][count];
767     while (pNextMsg) {
768         p_msg_header = (PL1L2MessageHdr) (pNextMsg + 1);
769         loc = get_stats_location(p_msg_header->nMessageType);
770         wls_fapi_free_buffer(pNextMsg, loc);
771         g_to_free_send_list[idx][count++] = 0L;
772         if (g_to_free_send_list[idx][count])
773             pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_send_list[idx][count];
774         else
775             pNextMsg = 0L;
776     }
777
778     NR5G_FAPI_LOG(DEBUG_LOG, ("Free %d\n", count));
779     g_to_free_send_list_cnt[idx] = 0;
780
781     return;
782 }
783
784 //------------------------------------------------------------------------------
785 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
786  *
787  *  @param[in]      pListElem Pointer to List element header
788  *  @param[in]      idx Subframe Number
789  *
790  *  @return         Number of blocks freed
791  *
792  *  @description    This function Frees all the blocks in a List Element Linked
793  *                  List coming from L1 by storing them into an array to be
794  *                  freed at a later point in time. Used by urllc thread.
795 **/
796 //------------------------------------------------------------------------------
797 void wls_fapi_add_send_apis_to_free_urllc(
798     PMAC2PHY_QUEUE_EL pListElem,
799     uint32_t idx)
800 {
801     PMAC2PHY_QUEUE_EL pNextMsg = NULL;
802     uint32_t count;
803
804     count = g_to_free_send_list_cnt_urllc[idx];
805     pNextMsg = pListElem;
806     while (pNextMsg) {
807         if (count >= TOTAL_FREE_BLOCKS) {
808             NR5G_FAPI_LOG(ERROR_LOG, ("%s: Reached max capacity of free list.\n"
809                     "\t\t\t\tlist index: %d list count: %d max list count: %d",
810                     __func__, idx, count, TOTAL_FREE_BLOCKS));
811             return;
812         }
813
814         g_to_free_send_list_urllc[idx][count++] = (uint64_t) pNextMsg;
815         pNextMsg = pNextMsg->pNext;
816     }
817
818     g_to_free_send_list_urllc[idx][count] = 0L;
819     g_to_free_send_list_cnt_urllc[idx] = count;
820
821     NR5G_FAPI_LOG(DEBUG_LOG, ("To Free %d\n", count));
822 }
823
824 //------------------------------------------------------------------------------
825 /** @ingroup nr5g_fapi_source_framework_wls_lib_group
826  *
827  *  @param[in]      idx subframe Number
828  *
829  *  @return         Number of blocks freed
830  *
831  *  @description    This function frees all blocks that have been added to the
832  *                  free array. Used by urllc thread.
833 **/
834 //------------------------------------------------------------------------------
835 void wls_fapi_free_send_free_list_urllc(
836     uint32_t idx)
837 {
838     PMAC2PHY_QUEUE_EL pNextMsg = NULL;
839     L1L2MessageHdr *p_msg_header = NULL;
840     int count = 0, loc = 0;
841
842     if (idx >= TO_FREE_SIZE_URLLC) {
843         NR5G_FAPI_LOG(ERROR_LOG, ("%s: list index: %d\n", __func__, idx));
844         return;
845     }
846
847     pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_send_list_urllc[idx][count];
848     while (pNextMsg) {
849         p_msg_header = (PL1L2MessageHdr) (pNextMsg + 1);
850         loc = get_stats_location(p_msg_header->nMessageType);
851         wls_fapi_free_buffer(pNextMsg, loc);
852         g_to_free_send_list_urllc[idx][count++] = 0L;
853         if (g_to_free_send_list_urllc[idx][count])
854             pNextMsg = (PMAC2PHY_QUEUE_EL) g_to_free_send_list_urllc[idx][count];
855         else
856             pNextMsg = 0L;
857     }
858
859     NR5G_FAPI_LOG(DEBUG_LOG, ("Free %d\n", count));
860     g_to_free_send_list_cnt_urllc[idx] = 0;
861
862     return;
863 }