02c89371cc01dbc35afaad82c5949e8744029211
[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_wls.h"
27 #include "nr5g_fapi_fapi2phy_wls.h"
28 #include "nr5g_fapi_log.h"
29
30 //------------------------------------------------------------------------------
31 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
32  *
33  *  @param data Pointer to validate
34  *
35  *  @return  TRUE If pointer is within valid shared WLS memory region
36  *           FALSE If pointer is out of valid shared WLS memory region
37  *
38  *  @description
39  *  This function validates pointer's in WLS shared memory region
40  *
41 **/
42 //------------------------------------------------------------------------------
43 uint8_t nr5g_fapi_fapi2phy_is_valid_wls_ptr(
44     void *data)
45 {
46     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
47     if ((unsigned long)data >= (unsigned long)p_wls_ctx->pPartitionMemBase &&
48         (unsigned long)data < ((unsigned long)p_wls_ctx->pPartitionMemBase +
49             p_wls_ctx->nPartitionMemSize)) {
50         return TRUE;
51     } else {
52         return FALSE;
53     }
54 }
55
56 //------------------------------------------------------------------------------
57 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
58  *
59  *  @param void
60  *
61  *  @return  A pointer to WLS_HANDLE stucture
62  *
63  *  @description
64  *  This function returns the WLS instance
65  *
66 **/
67 //------------------------------------------------------------------------------
68 static inline WLS_HANDLE nr5g_fapi_fapi2phy_wls_instance(
69     )
70 {
71     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
72     return p_wls_ctx->h_wls[NR5G_FAPI2PHY_WLS_INST];
73 }
74
75 //----------------------------------------------------------------------------------
76 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
77  *
78  *  @param[out]   data Location where First API from L1 is stored
79  *
80  *  @return  Size of Message sent from L1
81  *
82  *  @description
83  *  This function queries the APIs sent from L1 to L2 and gets the first pointer
84  *  to the linked list
85  *
86 **/
87 //----------------------------------------------------------------------------------
88 inline uint64_t *nr5g_fapi_fapi2phy_wls_get(
89     uint32_t * msg_size,
90     uint16_t * msg_type,
91     uint16_t * flags)
92 {
93     uint64_t *data = NULL;
94     WLS_HANDLE h_wls;
95     uint32_t ms = 0;
96     uint16_t mt = 0, f = 0;
97
98     h_wls = nr5g_fapi_fapi2phy_wls_instance();
99     data = (uint64_t *) WLS_Get(h_wls, &ms, &mt, &f);
100     *msg_size = ms, *msg_type = mt, *flags = f;
101     NR5G_FAPI_LOG(TRACE_LOG, ("[NR5G_FAPI][FAPI2PHY WLS][GET] %p size: %d "
102             "type: %x flags: %x", data, *msg_size, *msg_type, *flags));
103
104     return data;
105 }
106
107 //----------------------------------------------------------------------------------
108 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
109  *
110  *  @param[in]   p_msg Pointer to API block that needs to be sent to L1
111  *  @param[in]   msg_size Size of Message
112  *  @param[in]   msg_id Message Id
113  *  @param[in]   flags Special flags needed for WLS
114  *
115  *  @return  0 if SUCCESS
116  *
117  *  @description
118  *  This function adds a block of API from L2 to L1 which will be sent later
119  *
120 **/
121 //----------------------------------------------------------------------------------
122 inline uint8_t nr5g_fapi_fapi2phy_wls_put(
123     uint64_t p_msg,
124     uint32_t msg_size,
125     uint16_t msg_type,
126     uint16_t flags)
127 {
128     int ret = SUCCESS;
129     WLS_HANDLE h_phy_wls = nr5g_fapi_fapi2phy_wls_instance();
130     uint64_t pa = nr5g_fapi_wls_va_to_pa(h_phy_wls, (void *)p_msg);
131     NR5G_FAPI_LOG(TRACE_LOG, ("[NR5G_FAPI][FAPI2PHY WLS][PUT] %ld size: %d "
132             "type: %x flags: %x", pa, msg_size, msg_type, flags));
133     ret = WLS_Put(h_phy_wls, pa, msg_size, msg_type, flags);
134
135     return ret;
136 }
137
138 //----------------------------------------------------------------------------------
139 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
140  *
141  *  @param void
142  *
143  *  @return  0 if SUCCESS
144  *
145  *  @description
146  *  This function is called at WLS init and waits in an infinite for L1 to respond back with some information
147  *  needed by the L2
148  *
149 **/
150 //----------------------------------------------------------------------------------
151 inline uint8_t nr5g_fapi_fapi2phy_wls_ready(
152     )
153 {
154     int ret = SUCCESS;
155     //NR5G_FAPI_LOG(TRACE_LOG, ("Waiting for L1 to respond in WLS Ready"));
156     ret = WLS_Ready(nr5g_fapi_fapi2phy_wls_instance());
157     return ret;
158 }
159
160 //----------------------------------------------------------------------------------
161 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
162  *
163  *  @param   void
164  *
165  *  @return  Number of blocks of APIs received
166  *
167  *  @description
168  *  This functions waits in a infinite loop for L1 to send a list of APIs to MAC. This is called
169  *  during runtime when L2 sends a API to L1 and then waits for response back.
170  *
171 **/
172 //----------------------------------------------------------------------------------
173 inline uint8_t nr5g_fapi_fapi2phy_wls_wait(
174     )
175 {
176     int ret = SUCCESS;
177 //    NR5G_FAPI_LOG(TRACE_LOG, ("Waiting for L1 to respond in WLS Wait"));
178     ret = WLS_Wait(nr5g_fapi_fapi2phy_wls_instance());
179     return ret;
180 }
181
182 //------------------------------------------------------------------------------
183 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
184  *
185  *  @param[out]   data Location where First API from L1 is stored
186  *
187  *  @return  Size of Message sent from L1
188  *
189  *  @description
190  *  This function checks if this is the last message in this tti.
191  *
192 **/
193 //------------------------------------------------------------------------------
194 static inline uint8_t is_msg_present(
195     uint16_t flags)
196 {
197     return (!((flags & WLS_TF_FIN) || (flags == 0)));
198 }
199
200 //----------------------------------------------------------------------------------
201 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
202  *
203  *  @param[out]   data Location where First API from L1 is stored
204  *
205  *  @return  Size of Message sent from L1
206  *
207  *  @description
208  *  This function queries the APIs sent from L1 to L2 and gets the first pointer
209  *  to the linked list
210  *
211 **/
212 //----------------------------------------------------------------------------------
213 PMAC2PHY_QUEUE_EL nr5g_fapi_fapi2phy_wls_recv(
214     )
215 {
216     uint16_t msg_type = 0;
217     uint16_t flags = 0;
218     uint32_t msg_size = 0;
219     uint32_t num_elms = 0;
220     uint64_t *p_msg = NULL;
221     static uint32_t g_free_recv_idx = 0;
222     PMAC2PHY_QUEUE_EL p_qelm_list = NULL;
223     PMAC2PHY_QUEUE_EL p_qelm = NULL;
224     PMAC2PHY_QUEUE_EL p_tail_qelm = NULL;
225
226     num_elms = nr5g_fapi_fapi2phy_wls_wait();
227     if (!num_elms)
228         return p_qelm_list;
229
230     do {
231         p_msg = nr5g_fapi_fapi2phy_wls_get(&msg_size, &msg_type, &flags);
232         if (p_msg) {
233             WLS_HANDLE h_wls = nr5g_fapi_fapi2phy_wls_instance();
234             p_qelm = (PMAC2PHY_QUEUE_EL)
235                 nr5g_fapi_wls_pa_to_va(h_wls, (uint64_t) p_msg);
236             if (nr5g_fapi_fapi2phy_is_valid_wls_ptr(p_qelm) == FALSE) {
237                 printf("Error: Invalid Ptr\n");
238                 continue;
239             }
240             p_qelm->pNext = NULL;
241             if (p_qelm_list) {
242                 p_tail_qelm->pNext = p_qelm;
243                 p_tail_qelm = p_qelm;
244             } else {
245                 p_qelm_list = p_qelm;
246                 p_tail_qelm = p_qelm;
247             }
248         }
249         num_elms--;
250     } while (num_elms && is_msg_present(flags));
251
252     if (p_qelm_list) {
253         wls_fapi_add_recv_apis_to_free(p_qelm_list, g_free_recv_idx);
254         g_free_recv_idx++;
255         if (g_free_recv_idx >= TO_FREE_SIZE) {
256             g_free_recv_idx = 0;
257         }
258         // Free 10 TTIs Later
259         wls_fapi_free_recv_free_list(g_free_recv_idx);
260
261         wls_fapi_add_blocks_to_ul();
262     }
263
264     return p_qelm_list;
265 }
266
267 //------------------------------------------------------------------------------
268 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
269  *
270  *  @param[in]    p_msg_header Pointer to the TxSDuReq Message block
271  *  @param[out]   n_zbc_blocks Number of ZBC blocks
272  *
273  *  @return  1 if this block is a TxSduReq message. 0 else.
274  *
275  *  @description
276  *  This function checks if a block is a TxSduReq messages and counts the number
277  *  of ZBC blocks in this API
278  *
279 **/
280 //------------------------------------------------------------------------------
281 int nr5g_fapi_fapi2phy_is_sdu_zbc_block(
282     void *p_msg,
283     int *num_zbc_blocks)
284 {
285     PL1L2MessageHdr p_msg_header = (PL1L2MessageHdr) p_msg;
286     *num_zbc_blocks = 0;
287
288     if (p_msg_header->nMessageType == MSG_TYPE_PHY_TX_REQ) {
289         PTXRequestStruct p_dl_sdu_req = (PTXRequestStruct) p_msg_header;
290         PDLPDUDataStruct p_dl_pdu_data = (PDLPDUDataStruct) (p_dl_sdu_req + 1);
291         uint32_t i;
292         for (i = 0; i < p_dl_sdu_req->nPDU; i++) {
293             *num_zbc_blocks += (p_dl_pdu_data->nPduLen1 ? 1 : 0);
294             *num_zbc_blocks += (p_dl_pdu_data->nPduLen2 ? 1 : 0);
295             p_dl_pdu_data++;
296         }
297
298         if (*num_zbc_blocks) {
299             return 1;
300         }
301     }
302
303     return 0;
304 }
305
306 //----------------------------------------------------------------------------------
307 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
308  *
309  *  @param[in]   p_msg_header Pointer to the TxSduReq Message block
310  *  @param[in]   flags Special flags needed for WLS
311  *  @param[in]   n_zbc_blocks Number of ZBC blocks in list
312  *
313  *  @return  0 if SUCCESS
314  *
315  *  @description
316  *  This function adds all the ZBC blocks in a TXSDU Message and prepares them to
317  *  be sent to the L1
318  *
319 **/
320 //------------------------------------------------------------------------------
321 uint32_t nr5g_fapi_fapi2phy_send_zbc_blocks(
322     void *p_msg,
323     uint16_t flags)
324 {
325     PL1L2MessageHdr p_msg_header = (PL1L2MessageHdr) p_msg;
326     PTXRequestStruct p_dl_sdu_req = (PTXRequestStruct) p_msg_header;
327     PDLPDUDataStruct p_dl_pdu_data = (PDLPDUDataStruct) (p_dl_sdu_req + 1);
328     uint32_t i, j, is_last, is_last1, msg_type;
329     uint16_t list_flags = flags;
330
331     for (i = 0; i < p_dl_sdu_req->nPDU; i++) {
332         is_last = (i == (p_dl_sdu_req->nPDU - 1));
333         for (j = 0; j < MAX_DL_PER_UE_CODEWORD_NUM; j++) {
334             uint32_t pdu_len;
335             uint8_t *p_payload;
336             p_payload = NULL;
337             msg_type = 0;
338             if (j == 0) {
339                 pdu_len = p_dl_pdu_data->nPduLen1;
340                 p_payload = p_dl_pdu_data->pPayload1;
341                 msg_type = MSG_PHY_ZBC_BLOCK0_REQ;
342             } else {
343                 pdu_len = p_dl_pdu_data->nPduLen2;
344                 p_payload = p_dl_pdu_data->pPayload2;
345                 msg_type = MSG_PHY_ZBC_BLOCK1_REQ;
346             }
347
348             if (p_payload) {
349                 is_last1 = (((j == 0) && (p_dl_pdu_data->pPayload2 == 0)) ||
350                     (j == (MAX_DL_PER_UE_CODEWORD_NUM - 1)));
351                 if ((list_flags & WLS_TF_FIN) && is_last && is_last1) {
352                     flags = WLS_SG_LAST;
353                 } else {
354                     flags = WLS_SG_NEXT;
355                 }
356
357                 WLS_HANDLE h_phy_wls = nr5g_fapi_fapi2phy_wls_instance();
358                 if (WLS_Put(h_phy_wls, (uint64_t) p_payload, pdu_len, msg_type,
359                         flags) != SUCCESS) {
360                     printf("Error ZBC block 0x%016lx\n", (uint64_t) p_payload);
361                     return FAILURE;
362                 }
363             }
364         }
365         p_dl_pdu_data++;
366     }
367
368     return SUCCESS;
369 }
370
371 //------------------------------------------------------------------------------
372 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
373  *
374  *  @param[in]      A pointer to the phy instance
375  *  @param[in]      A data Pointer to the Linked list header
376  *
377  *  @return         0 if SUCCESS
378  *
379  *  @description    This function sends a list of APIs to the L1 via WLS
380  *
381 **/
382 //------------------------------------------------------------------------------
383 uint8_t nr5g_fapi_fapi2phy_wls_send(
384     void *data)
385 {
386     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
387     PMAC2PHY_QUEUE_EL p_curr_msg = NULL;
388     PL1L2MessageHdr p_msg_header;
389     uint16_t flags = 0;
390     uint8_t ret = SUCCESS;
391     int n_zbc_blocks = 0, is_zbc = 0, count = 0;
392     static uint32_t g_free_send_idx = 0;
393
394     p_curr_msg = (PMAC2PHY_QUEUE_EL) data;
395     wls_fapi_add_send_apis_to_free(p_curr_msg, g_free_send_idx);
396
397     if (pthread_mutex_lock((pthread_mutex_t *) & p_wls_ctx->fapi2phy_lock_send)) {
398         NR5G_FAPI_LOG(ERROR_LOG, ("unable to lock send pthread mutex"));
399         return FAILURE;
400     }
401
402     if (p_curr_msg->pNext) {
403         flags = WLS_SG_FIRST;
404         while (p_curr_msg) {
405             // only batch mode
406             count++;
407             p_msg_header = (PL1L2MessageHdr) (p_curr_msg + 1);
408             if (p_curr_msg->pNext) {    // FIRST/NEXT list element
409                 if (SUCCESS != nr5g_fapi_fapi2phy_wls_put((uint64_t) p_curr_msg,
410                         p_curr_msg->nMessageLen + sizeof(MAC2PHY_QUEUE_EL),
411                         p_msg_header->nMessageType, flags)) {
412                     if (pthread_mutex_unlock((pthread_mutex_t *) & p_wls_ctx->
413                             fapi2phy_lock_send)) {
414                         NR5G_FAPI_LOG(ERROR_LOG,
415                             ("unable to unlock send pthread mutex"));
416                     }
417                     return FAILURE;
418                 }
419
420                 if (nr5g_fapi_fapi2phy_is_sdu_zbc_block(p_msg_header, &n_zbc_blocks)) { // ZBC blocks
421                     if (nr5g_fapi_fapi2phy_send_zbc_blocks(p_msg_header,
422                             flags) != SUCCESS) {
423                         if (pthread_mutex_unlock((pthread_mutex_t *) &
424                                 p_wls_ctx->fapi2phy_lock_send)) {
425                             NR5G_FAPI_LOG(ERROR_LOG,
426                                 ("unable to unlock send pthread mutex"));
427                         }
428                         return FAILURE;
429                     }
430                 }
431                 p_curr_msg = p_curr_msg->pNext;
432             } else {            /* p_curr_msg->Next */
433                 // LAST
434                 flags = WLS_SG_LAST;
435                 is_zbc = 0;
436                 if (nr5g_fapi_fapi2phy_is_sdu_zbc_block(p_msg_header,
437                         &n_zbc_blocks)) {
438                     flags = WLS_SG_NEXT;
439                     is_zbc = 1;
440                 }
441                 if (nr5g_fapi_fapi2phy_wls_put((uint64_t) p_curr_msg,
442                         p_curr_msg->nMessageLen + sizeof(MAC2PHY_QUEUE_EL),
443                         p_msg_header->nMessageType, flags) != SUCCESS) {
444                     printf("Error\n");
445                     if (pthread_mutex_unlock((pthread_mutex_t *) & p_wls_ctx->
446                             fapi2phy_lock_send)) {
447                         NR5G_FAPI_LOG(ERROR_LOG,
448                             ("unable to unlock send pthread mutex"));
449                     }
450                     return FAILURE;
451                 }
452
453                 if (is_zbc) {   // ZBC blocks
454                     if (nr5g_fapi_fapi2phy_send_zbc_blocks(p_msg_header,
455                             WLS_SG_LAST) != SUCCESS) {
456                         printf("Error\n");
457                         if (pthread_mutex_unlock((pthread_mutex_t *) &
458                                 p_wls_ctx->fapi2phy_lock_send)) {
459                             NR5G_FAPI_LOG(ERROR_LOG,
460                                 ("unable to unlock send pthread mutex"));
461                         }
462                         return FAILURE;
463                     }
464                 }
465                 p_curr_msg = NULL;
466             }                   /* p_curr_msg->Next */
467             flags = WLS_SG_NEXT;
468         }
469     } else {                      // one block
470         count++;
471         if (nr5g_fapi_fapi2phy_is_sdu_zbc_block(p_curr_msg, &n_zbc_blocks)) {
472             printf("Error ZBC block cannot be only one in the list\n");
473             if (pthread_mutex_unlock((pthread_mutex_t *) & p_wls_ctx->
474                     fapi2phy_lock_send)) {
475                 NR5G_FAPI_LOG(ERROR_LOG,
476                     ("unable to unlock send pthread mutex"));
477             }
478             return FAILURE;
479         }
480
481         if (SUCCESS != nr5g_fapi_fapi2phy_wls_put((uint64_t) p_curr_msg,
482                 p_curr_msg->nMessageLen + sizeof(MAC2PHY_QUEUE_EL),
483                 p_curr_msg->nMessageType, flags)) {
484             printf("Error\n");
485             if (pthread_mutex_unlock((pthread_mutex_t *) & p_wls_ctx->
486                     fapi2phy_lock_send)) {
487                 NR5G_FAPI_LOG(ERROR_LOG,
488                     ("unable to unlock send pthread mutex"));
489             }
490             return FAILURE;
491         }
492     }
493
494     if (count > 1) {
495         g_free_send_idx++;
496         if (g_free_send_idx >= TO_FREE_SIZE)
497             g_free_send_idx = 0;
498
499         // Free 10 TTIs Later
500         wls_fapi_free_send_free_list(g_free_send_idx);
501     }
502
503     if (pthread_mutex_unlock((pthread_mutex_t *) & p_wls_ctx->
504             fapi2phy_lock_send)) {
505         NR5G_FAPI_LOG(ERROR_LOG, ("unable to unlock send pthread mutex"));
506         return FAILURE;
507     }
508     return ret;
509 }