1 /******************************************************************************
3 * Copyright (c) 2019 Intel.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 *******************************************************************************/
20 * @file This file has Shared Memory interface functions between FAPI and PHY
21 * @defgroup nr5g_fapi_source_framework_wls_fapi2phy_group
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"
30 //------------------------------------------------------------------------------
31 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
33 * @param data Pointer to validate
35 * @return TRUE If pointer is within valid shared WLS memory region
36 * FALSE If pointer is out of valid shared WLS memory region
39 * This function validates pointer's in WLS shared memory region
42 //------------------------------------------------------------------------------
43 uint8_t nr5g_fapi_fapi2phy_is_valid_wls_ptr(
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)) {
56 //------------------------------------------------------------------------------
57 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
61 * @return A pointer to WLS_HANDLE stucture
64 * This function returns the WLS instance
67 //------------------------------------------------------------------------------
68 static inline WLS_HANDLE nr5g_fapi_fapi2phy_wls_instance(
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];
75 //----------------------------------------------------------------------------------
76 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
78 * @param[out] data Location where First API from L1 is stored
80 * @return Size of Message sent from L1
83 * This function queries the APIs sent from L1 to L2 and gets the first pointer
87 //----------------------------------------------------------------------------------
88 inline uint64_t *nr5g_fapi_fapi2phy_wls_get(
93 uint64_t *data = NULL;
96 uint16_t mt = 0, f = 0;
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));
107 //----------------------------------------------------------------------------------
108 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
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
115 * @return 0 if SUCCESS
118 * This function adds a block of API from L2 to L1 which will be sent later
121 //----------------------------------------------------------------------------------
122 inline uint8_t nr5g_fapi_fapi2phy_wls_put(
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);
138 //----------------------------------------------------------------------------------
139 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
143 * @return 0 if SUCCESS
146 * This function is called at WLS init and waits in an infinite for L1 to respond back with some information
150 //----------------------------------------------------------------------------------
151 inline uint8_t nr5g_fapi_fapi2phy_wls_ready(
155 //NR5G_FAPI_LOG(TRACE_LOG, ("Waiting for L1 to respond in WLS Ready"));
156 ret = WLS_Ready(nr5g_fapi_fapi2phy_wls_instance());
160 //----------------------------------------------------------------------------------
161 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
165 * @return Number of blocks of APIs received
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.
172 //----------------------------------------------------------------------------------
173 inline uint8_t nr5g_fapi_fapi2phy_wls_wait(
177 // NR5G_FAPI_LOG(TRACE_LOG, ("Waiting for L1 to respond in WLS Wait"));
178 ret = WLS_Wait(nr5g_fapi_fapi2phy_wls_instance());
182 //------------------------------------------------------------------------------
183 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
185 * @param[out] data Location where First API from L1 is stored
187 * @return Size of Message sent from L1
190 * This function checks if this is the last message in this tti.
193 //------------------------------------------------------------------------------
194 static inline uint8_t is_msg_present(
197 return (!((flags & WLS_TF_FIN) || (flags == 0)));
200 //----------------------------------------------------------------------------------
201 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
203 * @param[out] data Location where First API from L1 is stored
205 * @return Size of Message sent from L1
208 * This function queries the APIs sent from L1 to L2 and gets the first pointer
212 //----------------------------------------------------------------------------------
213 PMAC2PHY_QUEUE_EL nr5g_fapi_fapi2phy_wls_recv(
216 uint16_t msg_type = 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;
226 num_elms = nr5g_fapi_fapi2phy_wls_wait();
231 p_msg = nr5g_fapi_fapi2phy_wls_get(&msg_size, &msg_type, &flags);
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");
240 p_qelm->pNext = NULL;
242 p_tail_qelm->pNext = p_qelm;
243 p_tail_qelm = p_qelm;
245 p_qelm_list = p_qelm;
246 p_tail_qelm = p_qelm;
250 } while (num_elms && is_msg_present(flags));
253 wls_fapi_add_recv_apis_to_free(p_qelm_list, g_free_recv_idx);
255 if (g_free_recv_idx >= TO_FREE_SIZE) {
258 // Free 10 TTIs Later
259 wls_fapi_free_recv_free_list(g_free_recv_idx);
261 wls_fapi_add_blocks_to_ul();
267 //------------------------------------------------------------------------------
268 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
270 * @param[in] p_msg_header Pointer to the TxSDuReq Message block
271 * @param[out] n_zbc_blocks Number of ZBC blocks
273 * @return 1 if this block is a TxSduReq message. 0 else.
276 * This function checks if a block is a TxSduReq messages and counts the number
277 * of ZBC blocks in this API
280 //------------------------------------------------------------------------------
281 int nr5g_fapi_fapi2phy_is_sdu_zbc_block(
285 PL1L2MessageHdr p_msg_header = (PL1L2MessageHdr) p_msg;
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);
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);
298 if (*num_zbc_blocks) {
306 //----------------------------------------------------------------------------------
307 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
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
313 * @return 0 if SUCCESS
316 * This function adds all the ZBC blocks in a TXSDU Message and prepares them to
320 //------------------------------------------------------------------------------
321 uint32_t nr5g_fapi_fapi2phy_send_zbc_blocks(
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;
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++) {
339 pdu_len = p_dl_pdu_data->nPduLen1;
340 p_payload = p_dl_pdu_data->pPayload1;
341 msg_type = MSG_PHY_ZBC_BLOCK0_REQ;
343 pdu_len = p_dl_pdu_data->nPduLen2;
344 p_payload = p_dl_pdu_data->pPayload2;
345 msg_type = MSG_PHY_ZBC_BLOCK1_REQ;
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) {
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,
360 printf("Error ZBC block 0x%016lx\n", (uint64_t) p_payload);
371 //------------------------------------------------------------------------------
372 /** @ingroup nr5g_fapi_source_framework_wls_fapi2phy_group
374 * @param[in] A pointer to the phy instance
375 * @param[in] A data Pointer to the Linked list header
377 * @return 0 if SUCCESS
379 * @description This function sends a list of APIs to the L1 via WLS
382 //------------------------------------------------------------------------------
383 uint8_t nr5g_fapi_fapi2phy_wls_send(
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;
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;
394 p_curr_msg = (PMAC2PHY_QUEUE_EL) data;
395 wls_fapi_add_send_apis_to_free(p_curr_msg, g_free_send_idx);
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"));
402 if (p_curr_msg->pNext) {
403 flags = WLS_SG_FIRST;
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"));
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,
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"));
431 p_curr_msg = p_curr_msg->pNext;
432 } else { /* p_curr_msg->Next */
436 if (nr5g_fapi_fapi2phy_is_sdu_zbc_block(p_msg_header,
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) {
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"));
453 if (is_zbc) { // ZBC blocks
454 if (nr5g_fapi_fapi2phy_send_zbc_blocks(p_msg_header,
455 WLS_SG_LAST) != SUCCESS) {
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"));
466 } /* p_curr_msg->Next */
469 } else { // one block
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"));
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)) {
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"));
496 if (g_free_send_idx >= TO_FREE_SIZE)
499 // Free 10 TTIs Later
500 wls_fapi_free_send_free_list(g_free_send_idx);
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"));