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.
This commit is contained in:
Robert Schmidt
2026-01-29 17:26:41 +01:00
parent c0a78e6c47
commit 4426fb1a2e
3 changed files with 75 additions and 35 deletions

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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,