Merge remote-tracking branch 'origin/rlc-less-locking' into integration_2026_w11 (!3919)
Reduce number of mutex locking in MAC->RLC direction Currently, the scheduler locks RLC for each operation. Concretely - for RLC status indication (to get amount of bytes per LC), it locks per LC - for RLC indication (UL traffic), it locks for each MAC SDU of which there can be multiple in a TB - for RLC data req (getting data from RLC to put into a transport block), it locks for each LCID and PDU to get. This can have a certain overhead, because we need to re-lock RLC multiple times instead of once (per operation above). In this MR, rework the interfaces such that it is possible to get all information/data in a single lock-unlock cycle, which should also help with "spikes" of scheduler times (in some scenarios, it seems the scheduler takes longer than 0.5ms, and while it's not only locking, re-locking might contribute), and an increase of number of UEs (e.g., instead of doing 3 * N UEs lock cycles for getting status of SRB1, SRB2, DRB1, we do only N times). Concretely, for each UEs RLC status indication, we lock once, only once per LCID when filling a TB (in particular for LCID 4, on high throughput, it might be many times), and only once per UL TB (for the common case of UL data). Minor fixes include the increase of the Aerial VNF thread priority, and reducing the maximum RLC indication size to reduce excessive computation (we can't have 1MB in one TB, it is too much).
This commit is contained in:
@@ -355,7 +355,7 @@ void *epoll_recv_task(void *arg)
|
||||
void create_recv_thread(int8_t affinity)
|
||||
{
|
||||
pthread_t thread_id;
|
||||
threadCreate(&thread_id, epoll_recv_task, NULL, "vnf_nvipc_aerial", affinity, OAI_PRIORITY_RT);
|
||||
threadCreate(&thread_id, epoll_recv_task, NULL, "vnf_nvipc_aerial", affinity, OAI_PRIORITY_RT_MAX);
|
||||
}
|
||||
|
||||
int load_hard_code_config(nv_ipc_config_t *config, int module_type, nv_ipc_transport_t _transport)
|
||||
|
||||
@@ -3898,6 +3898,8 @@ static int nr_ue_validate_successrar(uint8_t *pduP, int32_t pdu_len, NR_UE_MAC_I
|
||||
return n;
|
||||
}
|
||||
|
||||
#define MAX_NUM_DATA_IND 1024
|
||||
|
||||
///////////////////////////////////
|
||||
// brief: nr_ue_process_mac_pdu
|
||||
// function: parsing DL PDU header
|
||||
@@ -3962,6 +3964,9 @@ static void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_
|
||||
pdu_len -= n;
|
||||
}
|
||||
|
||||
nr_rlc_data_ind_t data_ind[MAX_NUM_DATA_IND] = {0};
|
||||
int num_data_ind = 0;
|
||||
|
||||
while (!done && pdu_len > 0){
|
||||
uint16_t mac_len = 0x0000;
|
||||
uint16_t mac_subheader_len = 0x0001; // default to fixed-length subheader = 1-oct
|
||||
@@ -3992,7 +3997,9 @@ static void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_
|
||||
|
||||
if (mac_len > 0) {
|
||||
LOG_DDUMP(NR_MAC, (void *)pduP, mac_subheader_len + mac_len, LOG_DUMP_CHAR, "DL_SCH_LCID_CCCH (e.g. RRCSetup) payload: ");
|
||||
nr_mac_rlc_data_ind(mac->ue_id, mac->ue_id, false, rx_lcid, (char *)(pduP + mac_subheader_len), mac_len);
|
||||
nr_rlc_data_ind_t ind = {.ch = rx_lcid, .buf = pduP + mac_subheader_len, .len = mac_len};
|
||||
data_ind[num_data_ind++] = ind;
|
||||
DevAssert(num_data_ind < MAX_NUM_DATA_IND);
|
||||
}
|
||||
break;
|
||||
case DL_SCH_LCID_TCI_STATE_ACT_UE_SPEC_PDSCH:
|
||||
@@ -4104,15 +4111,20 @@ static void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_
|
||||
// MAC SDU
|
||||
// From values 1 to 32 it equals to the identity of the logical channel
|
||||
case 1 ... 32:
|
||||
if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len))
|
||||
return;
|
||||
if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) {
|
||||
LOG_E(MAC, "get_mac_len(): invalid pdu_len %d (mac_len %d mac_subheader_len %d)\n", pdu_len, mac_len, mac_subheader_len);
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
// discard the received subPDU if RB is suspended
|
||||
if (is_lcid_suspended(mac, rx_lcid)) {
|
||||
LOG_W(NR_MAC, "Received PDU for a suspended RB, corresponding to LCID %d. Dropping it.\n", rx_lcid);
|
||||
break;
|
||||
}
|
||||
LOG_D(NR_MAC, "%4d.%2d : DLSCH -> LCID %d %d bytes\n", frameP, slot, rx_lcid, mac_len);
|
||||
nr_mac_rlc_data_ind(mac->ue_id, mac->ue_id, false, rx_lcid, (char *)(pduP + mac_subheader_len), mac_len);
|
||||
nr_rlc_data_ind_t ind = {.ch = rx_lcid, .buf = pduP + mac_subheader_len, .len = mac_len};
|
||||
data_ind[num_data_ind++] = ind;
|
||||
DevAssert(num_data_ind < MAX_NUM_DATA_IND);
|
||||
break;
|
||||
default:
|
||||
LOG_W(MAC, "unknown lcid %02x\n", rx_lcid);
|
||||
@@ -4120,9 +4132,13 @@ static void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_
|
||||
}
|
||||
pduP += (mac_subheader_len + mac_len);
|
||||
pdu_len -= (mac_subheader_len + mac_len);
|
||||
if (pdu_len < 0)
|
||||
if (pdu_len < 0) {
|
||||
LOG_E(MAC, "[UE %d][%d.%d] nr_ue_process_mac_pdu, residual mac pdu length %d < 0!\n", mac->ue_id, frameP, slot, pdu_len);
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
nr_mac_rlc_data_ind(mac->ue_id, mac->ue_id, false, data_ind, num_data_ind);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1461,23 +1461,24 @@ static void nr_update_sr(NR_UE_MAC_INST_t *mac, bool BSRsent)
|
||||
|
||||
static void nr_update_rlc_buffers_status(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP)
|
||||
{
|
||||
logical_chan_id_t ch[NR_MAX_NUM_LCID] = {0};
|
||||
int n = 0;
|
||||
for (int i = 0; i < mac->lc_ordered_list.count; i++) {
|
||||
nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i];
|
||||
if (lc_info->rb_suspended)
|
||||
continue;
|
||||
int lcid = lc_info->lcid;
|
||||
ch[n++] = lc_info->lcid;
|
||||
}
|
||||
|
||||
mac_rlc_status_resp_t ret[NR_MAX_NUM_LCID] = {0};
|
||||
nr_mac_rlc_status_ind(mac->ue_id, frameP, n, ch, ret);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
const logical_chan_id_t lcid = ch[i];
|
||||
const rlc_buffer_occupancy_t b = ret[i].bytes_in_buffer;
|
||||
NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid);
|
||||
mac_rlc_status_resp_t rlc_status = nr_mac_rlc_status_ind(mac->ue_id, frameP, lcid);
|
||||
if (rlc_status.bytes_in_buffer > 0) {
|
||||
LOG_D(NR_MAC,
|
||||
"[UE %d] LCID %d has %d bytes to transmit at sfn %d.%d\n",
|
||||
mac->ue_id,
|
||||
lcid,
|
||||
rlc_status.bytes_in_buffer,
|
||||
frameP,
|
||||
slotP);
|
||||
}
|
||||
lc_sched_info->LCID_buffer_remain = rlc_status.bytes_in_buffer;
|
||||
if (b > 0)
|
||||
LOG_D(NR_MAC, "[UE %d] LCID %d has %d bytes to transmit at sfn %d.%d\n", mac->ue_id, lcid, b, frameP, slotP);
|
||||
lc_sched_info->LCID_buffer_remain = b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1699,21 +1699,23 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP,
|
||||
/* get the PID of a HARQ process awaiting retrnasmission, or -1 otherwise */
|
||||
int current_harq_pid = sched_ctrl->retrans_dl_harq.head;
|
||||
|
||||
logical_chan_id_t lcid = DL_SCH_LCID_CCCH;
|
||||
logical_chan_id_t lcid = 0;
|
||||
if (current_harq_pid < 0) {
|
||||
// Check for data on SRB0 (RRCSetup)
|
||||
mac_rlc_status_resp_t srb_status = nr_mac_rlc_status_ind(UE->rnti, frameP, lcid);
|
||||
const logical_chan_id_t lcid_l[2] = {DL_SCH_LCID_CCCH, DL_SCH_LCID_DCCH};
|
||||
mac_rlc_status_resp_t stat[2];
|
||||
nr_mac_rlc_status_ind(UE->rnti, frameP, 2, lcid_l, stat);
|
||||
|
||||
if (srb_status.bytes_in_buffer == 0) {
|
||||
lcid = DL_SCH_LCID_DCCH;
|
||||
// Check for data on SRB1 (RRCReestablishment, RRCReconfiguration)
|
||||
srb_status = nr_mac_rlc_status_ind(UE->rnti, frameP, lcid);
|
||||
if (stat[0].bytes_in_buffer > 0) {
|
||||
// some data in SRB0 (likely RRCSetup)
|
||||
mac_sdu_length = stat[0].bytes_in_buffer;
|
||||
lcid = lcid_l[0];
|
||||
} else if (stat[1].bytes_in_buffer > 0) {
|
||||
// some data in SRB1 (likely RRCReestablishmnt/RRCReconfiguration)
|
||||
mac_sdu_length = stat[1].bytes_in_buffer;
|
||||
lcid = lcid_l[1];
|
||||
} else {
|
||||
return; // no data to forward
|
||||
}
|
||||
|
||||
// Need to wait until data for Msg4 is ready
|
||||
if (srb_status.bytes_in_buffer == 0)
|
||||
return;
|
||||
mac_sdu_length = srb_status.bytes_in_buffer;
|
||||
}
|
||||
|
||||
const int n_slots_frame = nr_mac->frame_structure.numb_slots_frame;
|
||||
|
||||
@@ -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 */
|
||||
@@ -326,31 +328,38 @@ static uint32_t update_dlsch_buffer(frame_t frame, slot_t slot, NR_UE_info_t *UE
|
||||
sched_ctrl->num_total_bytes = 0;
|
||||
sched_ctrl->dl_pdus_total = 0;
|
||||
|
||||
logical_chan_id_t ch[NR_MAX_NUM_LCID] = {0};
|
||||
int n = 0;
|
||||
/* loop over all activated logical channels */
|
||||
for (int i = 0; i < seq_arr_size(&sched_ctrl->lc_config); ++i) {
|
||||
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, i);
|
||||
const int lcid = c->lcid;
|
||||
const uint16_t rnti = UE->rnti;
|
||||
LOG_D(NR_MAC, "UE %x: LCID %d\n", rnti, lcid);
|
||||
memset(&sched_ctrl->rlc_status[lcid], 0, sizeof(sched_ctrl->rlc_status[lcid]));
|
||||
if (c->suspended)
|
||||
FOR_EACH_SEQ_ARR(const nr_lc_config_t *, c, &sched_ctrl->lc_config ) {
|
||||
logical_chan_id_t lcid = c->lcid;
|
||||
if (c->suspended || (lcid == DL_SCH_LCID_DTCH && nr_timer_is_active(&sched_ctrl->transm_interrupt))) {
|
||||
memset(&sched_ctrl->rlc_status[lcid], 0, sizeof(sched_ctrl->rlc_status[lcid]));
|
||||
continue;
|
||||
if (lcid == DL_SCH_LCID_DTCH && nr_timer_is_active(&sched_ctrl->transm_interrupt))
|
||||
continue;
|
||||
sched_ctrl->rlc_status[lcid] = nr_mac_rlc_status_ind(rnti, frame, lcid);
|
||||
}
|
||||
ch[n++] = lcid;
|
||||
}
|
||||
|
||||
if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0)
|
||||
mac_rlc_status_resp_t ret[NR_MAX_NUM_LCID] = {0};
|
||||
nr_mac_rlc_status_ind(UE->rnti, frame, n, ch, ret);
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
logical_chan_id_t lcid = ch[i];
|
||||
|
||||
if (ret[i].bytes_in_buffer == 0)
|
||||
continue;
|
||||
|
||||
sched_ctrl->rlc_status[lcid] = ret[i];
|
||||
sched_ctrl->dl_pdus_total += sched_ctrl->rlc_status[lcid].pdus_in_buffer;
|
||||
sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer;
|
||||
LOG_D(MAC,
|
||||
"%4d.%2d UE %04x LCID %d status: %d bytes, total buffer %d bytes %d PDUs\n",
|
||||
"%4d.%2d UE %04x LCID %d status: %d bytes, %d PDUs, total buffer %d bytes %d PDUs\n",
|
||||
frame,
|
||||
slot,
|
||||
UE->rnti,
|
||||
lcid,
|
||||
sched_ctrl->rlc_status[lcid].bytes_in_buffer,
|
||||
ret[i].bytes_in_buffer,
|
||||
ret[i].pdus_in_buffer,
|
||||
sched_ctrl->num_total_bytes,
|
||||
sched_ctrl->dl_pdus_total);
|
||||
}
|
||||
@@ -1289,47 +1298,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) {
|
||||
|
||||
@@ -144,11 +144,11 @@ void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch)
|
||||
sched_ctrl->num_total_bytes = 0;
|
||||
DevAssert(seq_arr_size(&sched_ctrl->lc_config) == 1);
|
||||
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, 0);
|
||||
const int lcid = c->lcid;
|
||||
const logical_chan_id_t lcid = c->lcid;
|
||||
const uint16_t rnti = UE->rnti;
|
||||
/* update sched_ctrl->num_total_bytes so that postprocessor schedules data,
|
||||
* if available */
|
||||
sched_ctrl->rlc_status[lcid] = nr_mac_rlc_status_ind(rnti, frame, lcid);
|
||||
nr_mac_rlc_status_ind(rnti, frame, 1, &lcid, &sched_ctrl->rlc_status[lcid]);
|
||||
sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer;
|
||||
|
||||
int CCEIndex = get_cce_index(mac,
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "LAYER2/nr_rlc/nr_rlc_oai_api.h"
|
||||
|
||||
//#define SRS_IND_DEBUG
|
||||
#define MAX_NUM_DATA_IND 1024
|
||||
|
||||
/* \brief Get the number of UL TDAs that could be used in slot, reachable
|
||||
* via specific k2. The output parameter first_idx is a pointer to the first
|
||||
@@ -395,6 +396,8 @@ static int nr_process_mac_pdu(instance_t module_idP,
|
||||
log_dump(NR_MAC, pduP, pdu_len, LOG_DUMP_CHAR, "\n");
|
||||
#endif
|
||||
|
||||
nr_rlc_data_ind_t data_ind[MAX_NUM_DATA_IND] = {0};
|
||||
int num_data_ind = 0;
|
||||
while (pdu_len > 0) {
|
||||
uint16_t mac_len = 0;
|
||||
uint8_t lcid = 0;
|
||||
@@ -416,7 +419,7 @@ static int nr_process_mac_pdu(instance_t module_idP,
|
||||
for (int i = 0; i < print_len; i++)
|
||||
printf("%02x ", pduP[i]);
|
||||
printf("\n");
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_D(NR_MAC,
|
||||
@@ -456,7 +459,9 @@ static int nr_process_mac_pdu(instance_t module_idP,
|
||||
}
|
||||
|
||||
if (prepare_initial_ul_rrc_message(RC.nrmac[module_idP], UE)) {
|
||||
nr_mac_rlc_data_ind(module_idP, UE->rnti, true, 0, (char *)(pduP + mac_subheader_len), mac_len);
|
||||
nr_rlc_data_ind_t ind = {.ch = 0, .buf = pduP + mac_subheader_len, .len = mac_len};
|
||||
data_ind[num_data_ind++] = ind;
|
||||
DevAssert(num_data_ind < MAX_NUM_DATA_IND);
|
||||
} else {
|
||||
LOG_E(NR_MAC, "prepare_initial_ul_rrc_message() returned false, cannot forward CCCH message\n");
|
||||
}
|
||||
@@ -475,7 +480,9 @@ static int nr_process_mac_pdu(instance_t module_idP,
|
||||
if (!srbc || srbc->suspended) {
|
||||
LOG_I(NR_MAC, "RNTI %04x LCID %d: ignoring %d bytes\n", UE->rnti, lcid, mac_len);
|
||||
} else {
|
||||
nr_mac_rlc_data_ind(module_idP, UE->rnti, true, lcid, (char *)(pduP + mac_subheader_len), mac_len);
|
||||
nr_rlc_data_ind_t ind = {.ch = lcid, .buf = pduP + mac_subheader_len, .len = mac_len};
|
||||
data_ind[num_data_ind++] = ind;
|
||||
DevAssert(num_data_ind < MAX_NUM_DATA_IND);
|
||||
|
||||
UE->mac_stats.ul.total_sdu_bytes += mac_len;
|
||||
UE->mac_stats.ul.lc_bytes[lcid] += mac_len;
|
||||
@@ -499,7 +506,9 @@ static int nr_process_mac_pdu(instance_t module_idP,
|
||||
} else {
|
||||
UE->mac_stats.ul.lc_bytes[lcid] += mac_len;
|
||||
|
||||
nr_mac_rlc_data_ind(module_idP, UE->rnti, true, lcid, (char *)(pduP + mac_subheader_len), mac_len);
|
||||
nr_rlc_data_ind_t ind = {.ch = lcid, .buf = pduP + mac_subheader_len, .len = mac_len};
|
||||
data_ind[num_data_ind++] = ind;
|
||||
DevAssert(num_data_ind < MAX_NUM_DATA_IND);
|
||||
|
||||
sdus += 1;
|
||||
/* Updated estimated buffer when receiving data */
|
||||
@@ -530,7 +539,7 @@ static int nr_process_mac_pdu(instance_t module_idP,
|
||||
case UL_SCH_LCID_SINGLE_ENTRY_PHR:
|
||||
if (harq_pid < 0) {
|
||||
LOG_E(NR_MAC, "Invalid HARQ PID %d\n", harq_pid);
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
NR_sched_pusch_t *sched_pusch = &sched_ctrl->ul_harq_processes[harq_pid].sched_pusch;
|
||||
|
||||
@@ -605,14 +614,18 @@ static int nr_process_mac_pdu(instance_t module_idP,
|
||||
|
||||
case UL_SCH_LCID_PADDING:
|
||||
// End of MAC PDU, can ignore the rest.
|
||||
return 0;
|
||||
// 38.321 Sec 6.1.5: "Presence and length of padding is implicit based
|
||||
// on TB size, size of MAC subPDU(s)."
|
||||
mac_len = pdu_len - mac_subheader_len; // will make pdu_len go to 0
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E(NR_MAC, "RNTI %0x [%d.%d], received unknown MAC header (LCID = 0x%02x)\n", UE->rnti, frameP, slot, lcid);
|
||||
return -1;
|
||||
mac_len = pdu_len - mac_subheader_len; // will make pdu_len go to 0
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
|
||||
if (lcid < 45 || lcid == 52 || lcid == 63) {
|
||||
LOG_I(NR_MAC, "In %s: dumping UL MAC SDU sub-header with length %d (LCID = 0x%02x):\n", __func__, mac_subheader_len, lcid);
|
||||
@@ -629,6 +642,8 @@ static int nr_process_mac_pdu(instance_t module_idP,
|
||||
pdu_len -= (mac_subheader_len + mac_len);
|
||||
}
|
||||
|
||||
nr_mac_rlc_data_ind(module_idP, UE->rnti, true, data_ind, num_data_ind);
|
||||
|
||||
UE->mac_stats.ul.num_mac_sdu += sdus;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -163,12 +163,12 @@ void nr_rlc_release_entity(int ue_id, logical_chan_id_t channel_id)
|
||||
void nr_mac_rlc_data_ind(const module_id_t module_idP,
|
||||
const uint16_t ue_id,
|
||||
const bool gnb_flagP,
|
||||
const logical_chan_id_t channel_idP,
|
||||
char *buffer_pP,
|
||||
const tb_size_t tb_sizeP)
|
||||
const nr_rlc_data_ind_t *data,
|
||||
int num_data)
|
||||
{
|
||||
if (gnb_flagP)
|
||||
T(T_ENB_RLC_MAC_UL, T_INT(module_idP), T_INT(ue_id), T_INT(channel_idP), T_INT(tb_sizeP));
|
||||
for (int i = 0; i < num_data; ++i)
|
||||
T(T_ENB_RLC_MAC_UL, T_INT(module_idP), T_INT(ue_id), T_INT(data[i].ch), T_INT(data[i].len));
|
||||
|
||||
nr_rlc_manager_lock(nr_rlc_ue_manager);
|
||||
nr_rlc_ue_t *ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, ue_id);
|
||||
@@ -176,20 +176,65 @@ void nr_mac_rlc_data_ind(const module_id_t module_idP,
|
||||
if(ue == NULL)
|
||||
LOG_I(RLC, "RLC instance for the given UE was not found \n");
|
||||
|
||||
nr_rlc_entity_t *rb = get_rlc_entity_from_lcid(ue, channel_idP);
|
||||
|
||||
if (rb != NULL) {
|
||||
LOG_D(RLC, "RB found! (channel ID %d) \n", channel_idP);
|
||||
rb->set_time(rb, get_nr_rlc_current_time());
|
||||
rb->recv_pdu(rb, buffer_pP, tb_sizeP);
|
||||
} else {
|
||||
LOG_E(RLC, "Fatal: no RB found (channel ID %d UE ID %d)\n", channel_idP, ue_id);
|
||||
// exit(1);
|
||||
for (int i = 0; i < num_data; ++i) {
|
||||
logical_chan_id_t ch = data[i].ch;
|
||||
nr_rlc_entity_t *rb = get_rlc_entity_from_lcid(ue, ch);
|
||||
if (rb != NULL) {
|
||||
LOG_D(RLC, "RB found! (channel ID %d) \n", ch);
|
||||
rb->set_time(rb, get_nr_rlc_current_time());
|
||||
rb->recv_pdu(rb, (char *)data[i].buf, data[i].len);
|
||||
} else {
|
||||
LOG_W(RLC, "no RB found (channel ID %d UE ID %d)\n", ch, ue_id);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -223,12 +268,10 @@ tbs_size_t nr_mac_rlc_data_req(const module_id_t module_idP,
|
||||
return ret;
|
||||
}
|
||||
|
||||
mac_rlc_status_resp_t nr_mac_rlc_status_ind(const uint16_t ue_id, const frame_t frame, const logical_chan_id_t channel_idP)
|
||||
static mac_rlc_status_resp_t _nr_rlc_status_ind(nr_rlc_ue_t *ue, frame_t frame, logical_chan_id_t channel_idP)
|
||||
{
|
||||
mac_rlc_status_resp_t ret;
|
||||
|
||||
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) {
|
||||
@@ -243,12 +286,10 @@ mac_rlc_status_resp_t nr_mac_rlc_status_ind(const uint16_t ue_id, const frame_t
|
||||
ret.bytes_in_buffer = buf_stat.status_size + buf_stat.retx_size + buf_stat.tx_size;
|
||||
} else {
|
||||
if (!(frame % 128) || channel_idP == 0) //to suppress this warning message
|
||||
LOG_W(RLC, "Radio Bearer (channel ID %d) is NULL for UE %d\n", channel_idP, ue_id);
|
||||
LOG_W(RLC, "Radio Bearer (channel ID %d) is NULL for UE %d\n", channel_idP, ue->ue_id);
|
||||
ret.bytes_in_buffer = 0;
|
||||
}
|
||||
|
||||
nr_rlc_manager_unlock(nr_rlc_ue_manager);
|
||||
|
||||
ret.pdus_in_buffer = 0;
|
||||
/* TODO: creation time may be important (unit: frame, as it seems) */
|
||||
ret.head_sdu_creation_time = 0;
|
||||
@@ -257,6 +298,16 @@ mac_rlc_status_resp_t nr_mac_rlc_status_ind(const uint16_t ue_id, const frame_t
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nr_mac_rlc_status_ind(uint16_t ue_id, frame_t frame, int n_ch, const logical_chan_id_t *ch, mac_rlc_status_resp_t *ret)
|
||||
{
|
||||
nr_rlc_manager_lock(nr_rlc_ue_manager);
|
||||
nr_rlc_ue_t *ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, ue_id);
|
||||
for (int i = 0; i < n_ch; ++i) {
|
||||
ret[i] = _nr_rlc_status_ind(ue, frame, ch[i]);
|
||||
}
|
||||
nr_rlc_manager_unlock(nr_rlc_ue_manager);
|
||||
}
|
||||
|
||||
rlc_op_status_t nr_rlc_data_req(const protocol_ctxt_t *const ctxt_pP,
|
||||
const srb_flag_t srb_flagP,
|
||||
const rb_id_t rb_idP,
|
||||
@@ -1022,7 +1073,7 @@ bool nr_rlc_get_statistics(int ue_id, int srb_flag, int rb_id, nr_rlc_statistics
|
||||
|
||||
// Patch buffer status using OAI results (no need to change anything in the RB)
|
||||
// rb->set_time(rb, get_nr_rlc_current_time());
|
||||
nr_rlc_entity_buffer_status_t oai_stat = rb->buffer_status(rb, 1000*1000);
|
||||
nr_rlc_entity_buffer_status_t oai_stat = rb->buffer_status(rb, 256 * 1000);
|
||||
out->rxbuf_occ_bytes = oai_stat.status_size;
|
||||
out->txbuf_occ_bytes = oai_stat.tx_size + oai_stat.retx_size;
|
||||
} else {
|
||||
|
||||
@@ -41,12 +41,32 @@ struct NR_RLC_Config;
|
||||
struct NR_LogicalChannelConfig;
|
||||
|
||||
int nr_rlc_module_init(nr_rlc_op_mode_t mode);
|
||||
typedef struct nr_rlc_data_ind {
|
||||
logical_chan_id_t ch;
|
||||
uint8_t *buf;
|
||||
tb_size_t len;
|
||||
} nr_rlc_data_ind_t;
|
||||
void nr_mac_rlc_data_ind(const module_id_t module_idP,
|
||||
const uint16_t ue_id,
|
||||
const bool gnb_flagP,
|
||||
const logical_chan_id_t channel_idP,
|
||||
char *buffer_pP,
|
||||
const tb_size_t tb_sizeP);
|
||||
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,
|
||||
@@ -59,7 +79,7 @@ rlc_op_status_t nr_rlc_data_req(const protocol_ctxt_t *const ctxt_pP,
|
||||
const mui_t muiP,
|
||||
sdu_size_t sdu_sizeP,
|
||||
uint8_t *sdu_pP);
|
||||
mac_rlc_status_resp_t nr_mac_rlc_status_ind(const uint16_t ue_id, const frame_t frame, const logical_chan_id_t channel_idP);
|
||||
void nr_mac_rlc_status_ind(uint16_t ue_id, frame_t frame, int n_ch, const logical_chan_id_t *ch, mac_rlc_status_resp_t *ret);
|
||||
|
||||
void nr_rlc_add_srb(int ue_id, int srb_id, const NR_RLC_BearerConfig_t *rlc_BearerConfig);
|
||||
void nr_rlc_add_drb(int ue_id, int drb_id, const NR_RLC_BearerConfig_t *rlc_BearerConfig);
|
||||
|
||||
Reference in New Issue
Block a user