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:
@@ -50,6 +50,8 @@
|
|||||||
#define WORD 32
|
#define WORD 32
|
||||||
//#define SIZE_OF_POINTER sizeof (void *)
|
//#define SIZE_OF_POINTER sizeof (void *)
|
||||||
|
|
||||||
|
#define MAX_NUM_DATA_REQ 1024
|
||||||
|
|
||||||
int get_dl_tda(const gNB_MAC_INST *nrmac, int slot)
|
int get_dl_tda(const gNB_MAC_INST *nrmac, int slot)
|
||||||
{
|
{
|
||||||
/* we assume that this function is mutex-protected from outside */
|
/* 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)
|
if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0)
|
||||||
continue; // no data for this LC tbs_size_t len = 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 ) {
|
tb_size_t pdu_siz[MAX_NUM_DATA_REQ];
|
||||||
// we do not know how much data we will get from RLC, i.e., whether it
|
int num = nr_mac_rlc_multi_data_req(module_id, rnti, true, lcid, bufEnd - buf, (char *)buf, pdu_siz, sizeofArray(pdu_siz));
|
||||||
// will be longer than 256B or not. Therefore, reserve space for long header, then
|
DevAssert(num <= sizeofArray(pdu_siz));
|
||||||
// fetch data, then fill real length
|
|
||||||
|
sdus += num;
|
||||||
|
int lcid_bytes = 0;
|
||||||
|
for (int j = 0; j < num; ++j) {
|
||||||
NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf;
|
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->R = 0;
|
||||||
header->F = 1;
|
header->F = 1;
|
||||||
header->LCID = lcid;
|
header->LCID = lcid;
|
||||||
header->L = htons(len);
|
header->L = htons(pdu_siz[j]);
|
||||||
buf += len+sizeof(NR_MAC_SUBHEADER_LONG);
|
buf += pdu_siz[j] + sizeof(NR_MAC_SUBHEADER_LONG);
|
||||||
dlsch_total_bytes += len;
|
dlsch_total_bytes += pdu_siz[j];
|
||||||
lcid_bytes += len;
|
lcid_bytes += pdu_siz[j];
|
||||||
sdus += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
UE->mac_stats.dl.lc_bytes[lcid] += lcid_bytes;
|
||||||
}
|
}
|
||||||
} else if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) {
|
} else if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) {
|
||||||
|
|||||||
@@ -191,6 +191,50 @@ void nr_mac_rlc_data_ind(const module_id_t module_idP,
|
|||||||
nr_rlc_manager_unlock(nr_rlc_ue_manager);
|
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,
|
tbs_size_t nr_mac_rlc_data_req(const module_id_t module_idP,
|
||||||
const uint16_t ue_id,
|
const uint16_t ue_id,
|
||||||
const bool gnb_flagP,
|
const bool gnb_flagP,
|
||||||
|
|||||||
@@ -51,6 +51,22 @@ void nr_mac_rlc_data_ind(const module_id_t module_idP,
|
|||||||
const bool gnb_flagP,
|
const bool gnb_flagP,
|
||||||
const nr_rlc_data_ind_t *data,
|
const nr_rlc_data_ind_t *data,
|
||||||
int num_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,
|
tbs_size_t nr_mac_rlc_data_req(const module_id_t module_idP,
|
||||||
const uint16_t ue_id,
|
const uint16_t ue_id,
|
||||||
const bool gnb_flagP,
|
const bool gnb_flagP,
|
||||||
|
|||||||
Reference in New Issue
Block a user