Files
2026-04-15 12:29:58 +02:00

308 lines
9.9 KiB
C

/*
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
*/
#include "wls_pnf.h"
#include <rte_eal.h>
#include <rte_string_fns.h>
#include <rte_common.h>
#include <rte_lcore.h>
#include <rte_debug.h>
#include <pnf_p7.h>
#include <sys/time.h>
#include "wls_lib.h"
#include "pnf.h"
#include "nr_nfapi_p7.h"
#include "nfapi/open-nFAPI/fapi/inc/nr_fapi_p7_utils.h"
// A copy of the PNF P7 config is needed for the message processing thread, in other transport mechanisms where P7 is handled in a
// different thread, the config is passed to it upon the thread creation
nfapi_pnf_p7_config_t *wls_pnf_p7_config = NULL;
void wls_pnf_set_p7_config(void *p7_config)
{
wls_pnf_p7_config = (nfapi_pnf_p7_config_t *)p7_config;
}
static WLS_MAC_CTX g_phy_wls;
uint8_t phy_dpdk_init(void);
uint8_t phy_wls_init(const char *dev_name, uint64_t nWlsMacMemSize, uint64_t nWlsPhyMemSize);
void phy_mac_recv();
void wls_mac_print_stats(void);
pnf_t *_this = NULL;
static PWLS_MAC_CTX wls_mac_get_ctx(void)
{
return &g_phy_wls;
}
static nfapi_pnf_config_t *cfg;
void *wls_fapi_pnf_nr_start_thread(void *ptr)
{
NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] IN WLS PNF NFAPI start thread %s\n", __FUNCTION__);
cfg = (nfapi_pnf_config_t *)ptr;
wls_fapi_nr_pnf_start();
return (void *)0;
}
void wls_pnf_close(pthread_t p5_thread)
{
_this->terminate = 1;
WLS_WakeUp(wls_mac_get_ctx()->hWls);
pthread_join(p5_thread, NULL);
if (WLS_Close(wls_mac_get_ctx()->hWls) != 0) {
NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] WLS_CLose call failed...\n");
} else {
NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] WLS_CLose called successfully...\n");
}
rte_eal_cleanup();
}
void wls_fapi_nr_pnf_stop()
{
AssertFatal(cfg->nr_stop_req, "STOP.request Handler should be set!");
nfapi_nr_stop_request_scf_t req = {0};
req.header.phy_id = 0;
req.header.message_id = NFAPI_NR_PHY_MSG_TYPE_STOP_REQUEST;
cfg->nr_stop_req(cfg, 0, &req);
}
int wls_fapi_nr_pnf_start()
{
int64_t ret;
// Verify that config is not null
if (cfg == 0)
return -1;
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__);
_this = (pnf_t *)(cfg);
_this->terminate = 0;
// Init PNF config
nfapi_pnf_phy_config_t *phy = malloc_or_fail(sizeof(nfapi_pnf_phy_config_t));
memset(phy, 0, sizeof(nfapi_pnf_phy_config_t));
phy->state = NFAPI_PNF_PHY_IDLE;
phy->phy_id = 0;
phy->next = (_this->_public).phys;
(_this->_public).phys = phy;
_this->_public.state = NFAPI_PNF_RUNNING;
// DPDK init
ret = phy_dpdk_init();
if (!ret) {
NFAPI_TRACE(NFAPI_TRACE_ERROR, "[PNF] DPDK Init - Failed\n");
return false;
}
NFAPI_TRACE(NFAPI_TRACE_INFO, "\n[PHY] DPDK Init - Done\n");
// WLS init
ret = phy_wls_init(WLS_DEV_NAME, WLS_MAC_MEMORY_SIZE, WLS_PHY_MEMORY_SIZE);
if (!ret) {
NFAPI_TRACE(NFAPI_TRACE_ERROR, "[PNF] WLS Init - Failed\n");
return false;
}
NFAPI_TRACE(NFAPI_TRACE_INFO, "\n[PHY] WLS Init - Done\n");
// Start Receiving loop from the VNF
NFAPI_TRACE(NFAPI_TRACE_INFO, "Start Receiving loop from the VNF\n");
phy_mac_recv();
// Should never get here, to be removed, align with present implementation of PNF loop
NFAPI_TRACE(NFAPI_TRACE_INFO, "\n[PHY] Exiting...\n");
return true;
}
uint8_t phy_dpdk_init(void)
{
unsigned long i;
char *argv[] = {"OAI_PNF", "--proc-type=primary", "--file-prefix", WLS_DEV_NAME, "--iova-mode=pa", "--no-pci"};
int argc = RTE_DIM(argv);
/* initialize EAL first */
NFAPI_TRACE(NFAPI_TRACE_INFO, "\n[PHY] Calling rte_eal_init: ");
for (i = 0; i < RTE_DIM(argv); i++) {
NFAPI_TRACE(NFAPI_TRACE_INFO, "%s ", argv[i]);
}
NFAPI_TRACE(NFAPI_TRACE_INFO, "\n");
if (rte_eal_init(argc, argv) < 0)
rte_panic("Cannot init EAL\n");
return true;
}
uint8_t phy_wls_init(const char *dev_name, uint64_t nWlsMacMemSize, uint64_t nWlsPhyMemSize)
// uint8_t phy_wls_init(const char *dev_name, uint64_t nBlockSize)
{
PWLS_MAC_CTX pWls = wls_mac_get_ctx();
pWls->nTotalAllocCnt = 0;
pWls->nTotalFreeCnt = 0;
pWls->nTotalUlBufAllocCnt = 0;
pWls->nTotalUlBufFreeCnt = 0;
pWls->nTotalDlBufAllocCnt = 0;
pWls->nTotalDlBufFreeCnt = 0;
pWls->hWls = WLS_Open(dev_name, WLS_SLAVE_CLIENT, &nWlsMacMemSize, &nWlsPhyMemSize);
if (pWls->hWls) {
/* allocate chuck of memory */
if (WLS_Alloc(pWls->hWls, nWlsMacMemSize + nWlsPhyMemSize) != NULL) {
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "WLS Memory allocated successfully\n");
} else {
NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unable to alloc WLS Memory\n");
return false;
}
} else {
NFAPI_TRACE(NFAPI_TRACE_ERROR, "can't open WLS instance");
return false;
}
return true;
}
bool wls_pnf_nr_send_p5_message(pnf_t *pnf, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len)
{
int packed_len = cfg->pack_func(msg, msg_len, pnf->tx_message_buffer, sizeof(pnf->tx_message_buffer), &pnf->_public.codec_config);
if (packed_len < 0) {
NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p5_message_pack failed (%d)\n", packed_len);
return false;
}
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "fapi_nr_p5_message_pack succeeded having packed %d bytes\n", packed_len);
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "in msg, msg_len is %d\n", msg->message_length);
PWLS_MAC_CTX pWls = wls_mac_get_ctx();
return wls_send_fapi_msg(pWls, msg->message_id, packed_len, pnf->tx_message_buffer);
}
bool wls_pnf_nr_send_p7_message(pnf_p7_t *pnf_p7, nfapi_nr_p7_message_header_t *msg, uint32_t msg_len)
{
UNUSED(msg_len);
if (pnf_p7->terminate) {
// don't send any further P7 messages after terminating
return false;
}
if (!isFAPIMessageIDValid(msg->message_id)) {
return false;
}
// if it's an nFAPI message, ignore
if ((msg->message_id == NFAPI_NR_PHY_MSG_TYPE_UL_NODE_SYNC || msg->message_id == NFAPI_NR_PHY_MSG_TYPE_DL_NODE_SYNC
|| msg->message_id == NFAPI_NR_PHY_MSG_TYPE_TIMING_INFO)) {
return false;
}
PWLS_MAC_CTX pWls = wls_mac_get_ctx();
int num_avail_blocks = WLS_NumBlocks(pWls->hWls);
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "num_avail_blocks is %d\n", num_avail_blocks);
while (num_avail_blocks < 2) {
num_avail_blocks = WLS_NumBlocks(pWls->hWls);
if (_this->terminate) {
return false;
}
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "num_avail_blocks is %d\n", num_avail_blocks);
}
/* get PA blocks for header and msg */
const uint64_t pa_hdr = dequeueBlock(pWls);
AssertFatal(pa_hdr, "WLS_DequeueBlock failed for pa_hdr\n");
const uint64_t pa_msg = dequeueBlock(pWls);
AssertFatal(pa_msg, "WLS_DequeueBlock failed for pa_msg\n");
p_fapi_api_queue_elem_t headerElem = WLS_PA2VA(pWls->hWls, pa_hdr);
AssertFatal(headerElem, "WLS_PA2VA failed for headerElem\n");
p_fapi_api_queue_elem_t fapiMsgElem = WLS_PA2VA(pWls->hWls, pa_msg);
AssertFatal(fapiMsgElem, "WLS_PA2VA failed for fapiMsgElem\n");
const uint8_t wls_header[] = {1, 0}; // num_messages , opaque_handle
fill_fapi_list_elem(headerElem, fapiMsgElem, FAPI_VENDOR_MSG_HEADER_IND, 1, 2);
memcpy((uint8_t *)(headerElem + 1), wls_header, 2);
const int packed_len = ((nfapi_pnf_p7_config_t *)pnf_p7)->pack_func(msg, (fapiMsgElem + 1), NFAPI_MAX_PACKED_MESSAGE_SIZE, NULL);
if (packed_len < 0) {
NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p7_message_pack failed (%d)\n", packed_len);
return false;
}
fill_fapi_list_elem(fapiMsgElem, NULL, msg->message_id, 1, packed_len + NFAPI_HEADER_LENGTH);
const uint8_t retval = wls_msg_send(pWls->hWls, headerElem);
return retval;
}
static void procPhyMessages(uint32_t msg_size, void *msg_buf, uint16_t msg_id)
{
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "[PHY] Received Msg ID 0x%02x Length %d\n", msg_id, msg_size);
if (msg_buf == NULL || _this == NULL) {
AssertFatal(msg_buf != NULL && _this != NULL, "%s: NULL parameters\n", __FUNCTION__);
}
// Add the size of the header to the message_size, because the size in the header does not include the header length
msg_size += NFAPI_NR_P5_HEADER_LENGTH;
switch (msg_id) {
case NFAPI_NR_PHY_MSG_TYPE_PARAM_REQUEST ... NFAPI_NR_PHY_MSG_TYPE_STOP_REQUEST:
pnf_nr_handle_p5_message(_this, msg_buf, msg_size);
break;
case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST ... NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION: {
pnf_nr_handle_p7_message(msg_buf, msg_size, (pnf_p7_t *)wls_pnf_p7_config, 0);
break;
}
default:
printf("\n Unknown Msg ID 0x%02x\n", msg_id);
break;
}
}
void phy_mac_recv()
{
/* Number of Memory blocks to get */
uint32_t msgSize;
uint16_t msgType;
uint16_t flags;
PWLS_MAC_CTX pWls = wls_mac_get_ctx();
// This flag is used to determine whether to return the received blocks to the PNF
bool to_return = false;
while (_this->terminate == 0) {
int numMsgToGet = WLS_Wait(pWls->hWls);
if (numMsgToGet == 0 || _this->terminate) {
continue;
}
uint64_t PAs[numMsgToGet];
uint8_t pa_idx = 0;
while (numMsgToGet--) {
PAs[pa_idx] = WLS_Get(pWls->hWls, &msgSize, &msgType, &flags);
pa_idx++;
}
for (int i = 0; i < pa_idx; i++) {
p_fapi_api_queue_elem_t msg = WLS_PA2VA(pWls->hWls, PAs[i]);
if (msg->msg_type != FAPI_VENDOR_MSG_HEADER_IND) {
uint8_t *msgt = (uint8_t *)(msg + 1);
uint32_t len = msgt[7] | (msgt[6] << 8) | (msgt[5] << 16) | (msgt[4] << 24);
procPhyMessages(len, (void *)(msg + 1), msg->msg_type);
} else {
// We check the header block to determine if it's the OAI VNF, if so, we're required to return the pages for enqueueing
if (!to_return) {
uint8_t *msgt = (uint8_t *)(msg + 1);
if (msgt[1] == 0xff) {
to_return = true;
}
}
}
}
// A STOP.indication might have been processed, which set's terminate to 1
// don't return pages in that case
if (_this->terminate) {
break;
}
if (to_return) {
// We only return the pages to be enqueued in case we're using the OAI VNF,
// The Radisys O-DU handles enqueueing the blocks differently, and also doesn't handle receiving a single block
for (int i = 0; i < pa_idx; i++) {
wls_return_msg_to_master(pWls, PAs[i]);
}
}
}
}