mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-15 13:40:29 +00:00
Compare commits
18 Commits
test-vecto
...
cuMAC_inte
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08d280f357 | ||
|
|
a3f6109d7c | ||
|
|
bc751da474 | ||
|
|
26b74de4bd | ||
|
|
7247d7daa8 | ||
|
|
7c0c318df7 | ||
|
|
7e2b55cc67 | ||
|
|
845d735dae | ||
|
|
c38962f530 | ||
|
|
516cb2902a | ||
|
|
0b54e9ab81 | ||
|
|
79f423052b | ||
|
|
61390d8a9c | ||
|
|
876fc5b205 | ||
|
|
284105da7c | ||
|
|
64b2a513b7 | ||
|
|
3a8c182e37 | ||
|
|
3860b51fde |
@@ -1333,6 +1333,9 @@ target_include_directories(L2_NR PRIVATE ${F1AP_DIR}/lib)
|
||||
if(E2_AGENT)
|
||||
target_compile_definitions(L2_NR PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT)
|
||||
endif()
|
||||
if (OAI_AERIAL_CUMAC)
|
||||
target_compile_definitions(L2_NR PUBLIC ENABLE_CUMAC)
|
||||
endif()
|
||||
|
||||
add_library(e1_if
|
||||
${NR_RRC_DIR}/cucp_cuup_direct.c
|
||||
@@ -1856,6 +1859,11 @@ if (OAI_AERIAL)
|
||||
target_compile_definitions(nr-softmodem PUBLIC ENABLE_AERIAL)
|
||||
target_link_libraries(nr-softmodem PUBLIC aerial_lib)
|
||||
endif()
|
||||
add_boolean_option(OAI_AERIAL_CUMAC OFF "Activate OAI's AERIAL_CUMAC driver" OFF)
|
||||
if (OAI_AERIAL_CUMAC)
|
||||
target_link_libraries(nr-softmodem PUBLIC aerial_cumac_lib)
|
||||
target_compile_definitions(nr-softmodem PUBLIC ENABLE_CUMAC)
|
||||
endif()
|
||||
if(E2_AGENT)
|
||||
target_link_libraries(nr-softmodem PUBLIC e2_agent e2_agent_arg e2_ran_func_du_cucp_cuup)
|
||||
target_compile_definitions(nr-softmodem PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT)
|
||||
|
||||
@@ -282,6 +282,9 @@ function main() {
|
||||
;;
|
||||
esac
|
||||
shift 2;;
|
||||
"--AERIAL_CUMAC"|"--Aerial_CuMAC"|"--aerial_cumac"|"--CUMAC"|"--cuMAC"|"--cumac")
|
||||
CMAKE_CMD="$CMAKE_CMD -DOAI_AERIAL_CUMAC=ON"
|
||||
shift;;
|
||||
-P | --phy_simulators)
|
||||
SIMUS_PHY=1
|
||||
CMAKE_CMD="$CMAKE_CMD -DENABLE_PHYSIM_TESTS=ON"
|
||||
|
||||
62
doc/cuMAC.md
Normal file
62
doc/cuMAC.md
Normal file
@@ -0,0 +1,62 @@
|
||||
Differences between SCH_TTI.request and PFM
|
||||
|
||||
Header is the same, effectively FAPI header
|
||||
then PFM has an offset of data followed by sfn, slot
|
||||
SCH_TTI.request after the header, has the sfn/slot, order which is shared to the other slot messages
|
||||
SCH_TTI request then is followed by info regarding the algorithm to run, to which cell the message refers to and some more cell info (num Ues, num Antennas, etc)
|
||||
PFM sort doesn't have any cell information, only related to UEs
|
||||
|
||||
|
||||
struct cumac_pfm_tti_req_t {
|
||||
cumac_msg_header_t header;
|
||||
{
|
||||
uint8_t message_count; //!< Number of messages in this transmission
|
||||
uint8_t handle_id; //!< handle_id is used as cell_id
|
||||
uint16_t type_id; //!< Message type identifier (cumac_msg_t)
|
||||
uint32_t body_len; //!< Length of message body in bytes
|
||||
uint8_t body[0]; //!< Variable-length message body (flexible array member)
|
||||
}
|
||||
uint32_t offset_ue_info_arr; // Offset of the PFM_UE_INFO data array in nvipc_buf->data_buf
|
||||
uint16_t sfn;
|
||||
uint16_t slot;
|
||||
uint16_t num_ue; // total number of UEs in the payload
|
||||
uint16_t num_output_sorted_lc[10];
|
||||
// number of output sorted LCs/LCGs per DL/UL QoS type, 0-9 are the indices of the QoS types:
|
||||
// 0 - dl_gbr_critical, 1 - dl_gbr_non_critical, 2 - dl_ngbr_critical, 3 - dl_ngbr_non_critical, 4 - dl_mbr_non_critical,
|
||||
// 5 - ul_gbr_critical, 6 - ul_gbr_non_critical, 7 - ul_ngbr_critical, 8 - ul_ngbr_non_critical, 9 - ul_mbr_non_critical.
|
||||
};
|
||||
|
||||
#define MAX_NUM_LCG 4
|
||||
#define MAX_NUM_LC 4
|
||||
struct PFM_UE_INFO {
|
||||
PFM_DL_LC_INFO dl_lc_info[MAX_NUM_LC];
|
||||
PFM_UL_LCG_INFO ul_lcg_info[MAX_NUM_LCG];
|
||||
uint32_t ambr;
|
||||
uint32_t rcurrent_dl;
|
||||
uint32_t rcurrent_ul;
|
||||
uint16_t rnti;
|
||||
uint8_t num_layers_dl;
|
||||
uint8_t num_layers_ul;
|
||||
uint8_t flags; // a collection of flags: flags & 0x01 - is_valid, flags & 0x02 - is_scheduled_dl, flags & 0x04 - is_scheduled_ul
|
||||
uint8_t carrier_id;
|
||||
uint8_t num_dl_lcs;
|
||||
uint8_t num_ul_lcgs;
|
||||
};
|
||||
|
||||
struct PFM_DL_LC_INFO {
|
||||
uint32_t tbs_scheduled;
|
||||
uint32_t ravg;
|
||||
uint32_t pfm;
|
||||
uint8_t flags; // a collection of flags: flags & 0x01 - is_valid, flags & 0x02 - reset ravg to 1.0
|
||||
uint8_t qos_type; // 0 - dl_gbr_critical, 1 - dl_gbr_non_critical, 2 - dl_ngbr_critical, 3 - dl_ngbr_non_critical, 4 - dl_mbr_non_critical
|
||||
uint8_t padding[2]; // Padding to align to 32-bit
|
||||
};
|
||||
|
||||
struct PFM_UL_LCG_INFO {
|
||||
uint32_t tbs_scheduled;
|
||||
uint32_t ravg;
|
||||
uint32_t pfm;
|
||||
uint8_t flags; // a collection of flags: flags & 0x01 - is_valid, flags & 0x02 - reset ravg to 1.0
|
||||
uint8_t qos_type; // 0 - ul_gbr_critical, 1 - ul_gbr_non_critical, 2 - ul_ngbr_critical, 3 - ul_ngbr_non_critical, 4 - ul_mbr_non_critical
|
||||
uint8_t padding[2]; // Padding to align to 32-bit
|
||||
};
|
||||
120
docker/Dockerfile.gNB.cumac.ubuntu
Normal file
120
docker/Dockerfile.gNB.cumac.ubuntu
Normal file
@@ -0,0 +1,120 @@
|
||||
#/*
|
||||
# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
# * contributor license agreements. See the NOTICE file distributed with
|
||||
# * this work for additional information regarding copyright ownership.
|
||||
# * The OpenAirInterface Software Alliance licenses this file to You under
|
||||
# * the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
# * except in compliance with the License.
|
||||
# * You may obtain a copy of the License at
|
||||
# *
|
||||
# * http://www.openairinterface.org/?page_id=698
|
||||
# *
|
||||
# * Unless required by applicable law or agreed to in writing, software
|
||||
# * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# * See the License for the specific language governing permissions and
|
||||
# * limitations under the License.
|
||||
# *-------------------------------------------------------------------------------
|
||||
# * For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
# * contact@openairinterface.org
|
||||
# */
|
||||
#---------------------------------------------------------------------
|
||||
#
|
||||
# Dockerfile for the Open-Air-Interface BUILD service
|
||||
# Valid for Ubuntu 24.04
|
||||
#
|
||||
#---------------------------------------------------------------------
|
||||
|
||||
FROM ran-base:latest AS ran-build
|
||||
|
||||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install --yes \
|
||||
wget \
|
||||
ninja-build \
|
||||
#unzip is needed for protobuf
|
||||
unzip \
|
||||
moreutils \
|
||||
vim-tiny \
|
||||
nano \
|
||||
# To build libnvipc
|
||||
cmake libpcap-dev libcunit1-dev libnuma-dev pkg-config
|
||||
|
||||
RUN rm -Rf /oai-ran
|
||||
WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
RUN /bin/sh oaienv && \
|
||||
tar -xvzf nvipc_src.*.tar.gz && \
|
||||
cd nvipc_src.* && \
|
||||
rm -rf build && mkdir build && cd build && \
|
||||
cmake .. -DNVIPC_DPDK_ENABLE=OFF -DNVIPC_DOCA_ENABLE=OFF -DNVIPC_CUDA_ENABLE=OFF -DENABLE_SLT_RSP=ON && \
|
||||
make -j && make install
|
||||
|
||||
RUN /bin/sh oaienv && \
|
||||
cd cmake_targets && \
|
||||
mkdir -p log && \
|
||||
./build_oai -c -w USRP --gNB --ninja --cumac --build-tool-opt -k10
|
||||
#\
|
||||
# --cmake-opt -DCMAKE_C_FLAGS="-Werror" --cmake-opt -DCMAKE_CXX_FLAGS="-Werror"
|
||||
|
||||
|
||||
#start from scratch for target executable
|
||||
FROM ubuntu:noble AS oai-gnb-aerial
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=Europe
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get upgrade --yes && \
|
||||
apt-get install --yes \
|
||||
software-properties-common \
|
||||
procps \
|
||||
libsctp1 \
|
||||
tzdata \
|
||||
libblas3 \
|
||||
libconfig9 \
|
||||
openssl \
|
||||
net-tools \
|
||||
iperf \
|
||||
iproute2 \
|
||||
iputils-ping \
|
||||
gdb \
|
||||
moreutils \
|
||||
libusb-1.0-0 \
|
||||
nvidia-cuda-toolkit \
|
||||
libyaml-cpp-dev && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /opt/oai-gnb/bin
|
||||
COPY --from=ran-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/nr-softmodem ./
|
||||
COPY --from=ran-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_test ./
|
||||
COPY ./docker/scripts/gnb_entrypoint.sh ./entrypoint.sh
|
||||
|
||||
COPY --from=ran-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/libparams_libconfig.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
|
||||
/usr/local/lib/
|
||||
|
||||
#copy files from nvIPC
|
||||
COPY --from=ran-build \
|
||||
/usr/local/lib/libfmtlog-shared.so \
|
||||
/usr/local/lib/libnvlog.so \
|
||||
/usr/local/lib/libnvipc.so \
|
||||
/usr/local/lib/
|
||||
|
||||
RUN ldconfig && \
|
||||
echo "---- ldd on nr-softmodem ----" && \
|
||||
ldd /opt/oai-gnb/bin/nr-softmodem && \
|
||||
echo "---- ldd on shared libraries ----" && \
|
||||
ldd /usr/local/lib/libparams_libconfig.so \
|
||||
/usr/local/lib/libfmtlog-shared.so \
|
||||
/usr/local/lib/libnvlog.so \
|
||||
/usr/local/lib/libnvipc.so
|
||||
|
||||
WORKDIR /opt/oai-gnb
|
||||
|
||||
COPY --from=ran-build /usr/local/bin/yq /usr/local/bin/yq
|
||||
ENTRYPOINT ["/opt/oai-gnb/bin/entrypoint.sh"]
|
||||
CMD ["/opt/oai-gnb/bin/cumac_test"]
|
||||
@@ -3,3 +3,4 @@
|
||||
add_subdirectory(nr_rlc)
|
||||
add_subdirectory(nr_pdcp)
|
||||
add_subdirectory(NR_MAC_UE)
|
||||
add_subdirectory(NR_MAC_gNB/integration/cuMAC)
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
/*Softmodem params*/
|
||||
#include "executables/softmodem-common.h"
|
||||
#include "../../../nfapi/oai_integration/vendor_ext.h"
|
||||
#include "PHY/defs_gNB.h"
|
||||
|
||||
#ifdef ENABLE_CUMAC
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_nvipc.h"
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
/////* DLSCH MAC PDU generation (6.1.2 TS 38.321) */////
|
||||
@@ -627,8 +632,210 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
int CC_id = 0;
|
||||
int slots_per_frame = mac->frame_structure.numb_slots_frame;
|
||||
|
||||
#ifdef ENABLE_CUMAC
|
||||
uint8_t connected_ues = 0;
|
||||
UE_iterator (UE_list, UE) {
|
||||
connected_ues++;
|
||||
}
|
||||
const slot_data_entry_t* cumac_slot_data = NULL;
|
||||
if (connected_ues!=0 && cumac_can_schedule()) {
|
||||
LOG_D(NR_MAC,"CUMAC SENDING SCH TTI_REQ with %d connected UES\n", connected_ues);
|
||||
/* const double k = 1.38064852e-23; // Boltzmann constant
|
||||
const double T = 290.0; // Temperature in K
|
||||
double thermalNoise = k * T * RC.gNB[0]->frame_parms.N_RB_DL * 12 * RC.gNB[0]->frame_parms.subcarrier_spacing;
|
||||
double nfLinear = pow(10.0, 20 / 10.0);
|
||||
double sigmasqrd = thermalNoise * nfLinear;
|
||||
|
||||
// for RFSim
|
||||
double SNR_db = 20.0;
|
||||
float sigmaSqrd = pow(10.0, -SNR_db / 10.0); */
|
||||
const uint8_t nBsAnt = RC.nrmac[0]->config->carrier_config.num_tx_ant.value;
|
||||
const uint8_t nUeAnt = RC.nrmac[0]->config->carrier_config.num_tx_ant.value;
|
||||
|
||||
// Pad nActiveUe to nMaxSchUePerCell so cuMAC UE selection fills all scheduler
|
||||
// slots with real indices. Without padding, unselected slots get avgRates=0 in
|
||||
// PRB allocation, which gives Inf PF and beats the real UE for the only PRG.
|
||||
// Dummy UEs use wbSinr=0 (lose in UE selection) and avgRatesActUe=1e38f (lose
|
||||
// in PRB allocation PF even if selected by the cuMAC scheduler).
|
||||
const uint16_t nMaxSchUe = cumac_nMax_schUePerCell();
|
||||
const uint16_t nActiveUe_padded = nMaxSchUe;
|
||||
|
||||
cumac_tti_req_bufs_t buffers;
|
||||
// calloc zero-initialises: dummy slots get CRNTI=0 and wbSinr=0.
|
||||
buffers.CRNTI = calloc(nActiveUe_padded, sizeof(uint16_t));
|
||||
buffers.avgRatesActUe = malloc(nActiveUe_padded * sizeof(float));
|
||||
buffers.newDataActUe = malloc(nActiveUe_padded * sizeof(int8_t));
|
||||
buffers.allocSolLastTxActUe = calloc(nActiveUe_padded * 2, sizeof(int16_t));
|
||||
buffers.mcsSelSolLastTxActUe = calloc(nActiveUe_padded, sizeof(int16_t));
|
||||
buffers.layerSelSolLastTxActUe = calloc(nActiveUe_padded, sizeof(int8_t));
|
||||
|
||||
// wbSinr layout: [nActiveUE × nUeAnt] in row-major order.
|
||||
// calloc zero-initialises so dummy slots get wbSinr=0 (lowest PF in UE selection).
|
||||
buffers.wbSinr = calloc(nActiveUe_padded * nUeAnt, sizeof(float));
|
||||
|
||||
for (int i = 0; i < nActiveUe_padded; i++) {
|
||||
buffers.newDataActUe[i] = -1;
|
||||
buffers.avgRatesActUe[i] = 1e38f; // dummy sentinel; overwritten for real UEs below
|
||||
}
|
||||
size_t idx = 0;
|
||||
UE_iterator (UE_list, UE) {
|
||||
buffers.avgRatesActUe[idx] = UE->dl_thr_ue;
|
||||
buffers.CRNTI[idx] = UE->rnti;
|
||||
if (UE->cumac_last_sol.has_prev_sol) {
|
||||
buffers.allocSolLastTxActUe[idx * 2] = UE->cumac_last_sol.alloc_sol[0];
|
||||
buffers.allocSolLastTxActUe[idx * 2 + 1] = UE->cumac_last_sol.alloc_sol[1];
|
||||
buffers.mcsSelSolLastTxActUe[idx] = UE->cumac_last_sol.mcs_sol;
|
||||
buffers.layerSelSolLastTxActUe[idx] = UE->cumac_last_sol.layer_sol;
|
||||
}
|
||||
|
||||
const CSI_report_t *csi = &UE->UE_sched_ctrl.CSI_report;
|
||||
int sinrx10; // 0.1 dB units
|
||||
if (csi->csirs_rsrp_report.nb > 0)
|
||||
sinrx10 = csi->csirs_rsrp_report.r[0].SINRx10;
|
||||
else if (csi->ssb_rsrp_report.nb > 0)
|
||||
sinrx10 = csi->ssb_rsrp_report.r[0].SINRx10;
|
||||
else
|
||||
sinrx10 = get_SINRx10_for_mcs(UE->UE_sched_ctrl.dl_max_mcs);
|
||||
|
||||
// sinrx10/10 = SINR in dB; divide by 10 again for the dB-to-linear exponent
|
||||
const float sinr_lin = powf(10.0f, sinrx10 / 100.0f);
|
||||
for (int l = 0; l < nUeAnt; l++)
|
||||
buffers.wbSinr[idx * nUeAnt + l] = sinr_lin;
|
||||
|
||||
//check retransmissions
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
|
||||
if (!nr_mac_ue_is_active(UE)) {
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
/* get the PID of a HARQ process awaiting retrnasmission, or -1 otherwise */
|
||||
int harq_pid = sched_ctrl->retrans_dl_harq.head;
|
||||
/* check if retransmision or not */
|
||||
buffers.newDataActUe[idx] = harq_pid >= 0? CUMAC_UE_RETRANSMISSION: CUMAC_UE_INTIAL_TRANSMISSION;
|
||||
|
||||
idx++;
|
||||
}
|
||||
const uint16_t prb_per_prg = cumac_nPrbPerPrg();
|
||||
// nPrbGrp must equal nMaxPrg from CONFIG.request — cuMAC validates data_num == buf_num.
|
||||
// prgMsk uses carrier-absolute PRG indices to guide cuMAC's metric computation
|
||||
// (masking PRGs outside the BWP gives them zero SINR). Note: the 4T4R scheduler
|
||||
// ignores prgMsk during the allocation phase, so the allocSol will span [0, nPrbGrp)
|
||||
// regardless; the response handler clips it to the BWP.
|
||||
const uint16_t nPrbGrp = cumac_nMaxPrg() > 0 ? cumac_nMaxPrg() : 1;
|
||||
buffers.prgMsk = calloc(nPrbGrp, sizeof(uint8_t)); // zero-init: unavailable by default
|
||||
if (prb_per_prg > 0) {
|
||||
UE_iterator(UE_list, UE) {
|
||||
bwp_info_t ue_bwp = get_pdsch_bwp_start_size(mac, UE);
|
||||
if (ue_bwp.bwpSize == 0)
|
||||
continue;
|
||||
const uint16_t first_prg = ue_bwp.bwpStart / prb_per_prg;
|
||||
const uint16_t end_prg = (ue_bwp.bwpStart + ue_bwp.bwpSize + prb_per_prg - 1) / prb_per_prg;
|
||||
for (uint16_t i = first_prg; i < end_prg && i < nPrbGrp; i++)
|
||||
buffers.prgMsk[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
cumac_wait_to_send();
|
||||
const uint32_t taskBitMap = TASK_BIT(CUMAC_TASK_UE_SELECTION) | TASK_BIT(CUMAC_TASK_PRB_ALLOCATION);
|
||||
cumac_sch_tti_req_args_t args = {.frame = frame,
|
||||
.slot = slot,
|
||||
.payload.cellID = 0,
|
||||
.payload.taskBitMask = taskBitMap,
|
||||
.payload.ULDLSch = SCH_TTI_DL,
|
||||
.payload.nActiveUe = nActiveUe_padded,
|
||||
.payload.nSrsUe = 0,
|
||||
.payload.nPrbGrp = nPrbGrp,
|
||||
.payload.nBsAnt = nBsAnt,
|
||||
.payload.nUeAnt = nUeAnt,
|
||||
.payload.sigmaSqrd = 1.0f, // hardcoded in cuMAC source code
|
||||
.buffers = &buffers};
|
||||
|
||||
if (taskBitMap & TASK_BIT(CUMAC_TASK_PRB_ALLOCATION)) {
|
||||
|
||||
uint16_t numData = args.payload.nActiveUe * args.payload.nPrbGrp * args.payload.nUeAnt;
|
||||
buffers.postEqSinr = malloc(numData * sizeof(float));
|
||||
|
||||
for (int ue = 0; ue < args.payload.nActiveUe; ue++) {
|
||||
for (int prg = 0; prg < args.payload.nPrbGrp; prg++) {
|
||||
for (int l = 0; l < args.payload.nUeAnt; l++) {
|
||||
buffers.postEqSinr[ue * args.payload.nPrbGrp * args.payload.nUeAnt
|
||||
+ prg * args.payload.nUeAnt + l] =
|
||||
buffers.wbSinr[ue * args.payload.nUeAnt + l];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
numData = cumac_nMax_schUePerCell() * args.payload.nPrbGrp * cumac_nPrbPerPrg() * args.payload.nUeAnt;
|
||||
buffers.sinVal = malloc(numData * sizeof(float));
|
||||
for (int i = 0; i < numData; i++) {
|
||||
buffers.sinVal[i] = 20.0f;
|
||||
}
|
||||
|
||||
const uint32_t prdLen = cumac_nMax_schUePerCell() * args.payload.nPrbGrp * cumac_nPrbPerPrg() * args.payload.nBsAnt * args.payload.nBsAnt;
|
||||
const uint32_t detLen = cumac_nMax_schUePerCell() * args.payload.nPrbGrp * cumac_nPrbPerPrg() * args.payload.nUeAnt * args.payload.nUeAnt;
|
||||
const uint32_t hLen = args.payload.nPrbGrp * cumac_nPrbPerPrg() * cumac_nMax_schUePerCell() * /*nMaxCell*/ 1 * args.payload.nBsAnt * args.payload.nUeAnt;
|
||||
|
||||
numData = detLen;
|
||||
buffers.detMat = malloc(numData * sizeof(cuComplex));
|
||||
for (int i = 0; i < numData; i++) {
|
||||
buffers.detMat[i].x = 0.5f;
|
||||
buffers.detMat[i].y = 0.5f;
|
||||
}
|
||||
|
||||
numData = hLen;
|
||||
buffers.estH_fr = malloc(numData * sizeof(cuComplex));
|
||||
for (int i = 0; i < numData; i++) {
|
||||
buffers.estH_fr[i].x = 0.5f;
|
||||
buffers.estH_fr[i].y = 0.5f;
|
||||
}
|
||||
|
||||
numData = prdLen;
|
||||
buffers.prdMat = malloc(numData * sizeof(cuComplex));
|
||||
for (int i = 0; i < numData; i++) {
|
||||
buffers.prdMat[i].x = 0.5f;
|
||||
buffers.prdMat[i].y = 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
cumac_send_msg(CUMAC_SCH_TTI_REQUEST, l2_build_sch_tti_request, &args);
|
||||
cumac_sch_tti_end_args_t tti_end_args = {.frame = frame, .slot = slot};
|
||||
cumac_send_msg(CUMAC_TTI_END, l2_build_tti_end, &tti_end_args);
|
||||
|
||||
// we have to wait for the response
|
||||
cumac_wait_to_process();
|
||||
cumac_slot_data = get_slot_data(frame, slot);
|
||||
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Loop UE_info->list to check retransmission */
|
||||
UE_iterator(UE_list, UE) {
|
||||
#ifdef ENABLE_CUMAC
|
||||
if (cumac_slot_data != NULL) {
|
||||
int ue_id = cumac_get_UE_ID_by_RNTI(frame, slot, UE->rnti);
|
||||
if (ue_id == -1)
|
||||
continue; // UE not in this TTI's active list
|
||||
if (cumac_slot_data->taskBitMask & TASK_BIT(CUMAC_TASK_UE_SELECTION)) {
|
||||
// Check that this UE appears in the set cuMAC selected for scheduling
|
||||
bool selected = false;
|
||||
for (int i = 0; i < cumac_slot_data->nMaxSchUePerCell; i++) {
|
||||
if (cumac_slot_data->setSchdUePerCellTTI[i] == (uint16_t)ue_id) {
|
||||
selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!selected)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP;
|
||||
|
||||
@@ -728,7 +935,10 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
}
|
||||
}
|
||||
|
||||
//For the moment, prevent sorting so that the indexes match what comes from cumac
|
||||
#ifndef ENABLE_CUMAC
|
||||
qsort(UE_sched, numUE, sizeof(UEsched_t), comparator);
|
||||
#endif
|
||||
UEsched_t *iterator = UE_sched;
|
||||
|
||||
const int min_rbSize = 5;
|
||||
@@ -786,7 +996,14 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
int rbStart = 0; // WRT BWP start
|
||||
int bwp_start = bwp_info.bwpStart;
|
||||
int bwp_size = bwp_info.bwpSize;
|
||||
// Freq-demain allocation
|
||||
#ifdef ENABLE_CUMAC
|
||||
int cumac_ue_id = (cumac_slot_data != NULL)
|
||||
? cumac_get_UE_ID_by_RNTI(frame, slot, iterator->UE->rnti)
|
||||
: -1;
|
||||
#endif
|
||||
#ifndef ENABLE_CUMAC
|
||||
|
||||
// Freq-domain allocation
|
||||
int max_rbSize = 0;
|
||||
if (!get_rb_alloc(min_rbSize, bwp_size, bwp_start, bwp_size, rballoc_mask, slbitmap, &rbStart, &max_rbSize)) {
|
||||
LOG_D(NR_MAC,
|
||||
@@ -800,7 +1017,51 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
iterator++;
|
||||
continue;
|
||||
}
|
||||
|
||||
#else
|
||||
if (cumac_ue_id < 0 || cumac_slot_data->allocSol == NULL
|
||||
|| !(cumac_slot_data->taskBitMask & TASK_BIT(CUMAC_TASK_PRB_ALLOCATION))) {
|
||||
// PRB allocation not available for this UE; skip
|
||||
reset_beam_status(&mac->beam_info, frame, slot, iterator->UE->UE_beam_index, slots_per_frame, beam.new_beam);
|
||||
iterator++;
|
||||
continue;
|
||||
}
|
||||
// Refresh BWP bounds at response-apply time to catch RRC reconfigurations
|
||||
bwp_info_t cur_bwp_info = get_pdsch_bwp_start_size(mac, iterator->UE);
|
||||
if (cur_bwp_info.bwpSize > 0) {
|
||||
bwp_start = cur_bwp_info.bwpStart;
|
||||
bwp_size = cur_bwp_info.bwpSize;
|
||||
}
|
||||
// allocSol gives [prgStart, prgEndExclusive] in PRG units; -1 means no allocation
|
||||
if (cumac_slot_data->allocSol[cumac_ue_id * 2] < 0) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] cuMAC returned no PRB allocation, skipping\n", rnti, frame, slot);
|
||||
reset_beam_status(&mac->beam_info, frame, slot, iterator->UE->UE_beam_index, slots_per_frame, beam.new_beam);
|
||||
iterator++;
|
||||
continue;
|
||||
}
|
||||
const int prb_per_prg = cumac_nPrbPerPrg();
|
||||
// allocSol gives carrier-absolute PRG indices. The 4T4R scheduler ignores prgMsk
|
||||
// during allocation and always returns [0, nPrbGrp); clip to the UE's current BWP.
|
||||
const int alloc_abs_start = cumac_slot_data->allocSol[cumac_ue_id * 2] * prb_per_prg;
|
||||
const int alloc_abs_end = cumac_slot_data->allocSol[cumac_ue_id * 2 + 1] * prb_per_prg;
|
||||
const int clipped_abs_start = alloc_abs_start > bwp_start ? alloc_abs_start : bwp_start;
|
||||
const int clipped_abs_end = alloc_abs_end < bwp_start + bwp_size ? alloc_abs_end : bwp_start + bwp_size;
|
||||
if (clipped_abs_end <= clipped_abs_start) {
|
||||
LOG_W(NR_MAC,
|
||||
"[UE %04x][%4d.%2d] cuMAC allocation [%d,%d) PRBs has no overlap with BWP [%d,%d), skipping\n",
|
||||
rnti,
|
||||
frame,
|
||||
slot,
|
||||
alloc_abs_start,
|
||||
alloc_abs_end,
|
||||
bwp_start,
|
||||
bwp_start + bwp_size);
|
||||
reset_beam_status(&mac->beam_info, frame, slot, iterator->UE->UE_beam_index, slots_per_frame, beam.new_beam);
|
||||
iterator++;
|
||||
continue;
|
||||
}
|
||||
rbStart = clipped_abs_start - bwp_start;
|
||||
uint16_t max_rbSize = clipped_abs_end - clipped_abs_start;
|
||||
#endif
|
||||
int CCEIndex = get_cce_index(mac,
|
||||
CC_id,
|
||||
slot,
|
||||
@@ -838,12 +1099,23 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
fill_pdcch_vrb_map(mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam.idx);
|
||||
|
||||
int l = get_dl_nrOfLayers(sched_ctrl, dl_bwp->dci_format);
|
||||
int mcs = iterator->selected_mcs;
|
||||
#ifdef ENABLE_CUMAC
|
||||
if (cumac_ue_id >= 0 && cumac_slot_data != NULL) {
|
||||
if ((cumac_slot_data->taskBitMask & TASK_BIT(CUMAC_TASK_MCS_SELECTION))
|
||||
&& cumac_slot_data->mcsSelSol != NULL)
|
||||
mcs = cumac_slot_data->mcsSelSol[cumac_ue_id];
|
||||
if ((cumac_slot_data->taskBitMask & TASK_BIT(CUMAC_TASK_LAYER_SELECTION))
|
||||
&& cumac_slot_data->layerSelSol != NULL)
|
||||
l = cumac_slot_data->layerSelSol[cumac_ue_id];
|
||||
}
|
||||
#endif
|
||||
NR_sched_pdsch_t sched_pdsch = {
|
||||
// rbSize below
|
||||
.rbStart = rbStart,
|
||||
.mcs = iterator->selected_mcs,
|
||||
.R = nr_get_code_rate_dl(iterator->selected_mcs, dl_bwp->mcsTableIdx),
|
||||
.Qm = nr_get_Qm_dl(iterator->selected_mcs, dl_bwp->mcsTableIdx),
|
||||
.mcs = mcs,
|
||||
.R = nr_get_code_rate_dl(mcs, dl_bwp->mcsTableIdx),
|
||||
.Qm = nr_get_Qm_dl(mcs, dl_bwp->mcsTableIdx),
|
||||
// tb_size below
|
||||
.dl_harq_pid = sched_ctrl->available_dl_harq.head,
|
||||
.pucch_allocation = alloc,
|
||||
@@ -880,6 +1152,17 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
|
||||
post_process_dlsch(mac, pp_pdsch, iterator->UE, &sched_pdsch);
|
||||
|
||||
#ifdef ENABLE_CUMAC
|
||||
// Store the scheduled solutions back into per-UE state for the next TTI's request
|
||||
if (cumac_ue_id >= 0 && cumac_slot_data != NULL) {
|
||||
iterator->UE->cumac_last_sol.has_prev_sol = true;
|
||||
iterator->UE->cumac_last_sol.alloc_sol[0] = (int16_t)sched_pdsch.rbStart;
|
||||
iterator->UE->cumac_last_sol.alloc_sol[1] = (int16_t)sched_pdsch.rbSize;
|
||||
iterator->UE->cumac_last_sol.mcs_sol = (int16_t)sched_pdsch.mcs;
|
||||
iterator->UE->cumac_last_sol.layer_sol = (int8_t)sched_pdsch.nrOfLayers;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* transmissions: directly allocate */
|
||||
n_rb_sched[beam.idx] -= sched_pdsch.rbSize;
|
||||
|
||||
@@ -889,6 +1172,10 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
remainUEs[beam.idx]--;
|
||||
iterator++;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CUMAC
|
||||
cumac_allow_send();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void nr_dlsch_preprocessor(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch)
|
||||
|
||||
@@ -242,6 +242,15 @@ static const int SINRx10_MCS_mapping[29] = {
|
||||
162, 170, 178, 186, 194, 202, 212, 220, 245 // 20..28
|
||||
};
|
||||
|
||||
int get_SINRx10_for_mcs(int mcs)
|
||||
{
|
||||
if (mcs < 0)
|
||||
mcs = 0;
|
||||
if (mcs > 28)
|
||||
mcs = 28;
|
||||
return SINRx10_MCS_mapping[mcs];
|
||||
}
|
||||
|
||||
int get_mcs_from_SINRx10(int mcs_table, int SINRx10, int Nl)
|
||||
{
|
||||
if (mcs_table != 0) {
|
||||
|
||||
44
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/CMakeLists.txt
Normal file
44
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/CMakeLists.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
if (OAI_AERIAL_CUMAC)
|
||||
message(STATUS "Building with support for Aerial cuMAC")
|
||||
add_library(aerial_cumac_lib
|
||||
cumac_msg.c
|
||||
cumac_msg_funcs.c
|
||||
cumac_nvipc.c
|
||||
)
|
||||
|
||||
find_library(NVIPC_LIB nvipc REQUIRED)
|
||||
if (NOT NVIPC_LIB)
|
||||
message(FATAL_ERROR "-- nvipc library not found")
|
||||
else ()
|
||||
message(STATUS " nvipc library found in ${NVIPC_LIB}")
|
||||
endif ()
|
||||
|
||||
find_library(NVLOG_LIB nvlog REQUIRED)
|
||||
if (NOT NVLOG_LIB)
|
||||
message(FATAL_ERROR "-- nvlog library not found")
|
||||
else ()
|
||||
message(STATUS " nvlog library found in ${NVLOG_LIB}")
|
||||
endif ()
|
||||
#target_compile_definitions(aerial_cumac_lib PUBLIC ENABLE_L2_SLT_RSP)
|
||||
target_link_libraries(aerial_cumac_lib PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
#target_link_libraries(aerial_cumac_lib PRIVATE nr_fapi_p5 nr_fapi_p7)
|
||||
target_link_libraries(aerial_cumac_lib PRIVATE "${NVLOG_LIB}" "${NVIPC_LIB}")
|
||||
find_package(CUDA REQUIRED)
|
||||
target_link_libraries(aerial_cumac_lib PUBLIC cudart)
|
||||
|
||||
#add_executable(cumac_test
|
||||
# cumac_test.c
|
||||
# cumac_msg_funcs.c
|
||||
# cumac_msg.c)
|
||||
#target_link_libraries(cumac_test PRIVATE "${NVLOG_LIB}" "${NVIPC_LIB}")
|
||||
##target_link_libraries(cumac_test PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
#target_link_libraries(cumac_test PRIVATE nr_fapi_p5 nr_fapi_p7)
|
||||
#target_link_libraries(cumac_test PRIVATE utils pthread UTIL ${T_LIB} minimal_lib )
|
||||
##flag for nvIPC
|
||||
#target_compile_definitions(cumac_test PUBLIC ENABLE_L2_SLT_RSP)
|
||||
## This makes it so cumac_test is always compiled whenever nr-softmodem is compiled
|
||||
#add_dependencies(nr-softmodem cumac_test )
|
||||
|
||||
else ()
|
||||
message(STATUS "No Support for Aerial cuMAC")
|
||||
endif ()
|
||||
893
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/api.h
Normal file
893
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/api.h
Normal file
@@ -0,0 +1,893 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cuda_fp16.h"
|
||||
#include "cuda.h"
|
||||
#include <cuda_runtime.h>
|
||||
#include <cuComplex.h>
|
||||
#include "cuda_bf16.h"
|
||||
|
||||
// cuMAC namespace
|
||||
namespace cumac {
|
||||
// defined constants
|
||||
constexpr uint16_t maxNumCoorCells_ = 20;
|
||||
constexpr uint16_t maxNumActUePerCell_ = 1024; // must be power of 2, max 1024
|
||||
constexpr uint16_t maxNumUegPerCell_ = 128; // must be power of 2, max 128
|
||||
constexpr uint16_t maxNumSchdUePerCellTTI_ = 16;
|
||||
constexpr uint16_t maxNumUeSchdPerCell_ = 16;
|
||||
constexpr uint16_t maxNumLayerPerGrpDL_ = 16;
|
||||
constexpr uint16_t maxNumLayerPerGrpUL_ = 8;
|
||||
constexpr uint16_t totNumPuschDmrsPort_ = 8;
|
||||
constexpr uint16_t totNumPdschDmrsPort_ = 8;
|
||||
constexpr uint16_t maxNumBsAnt_ = 64;
|
||||
constexpr uint16_t maxNumUeAnt_ = 4;
|
||||
constexpr uint16_t maxNumPrgPerCell_ = 273;
|
||||
constexpr uint16_t maxNumUeForGrpPerCell_ = 128; // must be power of 2, max 128
|
||||
constexpr uint16_t maxNumUeGrpSchdPerCell_ = 16;
|
||||
constexpr uint16_t maxNumLayerPerUe_ = 4;
|
||||
constexpr uint16_t minPow2MaxNumUeGrpPercell_ = 16; // smallest power of 2 >= MaxNumUeGrpSchdPerCell_
|
||||
|
||||
// multi-cell MU-MIMO UE grouping list
|
||||
struct multiCellMuGrpList {
|
||||
uint16_t* numUeInGrp = nullptr;
|
||||
// array of number of UEs in each UEG in the coordinated cell group
|
||||
// format: one dimensional array. array size: maxNumCoorCells_*maxNumUegPerCell_
|
||||
// denote cIdx = 0, 1, ... maxNumCoorCells_-1 as the coordinated cell index
|
||||
// denote uegIdx = 0, 1, ... maxNumUegPerCell_-1 as the UEG index
|
||||
// numUeInGrp[cIdx*maxNumUegPerCell_ + uegIdx] is the number of UEs in the uegIdx-th UEG in the cIdx-th coordinated cell
|
||||
|
||||
uint16_t* ueId = nullptr;
|
||||
// array of UE IDs for each UEG in the coordinated cell group
|
||||
// format: one dimensional array. array size: maxNumCoorCells_*maxNumUegPerCell_*maxNumLayerPerGrpDL_
|
||||
// denote cIdx = 0, 1, ... nCell-1 as the coordinated cell index
|
||||
// denote uegIdx = 0, 1, ... maxNumUegPerCell_-1 as the UEG index
|
||||
// denote uIdx = 0, 1, ... maxNumLayerPerGrpDL_-1 as the UE index
|
||||
// ueId[cIdx*maxNumUegPerCell_*maxNumLayerPerGrpDL_ + uegIdx*maxNumLayerPerGrpDL_ + uIdx] is the uIdx-th UE's active UE ID in the uegIdx-th UEG in the cIdx-th coordinated cell
|
||||
// 0xFFFF indicates an invalid element
|
||||
|
||||
int16_t* subbandId = nullptr;
|
||||
// array of subband IDs for each UEG in the coordinated cell group
|
||||
// format: one dimensional array. array size: maxNumCoorCells_*maxNumUegPerCell_
|
||||
// denote cIdx = 0, 1, ... maxNumCoorCells_-1 as the coordinated cell index
|
||||
// denote uegIdx = 0, 1, ... maxNumUegPerCell_-1 as the UEG index
|
||||
// subbandId[cIdx*maxNumUegPerCell_ + uegIdx] is the subband ID for the uegIdx-th UEG in the cIdx-th coordinated cell
|
||||
// -1 indicates no subband allocation for a UEG
|
||||
};
|
||||
|
||||
// cuMAC API data structures ////////////////////////////////////////////////////
|
||||
struct cumacCellGrpUeStatus { // per-UE information
|
||||
//----------------- data buffers -----------------
|
||||
uint32_t* lastSchdSlotActUe = nullptr;
|
||||
//* (For both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// last scheduled slot index for each active UE in the coordinated cells
|
||||
// format: one dimensional array, array size = nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the active UE index in the coordinated cells
|
||||
// lastSchdSlotActUe[uIdx] is the last scheduled slot index for the uIdx-th active UE in the coordinated cells
|
||||
// range of each element: [0, 0xFFFFFFFE]
|
||||
// 0xFFFFFFFF indicates a UE has not been scheduled yet
|
||||
// ** should be maintained throughout the session where cuMAC modules are being used
|
||||
|
||||
float* ueTxPow = nullptr;
|
||||
// array of each active UE’s total uplink transmit power (Watt) across all transmit antennas in the coordinated cell group.
|
||||
// format: one dimensional array. array size: nActiveUe
|
||||
// denote uIdx = 0, 1, …, nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// ueTxPow[uIdx] is the uIdx-th active UE’s total transmit power in Watt.
|
||||
|
||||
float* noiseVarActUe = nullptr;
|
||||
// array of each active UE’s per-Rx-antenna noise variance (Watt) in the coordinated cell group.
|
||||
// format: one dimensional array. array size: nActiveUe
|
||||
// denote uIdx = 0, 1, …, nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// noiseVarActUe[uIdx] is the uIdx-th active UE’s per-Rx-antenna noise variance in Watt.
|
||||
|
||||
float* avgRates = nullptr;
|
||||
//* (For 4TR SU-MIMO only)
|
||||
// per-UE long-term average data rates of the selected UEs per TTI in the coordinated cells
|
||||
// format: one dimensional array, array size = nUe
|
||||
// denote uIdx = 0, 1, ..., nUe-1 as the selected UE index in the coordinated cells
|
||||
// avgRates[uIdx] is the uIdx-th selected UE's long-term average data rate
|
||||
|
||||
float* avgRatesActUe = nullptr;
|
||||
//* (For both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// per-UE long-term average data rates of all active UEs in the coordinated cells
|
||||
// ** should be maintained throughout the session where cuMAC modules are being used
|
||||
// format: one dimensional array, array size = nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// avgRatesActUe[uIdx] is the uIdx-th active UE's long-term average data rate
|
||||
|
||||
int8_t* cqiActUe = nullptr;
|
||||
// array of the most recent reported CQI levels of all active UEs in the coordinated cells
|
||||
// format: one dimensional array, array size = nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// cqiActUe[uIdx] is the uIdx-th active UE's most recent reported CQI level
|
||||
// -1 indicates an invalid element
|
||||
// ! If no memory is allocated for this buffer, the SRS-based MCS selection is used. Otherwise the CQI-based MCS selection is used.
|
||||
|
||||
int8_t* riActUe = nullptr;
|
||||
// array of the most recent reported RI values of all active UEs in the coordinated cells
|
||||
// format: one dimensional array, array size = nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// riActUe[uIdx] is the uIdx-th active UE's most recent reported RI value
|
||||
// ** For each active UE uIdx, riActUe[uIdx] should be initialized to 1
|
||||
// -1 indicates an invalid element
|
||||
// ! If no memory is allocated for this buffer, the SRS-based layer selection is used. Otherwise the RI-based layer selection is used.
|
||||
|
||||
int8_t* pmiActUe = nullptr;
|
||||
// array of the most recent reported PMI values of all active UEs in the coordinated cells
|
||||
// format: one dimensional array, array size = nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// pmiActUe[uIdx] is the uIdx-th active UE's most recent reported PMI value
|
||||
// -1 indicates an invalid element
|
||||
// ! assuming that for each active UE uIdx, cqiActUe[uIdx], riActUe[uIdx] and pmiActUe[uIdx] are all from the UE's most recent CSI report
|
||||
|
||||
uint16_t* prioWeightActUe = nullptr;
|
||||
//* (For 4TR SU-MIMO only)
|
||||
// Priority weights of all active UEs in the coordinated cells
|
||||
// For priority-based UE selection
|
||||
// ** used/accessed by both the priority-based Round Robin UE selection and Round Robin PRG allocation modules
|
||||
// ** should be maintained throughout the session where cuMAC modules are being used
|
||||
// format: one dimensional array, array size = nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// prioWeightActUe[uIdx] is the uIdx-th active UE's priority weight
|
||||
// ** For each active UE uIdx, prioWeightActUe[uIdx] should be initialized to 0
|
||||
// 0xFFFF indicates an invalid element
|
||||
|
||||
uint32_t* bufferSize = nullptr;
|
||||
//* (For both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// per-UE buffer depth in bytes of UEs
|
||||
// format: one dimensional array, array size = nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the selected UE index in the coordinated cells
|
||||
// bufferSize[uIdx] is the buffer depth in bytes of the uIdx-th active UE
|
||||
|
||||
int8_t* tbErrLastActUe = nullptr;
|
||||
//* (For both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// TB decoding error indicators of all active UEs in the coordinated cells.
|
||||
// ** should be maintained throughout the session where cuMAC modules are being used
|
||||
// format: one dimensional array. Array size: nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// tbErrLastActUe[uIdx] is the uIdx-th active UE's TB decoding error indicator:
|
||||
// -1 - the last transmission is not a new transmission (is a re-transmission)
|
||||
// 0 – CRC pass
|
||||
// 1 – CRC failure
|
||||
// *Note that if the last transmission of a UE is not a new transmission, tbErrLastActUe of that UE should be set to -1.
|
||||
|
||||
int8_t* tbErrLast = nullptr;
|
||||
// TB decoding error indicators of the selected UEs's last transmission
|
||||
//* (for 4TR SU-MIMO)
|
||||
// format: one dimensional array, array size = nUe
|
||||
// denote uIdx = 0, 1, ..., nUe-1 as the selected UE index in the coordinated cells
|
||||
// tbErrLast[uIdx] is the uIdx-th selected UE's TB decoding error indicator
|
||||
//* (For 64TR MU-MIMO)
|
||||
// format: one dimensional array, array size = nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// tbErrLast[uIdx] is the uIdx-th active UE's TB decoding error indicator:
|
||||
// -1 - the last transmission is not a new transmission (is a re-transmission)
|
||||
// 0 – CRC pass
|
||||
// 1 – CRC failure
|
||||
// *Note that if the last transmission of a UE is not a new transmission, tbErrLast of that UE should be set to -1.
|
||||
|
||||
//----------------- HARQ related parameter fields -----------------
|
||||
// HARQ-based scheduling currently only supported for type-1 PRG allocation
|
||||
int8_t* newDataActUe = nullptr;
|
||||
//* (For both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// Indicators of initial transmission/retransmission for all active UEs
|
||||
// ** should be maintained throughout the session where cuMAC modules are being used
|
||||
// format: one dimensional array, array size = nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// newDataActUe[uIdx] is the indicator of initial transmission/retransmission for the uIdx-th active UE in the coordinated cells
|
||||
// 0 - retransmission, 1 - new data/initial transmission
|
||||
// -1 indicates an invalid element
|
||||
|
||||
int16_t* allocSolLastTx = nullptr;
|
||||
// The PRG allocation solution of the last transmission of the selected/scheduled UEs in the coordinated cells
|
||||
// Currently only support type-1 PRG allocation
|
||||
//* (For 4TR SU-MIMO)
|
||||
// format: one dimensional array, array size = 2*nUe
|
||||
// Two elements per selected UE, 1st element represents the starting PRG index and the 2nd element represents the ending PRG index plus one
|
||||
// -1 indicates that a given UE is not being allocated to any PRG
|
||||
// Using the UE ID mapping setSchdUePerCellTTI in the cumacSchdSol structure
|
||||
//* (For 64TR MU-MIMO)
|
||||
// format: one dimensional array. Array size: 2*nActiveUe
|
||||
// denote uIdx = 0, 1, …, nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// allocSolLastTx[2*uIdx] is the starting PRG index of the uIdx-th active UE’s last transmission.
|
||||
// allocSolLastTx[2*uIdx + 1] is the ending PRG index of the uIdx-th active UE’s last transmission plus one.
|
||||
// -1 indicates that a given UE is not being allocated to any PRG.
|
||||
|
||||
int16_t* mcsSelSolLastTx = nullptr;
|
||||
// MCS selection solution of the last transmission of the selected/scheduled UEs in the coordinated cells
|
||||
//* (For 4TR SU-MIMO)
|
||||
// format: one dimensional array, array size = nUe
|
||||
// denote uIdx = 0, 1, ..., nUe-1 as the 0-based UE index for the selected UEs in the coordinated cells
|
||||
// mcsSelSol[uIdx] indicates the MCS level for the uIdx-th selected UE in the coordinated cells.
|
||||
// Currently only support Table 5.1.3.1-2: MCS index table 2, 3GPP TS 38.214
|
||||
// Value of each element: 0, 1, ..., 27
|
||||
// -1 indicates an invalid element
|
||||
// Using the UE ID mapping setSchdUePerCellTTI in the cumacSchdSol structure
|
||||
//* (For 64TR MU-MIMO)
|
||||
// format: one dimensional array. Array size: nActiveUe
|
||||
// denote uIdx = 0, 1, …, nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// mcsSelSolLastTx[uIdx] is the MCS level of the uIdx-th active UE’s last transmission.
|
||||
// Range of each element:
|
||||
// 0, 1, …, 27 (Currently only support Table 5.1.3.1-2: MCS index table 2, 3GPP TS 38.214).
|
||||
// -1 indicates an element is invalid.
|
||||
|
||||
uint8_t* layerSelSolLastTx = nullptr;
|
||||
// layer selection solution of the last transmission of the selected/scheduled UEs in the coordinated cells
|
||||
//* (For 4TR SU-MIMO)
|
||||
// format: one dimensional array, array size = nUe
|
||||
// Each element represents the number of layers selected for a UE
|
||||
// Assumption's that the selected layers are the ones with the largest singular values
|
||||
// 0xFF indicates an invalid element
|
||||
// Using the UE ID mapping setSchdUePerCellTTI in the cumacSchdSol structure
|
||||
//* (For 64TR MU-MIMO)
|
||||
// format: one dimensional array. Array size: nActiveUe
|
||||
// denote uIdx = 0, 1, …, nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// layerSelSolLastTx[uIdx] is the number of layers of the uIdx-th active UE’s last transmission.
|
||||
// Range of each element: 0, 1, …, nUeAnt-1.
|
||||
// 0xFF (255) indicates an element is invalid.
|
||||
|
||||
float* beamformGainCurrTx = nullptr;
|
||||
//* (For 64TR MU-MIMO)
|
||||
// per-UE beamforming gains in dB of all active UEs' current scheduled transmissions in the coordinated cell group
|
||||
// format: one dimensional array, array size = nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// beamformGainCurrTx[uIdx] is the uIdx-th active UE's beamforming gain
|
||||
// Initialize beamformGainCurrTx to -100.0 dB for all UEs
|
||||
// -100.0 indicates an element is invalid
|
||||
|
||||
float* bfGainPrgCurrTx = nullptr;
|
||||
//* (For 64TR MU-MIMO)
|
||||
// per-UE and per-PRG beamforming gains in dB of all active UEs' current scheduled transmissions in the coordinated cell group
|
||||
// format: one dimensional array, array size = nActiveUe*nPrbGrp
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// denote prgIdx = 0, 1, ..., nPrbGrp-1 as the PRG index
|
||||
// bfGainPrgCurrTx[uIdx*nPrbGrp + prgIdx] is the uIdx-th active UE's beamforming gain for the prgIdx-th PRG in the current scheduled transmission
|
||||
// Initialize bfGainPrgCurrTx to -100.0 dB for all UEs and all PRGs
|
||||
// -100.0 indicates an element is invalid
|
||||
|
||||
float* beamformGainLastTx = nullptr;
|
||||
//* (For 64TR MU-MIMO)
|
||||
// per-UE beamforming gains in dB of all active UEs' last scheduled transmissions in the coordinated cell group
|
||||
// format: one dimensional array, array size = nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// beamformGainLastTx[uIdx] is the uIdx-th active UE's beamforming gain
|
||||
// Initialize beamformGainLastTx to -100.0 dB for all UEs
|
||||
// -100.0 indicates an element is invalid
|
||||
};
|
||||
|
||||
struct cumacCellGrpPrms { // coordinated cell group information
|
||||
//----------------- parameters -----------------
|
||||
uint8_t dlSchInd = 1;
|
||||
//* (For both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// DL/UL scheduling indicator
|
||||
// 0 - UL scheduling
|
||||
// 1 - DL scheduling
|
||||
// default is 1 for DL scheduling
|
||||
|
||||
uint8_t harqEnabledInd = 1;
|
||||
//* (For both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// HARQ enabled indicator
|
||||
// 0 - HARQ disabled
|
||||
// 1 - HARQ enabled
|
||||
// default is 1 for HARQ enabled
|
||||
|
||||
uint16_t nCell;
|
||||
//* (For both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// total number of cells in the coordinated cell group
|
||||
// range: [1, maxNumCoorCells_]
|
||||
|
||||
uint16_t nUe;
|
||||
//* (for 4TR SU-MIMO)
|
||||
// total number of selected/scheduled UEs for all coordinated cells per TTI
|
||||
// nUe = nCell*numUeSchdPerCellTTI
|
||||
// it is the upperbound for the number of selected/scheduled UEs for all coordinated cells when numUeSchdPerCellTTIArr is populated (not equal to nullptr)
|
||||
|
||||
uint16_t nActiveUe;
|
||||
//* (For both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// total number of active UEs in all coordinated cells
|
||||
// range: [0, maxNumCoorCells_*maxNumActUePerCell_]
|
||||
|
||||
uint8_t numUeSchdPerCellTTI = 16;
|
||||
//* (for 4TR SU-MIMO)
|
||||
// number of UEs selected/scheduled per TTI per cell when numUeSchdPerCellTTIArr is not populated (assigned to nullptr)
|
||||
// otherwise, it is the upperbound for the number of UEs that can be selected/scheduled per TTI per cell
|
||||
// current assumption's that 6 <= numUeSchdPerCellTTI <= 16. nUe = numUeSchdPerCellTTI*nCell
|
||||
//* (for 64TR MU-MIMO)
|
||||
// maximum total number of SU-MIMO and MU-MIMO UEs scheduled per TTI per cell
|
||||
// current assumption's that 6 <= numUeSchdPerCellTTI <= 16.
|
||||
|
||||
uint16_t numUeForGrpPerCell = 16;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// number of UEs considered for MU-MIMO UE grouping per cell
|
||||
|
||||
uint8_t nMaxLayerPerUeSuDl = 4;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// maximum number of layers per UE for SU-MIMO DL
|
||||
|
||||
uint8_t nMaxLayerPerUeSuUl = 4;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// maximum number of layers per UE for SU-MIMO UL
|
||||
|
||||
uint8_t nMaxLayerPerUeMuDl = 2;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// maximum number of layers per UE for MU-MIMO DL
|
||||
|
||||
uint8_t nMaxLayerPerUeMuUl = 2;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// maximum number of layers per UE for MU-MIMO UL
|
||||
|
||||
uint8_t nMaxUePerGrpUl = 8;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// maximum number of UEs per UEG for UL
|
||||
|
||||
uint8_t nMaxUePerGrpDl = 16;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// maximum number of UEs per UEG for DL
|
||||
|
||||
uint8_t nMaxLayerPerGrpUl = 8;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// maximum number of layers per UEG for UL
|
||||
|
||||
uint8_t nMaxLayerPerGrpDl = 16;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// maximum number of layers per UEG for DL
|
||||
|
||||
uint8_t nMaxUegPerCellDl = 4;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// maximum number of UEGs per cell for DL
|
||||
// range: [1, 16]
|
||||
|
||||
uint8_t nMaxUegPerCellUl = 4;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// maximum number of UEGs per cell for UL
|
||||
// range: [1, 16]
|
||||
|
||||
float muGrpSrsSnrMaxGap = 100.0;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// maximum gap among the SRS SNRs of UEs in the same MU-MIMO UEG
|
||||
// default is 6.0 dB.
|
||||
// set to a large value, e.g. 100.0 dB to disable the SRS SNR gap constraint for MU-MIMO UE grouping
|
||||
|
||||
float muGrpSrsSnrSplitThr = -100.0;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// Threshold to split the SRS SNR range for grouping UEs for MU-MIMO separately
|
||||
// default is 0 dB.
|
||||
// -100.0 indicates that the SRS SNR range is not split for MU-MIMO grouping.
|
||||
|
||||
uint8_t ueGrpMode = 0;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// UE grouping mode
|
||||
// 0 - dynamic UE grouping per TTI
|
||||
// 1 - flag-triggered UE grouping (controlled by the muUeGrpTrigger flag in cumacCellGrpPrms)
|
||||
// default is 0 for dynamic UE grouping per TTI
|
||||
|
||||
uint8_t muGrpUpdate = 0;
|
||||
//* (for 64TR MU-MIMO)
|
||||
// trigger for performing MU-MIMO UE grouping in the current TTI
|
||||
// 0 - not triggering UE grouping in the current TTI
|
||||
// 1 - triggering UE grouping in the current TTI
|
||||
// default is 0
|
||||
|
||||
uint8_t semiStatFreqAlloc = 0;
|
||||
//* (For 64TR MU-MIMO)
|
||||
// indication for whether or not to enable semi-static subband allocation for SU UEs/MU UEGs
|
||||
// 0 - disable semi-static subband allocation
|
||||
// 1 - enable semi-static subband allocation
|
||||
// default is 0 to disable semi-static subband allocation
|
||||
|
||||
uint8_t bfPowAllocScheme = 1;
|
||||
// power allocation scheme for beamforming weights computation
|
||||
// * currently only support Scheme 0 and 1
|
||||
// 0 - equal power allocation for RX side received per-layer beamforming gain
|
||||
// 1 - equal power allocation for TX side per-layer beamforming gain
|
||||
// 2 - water-filling power allocation for per-layer beamforming gain
|
||||
// 3 - water-filling power allocation for per-UE beamforming gain
|
||||
// default is 1
|
||||
|
||||
uint8_t mcsSelLutType = 0;
|
||||
//* (for both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// MCS selection look-up table type
|
||||
// 0 - LUT L1T1B024
|
||||
// 1 - LUT L1T1B050PRGS01_GTC25
|
||||
// default is 0
|
||||
// Currently only support Table 5.1.3.1-2: MCS index table 2, 3GPP TS 38.214
|
||||
|
||||
float mcsSelSinrCapThr = 25.99;
|
||||
//* (for both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// SINR capping threshold for MCS selection
|
||||
// default is the minimum required SINR for MCS 27, i.e. 25.99 dB. May add a margin to this default value for performance tuning.
|
||||
|
||||
uint8_t mcsSelCqi = 0;
|
||||
//* (for both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// whether to use wideband CQI or wideband SINR for MCS selection
|
||||
// 0 - use wideband SINR for MCS selection
|
||||
// 1 - use wideband CQI for MCS selection
|
||||
// default is 0 to use wideband SINR for MCS selection
|
||||
|
||||
uint16_t nMaxActUePerCell = maxNumActUePerCell_; // Maximum number of active UEs per cell. Default value is maxNumActUePerCell
|
||||
uint16_t nPrbGrp; // total number of PRGs
|
||||
uint8_t nBsAnt; // Each RU’s number of TX & RX antenna ports. Value: 4 or 64
|
||||
uint8_t nUeAnt; // Each active UE’s number of TX & RX antenna ports. Value: 2, 4. Assumption's that nUeAnt <= nBsAnt
|
||||
float W; // frequency bandwidth (Hz) of a PRG: 12 * SCS * # of PRBs per PRG
|
||||
float sigmaSqrd; // noise variance if channel is not normalized; 1/SNR if channel is normalized with transmit power
|
||||
float Pt_Rbg; // NA
|
||||
float Pt_rbgAnt; // NA
|
||||
uint8_t precodingScheme; // precoder type: 0 - no precoding, 1 - SVD precoding
|
||||
uint8_t receiverScheme; // receiver type: only support 1 - MMSE-IRC
|
||||
uint8_t allocType; // PRB allocation type: 0 - non-consecutive type 0 allocate, 1 - consecutive type 1 allocate
|
||||
float betaCoeff = 1.0; // coefficient for balancing cell-center and cell-edge UEs' performance in multi-cell scheduling. Default value is 1.0
|
||||
float sinValThr = 0.1; // (For 4TR SU-MIMO only) singular value threshold for layer selection, value is in (0, 1). Default value is 0.1
|
||||
float corrThr = 0.5; // channel vector correlation value threshold for layer selection, value is in (0, 1). Default value is 0.5
|
||||
uint16_t prioWeightStep = 100; // step size for UE priority weight increment per TTI if UE does not get scheduled. Default is 100
|
||||
float muCoeff = 1.5; // Coefficient for prioritizing UEs selected for MU-MIMO transmissions.
|
||||
float zfCoeff = 1e-16; // Scalar coefficient used for regularizing the zero-forcing beamformer.
|
||||
float srsSnrThr = -3.0; // Threshold on SRS reported SNR in dB for determining the feasibility of MU-MIMO transmission. Value: a real number in unit of dB. Default value is -3.0 (dB).
|
||||
float chanCorrThr = 0.7; // Threshold for the squared channel vector correlation value in UE grouping. Value: a real number between 0 and 1.0. Default: 0.1
|
||||
|
||||
//----------------- data buffers -----------------
|
||||
uint32_t* currSlotIdxPerCell = nullptr;
|
||||
//* (for both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// current slot index for each cell in the coordinated cell group
|
||||
// format: one dimensional array, array size = nCell
|
||||
// denote cIdx = 0, 1, ..., nCell-1 as the coordinated cell index
|
||||
// currSlotIdxPerCell[cIdx] is the current slot index for the cIdx-th cell
|
||||
// range of each element: [0, 0xFFFFFFFE]
|
||||
// 0xFFFFFFFF indicates an invalid element
|
||||
|
||||
uint16_t* cellId = nullptr;
|
||||
//* (for 4TR SU-MIMO)
|
||||
// coordinated cell indexes
|
||||
// format: one dimensional array for coordinated cell indexes (0, 1, ... nCell-1)
|
||||
// Currently only support coordinated cell indexes starting from 0
|
||||
|
||||
uint8_t* cellAssoc = nullptr;
|
||||
//* (for 4TR SU-MIMO)
|
||||
// cell-UE association profile for the selected UEs per TTI in the coordinated cells
|
||||
// format: one dimensional array, size: nCell*nUe
|
||||
// denote cIdx = 0, 1, ... nCell-1 as the coordinated cell index
|
||||
// denote uIdx = 0, 1, ..., nUe-1 as the selected UE index in the coordinated cells
|
||||
// cellAssoc[cIdx*nUe + uIdx] == 1 means the uIdx-th selected UE is associated with the cIdx-th coordinated cell, 0 otherwise
|
||||
// ** cellAssoc[cIdx*nUe + uIdx] should be set to 0 for all cIdx = 0, 1, ... nCell-1 if setSchdUePerCellTTI[uIdx] is 0xFFFF
|
||||
// ** using the global UE ID mapping setSchdUePerCellTTI in the cumacSchdSol structure
|
||||
|
||||
uint8_t* numUeSchdPerCellTTIArr = nullptr;
|
||||
//* (for 4TR SU-MIMO)
|
||||
// array of the numbers of UEs scheduled per TTI for each cell in the coordinated cell group
|
||||
// format: one dimensional array, size: nCell
|
||||
// denote cIdx = 0, 1, ... nCell-1 as the coordinated cell index
|
||||
// numUeSchdPerCellTTIArr[cIdx] is the number of UEs scheduled per TTI for the cIdx-th cell
|
||||
// assumption's that numUeSchdPerCellTTIArr[cIdx] <= numUeSchdPerCellTTI for all cIdx = 0, 1, ... nCell-1
|
||||
|
||||
uint8_t* cellAssocActUe = nullptr;
|
||||
// cell-UE association profile for all active UEs in the coordinated cells
|
||||
// format: one dimensional array, array size = nCell*nActiveUe
|
||||
// denote cIdx = 0, 1, ... nCell-1 as the coordinated cell index,
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// cellAssocActUe[cIdx*nActiveUe + uIdx] == 1 means the uIdx-th active UE is associated to cIdx-th coordinated cell, 0 otherwise
|
||||
|
||||
float* blerTargetActUe = nullptr;
|
||||
//* (for both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// array of BLER targets for all active UEs in the coordinated cells
|
||||
// format: one dimensional array, array size = nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// blerTargetActUe[uIdx] is the BLER target for the uIdx-th active UE
|
||||
// default value is 0.1
|
||||
|
||||
// floating type
|
||||
//* For 4TR SU-MIMO
|
||||
cuComplex* estH_fr = nullptr; // (FP32) estimated CFR channel coefficients per cell-UE link, per PRG, per Tx-Rx antenna pair for the selected UEs per TTI in the coordinated cells
|
||||
cuComplex* estH_fr_actUe = nullptr; // estimated CFR channel coefficients per cell-UE link, per PRG, per Tx-Rx antenna pair for all active UEs in the coordinated cells
|
||||
cuComplex* estH_fr_actUe_prd = nullptr;
|
||||
cuComplex* prdMat = nullptr;
|
||||
// DL precoding weights for all cells, per PRG, per pair of Tx antenna port and layer
|
||||
// format: one dimensional array, array size = nCell*nPrbGrp*nBsAnt*MaxNumLayerPerGrpDL_
|
||||
// denote cIdx = 0, 1, ..., nCell-1 as the coordinated cell index
|
||||
// denote prgIdx = 0, 1, ..., nPrbGrp-1 as the PRG index
|
||||
// denote antIdx = 0, 1, ..., nBsAnt-1 as the Tx antenna port index
|
||||
// denote layerIdx = 0, 1, ..., MaxNumLayerPerGrpDL_-1 as the layer index
|
||||
// prdMat[cIdx*nPrbGrp*nBsAnt*MaxNumLayerPerGrpDL_ + prgIdx*nBsAnt*MaxNumLayerPerGrpDL_ + antIdx*MaxNumLayerPerGrpDL_ + layerIdx] is the precoder weight from the layerIdx-th layer to the antIdx-th TX antenna port on the prgIdx-th PRG for the cIdx-th cell
|
||||
// un-used precoder weights entries are set to 0
|
||||
// prdMat is set to 0 for an un-allocated PRG in a cell
|
||||
|
||||
cuComplex* prdMat_actUe = nullptr; // precoder matrix coefficients per cell-UE link, per PRG, per symbol-Tx antenna pair for all active UEs in the coordinated cells
|
||||
cuComplex* detMat = nullptr; // detector matrix coefficients per cell-UE link, per PRG, per symbol-Tx antenna pair for the selected/scheduled UEs
|
||||
cuComplex* detMat_actUe = nullptr; // detector matrix coefficients per cell-UE link, per PRG, per symbol-Tx antenna pair for all active UEs in the coordinated cells
|
||||
|
||||
float* sinVal = nullptr; // singular values associated with each precoder matrix, per cell-UE link, per PRG, per layer (maximum number of layers is equal to the number of UE antennas) for the selected/scheduled UEs
|
||||
//* (For 4TR SU-MIMO)
|
||||
// Array of singular values of the PRG level SRS channel estimates for all active UEs in the coordinated cell group.
|
||||
// format: one-dimensional array, size: nActiveUe*nPrbGrp*nUeAnt
|
||||
// Per-UE, per-PRG, per-layer singular values obtained from the SVD of SRS channel matrices
|
||||
// For each active UE and on each PRG, the singular values are stored in descending order:
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the 0-based active UE index in the coordinated cells
|
||||
// denote prgIdx = 0, 1, ..., nPrbGrp-1 as the PRG index
|
||||
// denote layerIdx = 0, 1, ..., nUeAnt-1 as the layer index
|
||||
// sinVal[uIdx*nPrbGrp*nUeAnt + prgIdx*nUeAnt + layerIdx] is the UE uIdx's layerIdx-th largest singular value on PRG prgIdx
|
||||
|
||||
float* sinVal_actUe = nullptr; // singular values associated with each precoder matrix, per cell-UE link, per PRG, per layer (maximum number of layers is equal to the number of UE antennas) for all active UEs in the coordinated cells
|
||||
cuComplex** estH_fr_perUeBuffer = nullptr; // estimated CFR channel coefficients organized as per-UE buffers
|
||||
|
||||
// half-precision
|
||||
__nv_bfloat162* estH_fr_half = nullptr; // (FP16) estimated CFR channel coefficients per cell-UE link, per PRG, per Tx-Rx antenna pair for the selected UEs per TTI in the coordinated cells
|
||||
|
||||
float* postEqSinr = nullptr; // *** This SINR array will be used by multiple cuMAC modules throughput the simulation process. So it should be allocated at initialization phase and should not be allocated & freed per TTI
|
||||
//* (For 4TR SU-MIMO only)
|
||||
// per-PRG per-layer post-equalization SINRs for all active UEs in the coordinated cells
|
||||
// ** should be maintained throughout the session where cuMAC modules are being used
|
||||
// format: one dimensional array, array size = nActiveUe*nPrbGrp*nUeAnt
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// denote prgIdx = 0, 1, ..., nPrbGrp-1 as the PRG index
|
||||
// denote layerIdx = 0, 1, ..., nUeAnt-1 as the layer index
|
||||
// postEqSinr[uIdx*nPrbGrp*nUeAnt + prgIdx*nUeAnt + layerIdx] is the uIdx-th active UE's post-equalization SINR on the prgIdx-th PRG and the layerIdx-th layer
|
||||
|
||||
float* wbSinr = nullptr;
|
||||
//* (For both 4TR SU-MIMO and 64TR MU-MIMO)
|
||||
// per-layer wideband SINRs for all active UEs in the coordinated cell group
|
||||
// * wbSinr is used for the most recent wideband SINR values from either SU-MIMO or MU-MIMO transmissions
|
||||
// format: one dimensional array, array size = nActiveUe*nUeAnt
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the global UE index for all active UEs in the coordinated cells
|
||||
// denote layerIdx = 0, 1, ..., nUeAnt-1 as the layer index
|
||||
// wbSinr[uIdx*nUeAnt + layerIdx] is the uIdx-th active UE's wideband SINR on the layerIdx-th layer
|
||||
// if a single wideband SINR is available to each UE, set all elements with layerIdx > 0 to 0;
|
||||
// Initialize wbSinr to MCS 0's required SINR for all UEs
|
||||
|
||||
//----------------- HARQ related parameter fields -----------------
|
||||
// HARQ-based scheduling currently only supported for type-1 PRG allocation
|
||||
uint8_t** prgMsk = nullptr;
|
||||
//* (For 4TR SU-MIMO only)
|
||||
// Per-cell bit map for the availability of each PRG for allocation
|
||||
// format: two-dimensional array, size: nCell X nPrbGrp
|
||||
// 1st dimension for 0-based coordinated cell indexes (0, 1, ..., nCell-1)
|
||||
// 2nd dimension for the per-PRG indicators of availability for allocation
|
||||
// denote cIdx = 0, 1, ... nCell-1 as the coordinated cell index
|
||||
// denote prgIdx = 0, 1, ..., nPrbGrp-1 as the PRG index
|
||||
// prgMsk[cIdx][prgIdx] is the availability indicator for the prgIdx-th PRG in the cIdx-th coordinated cell
|
||||
// 0 - unavailable, 1 - available
|
||||
|
||||
//----------------- AODT specific data buffers -----------------
|
||||
cuComplex* prdMat_asim = nullptr;
|
||||
// Aerial Sim format SVD precoder array
|
||||
// SVD of DL/UL channel H = U*Sigma*V^H, precoder matrix is V matrix (right matrix of DL/UL channel H)
|
||||
// format: one-dimensional array, size: nUe*nPrbGrp*nBsAnt*nBsAnt (maximum size is used for mem allocate)
|
||||
// Per UE, per PRG, per data symbol-TX antenna pair SVD precoder matrix coefficients
|
||||
// denote uIdx = 0, 1, ..., nUe-1 as the 0-based UE index for the selected UEs in the coordinated cells
|
||||
// denote prgIdx = 0, 1, ..., nPrbGrp-1 as the PRG index
|
||||
// (for DL) denote antIdx = 0, 1, ..., nBsAnt-1 as the TX antenna port index
|
||||
// (for UL) denote antIdx = 0, 1, ..., nUeAnt-1 as the TX antenna port index
|
||||
// (for DL) denote symIdx = 0, 1, ..., nBsAnt-1 as the TX data symbol index
|
||||
// (for UL) denote symIdx = 0, 1, ..., nUeAnt-1 as the TX data symbol index
|
||||
// (for DL) prdMat_asim[uIdx*nPrbGrp*nBsAnt*nBsAnt + prgIdx*nBsAnt*nBsAnt + antIdx*nBsAnt + symIdx]
|
||||
// (for UL) prdMat_asim[uIdx*nPrbGrp*nUeAnt*nUeAnt + prgIdx*nUeAnt*nUeAnt + antIdx*nUeAnt + symIdx]
|
||||
// is the precoder weight of the uIdx-th selected UE on the prgIdx-th PRG and between the symIdx-th TX data symbol and the antIdx-th TX antenna port.
|
||||
// Using the UE ID mapping setSchdUePerCellTTI in the cumacSchdSol structure
|
||||
|
||||
cuComplex* detMat_asim = nullptr;
|
||||
// Aerial Sim format SVD detector array
|
||||
// SVD of DL/UL channel H = U*Sigma*V^H, detector matrix is U matrix (left matrix of DL/UL channel H)
|
||||
// (effective detector is U^H for DL and V^H for UL but the original U or V matrix is passed via detMat_asim)
|
||||
// format: one-dimensional array, size: nUe*nPrbGrp*nBsAnt*nBsAnt (maximum size is used for mem allocate)
|
||||
// Per UE, per PRG, per data symbol-RX antenna pair SVD detector matrix coefficients
|
||||
// denote uIdx = 0, 1, ..., nUe-1 as the 0-based UE index for the selected UEs in the coordinated cells
|
||||
// denote prgIdx = 0, 1, ..., nPrbGrp-1 as the PRG index
|
||||
// (for DL) denote symIdx = 0, 1, ..., nUeAnt-1 as the RX data symbol index
|
||||
// (for UL) denote symIdx = 0, 1, ..., nBsAnt-1 as the RX data symbol index
|
||||
// (for DL) denote antIdx = 0, 1, ..., nUeAnt-1 as the RX antenna port index
|
||||
// (for UL) denote antIdx = 0, 1, ..., nBsAnt-1 as the RX antenna port index
|
||||
// (for DL) detMat_asim[uIdx*nPrbGrp*nUeAnt*nUeAnt + prgIdx*nUeAnt*nUeAnt + symIdx*nUeAnt + antIdx]
|
||||
// (for UL) detMat_asim[uIdx*nPrbGrp*nBsAnt*nBsAnt + prgIdx*nBsAnt*nBsAnt + symIdx*nBsAnt + antIdx]
|
||||
// is the detector weight of the uIdx-th selected UE on the prgIdx-th PRG and between the symIdx-th RX data symbol and the antIdx-th RX antenna port.
|
||||
// Using the UE ID mapping setSchdUePerCellTTI in the cumacSchdSol structure
|
||||
|
||||
float* sinVal_asim = nullptr;
|
||||
// Aerial Sim format singular value array
|
||||
// format: one-dimensional array, size: nUe*nPrbGrp*nUeAnt
|
||||
// Per-UE, per-PRG, per-layer singular values obtained from SVD of CFR channel matrices
|
||||
// For each UE and on each PRG, the singular values are stored in descending order:
|
||||
// denote uIdx = 0, 1, ..., nUe-1 as the 0-based UE index for the selected UEs in the coordinated cells
|
||||
// denote prgIdx = 0, 1, ..., nPrbGrp-1 as the PRG index
|
||||
// denote layerIdx = 0, 1, ..., nUeAnt-1 as the layer index
|
||||
// sinVal_asim[uIdx*nPrbGrp*nUeAnt + prgIdx*nUeAnt + layerIdx] is the UE uIdx's layerIdx-th largest singular value on PRG prgIdx
|
||||
// Using the UE ID mapping setSchdUePerCellTTI in the cumacSchdSol structure
|
||||
|
||||
////////////////////////////////////////
|
||||
//* For 64TR MU-MIMO
|
||||
float* bsTxPow = nullptr;
|
||||
// array of each RU’s total downlink transmit power (Watt) across all transmit antennas in the coordinated cell group.
|
||||
// format: one dimensional array, array size = nCell
|
||||
// denote cIdx = 0, 1, …, nCell-1 as the coordinated cell index.
|
||||
// bsTxPow[cIdx] is the total transmit power of the cIdx-th cell’s RU.
|
||||
|
||||
cuComplex** srsEstChan = nullptr; // (FP32) estimated CFR channel coefficients per cell-UE link, per PRG, per Tx-Rx antenna pair for the selected UEs per TTI in the coordinated cells
|
||||
//* (For 64TR MU-MIMO only)
|
||||
// Per-cell array of the PRG level SRS channel estimates for the top-numUeForGrpPerCell UEs after UE sorting
|
||||
// UE indexing for each cell is based on the srsUeMap array defined below.
|
||||
// SRS channel estimates are stored as the downlink channels (from RU to UE).
|
||||
// UE transmit power for the SRS signal is excluded from the channel coefficient magnitude.
|
||||
// format: two-dimensional array: the 1st dimension is for cells, and the 2nd dimension is for UEs, PRGs, and UE/RU antenna ports.
|
||||
// array size: nCell X (nCell*numUeForGrpPerCell*nPrbGrp*nUeAnt*nBsAnt)
|
||||
// denote cIdx = 0, 1, …, nCell-1 as the coordinated cell index.
|
||||
// denote uIdx = 0, 1, …, nCell*numUeForGrpPerCell-1 as the UE index (local to the srsEstChan[cIdx] array).
|
||||
// denote prgIdx = 0, 1, …, nPrbGrp-1 as the PRG index.
|
||||
// denote ueAntIdx = 0, 1, …, nUeAnt as the UE antenna port index
|
||||
// denote bsAntIdx = 0, 1, …, nBsAnt-1 as the RU antenna port index
|
||||
// srsEstChan[cIdx][uIdx*nPrbGrp*nUeAnt*nBsAnt + prgIdx*nUeAnt*nBsAnt + ueAntIdx*nBsAnt + bsAntIdx] is the complex (downlink) channel coefficient between the cIdx-th cell and the UE with local ID uIdx on the prgIdx-th PRG, the ueAntIdx-th UE antenna port and the bsAntIdx-th RU antenna port.
|
||||
|
||||
int32_t** srsUeMap = nullptr;
|
||||
//* (For 64TR MU-MIMO only)
|
||||
// Per-cell UE index mapping array for the SRS channel estimates stored in srsEstChan.
|
||||
// format: two-dimensional array: the 1st dimension is for cells, and the 2nd dimension is for UEs.
|
||||
// array size: nCell X nActiveUe
|
||||
// denote cIdx = 0, 1, …, nCell-1 as the coordinated cell index.
|
||||
// denote uIdx = 0, 1, …, nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// srsUeMap[cIdx][uIdx] is the uIdx-th active UE’s index in the srsEstChan[cIdx] array.
|
||||
// srsUeMap[cIdx][uIdx] == -1 means that the uIdx-th active UE’s SRS channel estimates are not available in the srsEstChan[cIdx] array.
|
||||
// it is required that srsUeMap gets updated for the top numUeForGrpPerCell-th active UEs in each cell according to sortedUeList after the MU-MIMO UE sorting module.
|
||||
|
||||
float* srsWbSnr = nullptr;
|
||||
//* (For 64TR MU-MIMO only)
|
||||
// array of the reported wideband SNRs in dB measured within configured SRS bandwidth for all active UEs in the coordinated cell group.
|
||||
// format: one dimensional array. array size: nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the active UE index in the coordinated cell group.
|
||||
// srsWbSnr[uIdx] is the wideband SNR in dB measured within configured SRS bandwidth for the uIdx-th active UE in the coordinated cell group.
|
||||
// set srsWbSnr[uIdx] to -100.0 (dB) when the uIdx-th active UE's SRS measurements are not available or refreshed.
|
||||
};
|
||||
|
||||
struct cumacSchdSol { // scheduling solutions
|
||||
//----------------- data buffers -----------------
|
||||
multiCellMuGrpList* muGrpList = nullptr;
|
||||
//* (For 64TR MU-MIMO only)
|
||||
// multi-cell MU-MIMO UE grouping list
|
||||
// format: a single pointer to the multiCellMuGrpList structure
|
||||
|
||||
uint16_t* ueOrderInGrp = nullptr;
|
||||
//* (For 64TR MU-MIMO only)
|
||||
// The order of each active UE in its MU-MIMO group
|
||||
// format: one dimensional array. array size: nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// ueOrderInGrp[uIdx] is the order of the uIdx-th active UE in its MU-MIMO group
|
||||
// range of each element: 0, 1, ..., MaxNumLayerPerGrpDL_-1
|
||||
// initialized to 0xFFFF
|
||||
|
||||
int16_t* allocSol = nullptr;
|
||||
// PRB group allocation solution for the selected UEs per TTI in the coordinated cells
|
||||
//* (For 4TR SU-MIMO)
|
||||
// format: one dimensional array; array size and content differ for type-0 and type-1 allocations
|
||||
// For type-0: array size = nCell*nPrbGrp, each element represents the selected UE index (0, 1, ..., nUe-1) that a PRG is allocated to in a coordinated cell
|
||||
// -1 indicates that a give PRG is not allocated to any UE in a given cell
|
||||
// For type-1: array size = 2*nUe, two elements per selected UE, 1st element represents the starting PRG index and the 2nd element represents the ending PRG index plus one
|
||||
// -1 indicates that a given UE is not being allocated to any PRG
|
||||
// Using the UE ID mapping setSchdUePerCellTTI
|
||||
//* (For 64TR MU-MIMO)
|
||||
// Currently only support type-1 PRB allocation
|
||||
// format: one dimensional array. Array size: 2*nActiveUe
|
||||
// denote uIdx = 0, 1, …, nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// allocSol[2*uIdx] is the starting PRG index for the uIdx-th active UE.
|
||||
// allocSol[2*uIdx + 1] is the ending PRG index for the uIdx-th active UE plus one.
|
||||
// -1 indicates that a given UE is not being allocated to any PRG.
|
||||
|
||||
float* pfMetricArr = nullptr;
|
||||
//* (for 4TR SU-MIMO)
|
||||
// only applicable to type-1 PRB allocation, for storing computed PF metrices
|
||||
// array size = nCell * the minimum power of 2 that is no less than nPrbGrp*numUeSchdPerCellTTI
|
||||
// memory should be pre-allocated at initialization of cuMAC API
|
||||
|
||||
uint16_t* pfIdArr = nullptr;
|
||||
//* (for 4TR SU-MIMO)
|
||||
// only applicable to type-1 PRB allocation, for storing indices (indicating PRB and UE indecies) of computed PF metrices
|
||||
// array size = nCell * the minimum power of 2 that is no less than nPrbGrp*numUeSchdPerCellTTI
|
||||
// memory should be pre-allocated at initialization of cuMAC API
|
||||
|
||||
int16_t* mcsSelSol = nullptr;
|
||||
// MCS selection solution for the selected UEs per TTI in the coordinated cells
|
||||
//* (For 4TR SU-MIMO)
|
||||
// format: one dimensional array, array size = nUe
|
||||
// denote uIdx = 0, 1, ..., nUe-1 as the 0-based UE index for the selected UEs in the coordinated cells
|
||||
// mcsSelSol[uIdx] indicates the MCS level for the uIdx-th selected UE in the coordinated cells.
|
||||
// Currently only support Table 5.1.3.1-2: MCS index table 2, 3GPP TS 38.214
|
||||
// Value of each element: 0, 1, ..., 27
|
||||
// -1 indicates an invalid element
|
||||
// Using the UE ID mapping setSchdUePerCellTTI
|
||||
//* (For 64TR MU-MIMO)
|
||||
// format: one dimensional array. Array size: nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// mcsSelSol[uIdx] indicates the MCS level for the uIdx-th active UE in the coordinated cells.
|
||||
// Range of each element:
|
||||
// 0, 1, …, 27 (Currently only support Table 5.1.3.1-2: MCS index table 2, 3GPP TS 38.214).
|
||||
// -1 indicates an element is invalid.
|
||||
|
||||
uint16_t* setSchdUePerCellTTI = nullptr;
|
||||
// set of global IDs of the scheduled UEs per cell per TTI
|
||||
//* (for 4TR SU-MIMO)
|
||||
// format: one dimensional array, array size = nCell*numUeSchdPerCellTTI
|
||||
// denote cIdx = 0, 1, ... nCell-1 as the coordinated cell index,
|
||||
// denote i = 0, 1, ..., numUeSchdPerCellTTI-1 as the i-th scheduled UE in a cell
|
||||
// setSchdUePerCellTTI[cIdx*numUeSchdPerCellTTI + i] is within {0, 1, ..., nActiveUe-1} and is the active UE ID of the i-th scheduled UE in the cIdx-th cell.
|
||||
// 0xFFFF (65535) indicates an element is invalid (no scheduled UE).
|
||||
//* (for 64TR MU-MIMO)
|
||||
// format: one dimensional array, array size = nCell*numUeForGrpPerCell
|
||||
// denote cIdx = 0, 1, ... nCell-1 as the coordinated cell index,
|
||||
// denote i = 0, 1, ..., numUeForGrpPerCell-1 as the i-th scheduled UE in a cell
|
||||
// setSchdUePerCellTTI[cIdx*numUeForGrpPerCell + i] is within {0, 1, ..., nActiveUe-1} and is the active UE ID of the i-th scheduled UE in the cIdx-th cell.
|
||||
// 0xFFFF (65535) indicates an element is invalid (no scheduled UE).
|
||||
|
||||
uint8_t* layerSelSol = nullptr;
|
||||
// layer selection solution for the selected UEs per TTI in the coordinated cells
|
||||
//* (For 4TR SU-MIMO)
|
||||
// format: one dimensional array, array size = nUe
|
||||
// Each element represents the number of layers selected for a UE
|
||||
// Assumption's that the selected layers are the ones with the largest singular values
|
||||
// 0xFF indicates an invalid element
|
||||
// Using the UE ID mapping setSchdUePerCellTTI
|
||||
//* (For 64TR MU-MIMO)
|
||||
// layer selection solution for each active UE in the coordinated cells.
|
||||
// format: one dimensional array. Array size: nActiveUe
|
||||
// denote uIdx = 0, 1, …, nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// layerSelSol[uIdx] is the number of layers selected for the uIdx-th active UE.
|
||||
// Range of each element: 0, 1, …, nUeAnt-1.
|
||||
// 0xFF (255) indicates an element is invalid (the corresponding active is not being scheduled for transmission).
|
||||
// *The selected layers are always corresponding to the UE TX/RX antenna ports starting from port 0. Note that for downlink transmissions, the UE side may use more RX antennas to improve receiver performance.
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
//* For 64TR MU-MIMO
|
||||
uint8_t* muMimoInd = nullptr;
|
||||
//* (For 64TR MU-MIMO only)
|
||||
// indicators of MU-MIMO transmission feasibility for all active UEs in the coordinated cell group.
|
||||
// format: one dimensional array. array size: nActiveUe
|
||||
// denote uIdx = 0, 1, ..., nActiveUe-1 as the active UE index in the coordinated cell group.
|
||||
// muMimoInd[uIdx] is the indicator of MU-MIMO transmission feasibility for the uIdx-th active UE in the coordinated cell group.
|
||||
// muMimoInd[uIdx] == 1 means that UE uIdx is feasible for MU-MIMO.
|
||||
// muMimoInd[uIdx] == 0 means that UE uIdx is not feasible for MU-MIMO (only feasible for SU-MIMO).
|
||||
|
||||
uint16_t** sortedUeList = nullptr;
|
||||
//* (For 64TR MU-MIMO only)
|
||||
// array of sorted UE list for each cell.
|
||||
// two-dimensional array. array size: nCell X nMaxActUePerCell
|
||||
// denote cIdx = 0, 1, …, nCell-1 as the coordinated cell index.
|
||||
// denote uIdx = 0, 1, …, nMaxActUePerCell-1 as the UE rank in each cell.
|
||||
// sortedUeList[cIdx][uIdx] is the active UE index of the uIdx-th ranked UE in the cIdx-th cell.
|
||||
// 0xFFFF (65535) indicates an element is invalid.
|
||||
|
||||
uint8_t* nSCID = nullptr;
|
||||
//* (For 64TR MU-MIMO only)
|
||||
// array of the DMRS sequence initialization parameter n_SCID assigned for each active UE in the coordinated cells.
|
||||
// format: one dimensional array. Array size = nActiveUe
|
||||
// denote uIdx = 0, 1, …, nActiveUe-1 as the active UE index in the coordinated cells.
|
||||
// nSCID[uIdx] is the uIdx-th active UE’s assigned n_SCID value
|
||||
// Range of each element: 0 -> 1
|
||||
// 0xFF (255) indicates an element is invalid.
|
||||
};
|
||||
|
||||
// Outer-loop link adaptation (OLLA) data structure
|
||||
struct ollaParam {
|
||||
float delta_ini;
|
||||
float delta;
|
||||
float delta_up;
|
||||
float delta_down;
|
||||
};
|
||||
|
||||
// Aerial Scheduler Acceleration API data structures ////////////////////////////////////////////////////
|
||||
struct MAC_SCH_CONFIG_REQUEST { // static scheduler configuration parameters, passed from L2 stack host to cuMAC-CP at the initialization phase (one-time pass)
|
||||
uint8_t harqEnabledInd; // Indicator for whether HARQ is enabled
|
||||
uint8_t mcsSelCqi; // Indicator for whether MCS selection is based on CQI or SINR
|
||||
uint8_t nMaxCell; // A constant integer for the maximum number of cells in the cell group
|
||||
uint16_t nMaxActUePerCell; // A constant integer for the maximum number of active UEs per cell
|
||||
uint8_t nMaxSchUePerCell; // A constant integer for the maximum number of UEs that can be scheduled per TTI per cell
|
||||
uint16_t nMaxPrg; // A constant integer for the maximum number of PRGs for allocation in each cell
|
||||
uint8_t nPrbPerPrg; // A constant integer for the number of PRBs per PRG (PRB group)
|
||||
uint8_t nMaxBsAnt; // A constant integer for the maximum number of BS antenna ports.
|
||||
uint8_t nMaxUeAnt; // A constant integer for the maximum number of UE antenna ports.
|
||||
uint32_t scSpacing; // Subcarrier spacing of the carrier. Value: 15000, 30000, 60000, 120000 (Hz)
|
||||
uint8_t allocType; // Indicator for type-0 or type-1 PRG allocation
|
||||
uint8_t precoderType; // Indicator for the precoder type
|
||||
uint8_t receiverType; // Indicator for the receiver type
|
||||
uint8_t colMajChanAccess; // Indicator for whether the estimated narrow-band SRS channel matrices are stored in column-major order or in row-major order
|
||||
float betaCoeff; // Coefficient for adjusting the cell-edge UEs' performance in multi-cell scheduling
|
||||
float sinValThr; // Singular value threshold for layer selection
|
||||
float corrThr; // Channel vector correlation value threshold for layer selection
|
||||
float mcsSelSinrCapThr; // SINR capping threshold for MCS selection
|
||||
uint8_t mcsSelLutType; // MCS selection LUT type
|
||||
uint16_t prioWeightStep; // Step size for UE priority weight increment per TTI if UE does not get scheduled. For priority-based UE selection
|
||||
float* blerTargetActUe = nullptr; // BLER targets of all active UEs in the cell
|
||||
};
|
||||
|
||||
struct MAC_SCH_TTI_REQUEST {
|
||||
uint16_t cellID; // cell ID
|
||||
uint8_t ULDLSch = 1; // Indication for UL/DL scheduling. Value - 0: UL scheduling, 1: DL scheduling
|
||||
uint16_t nActiveUe; // total number of active UEs in the cell
|
||||
uint16_t nSrsUe; // the number of UEs in the cell that have refreshed SRS channel estimates
|
||||
uint16_t nPrbGrp; // the number of PRGs that can be allocated for the current TTI, excluding the PRGs that need to be reserved for HARQ re-tx's
|
||||
uint8_t nBsAnt; // number of BS antenna ports
|
||||
uint8_t nUeAnt; // number of UE antenna ports
|
||||
float sigmaSqrd = 1.0; // noise variance
|
||||
|
||||
// data buffer pointers
|
||||
uint16_t* CRNTI = nullptr; // C-RNTIs of all active UEs in the cell
|
||||
uint16_t* srsCRNTI = nullptr; // C-RNTIs of the UEs that have refreshed SRS channel estimates in the cell.
|
||||
uint8_t* prgMsk = nullptr; // Bit map for the availability of each PRG for allocation
|
||||
float* postEqSinr = nullptr; // array of the per-PRG per-layer post-equalizer SINRs of all active UEs in the cell
|
||||
float* wbSinr = nullptr; // array of wideband per-layer post-equalizer SINRs of all active UEs in the cell
|
||||
cuComplex* estH_fr = nullptr; // For FP32. array of the subband (per-PRG) SRS channel estimate coefficients for all active UEs in the cell
|
||||
cuComplex* estH_fr_half = nullptr; // For FP16. array of the subband (per-PRG) SRS channel estimate coefficients for all active UEs in the cell
|
||||
cuComplex* prdMat = nullptr; // array of the precoder/beamforming weights for all active UEs in the cell
|
||||
cuComplex* detMat = nullptr; // array of the detector/beamforming weights for all active UEs in the cell
|
||||
float* sinVal = nullptr; // array of the per-UE, per-PRG, per-layer singular values obtained from the SVD of the channel matrix
|
||||
float* avgRatesActUe = nullptr; // array of the long-term average data rates of all active UEs in the cell
|
||||
uint16_t* prioWeightActUe = nullptr; // For priority-based UE selection. Priority weights of all active UEs in the cell
|
||||
int8_t* tbErrLastActUe = nullptr; // TB decoding error indicators of all active UEs in the cell
|
||||
int8_t* newDataActUe = nullptr; // Indicators of initial transmission/retransmission for all active UEs in the cell
|
||||
int16_t* allocSolLastTxActUe = nullptr; // The PRG allocation solution for the last transmissions of all active UEs in the cell
|
||||
int16_t* mcsSelSolLastTxActUe = nullptr; // MCS selection solution for the last transmissions of all active UEs in the cell
|
||||
uint8_t* layerSelSolLastTxActUe = nullptr; // Layer selection solution for the last transmissions of all active UEs in the cell
|
||||
int8_t* cqiActUe = nullptr; // CQI values of all active UEs in the cell
|
||||
};
|
||||
|
||||
struct MAC_SCH_TTI_RESPONSE {
|
||||
uint16_t* setSchdUePerCellTTI = nullptr; // Set of IDs of the selected UEs for the cell
|
||||
int16_t* allocSol = nullptr; // PRB group allocation solution for all active UEs in the cell
|
||||
int16_t* mcsSelSol = nullptr; // MCS selection solution for all active UEs in the cell
|
||||
uint8_t* layerSelSol = nullptr; // Layer selection solution for all active UEs in the cell
|
||||
};
|
||||
|
||||
// cuMAC H5 TV saving/loading /////////////////////////////////////////////////
|
||||
struct cumacSchedulerParam {
|
||||
uint16_t nUe;
|
||||
uint16_t nCell; // number of coordinated cells
|
||||
uint16_t totNumCell; // number of all cells in the network. (not needed if channel buffer only contains channels within coordinated cells)
|
||||
uint16_t nPrbGrp;
|
||||
uint8_t nBsAnt;
|
||||
uint8_t nUeAnt; // assumption's that nUeAnt <= nBsAnt
|
||||
float W;
|
||||
float sigmaSqrd; // noise variance if channel is not normalized; 1/SNR if channel is normalized with transmit power, limitation: SNR (per antenna) should be <= 111 dB
|
||||
uint16_t maxNumUePerCell; // maximum number of selected UEs per cell per TTI
|
||||
uint16_t nMaxSchdUePerRnd; // maximum number of UEs per cell that can be scheduled per round
|
||||
float betaCoeff; // coefficient for improving cell edge UEs' performance in multi-cell scheduling
|
||||
uint16_t nActiveUe; // number of active UEs for all coordinated cells
|
||||
uint8_t numUeSchdPerCellTTI; // number of UEs scheduled per TTI per cell
|
||||
uint8_t precodingScheme;
|
||||
uint8_t receiverScheme;
|
||||
uint8_t allocType;
|
||||
uint8_t columnMajor;
|
||||
float sinValThr; // singular value threshold for layer selection
|
||||
uint16_t numUeForGrpPerCell;
|
||||
float chanCorrThr;
|
||||
float muCoeff;
|
||||
float srsSnrThr;
|
||||
uint16_t nMaxActUePerCell;
|
||||
float zfCoeff;
|
||||
uint8_t nMaxUePerGrpUl;
|
||||
uint8_t nMaxUePerGrpDl;
|
||||
uint8_t nMaxLayerPerGrpUl;
|
||||
uint8_t nMaxLayerPerGrpDl;
|
||||
uint8_t nMaxLayerPerUeSuUl;
|
||||
uint8_t nMaxLayerPerUeSuDl;
|
||||
uint8_t nMaxLayerPerUeMuUl;
|
||||
uint8_t nMaxLayerPerUeMuDl;
|
||||
uint8_t nMaxUegPerCellDl;
|
||||
uint8_t nMaxUegPerCellUl;
|
||||
float mcsSelSinrCapThr;
|
||||
float muGrpSrsSnrMaxGap;
|
||||
float muGrpSrsSnrSplitThr;
|
||||
uint8_t bfPowAllocScheme;
|
||||
uint8_t muGrpUpdate;
|
||||
uint8_t mcsSelLutType;
|
||||
uint8_t semiStatFreqAlloc;
|
||||
uint8_t harqEnabledInd;
|
||||
uint8_t mcsSelCqi;
|
||||
uint8_t dlSchInd;
|
||||
};
|
||||
}
|
||||
123
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cu_mac_api.h
Normal file
123
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cu_mac_api.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CU_MAC_API_H
|
||||
#define CU_MAC_API_H
|
||||
|
||||
#include "cumac_msg.h"
|
||||
|
||||
// todo: move the following constants to test case YAML file
|
||||
#define MAX_NUM_LCG 4
|
||||
#define MAX_NUM_LC 4
|
||||
#define MAX_NUM_UE 100 // a maximum of 512 UEs is supported
|
||||
#define MAX_NUM_OUTPUT_SORTED_LC_PER_QOS MAX_NUM_UE*MAX_NUM_LC // maximum number of output sorted LCs/LCGs per DL/UL QoS type, used for GPU memory allocation
|
||||
#define MAX_NUM_SCHEDULED_UE 16 // maximum number of scheduled UEs per time slot for both DL and UL
|
||||
#define IIR_ALPHA 0.001
|
||||
|
||||
// #define SLOT_INTERVAL_NS (500)
|
||||
#define SLOT_INTERVAL_NS 1E9 // Time slot interval in nanoseconds. Set to 1 second for debug only,
|
||||
#define SLOT_DURATION 0.0005 // Time slot interval in seconds, 0.5ms
|
||||
|
||||
#define NUM_TIME_SLOTS 10 // total number of time slots to simulate
|
||||
|
||||
struct PFM_DL_LC_INFO {
|
||||
uint32_t tbs_scheduled;
|
||||
uint32_t ravg;
|
||||
uint32_t pfm;
|
||||
uint8_t flags; // a collection of flags: flags & 0x01 - is_valid, flags & 0x02 - reset ravg to 1.0
|
||||
uint8_t qos_type; // 0 - dl_gbr_critical, 1 - dl_gbr_non_critical, 2 - dl_ngbr_critical, 3 - dl_ngbr_non_critical, 4 - dl_mbr_non_critical
|
||||
uint8_t padding[2]; // Padding to align to 32-bit
|
||||
};
|
||||
|
||||
struct PFM_UL_LCG_INFO {
|
||||
uint32_t tbs_scheduled;
|
||||
uint32_t ravg;
|
||||
uint32_t pfm;
|
||||
uint8_t flags; // a collection of flags: flags & 0x01 - is_valid, flags & 0x02 - reset ravg to 1.0
|
||||
uint8_t qos_type; // 0 - ul_gbr_critical, 1 - ul_gbr_non_critical, 2 - ul_ngbr_critical, 3 - ul_ngbr_non_critical, 4 - ul_mbr_non_critical
|
||||
uint8_t padding[2]; // Padding to align to 32-bit
|
||||
};
|
||||
|
||||
struct PFM_UE_INFO {
|
||||
struct PFM_DL_LC_INFO dl_lc_info[MAX_NUM_LC];
|
||||
struct PFM_UL_LCG_INFO ul_lcg_info[MAX_NUM_LCG];
|
||||
uint32_t ambr;
|
||||
uint32_t rcurrent_dl;
|
||||
uint32_t rcurrent_ul;
|
||||
uint16_t rnti;
|
||||
uint8_t num_layers_dl;
|
||||
uint8_t num_layers_ul;
|
||||
uint8_t flags; // a collection of flags: flags & 0x01 - is_valid, flags & 0x02 - is_scheduled_dl, flags & 0x04 - is_scheduled_ul
|
||||
uint8_t carrier_id;
|
||||
uint8_t num_dl_lcs;
|
||||
uint8_t num_ul_lcgs;
|
||||
};
|
||||
|
||||
/* ======================================================= */
|
||||
|
||||
struct PFM_DL_OUTPUT_INFO {
|
||||
uint16_t rnti;
|
||||
uint8_t lc_id;
|
||||
uint8_t padding; // Padding to align to 32-bit
|
||||
};
|
||||
|
||||
struct PFM_UL_OUTPUT_INFO {
|
||||
uint16_t rnti;
|
||||
uint8_t lcg_id;
|
||||
uint8_t padding; // Padding to align to 32-bit
|
||||
};
|
||||
|
||||
// expected output from the GPU
|
||||
struct PFM_DL_OUTPUT_INFO dl_gbr_critical[MAX_NUM_OUTPUT_SORTED_LC_PER_QOS];
|
||||
struct PFM_DL_OUTPUT_INFO dl_gbr_non_critical[MAX_NUM_OUTPUT_SORTED_LC_PER_QOS];
|
||||
struct PFM_DL_OUTPUT_INFO dl_ngbr_critical[MAX_NUM_OUTPUT_SORTED_LC_PER_QOS];
|
||||
struct PFM_DL_OUTPUT_INFO dl_ngbr_non_critical[MAX_NUM_OUTPUT_SORTED_LC_PER_QOS];
|
||||
struct PFM_DL_OUTPUT_INFO dl_mbr_non_critical[MAX_NUM_OUTPUT_SORTED_LC_PER_QOS];
|
||||
|
||||
struct PFM_UL_OUTPUT_INFO ul_gbr_critical[MAX_NUM_OUTPUT_SORTED_LC_PER_QOS];
|
||||
struct PFM_UL_OUTPUT_INFO ul_gbr_non_critical[MAX_NUM_OUTPUT_SORTED_LC_PER_QOS];
|
||||
struct PFM_UL_OUTPUT_INFO ul_ngbr_critical[MAX_NUM_OUTPUT_SORTED_LC_PER_QOS];
|
||||
struct PFM_UL_OUTPUT_INFO ul_ngbr_non_critical[MAX_NUM_OUTPUT_SORTED_LC_PER_QOS];
|
||||
struct PFM_UL_OUTPUT_INFO ul_mbr_non_critical[MAX_NUM_OUTPUT_SORTED_LC_PER_QOS];
|
||||
|
||||
struct cumac_pfm_tti_req_t {
|
||||
cumac_msg_header_t header;
|
||||
uint32_t offset_ue_info_arr; // Offset of the PFM_UE_INFO data array in nvipc_buf->data_buf
|
||||
uint16_t sfn;
|
||||
uint16_t slot;
|
||||
uint16_t num_ue; // total number of UEs in the payload
|
||||
uint16_t num_output_sorted_lc[10];
|
||||
// number of output sorted LCs/LCGs per DL/UL QoS type, 0-9 are the indices of the QoS types:
|
||||
// 0 - dl_gbr_critical, 1 - dl_gbr_non_critical, 2 - dl_ngbr_critical, 3 - dl_ngbr_non_critical, 4 - dl_mbr_non_critical,
|
||||
// 5 - ul_gbr_critical, 6 - ul_gbr_non_critical, 7 - ul_ngbr_critical, 8 - ul_ngbr_non_critical, 9 - ul_mbr_non_critical.
|
||||
};
|
||||
|
||||
struct cumac_pfm_tti_resp_t {
|
||||
cumac_msg_header_t header;
|
||||
uint16_t sfn;
|
||||
uint16_t slot;
|
||||
uint32_t offset_output_sorted_lc[10];
|
||||
// offset of output sorted LCs/LCGs list per DL/UL QoS type, 0-9 are the indices of the QoS types:
|
||||
// 0 - dl_gbr_critical, 1 - dl_gbr_non_critical, 2 - dl_ngbr_critical, 3 - dl_ngbr_non_critical, 4 - dl_mbr_non_critical,
|
||||
// 5 - ul_gbr_critical, 6 - ul_gbr_non_critical, 7 - ul_ngbr_critical, 8 - ul_ngbr_non_critical, 9 - ul_mbr_non_critical.
|
||||
uint16_t num_output_sorted_lc[10];
|
||||
// number of output sorted LCs/LCGs per DL/UL QoS type, 0-9 are the indices of the QoS types:
|
||||
// 0 - dl_gbr_critical, 1 - dl_gbr_non_critical, 2 - dl_ngbr_critical, 3 - dl_ngbr_non_critical, 4 - dl_mbr_non_critical,
|
||||
// 5 - ul_gbr_critical, 6 - ul_gbr_non_critical, 7 - ul_ngbr_critical, 8 - ul_ngbr_non_critical, 9 - ul_mbr_non_critical.
|
||||
};
|
||||
|
||||
#endif // CU_MAC_API_H
|
||||
78
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_msg.c
Normal file
78
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_msg.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "cumac_msg.h"
|
||||
|
||||
/**
|
||||
* Convert cuMAC message ID to human-readable string
|
||||
*
|
||||
* Provides a lookup table for cuMAC message type identifiers,
|
||||
* useful for logging and debugging purposes.
|
||||
*
|
||||
* @param[in] msg_id Message type identifier from cumac_msg_t enum
|
||||
*
|
||||
* @return Pointer to constant string containing message name.
|
||||
* Returns "UNKNOWN_CUMAC_MSG" for unrecognized message IDs.
|
||||
*/
|
||||
const char* get_cumac_msg_name(int msg_id)
|
||||
{
|
||||
switch(msg_id)
|
||||
{
|
||||
case CUMAC_PARAM_REQUEST:
|
||||
return "PARAM.req";
|
||||
case CUMAC_PARAM_RESPONSE:
|
||||
return "PARAM.resp";
|
||||
|
||||
case CUMAC_CONFIG_REQUEST:
|
||||
return "CONFIG.req";
|
||||
case CUMAC_CONFIG_RESPONSE:
|
||||
return "CONFIG.resp";
|
||||
|
||||
case CUMAC_START_REQUEST:
|
||||
return "START.req";
|
||||
case CUMAC_START_RESPONSE:
|
||||
return "START.resp";
|
||||
|
||||
case CUMAC_STOP_REQUEST:
|
||||
return "STOP.req";
|
||||
case CUMAC_STOP_RESPONSE:
|
||||
return "STOP.resp";
|
||||
|
||||
case CUMAC_ERROR_INDICATION:
|
||||
return "ERR.ind";
|
||||
|
||||
case CUMAC_TTI_ERROR_INDICATION:
|
||||
return "TTI_ERR.ind";
|
||||
case CUMAC_DL_TTI_REQUEST:
|
||||
return "DL_TTI.req";
|
||||
case CUMAC_UL_TTI_REQUEST:
|
||||
return "UL_TTI.req";
|
||||
|
||||
case CUMAC_SCH_TTI_REQUEST:
|
||||
return "SCH_TTI.req";
|
||||
case CUMAC_SCH_TTI_RESPONSE:
|
||||
return "SCH_TTI.resp";
|
||||
|
||||
case CUMAC_TTI_END:
|
||||
return "TTI_END.req";
|
||||
|
||||
default:
|
||||
return "UNKNOWN_CUMAC_MSG";
|
||||
}
|
||||
}
|
||||
322
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_msg.h
Normal file
322
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_msg.h
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _NV_CUMAC_MSG_
|
||||
#define _NV_CUMAC_MSG_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "cumac_pfm_sort.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//! Invalid buffer offset marker (all bits set)
|
||||
#define INVALID_CUMAC_BUF_OFFSET (0xFFFFFFFF)
|
||||
|
||||
/**
|
||||
* Get human-readable name for cuMAC message ID
|
||||
*
|
||||
* @param[in] msg_id Message identifier from cumac_msg_t enum
|
||||
*
|
||||
* @return Pointer to message name string, or "UNKNOWN_CUMAC_MSG" if invalid
|
||||
*/
|
||||
const char* get_cumac_msg_name(int msg_id);
|
||||
|
||||
/**
|
||||
* cuMAC message type identifiers
|
||||
*
|
||||
* Defines message types for cuMAC control plane protocol
|
||||
* including configuration, lifecycle, and TTI scheduling messages
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
CUMAC_PARAM_REQUEST = 0x00, //!< PARAM.request - Query parameters
|
||||
CUMAC_PARAM_RESPONSE = 0x01, //!< PARAM.response - Parameter response
|
||||
CUMAC_CONFIG_REQUEST = 0x02, //!< CONFIG.request - Configuration request
|
||||
CUMAC_CONFIG_RESPONSE = 0x03, //!< CONFIG.response - Configuration response
|
||||
CUMAC_START_REQUEST = 0x04, //!< START.request - Start cuMAC processing
|
||||
CUMAC_STOP_REQUEST = 0x05, //!< STOP.request - Stop cuMAC processing
|
||||
CUMAC_STOP_RESPONSE = 0x06, //!< STOP.response - Stop response
|
||||
CUMAC_ERROR_INDICATION = 0x07, //!< ERROR.indication - Error notification
|
||||
CUMAC_START_RESPONSE = 0x08, //!< START.response - Start response
|
||||
|
||||
CUMAC_DL_TTI_REQUEST = 0x80, //!< DL_TTI.request - Downlink TTI request (Not used currently)
|
||||
CUMAC_UL_TTI_REQUEST = 0x81, //!< UL_TTI.request - Uplink TTI request (Not used currently)
|
||||
|
||||
CUMAC_SCH_TTI_REQUEST = 0x82, //!< SCH_TTI.request - Scheduling TTI request
|
||||
CUMAC_SCH_TTI_RESPONSE = 0x83, //!< SCH_TTI.response - Scheduling TTI response
|
||||
|
||||
CUMAC_TTI_END = 0x8F, //!< TTI_END - End of TTI indication
|
||||
CUMAC_TTI_ERROR_INDICATION = 0x90, //!< TTI_ERROR.indication - TTI-specific error
|
||||
} cumac_msg_t;
|
||||
|
||||
/**
|
||||
* cuMAC task type enumeration
|
||||
*
|
||||
* Identifies which cuMAC scheduling algorithm to execute
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
CUMAC_TASK_UE_SELECTION = 0, //!< UE selection task (cumac::multiCellUeSelection)
|
||||
CUMAC_TASK_PRB_ALLOCATION = 1, //!< PRB allocation task (cumac::multiCellScheduler)
|
||||
CUMAC_TASK_LAYER_SELECTION = 2, //!< Layer selection task (cumac::multiCellLayerSel)
|
||||
CUMAC_TASK_MCS_SELECTION = 3, //!< MCS selection task (cumac::mcsSelectionLUT)
|
||||
CUMAC_TASK_PFM_SORT = 4, //!< PFM sorting task
|
||||
CUMAC_TASK_TOTAL_NUM = 5 //!< Total number of task types
|
||||
} cumac_task_type_t;
|
||||
|
||||
/**
|
||||
* cuMAC message header structure
|
||||
*
|
||||
* Based on SCF FAPI header format (see SCF222 document). All cuMAC messages begin with this header.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t message_count; //!< Number of messages in this transmission
|
||||
uint8_t handle_id; //!< handle_id is used as cell_id
|
||||
uint16_t type_id; //!< Message type identifier (cumac_msg_t)
|
||||
uint32_t body_len; //!< Length of message body in bytes
|
||||
uint8_t body[0]; //!< Variable-length message body (flexible array member)
|
||||
} cumac_msg_header_t;
|
||||
|
||||
/**
|
||||
* Slot-specific message header
|
||||
*
|
||||
* Extended header for TTI-related messages that includes timing information
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
cumac_msg_header_t header; //!< Standard message header
|
||||
uint16_t sfn; //!< Frame Number (0-1023)
|
||||
uint16_t slot; //!< Slot number within frame
|
||||
uint8_t payload[0]; //!< Variable-length payload (flexible array member)
|
||||
} cumac_slot_msg_header_t;
|
||||
|
||||
/**
|
||||
* CONFIG.request message structure
|
||||
*/
|
||||
typedef struct {
|
||||
cumac_msg_header_t header; //!< Message header with type CUMAC_CONFIG_REQUEST
|
||||
uint8_t body[]; //!< Configuration payload (cumac_config_req_payload_t)
|
||||
} cumac_config_req_t;
|
||||
|
||||
/**
|
||||
* CONFIG.response message structure
|
||||
*/
|
||||
typedef struct {
|
||||
cumac_msg_header_t header; //!< Message header with type CUMAC_CONFIG_RESPONSE
|
||||
int error_code; //!< Error code: 0 on success, other on failure
|
||||
} cumac_config_resp_t;
|
||||
|
||||
/**
|
||||
* START.request message structure
|
||||
*/
|
||||
typedef struct {
|
||||
cumac_msg_header_t header; //!< Message header with type CUMAC_START_REQUEST
|
||||
int start_param; //!< Start parameters (reserved for future use)
|
||||
} cumac_start_req_t;
|
||||
|
||||
/**
|
||||
* START.response message structure
|
||||
*/
|
||||
typedef struct {
|
||||
cumac_msg_header_t header; //!< Message header with type CUMAC_START_RESPONSE
|
||||
int error_code; //!< Error code: 0 on success, other on failure
|
||||
} cumac_start_resp_t;
|
||||
|
||||
/**
|
||||
* STOP.request message structure
|
||||
*/
|
||||
typedef struct {
|
||||
cumac_msg_header_t header; //!< Message header with type CUMAC_STOP_REQUEST
|
||||
int stop_param; //!< Stop parameters (reserved for future use)
|
||||
} cumac_stop_req_t;
|
||||
|
||||
/**
|
||||
* STOP.response message structure
|
||||
*/
|
||||
typedef struct {
|
||||
cumac_msg_header_t header; //!< Message header with type CUMAC_STOP_RESPONSE
|
||||
int error_code; //!< Error code: 0 on success, other on failure
|
||||
} cumac_stop_resp_t;
|
||||
|
||||
/**
|
||||
* ERROR.indication message structure
|
||||
*/
|
||||
typedef struct {
|
||||
cumac_msg_header_t header; //!< Message header with type CUMAC_ERROR_INDICATION
|
||||
int msg_id; //!< Message ID that caused the error
|
||||
int error_code; //!< Error code identifier
|
||||
int reason_code; //!< Detailed reason code for the error
|
||||
} cumac_err_ind_t;
|
||||
|
||||
/**
|
||||
* CONFIG.request payload structure
|
||||
*
|
||||
* Static scheduler configuration parameters passed from L2 stack to cuMAC-CP
|
||||
* during initialization phase (one-time configuration).
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t harqEnabledInd; //!< Indicator for whether HARQ is enabled
|
||||
uint8_t mcsSelCqi; //!< Indicator for whether MCS selection is based on CQI or SINR
|
||||
uint8_t nMaxCell; //!< A constant integer for the maximum number of cells in the cell group
|
||||
uint16_t nMaxActUePerCell; //!< A constant integer for the maximum number of active UEs per cell
|
||||
uint8_t nMaxSchUePerCell; //!< A constant integer for the maximum number of UEs that can be scheduled per TTI per cell
|
||||
uint16_t nMaxPrg; //!< A constant integer for the maximum number of PRGs for allocation in each cell
|
||||
uint16_t nPrbPerPrg; //!< A constant integer for the number of PRBs per PRG (PRB group)
|
||||
uint8_t nMaxBsAnt; //!< A constant integer for the maximum number of BS antenna ports.
|
||||
uint8_t nMaxUeAnt; //!< A constant integer for the maximum number of UE antenna ports.
|
||||
uint32_t scSpacing; //!< Subcarrier spacing of the carrier. Value: 15000, 30000, 60000, 120000 (Hz)
|
||||
uint8_t allocType; //!< Indicator for type-0 or type-1 PRG allocation
|
||||
uint8_t precoderType; //!< Indicator for the precoder type
|
||||
uint8_t receiverType; //!< Indicator for the receiver type
|
||||
uint8_t colMajChanAccess; //!< Indicator for whether the estimated narrow-band SRS channel matrices are stored in column-major order or in row-major order
|
||||
float betaCoeff; //!< Coefficient for adjusting the cell-edge UEs' performance in multi-cell scheduling
|
||||
float sinValThr; //!< Singular value threshold for layer selection
|
||||
float corrThr; //!< Channel vector correlation value threshold for layer selection
|
||||
float mcsSelSinrCapThr; //!< SINR capping threshold for MCS selection
|
||||
uint8_t mcsSelLutType; //!< MCS selection LUT type
|
||||
uint16_t prioWeightStep; //!< Step size for UE priority weight increment per TTI if UE does not get scheduled. For priority-based UE selection
|
||||
float blerTarget; //!< BLER target (same for all active UEs; expanded per-UE in cuMAC-CP)
|
||||
} cumac_config_req_payload_t;
|
||||
|
||||
/**
|
||||
* SCH_TTI.request buffer offsets structure
|
||||
*
|
||||
* Specifies byte offsets for data buffers in SCH_TTI.request message.
|
||||
* All offsets are relative to the start of the data payload.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t CRNTI; //!< C-RNTIs of all active UEs in the cell
|
||||
uint32_t srsCRNTI; //!< C-RNTIs of the UEs that have refreshed SRS channel estimates in the cell.
|
||||
uint32_t prgMsk; //!< Bit map for the availability of each PRG for allocation
|
||||
uint32_t postEqSinr; //!< Array of the per-PRG per-layer post-equalizer SINRs of all active UEs in the cell
|
||||
uint32_t wbSinr; //!< Array of wideband per-layer post-equalizer SINRs of all active UEs in the cell
|
||||
uint32_t estH_fr; //!< For FP32. Array of the subband (per-PRG) SRS channel estimate coefficients for all active UEs in the cell
|
||||
uint32_t estH_fr_half; //!< For FP16. Array of the subband (per-PRG) SRS channel estimate coefficients for all active UEs in the cell
|
||||
uint32_t prdMat; //!< Array of the precoder/beamforming weights for all active UEs in the cell
|
||||
uint32_t detMat; //!< Array of the detector/beamforming weights for all active UEs in the cell
|
||||
uint32_t sinVal; //!< Array of the per-UE, per-PRG, per-layer singular values obtained from the SVD of the channel matrix
|
||||
uint32_t avgRatesActUe; //!< Array of the long-term average data rates of all active UEs in the cell
|
||||
uint32_t prioWeightActUe; //!< For priority-based UE selection. Priority weights of all active UEs in the cell
|
||||
uint32_t tbErrLastActUe; //!< TB decoding error indicators of all active UEs in the cell
|
||||
uint32_t newDataActUe; //!< Indicators of initial transmission/retransmission for all active UEs in the cell
|
||||
uint32_t allocSolLastTxActUe; //!< The PRG allocation solution for the last transmissions of all active UEs in the cell
|
||||
uint32_t mcsSelSolLastTxActUe; //!< MCS selection solution for the last transmissions of all active UEs in the cell
|
||||
uint32_t layerSelSolLastTxActUe; //!< Layer selection solution for the last transmissions of all active UEs in the cell
|
||||
uint32_t pfmCellInfo; //!< PFM sorting input buffer
|
||||
} cumac_tti_req_buf_offsets_t;
|
||||
|
||||
/**
|
||||
* SCH_TTI.request payload structure
|
||||
*
|
||||
* Contains per-TTI scheduling parameters and buffer offset information
|
||||
*/
|
||||
// Payload of SCH_TTI.req
|
||||
typedef struct
|
||||
{
|
||||
uint32_t taskBitMask; //!< Indicate which cuMAC tasks to be scheduled. Each bit represent 1 task type defined in cumac_task_type_t
|
||||
uint16_t cellID; //!< cell ID
|
||||
uint8_t ULDLSch; //!< Indication for UL/DL scheduling. Value - 0: UL scheduling, 1: DL scheduling
|
||||
uint16_t nActiveUe; //!< total number of active UEs in the cell
|
||||
uint16_t nSrsUe; //!< the number of UEs in the cell that have refreshed SRS channel estimates
|
||||
uint16_t nPrbGrp; //!< the number of PRGs that can be allocated for the current TTI, excluding the PRGs that need to be reserved for HARQ re-tx's
|
||||
uint8_t nBsAnt; //!< number of BS antenna ports
|
||||
uint8_t nUeAnt; //!< number of UE antenna ports
|
||||
float sigmaSqrd; //!< noise variance
|
||||
|
||||
cumac_tti_req_buf_offsets_t offsets; //!< Data buffer offsets for input arrays
|
||||
|
||||
} cumac_tti_req_payload_t;
|
||||
|
||||
/**
|
||||
* SCH_TTI.request message structure
|
||||
*
|
||||
* Complete message including header, timing, and payload
|
||||
*/
|
||||
typedef struct {
|
||||
cumac_msg_header_t header; //!< Message header with type CUMAC_SCH_TTI_REQUEST
|
||||
uint16_t sfn; //!< Frame Number
|
||||
uint16_t slot; //!< Slot number
|
||||
|
||||
cumac_tti_req_payload_t payload; //!< Request payload with scheduling parameters
|
||||
} cumac_sch_tti_req_t;
|
||||
|
||||
/**
|
||||
* SCH_TTI.response buffer offsets structure
|
||||
*
|
||||
* Specifies byte offsets for output buffers in SCH_TTI.response message
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t setSchdUePerCellTTI; //!< Set of IDs of the selected UEs for the cell
|
||||
uint32_t allocSol; //!< PRB group allocation solution for all active UEs in the cell
|
||||
uint32_t layerSelSol; //!< Layer selection solution for all active UEs in the cell
|
||||
uint32_t mcsSelSol; //!< MCS selection solution for all active UEs in the cell
|
||||
uint32_t pfmSortSol; //!< PFM sorting output buffer
|
||||
} cumac_tti_resp_buf_offsets_t;
|
||||
|
||||
/**
|
||||
* SCH_TTI.response message structure
|
||||
*
|
||||
* Returns scheduling solutions computed by cuMAC
|
||||
*/
|
||||
typedef struct {
|
||||
cumac_msg_header_t header; //!< Message header with type CUMAC_SCH_TTI_RESPONSE
|
||||
uint16_t sfn; //!< Frame Number
|
||||
uint16_t slot; //!< Slot number
|
||||
uint16_t nUeSchd; //!< Number of UEs actually scheduled this TTI for this cell
|
||||
|
||||
cumac_tti_resp_buf_offsets_t offsets; //!< Data buffer offsets for output arrays
|
||||
} cumac_sch_tti_resp_t;
|
||||
|
||||
/**
|
||||
* TTI_END message structure
|
||||
*
|
||||
* Indicates completion of TTI processing
|
||||
*/
|
||||
typedef struct {
|
||||
cumac_msg_header_t header; //!< Message header with type CUMAC_TTI_END
|
||||
uint16_t sfn; //!< Frame Number
|
||||
uint16_t slot; //!< Slot number
|
||||
int end_param; //!< End parameters (reserved for future use)
|
||||
} cumac_tti_end_t;
|
||||
|
||||
/**
|
||||
* TTI_ERROR.indication message structure
|
||||
*
|
||||
* Reports TTI-specific errors during processing
|
||||
*/
|
||||
typedef struct {
|
||||
cumac_msg_header_t header; //!< Message header with type CUMAC_TTI_ERROR_INDICATION
|
||||
uint16_t sfn; //!< Frame Number
|
||||
uint16_t slot; //!< Slot number
|
||||
int msg_id; //!< Message ID that caused the error
|
||||
int error_code; //!< Error code identifier
|
||||
int reason_code; //!< Detailed reason code for the error
|
||||
} cumac_tti_err_ind_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* _NV_CUMAC_MSG_ */
|
||||
363
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_msg_funcs.c
Normal file
363
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_msg_funcs.c
Normal file
@@ -0,0 +1,363 @@
|
||||
#include "cumac_msg_funcs.h"
|
||||
|
||||
#include "cumac_nvipc.h"
|
||||
|
||||
#include <nv_ipc.h>
|
||||
#include <nvlog.h>
|
||||
#include <stdalign.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <asm-generic/errno-base.h>
|
||||
static size_t get_padding(size_t offset, size_t alignment)
|
||||
{
|
||||
return (alignment - (offset % alignment)) % alignment;
|
||||
}
|
||||
int l2_build_start_request(cumac_msg_t type, nv_ipc_msg_t *nvipc_buf, void* args) {
|
||||
if (type != CUMAC_START_REQUEST)
|
||||
return -EINVAL;
|
||||
cumac_start_req_t* req = nvipc_buf->msg_buf;
|
||||
nvipc_buf->msg_id = CUMAC_START_REQUEST;
|
||||
nvipc_buf->cell_id = 0;
|
||||
nvipc_buf->msg_len = sizeof(cumac_start_req_t);
|
||||
nvipc_buf->data_len = 0;
|
||||
nvipc_buf->data_buf = NULL;
|
||||
nvipc_buf->data_pool = NV_IPC_MEMPOOL_CPU_MSG;
|
||||
req->header.message_count = 1;
|
||||
req->header.handle_id = 0;
|
||||
req->header.type_id = CUMAC_START_REQUEST;
|
||||
req->header.body_len = sizeof(req->start_param);
|
||||
req->start_param = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int l2_build_config_request(cumac_msg_t type, nv_ipc_msg_t *nvipc_buf, void* args) {
|
||||
if (type != CUMAC_CONFIG_REQUEST)
|
||||
return -EINVAL;
|
||||
cumac_config_req_payload_t *payload = (cumac_config_req_payload_t*)args;
|
||||
cumac_config_req_t* req = (cumac_config_req_t*)nvipc_buf->msg_buf;
|
||||
nvipc_buf->msg_id = CUMAC_CONFIG_REQUEST;
|
||||
nvipc_buf->cell_id = 0;
|
||||
nvipc_buf->msg_len = sizeof(cumac_config_req_t);
|
||||
nvipc_buf->data_len = 0;
|
||||
nvipc_buf->data_buf = NULL;
|
||||
nvipc_buf->data_pool = NV_IPC_MEMPOOL_CPU_MSG;
|
||||
req->header.message_count = 1;
|
||||
req->header.handle_id = 0;
|
||||
req->header.type_id = CUMAC_CONFIG_REQUEST;
|
||||
req->header.body_len = sizeof(cumac_config_req_payload_t);
|
||||
memcpy(req->body, payload, sizeof(cumac_config_req_payload_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l2_build_sch_tti_request(cumac_msg_t type, nv_ipc_msg_t *nvipc_buf, void* args) {
|
||||
if (type != CUMAC_SCH_TTI_REQUEST)
|
||||
return -EINVAL;
|
||||
cumac_sch_tti_req_args_t *config_args = args;
|
||||
uint16_t frame = config_args->frame;
|
||||
uint16_t slot = config_args->slot;
|
||||
uint16_t nActiveUE = config_args->payload.nActiveUe;
|
||||
uint16_t nPRBGRP = config_args->payload.nPrbGrp;
|
||||
uint8_t nUEAnt = config_args->payload.nUeAnt;
|
||||
uint8_t nBSAnt = config_args->payload.nBsAnt;
|
||||
cumac_tti_req_bufs_t *req_buf = config_args->buffers;
|
||||
|
||||
slot_data_entry_t *slot_entry = &slot_data[frame][slot];
|
||||
// ensure buffers are free
|
||||
if (slot_entry->setSchdUePerCellTTI != NULL) {
|
||||
free(slot_entry->setSchdUePerCellTTI);
|
||||
}
|
||||
if (slot_entry->allocSol != NULL) {
|
||||
free(slot_entry->allocSol);
|
||||
}
|
||||
if (slot_entry->mcsSelSol != NULL) {
|
||||
free(slot_entry->mcsSelSol);
|
||||
}
|
||||
if (slot_entry->layerSelSol != NULL) {
|
||||
free(slot_entry->layerSelSol);
|
||||
}
|
||||
if (slot_entry->c_rnti != NULL) {
|
||||
free(slot_entry->c_rnti);
|
||||
}
|
||||
slot_entry->c_rnti = calloc(nActiveUE, sizeof(*req_buf->CRNTI));
|
||||
memcpy(slot_entry->c_rnti, req_buf->CRNTI, sizeof(*req_buf->CRNTI) * nActiveUE);
|
||||
cumac_sch_tti_req_t* req = (cumac_sch_tti_req_t*)nvipc_buf->msg_buf;
|
||||
uint8_t* data_buf = (uint8_t*)nvipc_buf->data_buf;
|
||||
nvipc_buf->msg_id = CUMAC_SCH_TTI_REQUEST;
|
||||
nvipc_buf->cell_id = config_args->payload.cellID;
|
||||
nvipc_buf->msg_len = sizeof(cumac_sch_tti_req_t);
|
||||
memcpy(&req->payload, &config_args->payload, sizeof(cumac_tti_req_payload_t));
|
||||
|
||||
|
||||
|
||||
req->sfn =frame;
|
||||
req->slot=slot;
|
||||
|
||||
req->header.message_count = 1;
|
||||
req->header.handle_id = 0;
|
||||
req->header.type_id = CUMAC_SCH_TTI_REQUEST;
|
||||
req->header.body_len = sizeof(cumac_tti_req_payload_t);
|
||||
|
||||
// Set all bytes to 0xFF since the unused offsets are to be set to 0xFFFFFFFF
|
||||
memset(&req->payload.offsets, 0xFF, sizeof req->payload.offsets);
|
||||
|
||||
// Copy data which need to be sent to GPU to the nvipc_buf->data_buf
|
||||
uint32_t offset = 0;
|
||||
uint32_t data_size = 0;
|
||||
uint32_t num_data = 0;
|
||||
|
||||
// Fill Common buffers
|
||||
offset += get_padding(offset, alignof(uint16_t));
|
||||
req->payload.offsets.CRNTI = offset;
|
||||
num_data = nActiveUE;
|
||||
data_size = sizeof(*req_buf->CRNTI) * num_data;
|
||||
LOG_D(NR_MAC,"CRNTI : ");
|
||||
for (int i = 0; i < num_data; ++i)
|
||||
LOG_D(NR_MAC,"%u ", req_buf->CRNTI[i]);
|
||||
LOG_D(NR_MAC,"\n");
|
||||
memcpy(data_buf + offset, req_buf->CRNTI, data_size);
|
||||
offset += data_size;
|
||||
|
||||
offset += get_padding(offset, alignof(uint8_t));
|
||||
req->payload.offsets.prgMsk = offset;
|
||||
num_data = nPRBGRP;
|
||||
data_size = sizeof(*req_buf->prgMsk) * num_data;
|
||||
LOG_D(NR_MAC,"PRG MASK : ");
|
||||
for (int i = 0; i < num_data; ++i)
|
||||
LOG_D(NR_MAC,"%u ", req_buf->prgMsk[i]);
|
||||
LOG_D(NR_MAC,"\n");
|
||||
memcpy(data_buf + offset, req_buf->prgMsk, data_size);
|
||||
offset += data_size;
|
||||
|
||||
offset += get_padding(offset, alignof(float));
|
||||
req->payload.offsets.wbSinr = offset;
|
||||
num_data = nActiveUE * nUEAnt;
|
||||
data_size = sizeof(*req_buf->wbSinr) * num_data;
|
||||
LOG_D(NR_MAC,"wbSinr : ");
|
||||
for (int i = 0; i < num_data; ++i)
|
||||
LOG_D(NR_MAC,"%f ", req_buf->wbSinr[i]);
|
||||
LOG_D(NR_MAC,"\n");
|
||||
memcpy(data_buf + offset, req_buf->wbSinr, data_size);
|
||||
offset += data_size;
|
||||
|
||||
offset += get_padding(offset, alignof(float));
|
||||
req->payload.offsets.avgRatesActUe = offset;
|
||||
num_data = nActiveUE;
|
||||
data_size = sizeof(*req_buf->avgRatesActUe) * num_data;
|
||||
LOG_D(NR_MAC,"avgRatesActUe : ");
|
||||
for (int i = 0; i < num_data; ++i)
|
||||
LOG_D(NR_MAC,"%f ", req_buf->avgRatesActUe[i]);
|
||||
LOG_D(NR_MAC,"\n");
|
||||
memcpy(data_buf + offset, req_buf->avgRatesActUe, data_size);
|
||||
offset += data_size;
|
||||
|
||||
// PRB Allocation specific buffers
|
||||
if (req->payload.taskBitMask & TASK_BIT(CUMAC_TASK_PRB_ALLOCATION)) {
|
||||
offset += get_padding(offset, alignof(float));
|
||||
req->payload.offsets.postEqSinr = offset;
|
||||
num_data = nActiveUE * nPRBGRP * nUEAnt;
|
||||
data_size = sizeof(*req_buf->postEqSinr) * num_data;
|
||||
LOG_D(NR_MAC,"postEqSinr : ");
|
||||
for (int i = 0; i < num_data; ++i)
|
||||
LOG_D(NR_MAC,"%f ", req_buf->postEqSinr[i]);
|
||||
LOG_D(NR_MAC,"\n");
|
||||
memcpy(data_buf + offset, req_buf->postEqSinr, data_size);
|
||||
offset += data_size;
|
||||
|
||||
offset += get_padding(offset, alignof(float));
|
||||
req->payload.offsets.sinVal = offset;
|
||||
num_data = slot_entry->nMaxSchUePerCell * nPRBGRP * cumac_nPrbPerPrg() * nUEAnt;
|
||||
data_size = sizeof(*req_buf->sinVal) * num_data;
|
||||
LOG_D(NR_MAC,"sinVal : ");
|
||||
for (int i = 0; i < num_data; ++i)
|
||||
LOG_D(NR_MAC,"%f ", req_buf->sinVal[i]);
|
||||
LOG_D(NR_MAC,"\n");
|
||||
memcpy(data_buf + offset, req_buf->sinVal, data_size);
|
||||
offset += data_size;
|
||||
|
||||
uint32_t prdLen, detLen;
|
||||
if(req->payload.ULDLSch == 1)
|
||||
{ // DL
|
||||
prdLen = slot_entry->nMaxSchUePerCell * nPRBGRP * cumac_nPrbPerPrg() * nBSAnt*nBSAnt;
|
||||
detLen = slot_entry->nMaxSchUePerCell * nPRBGRP * cumac_nPrbPerPrg() * nUEAnt * nUEAnt;
|
||||
}
|
||||
else
|
||||
{ // UL
|
||||
prdLen = slot_entry->nMaxSchUePerCell * nPRBGRP * cumac_nPrbPerPrg() * nUEAnt * nUEAnt;
|
||||
detLen = slot_entry->nMaxSchUePerCell * nPRBGRP * cumac_nPrbPerPrg() * nBSAnt*nBSAnt;
|
||||
}
|
||||
const uint32_t hLen = nPRBGRP * cumac_nPrbPerPrg() * slot_entry->nMaxSchUePerCell * /*nMaxCell*/ 1 * nBSAnt * nUEAnt;
|
||||
|
||||
offset += get_padding(offset, alignof(cuComplex));
|
||||
req->payload.offsets.detMat = offset;
|
||||
data_size = sizeof(*req_buf->detMat) * detLen;
|
||||
LOG_D(NR_MAC,"detMat : ");
|
||||
for (int i = 0; i < detLen; ++i)
|
||||
LOG_D(NR_MAC,"x = %f , y= %f ", req_buf->detMat[i].x, req_buf->detMat[i].y);
|
||||
LOG_D(NR_MAC,"\n");
|
||||
memcpy(data_buf + offset, req_buf->detMat, data_size);
|
||||
offset += data_size;
|
||||
|
||||
offset += get_padding(offset, alignof(cuComplex));
|
||||
req->payload.offsets.estH_fr = offset;
|
||||
data_size = sizeof(*req_buf->estH_fr) * hLen;
|
||||
LOG_D(NR_MAC,"estH_fr : ");
|
||||
for (int i = 0; i < hLen; ++i)
|
||||
LOG_D(NR_MAC,"x = %f , y= %f ", req_buf->estH_fr[i].x, req_buf->estH_fr[i].y);
|
||||
LOG_D(NR_MAC,"\n");
|
||||
memcpy(data_buf + offset, req_buf->estH_fr, data_size);
|
||||
offset += data_size;
|
||||
|
||||
offset += get_padding(offset, alignof(cuComplex));
|
||||
req->payload.offsets.prdMat = offset;
|
||||
data_size = sizeof(*req_buf->prdMat) * prdLen;
|
||||
LOG_D(NR_MAC,"prdMat : ");
|
||||
for (int i = 0; i < prdLen; ++i)
|
||||
LOG_D(NR_MAC,"x = %f , y= %f ", req_buf->prdMat[i].x, req_buf->prdMat[i].y);
|
||||
LOG_D(NR_MAC,"\n");
|
||||
memcpy(data_buf + offset, req_buf->prdMat, data_size);
|
||||
offset += data_size;
|
||||
|
||||
if (req_buf->allocSolLastTxActUe != NULL) {
|
||||
offset += get_padding(offset, alignof(int16_t));
|
||||
req->payload.offsets.allocSolLastTxActUe = offset;
|
||||
data_size = sizeof(*req_buf->allocSolLastTxActUe) * nActiveUE * 2;
|
||||
memcpy(data_buf + offset, req_buf->allocSolLastTxActUe, data_size);
|
||||
offset += data_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (req->payload.taskBitMask & TASK_BIT(CUMAC_TASK_MCS_SELECTION)) {
|
||||
offset += get_padding(offset, alignof(int8_t));
|
||||
req->payload.offsets.tbErrLastActUe = offset;
|
||||
data_size = sizeof(*req_buf->tbErrLastActUe) * nActiveUE;
|
||||
LOG_D(NR_MAC,"tbErrLastActUe : ");
|
||||
for (int i = 0; i < nActiveUE; ++i)
|
||||
LOG_D(NR_MAC,"%d ", req_buf->tbErrLastActUe[i]);
|
||||
LOG_D(NR_MAC,"\n");
|
||||
memcpy(data_buf + offset, req_buf->tbErrLastActUe, data_size);
|
||||
offset += data_size;
|
||||
|
||||
if (req_buf->mcsSelSolLastTxActUe != NULL) {
|
||||
offset += get_padding(offset, alignof(int16_t));
|
||||
req->payload.offsets.mcsSelSolLastTxActUe = offset;
|
||||
data_size = sizeof(*req_buf->mcsSelSolLastTxActUe) * nActiveUE;
|
||||
memcpy(data_buf + offset, req_buf->mcsSelSolLastTxActUe, data_size);
|
||||
offset += data_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (req->payload.taskBitMask & TASK_BIT(CUMAC_TASK_LAYER_SELECTION)) {
|
||||
if (req_buf->layerSelSolLastTxActUe != NULL) {
|
||||
offset += get_padding(offset, alignof(int8_t));
|
||||
req->payload.offsets.layerSelSolLastTxActUe = offset;
|
||||
data_size = sizeof(*req_buf->layerSelSolLastTxActUe) * nActiveUE;
|
||||
memcpy(data_buf + offset, req_buf->layerSelSolLastTxActUe, data_size);
|
||||
offset += data_size;
|
||||
}
|
||||
}
|
||||
|
||||
offset += get_padding(offset, alignof(int8_t));
|
||||
req->payload.offsets.newDataActUe = offset;
|
||||
num_data = nActiveUE;
|
||||
data_size = sizeof(*req_buf->newDataActUe) * num_data;
|
||||
LOG_D(NR_MAC,"newDataActUe : ");
|
||||
for (int i = 0; i < num_data; ++i)
|
||||
LOG_D(NR_MAC,"%d ", req_buf->newDataActUe[i]);
|
||||
LOG_D(NR_MAC,"\n");
|
||||
memcpy(data_buf + offset, req_buf->newDataActUe, data_size);
|
||||
offset += data_size;
|
||||
|
||||
nvipc_buf->data_len = offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l2_build_tti_end(cumac_msg_t type, nv_ipc_msg_t *nvipc_buf, void* args) {
|
||||
if (type != CUMAC_TTI_END)
|
||||
return -EINVAL;
|
||||
cumac_sch_tti_end_args_t *tti_end_args = args;
|
||||
cumac_tti_end_t* req = nvipc_buf->msg_buf;
|
||||
nvipc_buf->msg_id = CUMAC_TTI_END;
|
||||
nvipc_buf->cell_id = 0;
|
||||
nvipc_buf->msg_len = sizeof(cumac_tti_end_t);
|
||||
nvipc_buf->data_len = 0;
|
||||
nvipc_buf->data_buf = NULL;
|
||||
nvipc_buf->data_pool = NV_IPC_MEMPOOL_CPU_MSG;
|
||||
req->header.message_count = 1;
|
||||
req->header.handle_id = 0;
|
||||
req->header.type_id = CUMAC_TTI_END;
|
||||
req->header.body_len = sizeof(req->end_param);
|
||||
req->end_param = 0;
|
||||
req->sfn = tti_end_args->frame;
|
||||
req->slot = tti_end_args->slot;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cumac_handle_sch_tti_response(cumac_msg_t type, nv_ipc_msg_t *nvipc_buf, slot_data_entry_t *slot_data_entry)
|
||||
{
|
||||
if (type != CUMAC_SCH_TTI_RESPONSE)
|
||||
return;
|
||||
cumac_sch_tti_resp_t *resp = nvipc_buf->msg_buf;
|
||||
uint8_t *buf_home = (nvipc_buf->data_buf);
|
||||
//!< Set of IDs of the selected UEs for the cell
|
||||
slot_data_entry->setSchdUePerCellTTI =
|
||||
calloc(slot_data_entry->nMaxSchUePerCell, sizeof(uint16_t));
|
||||
//!< PRB group allocation solution for all active UEs in the cell
|
||||
slot_data_entry->allocSol = calloc(slot_data_entry->allocSolSize, sizeof(int16_t));
|
||||
//!< MCS selection solution for all active UEs in the cell
|
||||
slot_data_entry->mcsSelSol = calloc(slot_data_entry->nActiveUe, sizeof(int16_t));
|
||||
//!< Layer selection solution for all active UEs in the cell
|
||||
slot_data_entry->layerSelSol = calloc(slot_data_entry->nActiveUe, sizeof(uint8_t));
|
||||
|
||||
LOG_D(NR_MAC,"Received SCH_TTI.response with data\n");
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
LOG_D(NR_MAC,"message 0x%02x\n", type);
|
||||
LOG_I(NR_MAC,"From TTI_REQ/TTI_END to RESPONSE %ld , %ld\n",
|
||||
nvlog_timespec_interval(&slot_data_entry->tti_req_timestamp, &now),
|
||||
nvlog_timespec_interval(&slot_data_entry->tti_end_timestamp, &now));
|
||||
LOG_D(NR_MAC,"Used values in originating SCH_TTI.request:\n");
|
||||
LOG_D(NR_MAC,"\tnMaxSchUePerCell = %d\n", slot_data_entry->nMaxSchUePerCell);
|
||||
LOG_D(NR_MAC,"\tallocSolSize = %d\n", slot_data_entry->allocSolSize);
|
||||
LOG_D(NR_MAC,"\tnActiveUe = %d\n", slot_data_entry->nActiveUe);
|
||||
|
||||
LOG_D(NR_MAC,"Offsets : \n\tsetSchdUePerCellTTI 0x%04x\n", resp->offsets.setSchdUePerCellTTI);
|
||||
LOG_D(NR_MAC,"\tallocSol 0x%04x\n", resp->offsets.allocSol);
|
||||
LOG_D(NR_MAC,"\tmcsSelSol 0x%04x\n", resp->offsets.mcsSelSol);
|
||||
LOG_D(NR_MAC,"\tlayerSelSol 0x%04x\n", resp->offsets.layerSelSol);
|
||||
|
||||
if (resp->offsets.setSchdUePerCellTTI != 0xFFFFFFFF) {
|
||||
const uint16_t *src = (uint16_t *)(buf_home + resp->offsets.setSchdUePerCellTTI);
|
||||
memcpy(slot_data_entry->setSchdUePerCellTTI, src, slot_data_entry->nMaxSchUePerCell * sizeof(uint16_t));
|
||||
LOG_D(NR_MAC,"setSchdUePerCellTTI :\n");
|
||||
for (int i = 0; i < slot_data_entry->nMaxSchUePerCell; i++) {
|
||||
LOG_D(NR_MAC,"\tIDX %d = %d \n", i, slot_data_entry->setSchdUePerCellTTI[i]);
|
||||
}
|
||||
}
|
||||
if (resp->offsets.allocSol != 0xFFFFFFFF) {
|
||||
const uint16_t *src = (uint16_t *)(buf_home + resp->offsets.allocSol);
|
||||
memcpy(slot_data_entry->allocSol, src, slot_data_entry->allocSolSize * sizeof(*slot_data_entry->allocSol));
|
||||
LOG_D(NR_MAC,"allocSol:\n");
|
||||
for (int i = 0; i < slot_data_entry->allocSolSize; i++) {
|
||||
LOG_D(NR_MAC,"\tIDX %d = 0x%02x \n", i, src[i]);
|
||||
|
||||
}
|
||||
}
|
||||
if (resp->offsets.mcsSelSol != 0xFFFFFFFF) {
|
||||
const int16_t *src = (int16_t *)(buf_home + resp->offsets.mcsSelSol);
|
||||
memcpy(slot_data_entry->mcsSelSol, src, slot_data_entry->nActiveUe * sizeof(*slot_data_entry->mcsSelSol));
|
||||
LOG_D(NR_MAC,"mcsSelSol :\n");
|
||||
for (int i = 0; i < slot_data_entry->nActiveUe; i++) {
|
||||
LOG_D(NR_MAC,"\tIDX %d = 0x%02x \n", i, slot_data_entry->mcsSelSol[i]);
|
||||
}
|
||||
}
|
||||
if (resp->offsets.layerSelSol != 0xFFFFFFFF) {
|
||||
const uint8_t *src = (uint8_t *)(buf_home + resp->offsets.layerSelSol);
|
||||
memcpy(slot_data_entry->layerSelSol, src, slot_data_entry->nActiveUe);
|
||||
LOG_D(NR_MAC,"layerSelSol :\n");
|
||||
for (int i = 0; i < slot_data_entry->nActiveUe; i++) {
|
||||
LOG_D(NR_MAC,"\tIDX %d = 0x%02x \n", i, slot_data_entry->layerSelSol[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// Created by user on 10 Oct 2025.
|
||||
//
|
||||
|
||||
#ifndef OPENAIRINTERFACE_CUMAC_MSG_FUNCS_H
|
||||
#define OPENAIRINTERFACE_CUMAC_MSG_FUNCS_H
|
||||
#include "cumac_msg.h"
|
||||
#include <cuComplex.h>
|
||||
#include <cuda_bf16.h>
|
||||
#include <nv_ipc.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#define SCH_TTI_UL 0
|
||||
#define SCH_TTI_DL 1
|
||||
|
||||
// Buffer offsets for SCH_TTI.req
|
||||
typedef struct {
|
||||
uint16_t *CRNTI; // C-RNTIs of all active UEs in the cell
|
||||
uint16_t *srsCRNTI; // C-RNTIs of the UEs that have refreshed SRS channel estimates in the cell.
|
||||
uint8_t *prgMsk; // Bit map for the availability of each PRG for allocation
|
||||
float *postEqSinr; // Array of the per-PRG per-layer post-equalizer SINRs of all active UEs in the cell
|
||||
float *wbSinr; // Array of wideband per-layer post-equalizer SINRs of all active UEs in the cell
|
||||
cuComplex
|
||||
*estH_fr; // For FP32. Array of the subband (per-PRG) SRS channel estimate coefficients for all active UEs in the cell
|
||||
__nv_bfloat162_raw
|
||||
*estH_fr_half; // For FP16. Array of the subband (per-PRG) SRS channel estimate coefficients for all active UEs in the cell
|
||||
cuComplex *prdMat; // Array of the precoder/beamforming weights for all active UEs in the cell
|
||||
cuComplex *detMat; // Array of the detector/beamforming weights for all active UEs in the cell
|
||||
float *sinVal; // Array of the per-UE, per-PRG, per-layer singular values obtained from the SVD of the channel matrix
|
||||
float *avgRatesActUe; // Array of the long-term average data rates of all active UEs in the cell
|
||||
uint16_t *prioWeightActUe; // For priority-based UE selection. Priority weights of all active UEs in the cell
|
||||
int8_t *tbErrLastActUe; // TB decoding error indicators of all active UEs in the cell
|
||||
int8_t *newDataActUe; // Indicators of initial transmission/retransmission for all active UEs in the cell
|
||||
int16_t *allocSolLastTxActUe; // The PRG allocation solution for the last transmissions of all active UEs in the cell
|
||||
int16_t *mcsSelSolLastTxActUe; // MCS selection solution for the last transmissions of all active UEs in the cell
|
||||
int8_t *layerSelSolLastTxActUe; // Layer selection solution for the last transmissions of all active UEs in the cell
|
||||
} cumac_tti_req_bufs_t;
|
||||
|
||||
typedef struct {
|
||||
int32_t cellId;
|
||||
cumac_config_req_payload_t payload;
|
||||
} cumac_config_req_args_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t frame ;
|
||||
uint16_t slot ;
|
||||
cumac_tti_req_payload_t payload;
|
||||
cumac_tti_req_bufs_t *buffers;
|
||||
} cumac_sch_tti_req_args_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t frame ;
|
||||
uint16_t slot ;
|
||||
} cumac_sch_tti_end_args_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t nMaxSchUePerCell;
|
||||
uint16_t allocSolSize;
|
||||
uint8_t nActiveUe;
|
||||
uint32_t taskBitMask; // task bits from the SCH_TTI.request that produced this entry
|
||||
struct timespec tti_req_timestamp;
|
||||
struct timespec tti_end_timestamp;
|
||||
// Response data per slot
|
||||
// Save RNTI when creating sch_tti_req
|
||||
uint16_t *c_rnti;
|
||||
uint16_t *setSchdUePerCellTTI;
|
||||
int16_t *allocSol;
|
||||
int16_t *mcsSelSol;
|
||||
uint8_t *layerSelSol;
|
||||
|
||||
} slot_data_entry_t ;
|
||||
|
||||
#define TASK_BIT(t) (1u << (t))
|
||||
#define CUMAC_UE_RETRANSMISSION 0
|
||||
#define CUMAC_UE_INTIAL_TRANSMISSION 1
|
||||
|
||||
|
||||
|
||||
typedef int (*build_cumac_msg_fn_v_t)(cumac_msg_t type,nv_ipc_msg_t *nvipc_buf, void* args);
|
||||
int l2_build_start_request(cumac_msg_t type, nv_ipc_msg_t *nvipc_buf, void* args);
|
||||
int l2_build_config_request(cumac_msg_t type, nv_ipc_msg_t *nvipc_buf, void* args);
|
||||
int l2_build_sch_tti_request(cumac_msg_t type, nv_ipc_msg_t *nvipc_buf, void* args);
|
||||
int l2_build_tti_end(cumac_msg_t type, nv_ipc_msg_t *nvipc_buf, void* args);
|
||||
void cumac_handle_sch_tti_response(cumac_msg_t type, nv_ipc_msg_t *nvipc_buf, slot_data_entry_t *slot_data) ;
|
||||
#endif // OPENAIRINTERFACE_CUMAC_MSG_FUNCS_H
|
||||
327
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_nvipc.c
Normal file
327
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_nvipc.c
Normal file
@@ -0,0 +1,327 @@
|
||||
//
|
||||
// Created by user on 27 Jan 2026.
|
||||
//
|
||||
|
||||
#include "cumac_nvipc.h"
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <stdatomic.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "nv_ipc_utils.h"
|
||||
#include "cu_mac_api.h"
|
||||
#include "cumac_msg.h"
|
||||
#include "cumac_msg_funcs.h"
|
||||
#include "LOG/log.h"
|
||||
|
||||
#ifdef CUMAC_TIMING_DEBUG
|
||||
|
||||
#endif
|
||||
|
||||
bool recv_task_running = false;
|
||||
static nv_ipc_config_t nv_ipc_config;
|
||||
static bool cumac_start = false;
|
||||
nv_ipc_t* ipc;
|
||||
#define MAX_EVENTS 10
|
||||
#define RECV_BUF_LEN 8192
|
||||
char cpu_buf_recv[RECV_BUF_LEN];
|
||||
/* Log TAG configured in nvlog */
|
||||
static int TAG = (NVLOG_TAG_BASE_NVIPC + 0);
|
||||
static bool waiting_tti_resp = false;
|
||||
static bool has_sent_tti_end = false;
|
||||
static bool has_sent_conf_req = false;
|
||||
slot_data_entry_t *slot_data[MAX_FRAME_NUMBER];
|
||||
pthread_mutex_t cumac_can_send_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_t cumac_can_process_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static uint16_t nMaxSchUePerCell;
|
||||
static uint8_t allocType;
|
||||
static uint16_t nPrbPerPrg;
|
||||
static uint16_t nMaxPrg;
|
||||
|
||||
uint16_t cumac_nMax_schUePerCell() {
|
||||
return nMaxSchUePerCell;
|
||||
}
|
||||
|
||||
uint16_t cumac_nPrbPerPrg() {
|
||||
return nPrbPerPrg;
|
||||
}
|
||||
|
||||
uint16_t cumac_nMaxPrg() {
|
||||
return nMaxPrg;
|
||||
}
|
||||
|
||||
int cumac_get_UE_ID_by_RNTI(const uint16_t frame, const uint16_t slot, const uint16_t rnti) {
|
||||
const slot_data_entry_t *slot_data_entry = get_slot_data(frame,slot);
|
||||
AssertFatal(slot_data_entry, "Entry should not be null!");
|
||||
for (int i = 0; i < slot_data_entry->nActiveUe; ++i) {
|
||||
if (slot_data_entry->c_rnti[i] == rnti) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
slot_data_entry_t* get_slot_data(const uint16_t frame, const uint16_t slot) {
|
||||
return &slot_data[frame][slot];
|
||||
}
|
||||
|
||||
|
||||
bool cumac_can_schedule() {
|
||||
return !waiting_tti_resp;
|
||||
}
|
||||
void cumac_set_can_schedule(bool val) {
|
||||
waiting_tti_resp = !val;
|
||||
}
|
||||
bool cumac_send_msg(cumac_msg_t type, build_cumac_msg_fn_v_t fn, void* args)
|
||||
{
|
||||
if ( has_sent_tti_end || (type == CUMAC_CONFIG_REQUEST && has_sent_conf_req) || (type == CUMAC_SCH_TTI_REQUEST && waiting_tti_resp)) {
|
||||
return false;
|
||||
}
|
||||
if (type == CUMAC_SCH_TTI_REQUEST && !waiting_tti_resp) {
|
||||
waiting_tti_resp = true;
|
||||
cumac_sch_tti_req_args_t *sch_tti_args = args;
|
||||
slot_data_entry_t *slot_data_entry = &slot_data[sch_tti_args->frame][sch_tti_args->slot];
|
||||
slot_data_entry->nActiveUe = sch_tti_args->payload.nActiveUe;
|
||||
slot_data_entry->allocSolSize = sch_tti_args->payload.nActiveUe * 2; // for Type 1 allocation
|
||||
slot_data_entry->nMaxSchUePerCell = nMaxSchUePerCell;
|
||||
slot_data_entry->taskBitMask = sch_tti_args->payload.taskBitMask;
|
||||
}
|
||||
if (type == CUMAC_TTI_END) {
|
||||
has_sent_tti_end = true;
|
||||
}
|
||||
if (type == CUMAC_CONFIG_REQUEST) {
|
||||
has_sent_conf_req = true;
|
||||
printf("Got CONFIG.request, initializing slot data matrix\n");
|
||||
// Determine number of slots per frame from SCS
|
||||
const cumac_config_req_payload_t* conf_req_payload = args;
|
||||
// Save nMax UE and allocation type for later
|
||||
nMaxSchUePerCell = conf_req_payload->nMaxSchUePerCell;
|
||||
allocType = conf_req_payload->allocType;
|
||||
nPrbPerPrg = conf_req_payload->nPrbPerPrg;
|
||||
nMaxPrg = conf_req_payload->nMaxPrg;
|
||||
const uint8_t num_slots = 10 << conf_req_payload->scSpacing;
|
||||
printf("Number of slots per frame: %d\n", num_slots);
|
||||
// Init slot data structure for later use
|
||||
for (int i = 0; i < MAX_FRAME_NUMBER; ++i) {
|
||||
printf("Initializing frame %d\n", i);
|
||||
slot_data[i] = calloc(num_slots, sizeof(slot_data_entry_t));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CUMAC_TIMING_DEBUG
|
||||
printf("message 0x%02x\n", type);
|
||||
struct timespec t1, t2, t3, t4;
|
||||
clock_gettime(CLOCK_REALTIME, &t1);
|
||||
#endif
|
||||
nv_ipc_msg_t send_msg;
|
||||
send_msg.data_pool = NV_IPC_MEMPOOL_CPU_DATA;
|
||||
if (ipc->tx_allocate(ipc, &send_msg, 0) != 0) {
|
||||
NVLOGE(TAG, AERIAL_NVIPC_API_EVENT, "NVIPC memory pool full");
|
||||
return NULL;
|
||||
}
|
||||
#ifdef CUMAC_TIMING_DEBUG
|
||||
clock_gettime(CLOCK_REALTIME, &t2);
|
||||
#endif
|
||||
if (fn(type,&send_msg, args) < 0) {
|
||||
ipc->tx_release(ipc, &send_msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CUMAC_TIMING_DEBUG
|
||||
clock_gettime(CLOCK_REALTIME, &t3);
|
||||
#endif
|
||||
if (ipc->tx_send_msg(ipc, &send_msg) < 0) {
|
||||
ipc->tx_release(ipc, &send_msg);
|
||||
return NULL;
|
||||
}
|
||||
ipc->tx_tti_sem_post(ipc);
|
||||
|
||||
if (type == CUMAC_SCH_TTI_REQUEST) {
|
||||
const cumac_sch_tti_req_args_t *sch_tti_args = args;
|
||||
slot_data_entry_t *slot_data_entry = &slot_data[sch_tti_args->frame][sch_tti_args->slot];
|
||||
clock_gettime(CLOCK_REALTIME, &slot_data_entry->tti_req_timestamp);
|
||||
}
|
||||
if (type == CUMAC_TTI_END) {
|
||||
const cumac_sch_tti_end_args_t *tti_end_args = args;
|
||||
slot_data_entry_t *slot_data_entry = &slot_data[tti_end_args->frame][tti_end_args->slot];
|
||||
clock_gettime(CLOCK_REALTIME, &slot_data_entry->tti_end_timestamp);
|
||||
}
|
||||
|
||||
#ifdef CUMAC_TIMING_DEBUG
|
||||
clock_gettime(CLOCK_REALTIME, &t4);
|
||||
printf("message 0x%02x\n", type);
|
||||
printf("alloc: %ld ns\n", nvlog_timespec_interval(&t1, &t2));
|
||||
printf("build: %ld ns\n", nvlog_timespec_interval(&t2, &t3));
|
||||
printf("send : %ld ns\n", nvlog_timespec_interval(&t3, &t4));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void* epoll_recv_task(void* arg) {
|
||||
struct epoll_event ev, events[MAX_EVENTS];
|
||||
|
||||
printf("Aerial cuMAC recv task start \n");
|
||||
|
||||
int epoll_fd = epoll_create1(0);
|
||||
if (epoll_fd == -1) {
|
||||
printf("%s epoll_create failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ipc_rx_event_fd = ipc->get_fd(ipc);
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.fd = ipc_rx_event_fd;
|
||||
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) {
|
||||
printf("%s epoll_ctl failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
while (1) {
|
||||
if (!recv_task_running) {
|
||||
recv_task_running = true;
|
||||
LOG_D(NR_MAC,"%s: epoll_recv_task started\n", __func__);
|
||||
}
|
||||
LOG_D(NR_MAC,"%s: epoll_wait fd_rx=%d ...\n", __func__, ipc_rx_event_fd);
|
||||
|
||||
int nfds;
|
||||
do {
|
||||
// epoll_wait() may return EINTR when get unexpected signal SIGSTOP from system
|
||||
nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
|
||||
} while (nfds == -1 && errno == EINTR);
|
||||
|
||||
if (nfds < 0) {
|
||||
printf("epoll_wait failed: epoll_fd=%d nfds=%d err=%d - %s\n", epoll_fd, nfds, errno, strerror(errno));
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
for (n = 0; n < nfds; ++n) {
|
||||
if (events[n].data.fd == ipc_rx_event_fd) {
|
||||
ipc->get_value(ipc);
|
||||
nv_ipc_msg_t recv_msg;
|
||||
while (cumac_recv_msg(&recv_msg) == 0)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(epoll_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cumac_nvipc_init() {
|
||||
if (ipc != NULL) {
|
||||
return false;
|
||||
}
|
||||
// Create configuration
|
||||
nv_ipc_config.ipc_transport = NV_IPC_TRANSPORT_SHM;
|
||||
if (set_nv_ipc_default_config(&nv_ipc_config, NV_IPC_MODULE_SECONDARY) < 0) {
|
||||
printf("%s: set configuration failed\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
int cuda_device_id = -1;
|
||||
printf("CUDA device ID configured : %d \n", cuda_device_id);
|
||||
nv_ipc_config.transport_config.shm.cuda_device_id = cuda_device_id;
|
||||
// Create nv_ipc_t instance
|
||||
printf("%s: creating IPC interface with prefix %s\n", __func__, "cumac");
|
||||
strcpy(nv_ipc_config.transport_config.shm.prefix, "cumac");
|
||||
if ((ipc = create_nv_ipc_interface(&nv_ipc_config)) == NULL) {
|
||||
printf("%s: create IPC interface failed\n", __func__);
|
||||
return false;
|
||||
}
|
||||
printf("%s: create IPC interface successful\n", __func__);
|
||||
// setup receiver thread
|
||||
sleep(1);
|
||||
|
||||
mutexinit(cumac_can_send_mutex);
|
||||
mutexinit(cumac_can_process_mutex);
|
||||
// Set initial lock state
|
||||
pthread_mutex_unlock(&cumac_can_send_mutex);
|
||||
pthread_mutex_lock(&cumac_can_process_mutex);
|
||||
|
||||
pthread_t thread_id;
|
||||
pthread_create(&thread_id, NULL, epoll_recv_task, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
int cumac_recv_msg(nv_ipc_msg_t* recv_msg)
|
||||
{
|
||||
if (ipc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
recv_msg->msg_buf = NULL;
|
||||
recv_msg->data_buf = NULL;
|
||||
|
||||
// Allocate buffer for TX message
|
||||
if (ipc->rx_recv_msg(ipc, recv_msg) < 0) {
|
||||
LOG_D(NR_MAC,"%s: no more message available\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_D(NR_MAC,"recv: cell_id=%d msg_id=0x%02X msg_len=%d data_len=%d data_pool=%d\n",
|
||||
recv_msg->cell_id,
|
||||
recv_msg->msg_id,
|
||||
recv_msg->msg_len,
|
||||
recv_msg->data_len,
|
||||
recv_msg->data_pool);
|
||||
|
||||
cumac_handle_rx_msg(recv_msg);
|
||||
|
||||
|
||||
// Release buffer of RX message
|
||||
int release_retval = ipc->rx_release(ipc, recv_msg);
|
||||
if (release_retval != 0) {
|
||||
LOG_D(NR_MAC,"%s error: release RX buffer failed Error: %d\n", __FUNCTION__, release_retval);
|
||||
return release_retval;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cumac_handle_rx_msg(nv_ipc_msg_t* recv_msg) {
|
||||
switch (recv_msg->msg_id) {
|
||||
case CUMAC_CONFIG_RESPONSE:
|
||||
// Send Start request
|
||||
cumac_send_msg(CUMAC_START_REQUEST,l2_build_start_request, NULL);
|
||||
break;
|
||||
case CUMAC_START_RESPONSE:
|
||||
cumac_start = true;
|
||||
break;
|
||||
case CUMAC_SCH_TTI_RESPONSE: {
|
||||
// Handle SCH_TTI.request
|
||||
cumac_sch_tti_resp_t* resp = recv_msg->msg_buf;
|
||||
cumac_handle_sch_tti_response(CUMAC_SCH_TTI_RESPONSE, recv_msg, &slot_data[resp->sfn][resp->slot]);
|
||||
waiting_tti_resp = false;
|
||||
has_sent_tti_end = false;
|
||||
cumac_allow_send();
|
||||
cumac_allow_process();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cumac_wait_to_send() {
|
||||
pthread_mutex_lock(&cumac_can_send_mutex);
|
||||
}
|
||||
|
||||
void cumac_allow_send() {
|
||||
pthread_mutex_unlock(&cumac_can_send_mutex);
|
||||
}
|
||||
|
||||
void cumac_wait_to_process() {
|
||||
pthread_mutex_lock(&cumac_can_process_mutex);
|
||||
}
|
||||
|
||||
void cumac_allow_process() {
|
||||
pthread_mutex_unlock(&cumac_can_process_mutex);
|
||||
}
|
||||
33
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_nvipc.h
Normal file
33
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_nvipc.h
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// Created by user on 27 Jan 2026.
|
||||
//
|
||||
|
||||
#ifndef OPENAIRINTERFACE_CUMAC_NVIPC_H
|
||||
#define OPENAIRINTERFACE_CUMAC_NVIPC_H
|
||||
#include "cumac_msg.h"
|
||||
#include "cumac_msg_funcs.h"
|
||||
#include "PHY/defs_common.h"
|
||||
|
||||
#include <nv_ipc.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern slot_data_entry_t *slot_data[MAX_FRAME_NUMBER];
|
||||
extern pthread_mutex_t cumac_can_send_mutex;
|
||||
extern pthread_mutex_t cumac_can_process_mutex;
|
||||
|
||||
bool cumac_nvipc_init();
|
||||
int cumac_recv_msg(nv_ipc_msg_t* recv_msg);
|
||||
uint16_t cumac_nMax_schUePerCell();
|
||||
uint16_t cumac_nPrbPerPrg();
|
||||
uint16_t cumac_nMaxPrg();
|
||||
int cumac_get_UE_ID_by_RNTI(const uint16_t frame, const uint16_t slot, const uint16_t rnti);
|
||||
slot_data_entry_t* get_slot_data(const uint16_t frame, const uint16_t slot);
|
||||
bool cumac_can_schedule();
|
||||
void cumac_set_can_schedule(bool val);
|
||||
bool cumac_send_msg(cumac_msg_t type,build_cumac_msg_fn_v_t fn, void* args);
|
||||
void cumac_handle_rx_msg(nv_ipc_msg_t* recv_msg);
|
||||
void cumac_wait_to_send();
|
||||
void cumac_allow_send();
|
||||
void cumac_wait_to_process();
|
||||
void cumac_allow_process();
|
||||
#endif // OPENAIRINTERFACE_CUMAC_NVIPC_H
|
||||
137
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_pfm_sort.h
Normal file
137
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_pfm_sort.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _CUMAC_PFM_SORT_DATA_TYPE_
|
||||
#define _CUMAC_PFM_SORT_DATA_TYPE_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// ************************************************** PFM sorting constants **************************************************
|
||||
/// @brief Time slot interval in seconds
|
||||
#define CUMAC_PFM_SLOT_DURATION (0.0005F) // 0.5 ms
|
||||
|
||||
/// @brief Maximum number of cells
|
||||
#define CUMAC_PFM_MAX_NUM_CELL (40U)
|
||||
|
||||
/// @brief Maximum number of UEs for PFM sorting per cell
|
||||
/// @note a maximum of 512 UEs per cell can be supported
|
||||
#define CUMAC_PFM_MAX_NUM_UE_PER_CELL (512U)
|
||||
|
||||
/// @brief Number of QoS types for UL
|
||||
/// @note 0 - ul_gbr_critical, 1 - ul_gbr_non_critical, 2 - ul_ngbr_critical, 3 - ul_ngbr_non_critical, 4 - ul_mbr_non_critical
|
||||
#define CUMAC_PFM_NUM_QOS_TYPES_UL (5U)
|
||||
|
||||
/// @brief Number of QoS types for DL
|
||||
/// @note 0 - dl_gbr_critical, 1 - dl_gbr_non_critical, 2 - dl_ngbr_critical, 3 - dl_ngbr_non_critical, 4 - dl_mbr_non_critical
|
||||
#define CUMAC_PFM_NUM_QOS_TYPES_DL (5U)
|
||||
|
||||
/// @brief Maximum number of LCGs per UE (for UL)
|
||||
#define CUMAC_PFM_MAX_NUM_LCG_PER_UE (4U)
|
||||
|
||||
/// @brief Maximum number of LCs per UE (for DL)
|
||||
#define CUMAC_PFM_MAX_NUM_LC_PER_UE (4U)
|
||||
|
||||
/// @brief Maximum number of output sorted LCs per DL QoS type per cell
|
||||
#define CUMAC_PFM_MAX_NUM_SORTED_LC_PER_QOS (CUMAC_PFM_MAX_NUM_UE_PER_CELL * CUMAC_PFM_MAX_NUM_LC_PER_UE)
|
||||
|
||||
/// @brief Maximum number of output sorted LCGs per UL QoS type per cell
|
||||
#define CUMAC_PFM_MAX_NUM_SORTED_LCG_PER_QOS (CUMAC_PFM_MAX_NUM_UE_PER_CELL * CUMAC_PFM_MAX_NUM_LCG_PER_UE)
|
||||
|
||||
/// @brief Maximum number of scheduled UEs per cell per time slot for both DL and UL
|
||||
#define CUMAC_PFM_MAX_NUM_SCHEDULED_UE_PER_CELL (16U)
|
||||
|
||||
/// @brief IIR alpha for ravg calculation
|
||||
#define CUMAC_PFM_IIR_ALPHA (0.001F)
|
||||
|
||||
#define CUMAC_INVALID_RNTI (0U)
|
||||
|
||||
// ************************************************** PFM sorting request data structures (sent from L2 stack host to cuMAC-CP) **************************************************
|
||||
/// @brief Downlink LC info structure
|
||||
typedef struct {
|
||||
uint32_t tbs_scheduled; // TBS scheduled last time for this LC
|
||||
uint8_t flags; // a collection of flags: flags & 0x01 - is_valid, flags & 0x02 - reset ravg to 1.0
|
||||
uint8_t qos_type; // 0 - dl_gbr_critical, 1 - dl_gbr_non_critical, 2 - dl_ngbr_critical, 3 - dl_ngbr_non_critical, 4 - dl_mbr_non_critical
|
||||
} cumac_pfm_dl_lc_info_t;
|
||||
|
||||
/// @brief Uplink LCG info structure
|
||||
typedef struct {
|
||||
uint32_t tbs_scheduled; // TBS scheduled last time for this LCG
|
||||
uint8_t flags; // a collection of flags: flags & 0x01 - is_valid, flags & 0x02 - reset ravg to 1.0
|
||||
uint8_t qos_type; // 0 - ul_gbr_critical, 1 - ul_gbr_non_critical, 2 - ul_ngbr_critical, 3 - ul_ngbr_non_critical, 4 - ul_mbr_non_critical
|
||||
} cumac_pfm_ul_lcg_info_t;
|
||||
|
||||
/// @brief Per-UE info structure
|
||||
typedef struct {
|
||||
uint32_t rcurrent_dl; // current instantaneous rate of this UE for DL
|
||||
uint32_t rcurrent_ul; // current instantaneous rate of this UE for UL
|
||||
uint16_t rnti; // RNTI of this UE
|
||||
uint16_t id; // cuMAC 0-based UE ID of this UE
|
||||
uint8_t num_layers_dl; // number of layers scheduled for this UE last time for DL
|
||||
uint8_t num_layers_ul; // number of layers scheduled for this UE last time for UL
|
||||
uint8_t flags; // a collection of flags: flags & 0x01 - is_scheduled_dl, flags & 0x02 - is_scheduled_ul
|
||||
cumac_pfm_dl_lc_info_t dl_lc_info[CUMAC_PFM_MAX_NUM_LC_PER_UE]; // LCs configured for this UE for DL
|
||||
cumac_pfm_ul_lcg_info_t ul_lcg_info[CUMAC_PFM_MAX_NUM_LCG_PER_UE]; // LCGs configured for this UE for UL
|
||||
} cumac_pfm_ue_info_t;
|
||||
|
||||
/// @brief PFM sorting request data structure per cell
|
||||
typedef struct {
|
||||
uint16_t num_ue; // number of UEs for the PFM sorting in the current slot for this cell
|
||||
uint8_t num_lc_per_ue; // number of LCs per UE for the PFM sorting in the current slot for this cell
|
||||
uint8_t num_lcg_per_ue; // number of LCGs per UE for the PFM sorting in the current slot for this cell
|
||||
uint16_t num_output_sorted_lc[CUMAC_PFM_NUM_QOS_TYPES_UL + CUMAC_PFM_NUM_QOS_TYPES_DL]; // array of number of output sorted LCs/LCGs per DL/UL QoS type
|
||||
cumac_pfm_ue_info_t ue_info[CUMAC_PFM_MAX_NUM_UE_PER_CELL]; // UE info for the PFM sorting in the current slot for this cell
|
||||
} cumac_pfm_cell_info_t;
|
||||
|
||||
// ************************************************** PFM sorting device output data structures **************************************************
|
||||
/// @brief DL output info structure for the GPU PFM sorting
|
||||
typedef struct {
|
||||
uint16_t rnti; // UE RNTI of this DL info struct
|
||||
uint8_t lc_id; // LC ID of this DL info struct
|
||||
} cumac_pfm_dl_output_info_t;
|
||||
|
||||
/// @brief UL output info structure for the GPU PFM sorting
|
||||
typedef struct {
|
||||
uint16_t rnti; // UE RNTI of this UL info struct
|
||||
uint8_t lcg_id; // LCG ID of this UL info struct
|
||||
} cumac_pfm_ul_output_info_t;
|
||||
|
||||
/// @brief Output info structure for the GPU PFM sorting per cell
|
||||
typedef struct {
|
||||
cumac_pfm_dl_output_info_t dl_gbr_critical[CUMAC_PFM_MAX_NUM_SORTED_LC_PER_QOS]; // array of sorted LCs for the GBR critical QoS type
|
||||
cumac_pfm_dl_output_info_t dl_gbr_non_critical[CUMAC_PFM_MAX_NUM_SORTED_LC_PER_QOS]; // array of sorted LCs for the GBR non-critical QoS type
|
||||
cumac_pfm_dl_output_info_t dl_ngbr_critical[CUMAC_PFM_MAX_NUM_SORTED_LC_PER_QOS]; // array of sorted LCs for the NGBR critical QoS type
|
||||
cumac_pfm_dl_output_info_t dl_ngbr_non_critical[CUMAC_PFM_MAX_NUM_SORTED_LC_PER_QOS]; // array of sorted LCs for the NGBR non-critical QoS type
|
||||
cumac_pfm_dl_output_info_t dl_mbr_non_critical[CUMAC_PFM_MAX_NUM_SORTED_LC_PER_QOS]; // array of sorted LCs for the MBR non-critical QoS type
|
||||
|
||||
cumac_pfm_ul_output_info_t ul_gbr_critical[CUMAC_PFM_MAX_NUM_SORTED_LCG_PER_QOS]; // array of sorted LCGs for the GBR critical QoS type
|
||||
cumac_pfm_ul_output_info_t ul_gbr_non_critical[CUMAC_PFM_MAX_NUM_SORTED_LCG_PER_QOS]; // array of sorted LCGs for the GBR non-critical QoS type
|
||||
cumac_pfm_ul_output_info_t ul_ngbr_critical[CUMAC_PFM_MAX_NUM_SORTED_LCG_PER_QOS]; // array of sorted LCGs for the NGBR critical QoS type
|
||||
cumac_pfm_ul_output_info_t ul_ngbr_non_critical[CUMAC_PFM_MAX_NUM_SORTED_LCG_PER_QOS]; // array of sorted LCGs for the NGBR non-critical QoS type
|
||||
cumac_pfm_ul_output_info_t ul_mbr_non_critical[CUMAC_PFM_MAX_NUM_SORTED_LCG_PER_QOS]; // array of sorted LCGs for the MBR non-critical QoS type
|
||||
} cumac_pfm_output_cell_info_t;
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* _CUMAC_PFM_SORT_DATA_TYPE_ */
|
||||
513
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_test.c
Normal file
513
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_test.c
Normal file
@@ -0,0 +1,513 @@
|
||||
|
||||
|
||||
#include "cumac_test.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <stdatomic.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "nv_utils.h"
|
||||
#include "nv_ipc.h"
|
||||
#include "nv_ipc_utils.h"
|
||||
#include "cu_mac_api.h"
|
||||
#include "cumac_msg_funcs.h"
|
||||
|
||||
/* YAML config path */
|
||||
#define YAML_CONFIG_PATH "./cuMAC-CP/examples/L2IntegrationExample/l2_nvipc.yaml"
|
||||
#define MAX_PATH_LEN (1024)
|
||||
|
||||
nv_ipc_config_t nv_ipc_config;
|
||||
|
||||
bool can_start = false;
|
||||
/* C replacement for std::pair<uint16_t,uint8_t> */
|
||||
typedef struct {
|
||||
uint16_t ue;
|
||||
uint8_t lc;
|
||||
} scheduled_ue_lc;
|
||||
|
||||
/* Log TAG configured in nvlog */
|
||||
static int TAG = (NVLOG_TAG_BASE_NVIPC + 0);
|
||||
|
||||
nv_ipc_t* ipc = NULL;
|
||||
|
||||
#define SENDER_THREAD_CORE (8)
|
||||
#define RECV_THREAD_CORE (9)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Build a TX message
|
||||
static int l2_build_tx_msg(nv_ipc_msg_t* nvipc_buf,
|
||||
uint32_t slot,
|
||||
uint32_t sfn,
|
||||
uint32_t num_ue,
|
||||
struct PFM_UE_INFO* test_data)
|
||||
{
|
||||
if (ipc == NULL || nvipc_buf == NULL) {
|
||||
NVLOGE(TAG, AERIAL_NVIPC_API_EVENT, "%s: ipc or msg buffer is NULL", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct cumac_pfm_tti_req_t* req = (struct cumac_pfm_tti_req_t*)nvipc_buf->msg_buf;
|
||||
uint8_t* data_buf = (uint8_t*)nvipc_buf->data_buf;
|
||||
|
||||
req->header.type_id = CUMAC_SCH_TTI_REQUEST;
|
||||
req->sfn = sfn;
|
||||
req->slot = slot;
|
||||
req->num_ue = num_ue;
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
req->num_output_sorted_lc[i] = MAX_NUM_OUTPUT_SORTED_LC_PER_QOS;
|
||||
}
|
||||
|
||||
uint32_t offset = 0;
|
||||
uint32_t data_size = sizeof(struct PFM_UE_INFO) * num_ue;
|
||||
|
||||
req->offset_ue_info_arr = offset;
|
||||
memcpy(data_buf + offset, test_data, data_size);
|
||||
offset += data_size;
|
||||
|
||||
nvipc_buf->msg_id = CUMAC_SCH_TTI_REQUEST;
|
||||
nvipc_buf->cell_id = 0;
|
||||
nvipc_buf->msg_len = sizeof(struct cumac_pfm_tti_req_t);
|
||||
nvipc_buf->data_len = data_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int test_l2_send_slot(uint32_t slot, uint32_t sfn, uint32_t num_ue, struct PFM_UE_INFO* test_data)
|
||||
{
|
||||
struct timespec t1, t2, t3, t4, t5, t6;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &t1);
|
||||
|
||||
nv_ipc_msg_t send_msg;
|
||||
send_msg.data_pool = NV_IPC_MEMPOOL_CPU_DATA;
|
||||
|
||||
if (ipc->tx_allocate(ipc, &send_msg, 0) != 0) {
|
||||
NVLOGE(TAG, AERIAL_NVIPC_API_EVENT, "NVIPC memory pool full");
|
||||
return -1;
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &t2);
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &t3);
|
||||
if (l2_build_tx_msg(&send_msg, slot, sfn, num_ue, test_data) < 0) {
|
||||
ipc->tx_release(ipc, &send_msg);
|
||||
return -1;
|
||||
}
|
||||
clock_gettime(CLOCK_REALTIME, &t4);
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &t5);
|
||||
if (ipc->tx_send_msg(ipc, &send_msg) < 0) {
|
||||
ipc->tx_release(ipc, &send_msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ipc->tx_tti_sem_post(ipc);
|
||||
clock_gettime(CLOCK_REALTIME, &t6);
|
||||
|
||||
printf("alloc: %ld ns\n", nvlog_timespec_interval(&t1, &t2));
|
||||
printf("build: %ld ns\n", nvlog_timespec_interval(&t3, &t4));
|
||||
printf("send : %ld ns\n", nvlog_timespec_interval(&t5, &t6));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void get_next_slot_timespec(struct timespec* ts, uint64_t interval_nsec)
|
||||
{
|
||||
ts->tv_nsec += interval_nsec;
|
||||
while (ts->tv_nsec >= 1000000000L) {
|
||||
ts->tv_nsec -= 1000000000L;
|
||||
ts->tv_sec++;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// C versions of prepare_slot_data_dl / ul
|
||||
|
||||
void prepare_slot_data_dl(struct PFM_UE_INFO* test_data, scheduled_ue_lc* sched_list, int slot_idx)
|
||||
{
|
||||
if (slot_idx == 0) {
|
||||
for (int i = 0; i < MAX_NUM_SCHEDULED_UE; i++) {
|
||||
sched_list[i].ue = i;
|
||||
sched_list[i].lc = rand() % MAX_NUM_LC;
|
||||
}
|
||||
|
||||
for (int u = 0; u < MAX_NUM_UE; u++) {
|
||||
for (int lc = 0; lc < MAX_NUM_LC; lc++) {
|
||||
struct PFM_DL_LC_INFO* p = &test_data[u].dl_lc_info[lc];
|
||||
p->pfm = 0;
|
||||
p->ravg = 1;
|
||||
p->flags = 0x03;
|
||||
p->qos_type = rand() % 5;
|
||||
p->tbs_scheduled = 0;
|
||||
}
|
||||
test_data[u].num_dl_lcs = MAX_NUM_LC;
|
||||
test_data[u].ambr = 50000000;
|
||||
test_data[u].rcurrent_dl = 1000000 + rand() % 20000000;
|
||||
test_data[u].rnti = u;
|
||||
test_data[u].num_layers_dl = rand() % 2 + 1;
|
||||
test_data[u].flags = 0x07;
|
||||
test_data[u].carrier_id = 0;
|
||||
}
|
||||
} else {
|
||||
for (int u = 0; u < MAX_NUM_UE; u++)
|
||||
for (int lc = 0; lc < MAX_NUM_LC; lc++)
|
||||
test_data[u].dl_lc_info[lc].tbs_scheduled = 0;
|
||||
|
||||
for (int i = 0; i < MAX_NUM_SCHEDULED_UE; i++) {
|
||||
uint16_t ue = sched_list[i].ue;
|
||||
uint8_t lc = sched_list[i].lc;
|
||||
|
||||
test_data[ue].dl_lc_info[lc].tbs_scheduled = (uint32_t)floorf((float)test_data[ue].rcurrent_dl * SLOT_DURATION);
|
||||
|
||||
sched_list[i].ue = (ue + MAX_NUM_SCHEDULED_UE) % MAX_NUM_UE;
|
||||
sched_list[i].lc = rand() % MAX_NUM_LC;
|
||||
}
|
||||
|
||||
for (int u = 0; u < MAX_NUM_UE; u++) {
|
||||
test_data[u].rcurrent_dl = 1000000 + rand() % 20000000;
|
||||
test_data[u].num_layers_dl = rand() % 2 + 1;
|
||||
for (int lc = 0; lc < MAX_NUM_LC; lc++)
|
||||
test_data[u].dl_lc_info[lc].flags = 0x01;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void prepare_slot_data_ul(struct PFM_UE_INFO* test_data, scheduled_ue_lc* sched_list, int slot_idx)
|
||||
{
|
||||
if (slot_idx == 0) {
|
||||
for (int i = 0; i < MAX_NUM_SCHEDULED_UE; i++) {
|
||||
sched_list[i].ue = i;
|
||||
sched_list[i].lc = rand() % MAX_NUM_LCG;
|
||||
}
|
||||
|
||||
for (int u = 0; u < MAX_NUM_UE; u++) {
|
||||
for (int g = 0; g < MAX_NUM_LCG; g++) {
|
||||
struct PFM_UL_LCG_INFO* p = &test_data[u].ul_lcg_info[g];
|
||||
p->pfm = 0;
|
||||
p->ravg = 1;
|
||||
p->flags = 0x03;
|
||||
p->qos_type = rand() % 5;
|
||||
p->tbs_scheduled = 0;
|
||||
}
|
||||
test_data[u].num_ul_lcgs = MAX_NUM_LCG;
|
||||
test_data[u].ambr = 20000000;
|
||||
test_data[u].rcurrent_ul = 500000 + rand() % 10000000;
|
||||
test_data[u].rnti = u;
|
||||
test_data[u].num_layers_ul = rand() % 2 + 1;
|
||||
test_data[u].flags = 0x07;
|
||||
test_data[u].carrier_id = 0;
|
||||
}
|
||||
} else {
|
||||
for (int u = 0; u < MAX_NUM_UE; u++)
|
||||
for (int g = 0; g < MAX_NUM_LCG; g++)
|
||||
test_data[u].ul_lcg_info[g].tbs_scheduled = 0;
|
||||
|
||||
for (int i = 0; i < MAX_NUM_SCHEDULED_UE; i++) {
|
||||
uint16_t ue = sched_list[i].ue;
|
||||
uint8_t g = sched_list[i].lc;
|
||||
|
||||
test_data[ue].ul_lcg_info[g].tbs_scheduled = (uint32_t)floorf((float)test_data[ue].rcurrent_ul * SLOT_DURATION);
|
||||
|
||||
sched_list[i].ue = (ue + MAX_NUM_SCHEDULED_UE) % MAX_NUM_UE;
|
||||
sched_list[i].lc = rand() % MAX_NUM_LCG;
|
||||
}
|
||||
|
||||
for (int u = 0; u < MAX_NUM_UE; u++) {
|
||||
test_data[u].rcurrent_ul = 500000 + rand() % 10000000;
|
||||
test_data[u].num_layers_ul = rand() % 2 + 1;
|
||||
for (int g = 0; g < MAX_NUM_LCG; g++)
|
||||
test_data[u].ul_lcg_info[g].flags = 0x01;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int load_hard_code_config(nv_ipc_config_t* config, int module_type, nv_ipc_transport_t _transport)
|
||||
{
|
||||
// Create configuration
|
||||
config->ipc_transport = _transport;
|
||||
if (set_nv_ipc_default_config(config, module_type) < 0) {
|
||||
printf("%s: set configuration failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int test_cuda_device_id = -1;
|
||||
printf("CUDA device ID configured : %d \n", test_cuda_device_id);
|
||||
config->transport_config.shm.cuda_device_id = test_cuda_device_id;
|
||||
if (test_cuda_device_id >= 0) {
|
||||
config->transport_config.shm.mempool_size[NV_IPC_MEMPOOL_CUDA_DATA].pool_len = 128;
|
||||
config->transport_config.shm.mempool_size[NV_IPC_MEMPOOL_CPU_DATA].pool_len = 1024;
|
||||
config->transport_config.shm.mempool_size[NV_IPC_MEMPOOL_CPU_MSG].pool_len = 4096;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
srand(time(NULL));
|
||||
nvIPC_Init();
|
||||
/*// Want to use transport SHM, type epoll, module secondary (reads the created shm from cuphycontroller)
|
||||
load_hard_code_config(&nv_ipc_config, NV_IPC_MODULE_SECONDARY, NV_IPC_TRANSPORT_SHM);
|
||||
// Create nv_ipc_t instance
|
||||
printf("%s: creating IPC interface with prefix %s\n", __func__, "cumac");
|
||||
strcpy(nv_ipc_config.transport_config.shm.prefix, "cumac");
|
||||
if ((ipc = create_nv_ipc_interface(&nv_ipc_config)) == NULL) {
|
||||
printf("%s: create IPC interface failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
printf("%s: create IPC interface successful\n", __func__);
|
||||
|
||||
|
||||
pthread_t tid;
|
||||
pthread_create(&tid, NULL, l2_blocking_recv_task, NULL);
|
||||
*/
|
||||
sleep(1);
|
||||
|
||||
usleep(1000000);
|
||||
while (!can_start) {
|
||||
sleep(1);
|
||||
}
|
||||
static struct PFM_UE_INFO test_data[MAX_NUM_UE];
|
||||
static scheduled_ue_lc sched_dl[MAX_NUM_SCHEDULED_UE];
|
||||
static scheduled_ue_lc sched_ul[MAX_NUM_SCHEDULED_UE];
|
||||
|
||||
uint16_t sfn = 0, slot = 0;
|
||||
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_nsec = 0;
|
||||
ts.tv_sec++;
|
||||
|
||||
// pthread_setname_np(pthread_self(), "l2_sender");
|
||||
//nv_set_sched_fifo_priority(80);
|
||||
//nv_assign_thread_cpu_core(SENDER_THREAD_CORE);
|
||||
|
||||
for (int i = 0; i < NUM_TIME_SLOTS; i++) {
|
||||
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, NULL);
|
||||
|
||||
prepare_slot_data_dl(test_data, sched_dl, i);
|
||||
prepare_slot_data_ul(test_data, sched_ul, i);
|
||||
|
||||
test_l2_send_slot(slot, sfn, MAX_NUM_UE, test_data);
|
||||
|
||||
slot++;
|
||||
if (slot >= 20) {
|
||||
slot = 0;
|
||||
sfn = (sfn + 1) % 1024;
|
||||
}
|
||||
|
||||
get_next_slot_timespec(&ts, SLOT_INTERVAL_NS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool recv_task_running = false;
|
||||
nv_ipc_config_t nv_ipc_config;
|
||||
#define MAX_EVENTS 10
|
||||
#define RECV_BUF_LEN 8192
|
||||
char cpu_buf_recv[RECV_BUF_LEN];
|
||||
//nv_ipc_t* ipc;
|
||||
typedef int (*build_cumac_msg_fn_v_t)(cumac_msg_t type,nv_ipc_msg_t *nvipc_buf, void * args);
|
||||
bool cumac_test_send_msg(cumac_msg_t type,build_cumac_msg_fn_v_t fn, void* args)
|
||||
{
|
||||
struct timespec t1, t2, t3, t4;
|
||||
clock_gettime(CLOCK_REALTIME, &t1);
|
||||
nv_ipc_msg_t send_msg;
|
||||
send_msg.data_pool = NV_IPC_MEMPOOL_CPU_DATA;
|
||||
if (ipc->tx_allocate(ipc, &send_msg, 0) != 0) {
|
||||
NVLOGE(TAG, AERIAL_NVIPC_API_EVENT, "NVIPC memory pool full");
|
||||
return NULL;
|
||||
}
|
||||
clock_gettime(CLOCK_REALTIME, &t2);
|
||||
if (fn(type,&send_msg, args) < 0) {
|
||||
ipc->tx_release(ipc, &send_msg);
|
||||
return NULL;
|
||||
}
|
||||
clock_gettime(CLOCK_REALTIME, &t3);
|
||||
if (ipc->tx_send_msg(ipc, &send_msg) < 0) {
|
||||
ipc->tx_release(ipc, &send_msg);
|
||||
return NULL;
|
||||
}
|
||||
ipc->tx_tti_sem_post(ipc);
|
||||
clock_gettime(CLOCK_REALTIME, &t4);
|
||||
printf("alloc: %ld ns\n", nvlog_timespec_interval(&t1, &t2));
|
||||
printf("build: %ld ns\n", nvlog_timespec_interval(&t2, &t3));
|
||||
printf("send : %ld ns\n", nvlog_timespec_interval(&t3, &t4));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ipc_handle_rx_msg(nv_ipc_msg_t* recv_msg) {
|
||||
switch (recv_msg->msg_id) {
|
||||
case CUMAC_CONFIG_RESPONSE:
|
||||
// Send Start request
|
||||
cumac_test_send_msg(CUMAC_START_REQUEST,l2_build_start_request, NULL);
|
||||
case CUMAC_START_RESPONSE:
|
||||
can_start = true;
|
||||
|
||||
default:;
|
||||
}
|
||||
}
|
||||
// Always allocate message buffer, but allocate data buffer only when data_len > 0
|
||||
static int cumac_recv_msg(nv_ipc_msg_t* recv_msg)
|
||||
{
|
||||
if (ipc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
recv_msg->msg_buf = NULL;
|
||||
recv_msg->data_buf = NULL;
|
||||
|
||||
// Allocate buffer for TX message
|
||||
if (ipc->rx_recv_msg(ipc, recv_msg) < 0) {
|
||||
printf("%s: no more message available\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("recv: cell_id=%d msg_id=0x%02X msg_len=%d data_len=%d data_pool=%d\n",
|
||||
recv_msg->cell_id,
|
||||
recv_msg->msg_id,
|
||||
recv_msg->msg_len,
|
||||
recv_msg->data_len,
|
||||
recv_msg->data_pool);
|
||||
|
||||
ipc_handle_rx_msg(recv_msg);
|
||||
|
||||
|
||||
// Release buffer of RX message
|
||||
int release_retval = ipc->rx_release(ipc, recv_msg);
|
||||
if (release_retval != 0) {
|
||||
printf("%s error: release RX buffer failed Error: %d\n", __FUNCTION__, release_retval);
|
||||
return release_retval;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void* epoll_recv_task(void* arg)
|
||||
{
|
||||
struct epoll_event ev, events[MAX_EVENTS];
|
||||
|
||||
printf("Aerial cuMAC recv task start \n");
|
||||
|
||||
int epoll_fd = epoll_create1(0);
|
||||
if (epoll_fd == -1) {
|
||||
printf("%s epoll_create failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ipc_rx_event_fd = ipc->get_fd(ipc);
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.fd = ipc_rx_event_fd;
|
||||
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) {
|
||||
printf("%s epoll_ctl failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
while (1) {
|
||||
if (!recv_task_running) {
|
||||
recv_task_running = true;
|
||||
printf("%s: epoll_recv_task started\n", __func__);
|
||||
cumac_config_req_payload_t conf_req_payload;
|
||||
conf_req_payload.harqEnabledInd = 0;
|
||||
conf_req_payload.mcsSelCqi = 0;
|
||||
conf_req_payload.nMaxCell = 1;
|
||||
conf_req_payload.nMaxActUePerCell = 16;
|
||||
conf_req_payload.nMaxSchUePerCell = 1;
|
||||
conf_req_payload.nMaxPrg = 1;
|
||||
conf_req_payload.nPrbPerPrg = 255;
|
||||
conf_req_payload.nMaxBsAnt = 4;
|
||||
conf_req_payload.nMaxUeAnt = 4;
|
||||
conf_req_payload.scSpacing = 1;
|
||||
conf_req_payload.allocType = 1;
|
||||
conf_req_payload.precoderType = 0;
|
||||
conf_req_payload.receiverType = 0;
|
||||
conf_req_payload.colMajChanAccess = 0;
|
||||
conf_req_payload.betaCoeff = 1;
|
||||
conf_req_payload.sinValThr = 0.1f;
|
||||
conf_req_payload.corrThr = 0.1f;
|
||||
conf_req_payload.mcsSelSinrCapThr = 0;
|
||||
conf_req_payload.mcsSelLutType = 1;
|
||||
conf_req_payload.prioWeightStep = 1;
|
||||
cumac_test_send_msg(CUMAC_CONFIG_REQUEST,l2_build_config_request, &conf_req_payload);
|
||||
printf("%s: cumac_send_msg called\n", __func__);
|
||||
}
|
||||
printf("%s: epoll_wait fd_rx=%d ...\n", __func__, ipc_rx_event_fd);
|
||||
|
||||
int nfds;
|
||||
do {
|
||||
// epoll_wait() may return EINTR when get unexpected signal SIGSTOP from system
|
||||
nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
|
||||
} while (nfds == -1 && errno == EINTR);
|
||||
|
||||
if (nfds < 0) {
|
||||
printf("epoll_wait failed: epoll_fd=%d nfds=%d err=%d - %s\n", epoll_fd, nfds, errno, strerror(errno));
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
for (n = 0; n < nfds; ++n) {
|
||||
if (events[n].data.fd == ipc_rx_event_fd) {
|
||||
ipc->get_value(ipc);
|
||||
nv_ipc_msg_t recv_msg;
|
||||
while (cumac_recv_msg(&recv_msg) == 0)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(epoll_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int nvIPC_Init()
|
||||
{
|
||||
// Want to use transport SHM, type epoll, module secondary (reads the created shm from cuphycontroller)
|
||||
load_hard_code_config(&nv_ipc_config, NV_IPC_MODULE_SECONDARY, NV_IPC_TRANSPORT_SHM);
|
||||
// Create nv_ipc_t instance
|
||||
printf("%s: creating IPC interface with prefix %s\n", __func__, "cumac");
|
||||
strcpy(nv_ipc_config.transport_config.shm.prefix, "cumac");
|
||||
if ((ipc = create_nv_ipc_interface(&nv_ipc_config)) == NULL) {
|
||||
printf("%s: create IPC interface failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
printf("%s: create IPC interface successful\n", __func__);
|
||||
sleep(1);
|
||||
pthread_t thread_id;
|
||||
pthread_create(&thread_id, NULL, epoll_recv_task, NULL);
|
||||
//threadCreate(&thread_id, epoll_recv_task, NULL, "nvipc_cumac", 13, OAI_PRIORITY_RT);
|
||||
|
||||
while (!recv_task_running) {
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /*
|
||||
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
|
||||
{
|
||||
exit(1);
|
||||
}*/
|
||||
// int main(int argc, char* argv[])
|
||||
// {
|
||||
// nvIPC_Init();
|
||||
// sleep(300);
|
||||
// return 0;
|
||||
// }
|
||||
26
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_test.h
Normal file
26
openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_test.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// Created by user on 20 Nov 2025.
|
||||
//
|
||||
|
||||
#ifndef OPENAIRINTERFACE_CUMAC_TEST_H
|
||||
#define OPENAIRINTERFACE_CUMAC_TEST_H
|
||||
#include "nv_ipc.h"
|
||||
#include <bits/types/struct_timeval.h>
|
||||
#include "nv_ipc_utils.h"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "cumac_msg.h"
|
||||
#include "cumac_msg_funcs.h"
|
||||
#include <sys/epoll.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "../../../../../common/utils/system.h"
|
||||
#include "../../../../../common/platform_types.h"
|
||||
|
||||
int nvIPC_Init();
|
||||
#endif // OPENAIRINTERFACE_CUMAC_TEST_H
|
||||
@@ -373,6 +373,7 @@ uint16_t get_pm_index(const gNB_MAC_INST *nrmac,
|
||||
int xp_pdsch_antenna_ports);
|
||||
|
||||
int get_mcs_from_SINRx10(int mcs_table, int SINRx10, int Nl);
|
||||
int get_SINRx10_for_mcs(int mcs);
|
||||
uint8_t get_mcs_from_cqi(int mcs_table, int cqi_table, int cqi_idx);
|
||||
|
||||
uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format);
|
||||
|
||||
@@ -794,6 +794,15 @@ typedef struct NR_UE_info {
|
||||
// dedicated BWP is always 1 from the UE's point of view, even if the gNB has multiple BWPs.
|
||||
// The below ID is the "true" (non-consecutive) BWP ID from the gNB's point of view
|
||||
NR_BWP_Id_t local_bwp_id;
|
||||
#ifdef ENABLE_CUMAC
|
||||
// Per-UE state carried from one SCH_TTI.response into the next SCH_TTI.request as feedback
|
||||
struct {
|
||||
bool has_prev_sol; // true once at least one SCH_TTI.response has been processed
|
||||
int16_t alloc_sol[2]; // last [rbStart, rbSize] from allocSol
|
||||
int16_t mcs_sol; // last MCS from mcsSelSol
|
||||
int8_t layer_sol; // last layer count from layerSelSol
|
||||
} cumac_last_sol;
|
||||
#endif
|
||||
} NR_UE_info_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
#include "openair2/PHY_INTERFACE/queue_t.h"
|
||||
#include "utils.h"
|
||||
#include "nfapi/oai_integration/nfapi_pnf.h"
|
||||
|
||||
#ifdef ENABLE_CUMAC
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/integration/cuMAC/cumac_nvipc.h"
|
||||
#endif
|
||||
#define MAX_IF_MODULES 100
|
||||
|
||||
static NR_IF_Module_t *nr_if_inst[MAX_IF_MODULES];
|
||||
@@ -441,6 +443,33 @@ NR_IF_Module_t *NR_IF_Module_init(int Mod_id) {
|
||||
AssertFatal(Mod_id<MAX_MODULES,"Asking for Module %d > %d\n",Mod_id,MAX_IF_MODULES);
|
||||
LOG_D(PHY, "Installing callbacks for IF_Module - UL_indication\n");
|
||||
|
||||
#ifdef ENABLE_CUMAC
|
||||
cumac_nvipc_init();
|
||||
cumac_config_req_payload_t conf_req_payload;
|
||||
conf_req_payload.harqEnabledInd = 0;
|
||||
conf_req_payload.mcsSelCqi = 0;
|
||||
conf_req_payload.nMaxCell = 1;
|
||||
conf_req_payload.nMaxActUePerCell = 16;
|
||||
conf_req_payload.nMaxSchUePerCell = 8;
|
||||
conf_req_payload.nMaxPrg = 106;
|
||||
conf_req_payload.nPrbPerPrg = 1;
|
||||
conf_req_payload.nMaxBsAnt = 1;
|
||||
conf_req_payload.nMaxUeAnt = 1;
|
||||
conf_req_payload.scSpacing = 1;
|
||||
conf_req_payload.allocType = 1;
|
||||
conf_req_payload.precoderType = 0;
|
||||
conf_req_payload.receiverType = 0;
|
||||
conf_req_payload.colMajChanAccess = 0;
|
||||
conf_req_payload.betaCoeff = 1;
|
||||
conf_req_payload.sinValThr = 0.1f;
|
||||
conf_req_payload.corrThr = 0.1f;
|
||||
conf_req_payload.mcsSelSinrCapThr = 0;
|
||||
conf_req_payload.mcsSelLutType = 1;
|
||||
conf_req_payload.prioWeightStep = 1;
|
||||
conf_req_payload.blerTarget = 0.1f; //new parameter
|
||||
cumac_send_msg(CUMAC_CONFIG_REQUEST,l2_build_config_request, &conf_req_payload);
|
||||
#endif
|
||||
|
||||
if (nr_if_inst[Mod_id]==NULL) {
|
||||
nr_if_inst[Mod_id] = (NR_IF_Module_t*)malloc(sizeof(NR_IF_Module_t));
|
||||
memset((void*)nr_if_inst[Mod_id],0,sizeof(NR_IF_Module_t));
|
||||
|
||||
@@ -206,14 +206,14 @@ RUs = (
|
||||
);
|
||||
|
||||
|
||||
rfsimulator :
|
||||
rfsimulator = (
|
||||
{
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs";
|
||||
};
|
||||
});
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
|
||||
Reference in New Issue
Block a user