* INTC Contribution to the O-RAN F Release for O-DU Low
[o-du/phy.git] / fapi_5g / source / framework / wls / fapi2mac / nr5g_fapi_fapi2mac_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 MAC 
21  *
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_fapi2mac_wls.h"
28 #include "nr5g_fapi_log.h"
29 #include "nr5g_fapi_framework.h"
30
31 static p_fapi_api_queue_elem_t p_fapi2mac_buffers;
32
33 uint64_t *nr5g_fapi_fapi2mac_wls_get(
34     uint32_t * const msg_size,
35     uint16_t * const msg_type,
36     uint16_t * const flags);
37
38 uint8_t nr5g_fapi_fapi2mac_wls_put(
39     const p_fapi_api_queue_elem_t p_msg,
40     uint32_t msg_size,
41     uint16_t msg_type,
42     uint16_t flags);
43
44 uint8_t nr5g_fapi_fapi2mac_wls_send(
45     const p_fapi_api_queue_elem_t p_list_elem,
46     bool is_urllc);
47
48 //------------------------------------------------------------------------------
49 /** @ingroup nr5g_fapi_source_framework_wls_fapi2mac_group
50  *
51  *  @param data Pointer to validate
52  *
53  *  @return  TRUE If pointer is within valid shared WLS memory region
54  *           FALSE If pointer is out of valid shared WLS memory region
55  *
56  *  @description
57  *  This function validates pointer's in WLS shared memory region
58  *
59 **/
60 //------------------------------------------------------------------------------
61 uint8_t nr5g_fapi_fapi2mac_is_valid_wls_ptr(
62     void *data)
63 {
64     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
65     if ((unsigned long)data >= (unsigned long)p_wls_ctx->shmem &&
66         (unsigned long)data < ((unsigned long)p_wls_ctx->shmem +
67             p_wls_ctx->nPartitionMemSize)) {
68         return TRUE;
69     } else {
70         return FALSE;
71     }
72 }
73
74 //------------------------------------------------------------------------------
75 /** @ingroup nr5g_fapi_source_framework_wls_fapi2mac_group
76  *
77  *  @param void
78  *
79  *  @return  A pointer to WLS_HANDLE stucture
80  *
81  *  @description
82  *  This function returns the WLS instance
83  *
84 **/
85 //------------------------------------------------------------------------------
86 static inline WLS_HANDLE nr5g_fapi_fapi2mac_wls_instance(
87     )
88 {
89     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
90
91     return p_wls_ctx->h_wls[NR5G_FAPI2MAC_WLS_INST];
92 }
93
94 //------------------------------------------------------------------------------
95 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
96  *
97  *  @param   void
98  *
99  *  @return  Pointer to the memory block
100  *
101  *  @description
102  *  This function allocates a block of memory from the pool
103  *
104 **/
105 //------------------------------------------------------------------------------
106 void *nr5g_fapi_fapi2mac_wls_alloc_buffer(
107     )
108 {
109     uint64_t pa_block = 0;
110     void *p_va_block = NULL;
111     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
112     WLS_HANDLE h_wls = nr5g_fapi_fapi2mac_wls_instance();
113
114     if (pthread_mutex_lock((pthread_mutex_t *) &
115             p_wls_ctx->fapi2mac_lock_alloc)) {
116         NR5G_FAPI_LOG(ERROR_LOG, ("unable to lock alloc pthread mutex"));
117         return NULL;
118     }
119     if (p_fapi2mac_buffers) {
120         p_va_block = (void *)p_fapi2mac_buffers;
121         p_fapi2mac_buffers = p_fapi2mac_buffers->p_next;
122     } else {
123         pa_block = (uint64_t) WLS_DequeueBlock((void *)h_wls);
124         if (!pa_block) {
125             if (pthread_mutex_unlock((pthread_mutex_t *) &
126                     p_wls_ctx->fapi2mac_lock_alloc)) {
127                 NR5G_FAPI_LOG(ERROR_LOG,
128                     ("unable to unlock alloc pthread mutex"));
129                 return NULL;
130             }
131             //NR5G_FAPI_LOG(ERROR_LOG, ("nr5g_fapi_fapi2phy_wls_alloc_buffer alloc error\n"));
132             return NULL;
133         }
134         p_va_block = (void *)nr5g_fapi_wls_pa_to_va(h_wls, pa_block);
135     }
136     if (pthread_mutex_unlock((pthread_mutex_t *) &
137             p_wls_ctx->fapi2mac_lock_alloc)) {
138         NR5G_FAPI_LOG(ERROR_LOG, ("unable to unlock alloc pthread mutex"));
139         return NULL;
140     }
141     return p_va_block;
142 }
143
144 //------------------------------------------------------------------------------
145 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
146  *
147  *  @param   void
148  *
149  *  @return  Pointer to the memory block
150  *
151  *  @description
152  *  This function allocates a block of memory from the pool
153  *
154 **/
155 //------------------------------------------------------------------------------
156 void nr5g_fapi_fapi2mac_wls_free_buffer(
157     void *buffers)
158 {
159     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
160
161     if (pthread_mutex_lock((pthread_mutex_t *) &
162             p_wls_ctx->fapi2mac_lock_alloc)) {
163         NR5G_FAPI_LOG(ERROR_LOG, ("unable to lock alloc pthread mutex"));
164         return;
165     }
166     if (p_fapi2mac_buffers) {
167         ((p_fapi_api_queue_elem_t) buffers)->p_next = p_fapi2mac_buffers;
168         p_fapi2mac_buffers = (p_fapi_api_queue_elem_t) buffers;
169     } else {
170         p_fapi2mac_buffers = (p_fapi_api_queue_elem_t) buffers;
171         p_fapi2mac_buffers->p_next = NULL;
172     }
173
174     if (pthread_mutex_unlock((pthread_mutex_t *) &
175             p_wls_ctx->fapi2mac_lock_alloc)) {
176         NR5G_FAPI_LOG(ERROR_LOG, ("unable to unlock alloc pthread mutex"));
177         return;
178     }
179 }
180
181 //------------------------------------------------------------------------------
182 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
183  *
184  *  @param void
185  *
186  *  @return  0 if SUCCESS
187  *
188  *  @description
189  *  This function is called at WLS init and waits infinitely for L1 to respond back with some information
190  *  needed by the L2
191  *
192 **/
193 //------------------------------------------------------------------------------
194 uint8_t nr5g_fapi_fapi2mac_wls_ready(
195     )
196 {
197     int ret = SUCCESS;
198     ret = WLS_Ready1(nr5g_fapi_fapi2mac_wls_instance());
199     return ret;
200 }
201
202 //------------------------------------------------------------------------------
203 /** @ingroup nr5g_fapi_source_framework_wls_fapi2mac_group
204  *
205  *  @param   void
206  *
207  *  @return  Number of blocks of APIs received
208  *
209  *  @description
210  *  This functions waits in an infinite loop for L1 to send a list of APIs to MAC. This is called
211  *  during runtime when L2 sends API to L1 and then waits for a response back.
212  *
213 **/
214 //------------------------------------------------------------------------------
215 uint32_t nr5g_fapi_fapi2mac_wls_wait(
216     )
217 {
218     int ret = SUCCESS;
219 //    NR5G_FAPI_LOG(TRACE_LOG, ("Waiting for MAC to respond in WLS Wait"));
220     ret = WLS_Wait1(nr5g_fapi_fapi2mac_wls_instance());
221     return ret;
222 }
223
224 //------------------------------------------------------------------------------
225 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
226  *
227  *  @param[out]   data Location where First API from L1 is stored
228  *
229  *  @return  Size of Message sent from L1
230  *
231  *  @description
232  *  This function checks if this is the last message in this tti.
233  *
234 **/
235 //------------------------------------------------------------------------------
236 static inline uint8_t is_msg_present(
237     uint16_t flags)
238 {
239     return (!((flags & WLS_TF_FIN) || (flags == 0)));
240 }
241
242 //------------------------------------------------------------------------------
243 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
244  *
245  *  @param[out]   data Location where First API from L1 is stored
246  *
247  *  @return  Size of Message sent from L1
248  *
249  *  @description
250  *  This function queries the APIs sent from L1 to L2 and gets the first pointer
251  *  to the linked list
252  *
253 **/
254 //------------------------------------------------------------------------------
255 uint64_t *nr5g_fapi_fapi2mac_wls_get(
256     uint32_t * const msg_size,
257     uint16_t * const msg_type,
258     uint16_t * const flags)
259 {
260     uint64_t *data = NULL;
261     WLS_HANDLE h_wls;
262     uint32_t ms = 0;
263     uint16_t mt = 0, f = 0;
264
265     h_wls = nr5g_fapi_fapi2mac_wls_instance();
266     data = (uint64_t *) WLS_Get1(h_wls, &ms, &mt, &f);
267     *msg_size = ms, *msg_type = mt, *flags = f;
268     NR5G_FAPI_LOG(TRACE_LOG, ("[FAPI2MAC WLS][GET] %p size: %d "
269             "type: %x flags: %x", data, *msg_size, *msg_type, *flags));
270
271     return data;
272 }
273
274 //------------------------------------------------------------------------------
275 /** @ingroup nr5g_fapi_source_framework_wls_fapi2mac_group
276  *
277  *  @param[in]   ptr Pointer to the block to send
278  *  @param[in]   size Size of the block to send
279  *
280  *  @return  0 if SUCCESS
281  *
282  *  @description
283  *  This function sends a single block of API from PHY to MAC
284  *
285 **/
286 //------------------------------------------------------------------------------
287 inline uint8_t nr5g_fapi_fapi2mac_wls_put(
288     const p_fapi_api_queue_elem_t p_msg,
289     uint32_t msg_size,
290     uint16_t msg_type,
291     uint16_t flags)
292 {
293     uint8_t ret = SUCCESS;
294
295     WLS_HANDLE h_mac_wls = nr5g_fapi_fapi2mac_wls_instance();
296     uint64_t pa = nr5g_fapi_wls_va_to_pa(h_mac_wls, (void *)p_msg);
297     NR5G_FAPI_LOG(TRACE_LOG, ("[FAPI2MAC WLS][PUT] %ld size: %d "
298             "type: %x flags: %x", pa, msg_size, msg_type, flags));
299
300     ret = WLS_Put1(h_mac_wls, (uint64_t) pa, msg_size, msg_type, flags);
301
302     return ret;
303 }
304
305 //------------------------------------------------------------------------------
306 /** @ingroup nr5g_fapi_source_framework_wls_fapi2mac_group
307  *
308  *  @param[in]   p_list Pointer to the linked list head
309  *
310  *  @return  0 if SUCCESS
311  *
312  *  @description
313  *  This function sends a linked list of APIs from PHY to MAC.
314  *
315 **/
316 //------------------------------------------------------------------------------
317 uint8_t nr5g_fapi_fapi2mac_wls_send(
318     const p_fapi_api_queue_elem_t p_list_elem,
319     bool is_urllc)
320 {
321     uint8_t ret = SUCCESS;
322     p_fapi_api_queue_elem_t p_curr_msg = NULL;
323     fapi_msg_t *p_msg_header = NULL;
324     uint16_t flags = 0;
325     uint16_t flags_urllc = (is_urllc ? WLS_TF_URLLC : 0);
326     p_nr5g_fapi_wls_context_t p_wls_ctx = nr5g_fapi_wls_context();
327     uint64_t start_tick = __rdtsc();
328
329     p_curr_msg = p_list_elem;
330
331     if (pthread_mutex_lock((pthread_mutex_t *) & p_wls_ctx->fapi2mac_lock_send)) {
332         NR5G_FAPI_LOG(ERROR_LOG, ("unable to lock send pthread mutex"));
333         return FAILURE;
334     }
335
336     if (p_curr_msg && p_curr_msg->p_next) {
337         flags = WLS_SG_FIRST | flags_urllc;
338         if (p_curr_msg->msg_type == FAPI_VENDOR_MSG_HEADER_IND) {
339             if (SUCCESS != nr5g_fapi_fapi2mac_wls_put(p_curr_msg,
340                     p_curr_msg->msg_len + sizeof(fapi_api_queue_elem_t),
341                     FAPI_VENDOR_MSG_HEADER_IND, flags)) {
342                 printf("Error\n");
343                 if (pthread_mutex_unlock((pthread_mutex_t *) &
344                         p_wls_ctx->fapi2mac_lock_send)) {
345                     NR5G_FAPI_LOG(ERROR_LOG,
346                         ("unable to unlock send pthread mutex"));
347                 }
348                 return FAILURE;
349             }
350             p_curr_msg = p_curr_msg->p_next;
351             flags = WLS_SG_NEXT | flags_urllc;
352         }
353
354         while (p_curr_msg) {
355             // only batch mode
356             p_msg_header = (fapi_msg_t *) (p_curr_msg + 1);
357             if (p_curr_msg->p_next) {   // FIRST/NEXT
358                 if (SUCCESS != nr5g_fapi_fapi2mac_wls_put(p_curr_msg,
359                         p_curr_msg->msg_len + sizeof(fapi_api_queue_elem_t),
360                         p_msg_header->msg_id, flags)) {
361                     printf("Error\n");
362                     if (pthread_mutex_unlock((pthread_mutex_t *) &
363                             p_wls_ctx->fapi2mac_lock_send)) {
364                         NR5G_FAPI_LOG(ERROR_LOG,
365                             ("unable to unlock send pthread mutex"));
366                     }
367                     return FAILURE;
368                 }
369                 p_curr_msg = p_curr_msg->p_next;
370             } else {            // LAST
371                 flags = WLS_SG_LAST | flags_urllc;
372                 if (SUCCESS != nr5g_fapi_fapi2mac_wls_put(p_curr_msg,
373                         p_curr_msg->msg_len + sizeof(fapi_api_queue_elem_t),
374                         p_msg_header->msg_id, flags)) {
375                     printf("Error\n");
376                     if (pthread_mutex_unlock((pthread_mutex_t *) &
377                             p_wls_ctx->fapi2mac_lock_send)) {
378                         NR5G_FAPI_LOG(ERROR_LOG,
379                             ("unable to unlock send pthread mutex"));
380                     }
381                     return FAILURE;
382                 }
383                 p_curr_msg = NULL;
384             }
385             flags = WLS_SG_NEXT | flags_urllc;
386         }
387     }
388
389     if (pthread_mutex_unlock((pthread_mutex_t *) &
390             p_wls_ctx->fapi2mac_lock_send)) {
391         NR5G_FAPI_LOG(ERROR_LOG, ("unable to unlock send pthread mutex"));
392         return FAILURE;
393     }
394     tick_total_wls_send_per_tti_ul += __rdtsc() - start_tick;
395
396     return ret;
397 }
398
399 //------------------------------------------------------------------------------
400 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
401  *
402  *  @param[out]   data Location where First API from L1 is stored
403  *
404  *  @return  Size of Message sent from L1
405  *
406  *  @description
407  *  This function queries the APIs sent from L1 to L2 and gets the first pointer
408  *  to the linked list
409  *
410 **/
411 //------------------------------------------------------------------------------
412 p_fapi_api_queue_elem_t nr5g_fapi_fapi2mac_wls_recv(
413     )
414 {
415     uint16_t msg_type = 0;
416     uint16_t flags = 0;
417     uint32_t msg_size = 0;
418     uint32_t num_elms = 0;
419     uint64_t *p_msg = NULL;
420     p_fapi_api_queue_elem_t p_qelm_list = NULL, p_urllc_qelm_list = NULL;
421     p_fapi_api_queue_elem_t p_qelm = NULL;
422     p_fapi_api_queue_elem_t p_tail_qelm = NULL, p_urllc_tail_qelm = NULL;
423     WLS_HANDLE h_wls = nr5g_fapi_fapi2mac_wls_instance();
424     uint64_t start_tick = 0;
425
426     num_elms = nr5g_fapi_fapi2mac_wls_wait();
427     if (!num_elms)
428         return p_qelm_list;
429
430     start_tick = __rdtsc();
431     do {
432         p_msg = nr5g_fapi_fapi2mac_wls_get(&msg_size, &msg_type, &flags);
433         if (p_msg) {
434             p_qelm = (p_fapi_api_queue_elem_t) nr5g_fapi_wls_pa_to_va(h_wls,
435                 (uint64_t) p_msg);
436             if (nr5g_fapi_fapi2mac_is_valid_wls_ptr(p_qelm) == FALSE) {
437                 printf("Error: Invalid Ptr\n");
438                 continue;
439             }
440             p_qelm->p_next = NULL;
441             
442             if (flags & WLS_TF_URLLC)
443             {
444                 if (p_urllc_qelm_list) {
445                     p_urllc_tail_qelm = p_urllc_qelm_list;
446                     while (NULL != p_urllc_tail_qelm->p_next) {
447                         p_urllc_tail_qelm = p_urllc_tail_qelm->p_next;
448                     }
449                     p_urllc_tail_qelm->p_next = p_qelm;
450                 } else {
451                     p_urllc_qelm_list = p_qelm;
452                 }
453             } else {
454             if (p_qelm_list) {
455                 p_tail_qelm = p_qelm_list;
456                 while (NULL != p_tail_qelm->p_next) {
457                     p_tail_qelm = p_tail_qelm->p_next;
458                 }
459                 p_tail_qelm->p_next = p_qelm;
460             } else {
461                 p_qelm_list = p_qelm;
462             }
463         }
464         }
465         num_elms--;
466     } while (num_elms && is_msg_present(flags));
467
468     if (p_urllc_qelm_list) {
469         nr5g_fapi_urllc_thread_callback((void *) p_urllc_qelm_list,
470                &nr5g_fapi_get_nr5g_fapi_phy_ctx()->urllc_mac2phy_params);
471     }
472
473     tick_total_wls_get_per_tti_dl += __rdtsc() - start_tick;
474
475     return p_qelm_list;
476 }