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