From 4426fb1a2e53765d855f63df146db0fba6dd721b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 29 Jan 2026 17:26:41 +0100 Subject: [PATCH] RLC data req: Add API to fill multiple RLC PDUs in one TB, use at gNB Adds the API, which will always prepend a 3 byte header before writing a PDU. This can be used to call less often into RLC, and avoid potential locking. The API is used at the gNB DLSCH scheduler. Also, this removes the "overhead" calculation: since we fill the entire TB at once, RLC will leave space for headers as necessary. --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 50 ++++++------------- openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c | 44 ++++++++++++++++ openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h | 16 ++++++ 3 files changed, 75 insertions(+), 35 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 075e46dd52..313260c225 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -50,6 +50,8 @@ #define WORD 32 //#define SIZE_OF_POINTER sizeof (void *) +#define MAX_NUM_DATA_REQ 1024 + int get_dl_tda(const gNB_MAC_INST *nrmac, int slot) { /* we assume that this function is mutex-protected from outside */ @@ -1298,47 +1300,25 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0) continue; // no data for this LC tbs_size_t len = 0; - int lcid_bytes=0; - while (bufEnd-buf > sizeof(NR_MAC_SUBHEADER_LONG) + 1 ) { - // we do not know how much data we will get from RLC, i.e., whether it - // will be longer than 256B or not. Therefore, reserve space for long header, then - // fetch data, then fill real length + + tb_size_t pdu_siz[MAX_NUM_DATA_REQ]; + int num = nr_mac_rlc_multi_data_req(module_id, rnti, true, lcid, bufEnd - buf, (char *)buf, pdu_siz, sizeofArray(pdu_siz)); + DevAssert(num <= sizeofArray(pdu_siz)); + + sdus += num; + int lcid_bytes = 0; + for (int j = 0; j < num; ++j) { NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf; - /* limit requested number of bytes to what preprocessor specified, or - * such that TBS is full */ - const rlc_buffer_occupancy_t ndata = min(sched_ctrl->rlc_status[lcid].bytes_in_buffer, - bufEnd-buf-sizeof(NR_MAC_SUBHEADER_LONG)); - tbs_size_t len = nr_mac_rlc_data_req(module_id, - rnti, - true, - lcid, - ndata, - (char *)buf+sizeof(NR_MAC_SUBHEADER_LONG)); - LOG_D(NR_MAC, - "%4d.%2d RNTI %04x: %d bytes from %s %d (ndata %d, remaining size %ld)\n", - frame, - slot, - rnti, - len, - lcid < 4 ? "DCCH" : "DTCH", - lcid, - ndata, - bufEnd-buf-sizeof(NR_MAC_SUBHEADER_LONG)); - - if (len == 0) - break; - - T(T_GNB_MAC_LCID_DL, T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(lcid), T_INT(len * 8), T_INT(nr_rlc_tx_list_occupancy(rnti, lcid))); header->R = 0; header->F = 1; header->LCID = lcid; - header->L = htons(len); - buf += len+sizeof(NR_MAC_SUBHEADER_LONG); - dlsch_total_bytes += len; - lcid_bytes += len; - sdus += 1; + header->L = htons(pdu_siz[j]); + buf += pdu_siz[j] + sizeof(NR_MAC_SUBHEADER_LONG); + dlsch_total_bytes += pdu_siz[j]; + lcid_bytes += pdu_siz[j]; } + T(T_GNB_MAC_LCID_DL, T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(lcid), T_INT(lcid_bytes), T_INT(nr_rlc_tx_list_occupancy(rnti, lcid))); UE->mac_stats.dl.lc_bytes[lcid] += lcid_bytes; } } else if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) { diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 9710df661e..08741b100b 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -191,6 +191,50 @@ void nr_mac_rlc_data_ind(const module_id_t module_idP, nr_rlc_manager_unlock(nr_rlc_ue_manager); } +int nr_mac_rlc_multi_data_req(const module_id_t module_idP, + const uint16_t ue_id, + const bool gnb_flagP, + const logical_chan_id_t channel_idP, + tb_size_t tb_sizeP, + char *buffer_pP, + tb_size_t *pdu_siz, + int pdu_siz_len) +{ + int ret = 0; + + nr_rlc_manager_lock(nr_rlc_ue_manager); + nr_rlc_ue_t *ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, ue_id); + nr_rlc_entity_t *rb = get_rlc_entity_from_lcid(ue, channel_idP); + + if (rb != NULL) { + rb->set_time(rb, get_nr_rlc_current_time()); + while (tb_sizeP - 3 > 0 && pdu_siz_len > 0) { + // fill PDU in buffer, store size of PDU + pdu_siz[0] = rb->generate_pdu(rb, buffer_pP + 3, tb_sizeP - 3); + if (pdu_siz[0] == 0) + break; + LOG_D(RLC, "MAC PDU created: channel_idP %d len %d\n", channel_idP, pdu_siz[0]); + // reserve header + tb_sizeP -= 3 + pdu_siz[0]; + buffer_pP += 3 + pdu_siz[0]; + pdu_siz++; + pdu_siz_len--; + ret++; + } + } else { + LOG_D(RLC, "MAC PDU failed to get created for channel_idP:%d \n", channel_idP); + ret = 0; + } + + nr_rlc_manager_unlock(nr_rlc_ue_manager); + + if (gnb_flagP) + T(T_ENB_RLC_MAC_DL, T_INT(module_idP), T_INT(ue_id), + T_INT(channel_idP), T_INT(ret)); + + return ret; +} + tbs_size_t nr_mac_rlc_data_req(const module_id_t module_idP, const uint16_t ue_id, const bool gnb_flagP, diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h index 93759ef161..cf5d088834 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h @@ -51,6 +51,22 @@ void nr_mac_rlc_data_ind(const module_id_t module_idP, const bool gnb_flagP, const nr_rlc_data_ind_t *data, int num_data); +/* \brief Fill up to pdu_siz_len RLC PDUs into buffer pointed to by buffer_pP, + * or until tb_sizeP is reached. Each PDU is preceded by 3 bytes (nothing is + * written) that have to be filled by the consumer (with a MAC sub-PDU + * subheader). This function fills up to an entire TB in a single call, unlike + * nr_mac_rlc_data_req() that fills only one RLC PDU in one step. */ +int nr_mac_rlc_multi_data_req(const module_id_t module_idP, + const uint16_t ue_id, + const bool gnb_flagP, + const logical_chan_id_t channel_idP, + const tb_size_t tb_sizeP, + char *buffer_pP, + tb_size_t *pdu_siz, + int pdu_siz_len); +/* \brief Fill one RLC PDU into buffer pointed to by buffer_pP, or until + * tb_sizeP is reached. Note that NO header is prepended (for a MAC sub-PDU + * subheader), and the user of the API has to fill the necessary data. */ tbs_size_t nr_mac_rlc_data_req(const module_id_t module_idP, const uint16_t ue_id, const bool gnb_flagP,