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