Commit 18bc8c7f authored by Robert Schmidt's avatar Robert Schmidt Committed by ChiehChun

Reorder DLSCH MAC PDU logic

Before this commit, the DLSCH scheduler would construct the MAC PDU by
reading RLC data into a memory on the stack, and then construct the PDU
with CEs first. There are at least two problems:
- we need to keep track of the exact number of bytes of CEs (cumbersome)
  to calculate the number of MAC SDUs to include
- we needlessly copy data around.

This commit does the following instead:
- write all CEs first (no need of keeping track of this in DLSCH and a
  separate function)
- then read MAC SDUs directly into nFAPI as much as possible or
  necessary, without recopying
parent 1b25b2b1
...@@ -56,27 +56,22 @@ ...@@ -56,27 +56,22 @@
#define WORD 32 #define WORD 32
//#define SIZE_OF_POINTER sizeof (void *) //#define SIZE_OF_POINTER sizeof (void *)
int nr_generate_dlsch_pdu(module_id_t module_idP, // Compute and write all MAC CEs and subheaders, and return number of written
NR_UE_sched_ctrl_t *ue_sched_ctl, // bytes
unsigned char *sdus_payload, int nr_write_ce_dlsch_pdu(module_id_t module_idP,
const NR_UE_sched_ctrl_t *ue_sched_ctl,
unsigned char *mac_pdu, unsigned char *mac_pdu,
unsigned char num_sdus,
unsigned short *sdu_lengths,
unsigned char *sdu_lcids,
unsigned char drx_cmd, unsigned char drx_cmd,
unsigned char *ue_cont_res_id, unsigned char *ue_cont_res_id)
unsigned short post_padding) { {
gNB_MAC_INST *gNB = RC.nrmac[module_idP]; gNB_MAC_INST *gNB = RC.nrmac[module_idP];
NR_MAC_SUBHEADER_FIXED *mac_pdu_ptr = (NR_MAC_SUBHEADER_FIXED *) mac_pdu; NR_MAC_SUBHEADER_FIXED *mac_pdu_ptr = (NR_MAC_SUBHEADER_FIXED *) mac_pdu;
unsigned char *dlsch_buffer_ptr = sdus_payload;
uint8_t last_size = 0; uint8_t last_size = 0;
int offset = 0, mac_ce_size, i, timing_advance_cmd, tag_id = 0; int offset = 0, mac_ce_size, i, timing_advance_cmd, tag_id = 0;
// MAC CEs // MAC CEs
uint8_t mac_header_control_elements[16], *ce_ptr; uint8_t mac_header_control_elements[16], *ce_ptr;
ce_ptr = &mac_header_control_elements[0]; ce_ptr = &mac_header_control_elements[0];
// 1) Compute MAC CE and related subheaders
// DRX command subheader (MAC CE size 0) // DRX command subheader (MAC CE size 0)
if (drx_cmd != 255) { if (drx_cmd != 255) {
mac_pdu_ptr->R = 0; mac_pdu_ptr->R = 0;
...@@ -301,42 +296,6 @@ int nr_generate_dlsch_pdu(module_id_t module_idP, ...@@ -301,42 +296,6 @@ int nr_generate_dlsch_pdu(module_id_t module_idP,
} }
} }
// 2) Generation of DLSCH MAC subPDUs including subheaders and MAC SDUs
for (i = 0; i < num_sdus; i++) {
if (sdu_lengths[i] < 256) {
((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->R = 0;
((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->F = 0;
((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->LCID = sdu_lcids[i];
((NR_MAC_SUBHEADER_SHORT *) mac_pdu_ptr)->L = (unsigned char) sdu_lengths[i];
last_size = 2;
} else {
((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->R = 0;
((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->F = 1;
((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->LCID = sdu_lcids[i];
((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->L1 = ((unsigned short) sdu_lengths[i] >> 8) & 0xff;
((NR_MAC_SUBHEADER_LONG *) mac_pdu_ptr)->L2 = (unsigned short) sdu_lengths[i] & 0xff;
last_size = 3;
}
mac_pdu_ptr += last_size;
// 3) cycle through SDUs, compute each relevant and place dlsch_buffer in
memcpy((void *) mac_pdu_ptr, (void *) dlsch_buffer_ptr, sdu_lengths[i]);
dlsch_buffer_ptr += sdu_lengths[i];
mac_pdu_ptr += sdu_lengths[i];
LOG_D(MAC, "Generate DLSCH header num sdu %d len header %d len sdu %d -> offset %ld\n", num_sdus, last_size, sdu_lengths[i], (unsigned char *)mac_pdu_ptr - mac_pdu);
}
// 4) Compute final offset for padding
if (post_padding > 0) {
((NR_MAC_SUBHEADER_FIXED *) mac_pdu_ptr)->R = 0;
((NR_MAC_SUBHEADER_FIXED *) mac_pdu_ptr)->LCID = DL_SCH_LCID_PADDING;
mac_pdu_ptr++;
LOG_D(MAC, "Generate Padding -> offset %ld\n", (unsigned char *)mac_pdu_ptr - mac_pdu);
} else {
// no MAC subPDU with padding
}
// compute final offset // compute final offset
offset = ((unsigned char *) mac_pdu_ptr - mac_pdu); offset = ((unsigned char *) mac_pdu_ptr - mac_pdu);
//printf("Offset %d \n", ((unsigned char *) mac_pdu_ptr - mac_pdu)); //printf("Offset %d \n", ((unsigned char *) mac_pdu_ptr - mac_pdu));
...@@ -586,7 +545,7 @@ void nr_schedule_ue_spec(module_id_t module_id, ...@@ -586,7 +545,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
const int nrOfLayers = 1; const int nrOfLayers = 1;
const uint16_t R = nr_get_code_rate_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx); const uint16_t R = nr_get_code_rate_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx);
const uint8_t Qm = nr_get_Qm_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx); const uint8_t Qm = nr_get_Qm_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx);
const uint32_t TBS = uint32_t TBS =
nr_compute_tbs(nr_get_Qm_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx), nr_compute_tbs(nr_get_Qm_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx),
nr_get_code_rate_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx), nr_get_code_rate_dl(sched_ctrl->mcs, sched_ctrl->mcsTableIdx),
sched_ctrl->rbSize, sched_ctrl->rbSize,
...@@ -836,108 +795,105 @@ void nr_schedule_ue_spec(module_id_t module_id, ...@@ -836,108 +795,105 @@ void nr_schedule_ue_spec(module_id_t module_id,
harq->ndi); harq->ndi);
} else { /* initial transmission */ } else { /* initial transmission */
/* reserve space for timing advance of UE if necessary, const int ntx_req = gNB_mac->TX_req[CC_id].Number_of_PDUs;
* nr_generate_dlsch_pdu() checks for ta_apply and add TA CE if necessary */ nfapi_nr_pdu_t *tx_req = &gNB_mac->TX_req[CC_id].pdu_list[ntx_req];
const int ta_len = (sched_ctrl->ta_apply) ? 2 : 0; tx_req->PDU_length = TBS;
tx_req->PDU_index = pduindex;
/* Get RLC data */ tx_req->num_TLV = 1;
int header_length_total = 0; tx_req->TLVs[0].length = TBS + 2;
int header_length_last = 0; /* pointer to directly generate the PDU into the nFAPI structure */
int sdu_length_total = 0; uint8_t *buf = (uint8_t *) tx_req->TLVs[0].value.direct;
int num_sdus = 0; gNB_mac->TX_req[CC_id].Number_of_PDUs++;
uint16_t sdu_lengths[NB_RB_MAX] = {0}; gNB_mac->TX_req[CC_id].SFN = frame;
uint8_t mac_sdus[MAX_NR_DLSCH_PAYLOAD_BYTES]; gNB_mac->TX_req[CC_id].Slot = slot;
unsigned char sdu_lcids[NB_RB_MAX] = {0};
/* first, write all CEs that might be there */
int written = nr_write_ce_dlsch_pdu(module_id,
sched_ctrl,
(unsigned char *)buf,
255, // no drx
NULL); // contention res id
buf += written;
TBS -= written;
DevAssert(TBS > 3);
/* next, get RLC data */
// 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
NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf;
buf += 3;
TBS -= 3;
const int lcid = DL_SCH_LCID_DTCH; const int lcid = DL_SCH_LCID_DTCH;
int dlsch_total_bytes = 0;
if (sched_ctrl->num_total_bytes > 0) { if (sched_ctrl->num_total_bytes > 0) {
/* this is the data from the RLC we would like to request (e.g., only /* this is the data from the RLC we would like to request (e.g., only
* some bytes for first LC and some more from a second one */ * some bytes for first LC and some more from a second one */
const rlc_buffer_occupancy_t ndata = sched_ctrl->rlc_status[lcid].bytes_in_buffer; const rlc_buffer_occupancy_t ndata = min(sched_ctrl->rlc_status[lcid].bytes_in_buffer, TBS);
/* this is the maximum data we can transport based on TBS minus headers */ const tbs_size_t len = mac_rlc_data_req(module_id,
const int mindata = min(ndata, TBS - ta_len - header_length_total - sdu_length_total - 2 - (ndata >= 256)); rnti,
module_id,
frame,
ENB_FLAG_YES,
MBMS_FLAG_NO,
lcid,
ndata,
(char *)buf,
0,
0);
LOG_D(MAC, LOG_D(MAC,
"[gNB %d][USER-PLANE DEFAULT DRB] Frame %d : DTCH->DLSCH, Requesting " "%4d.%2d RNTI %04x: %d bytes from DTCH %d (ndata %d, rem TBS %d)\n",
"%d bytes from RLC (lcid %d total hdr len %d), TBS: %d \n \n",
module_id,
frame, frame,
mindata, slot,
rnti,
len,
lcid, lcid,
header_length_total, ndata,
TBS); TBS);
sdu_lengths[num_sdus] = mac_rlc_data_req(module_id, header->R = 0;
rnti, header->F = 1;
module_id, header->LCID = lcid;
frame, header->L1 = (len >> 8) & 0xff;
ENB_FLAG_YES, header->L2 = len & 0xff;
MBMS_FLAG_NO, TBS -= len;
lcid, buf += len;
mindata, dlsch_total_bytes += len;
(char *)&mac_sdus[sdu_length_total],
0,
0);
LOG_D(MAC,
"[gNB %d][USER-PLANE DEFAULT DRB] Got %d bytes for DTCH %d \n",
module_id,
sdu_lengths[num_sdus],
lcid);
sdu_lcids[num_sdus] = lcid;
sdu_length_total += sdu_lengths[num_sdus];
header_length_last = 1 + 1 + (sdu_lengths[num_sdus] >= 128);
header_length_total += header_length_last;
num_sdus++;
} }
else if (get_softmodem_params()->phy_test) { else if (get_softmodem_params()->phy_test) {
LOG_D(MAC, "Configuring DL_TX in %d.%d: random data\n", frame, slot); LOG_D(MAC, "Configuring DL_TX in %d.%d: TBS %d B of random data\n", frame, slot, TBS);
// fill dlsch_buffer with random data // fill dlsch_buffer with random data
for (int i = 0; i < TBS; i++) for (int i = 0; i < TBS; i++)
mac_sdus[i] = (unsigned char) (lrand48()&0xff); buf[i] = lrand48() & 0xff;
sdu_lcids[0] = 0x3f; // DRB header->R = 0;
sdu_lengths[0] = TBS - ta_len - 3; header->F = 1;
header_length_total += 2 + (sdu_lengths[0] >= 256); header->LCID = DL_SCH_LCID_PADDING;
sdu_length_total += sdu_lengths[0]; header->L1 = (TBS >> 8) & 0xff;
num_sdus +=1; header->L2 = TBS & 0xff;
TBS -= TBS;
buf += TBS;
dlsch_total_bytes += TBS;
} }
UE_info->mac_stats[UE_id].dlsch_total_bytes += TBS; // Add padding header and zero rest out if there is space left
UE_info->mac_stats[UE_id].lc_bytes_tx[lcid] += sdu_length_total; if (TBS > 0) {
NR_MAC_SUBHEADER_FIXED *padding = (NR_MAC_SUBHEADER_FIXED *) buf;
const int post_padding = TBS > header_length_total + sdu_length_total + ta_len; padding->R = 0;
padding->LCID = DL_SCH_LCID_PADDING;
const int ntx_req = gNB_mac->TX_req[CC_id].Number_of_PDUs; TBS -= 1;
nfapi_nr_pdu_t *tx_req = &gNB_mac->TX_req[CC_id].pdu_list[ntx_req]; buf += 1;
/* pointer to directly generate the PDU into the nFAPI structure */ while (TBS > 0) {
uint32_t *buf = tx_req->TLVs[0].value.direct; *buf = 0;
buf += 1;
const int offset = nr_generate_dlsch_pdu( TBS -= 1;
module_id, }
sched_ctrl,
(unsigned char *)mac_sdus,
(unsigned char *)buf,
num_sdus, // num_sdus
sdu_lengths,
sdu_lcids,
255, // no drx
NULL, // contention res id
post_padding);
// Padding: fill remainder of DLSCH with 0
if (post_padding > 0) {
for (int j = 0; j < TBS - offset; j++)
buf[offset + j] = 0;
} }
/* the buffer has been filled by nr_generate_dlsch_pdu(), below we simply UE_info->mac_stats[UE_id].dlsch_total_bytes += dlsch_total_bytes;
* fill the remaining information */ UE_info->mac_stats[UE_id].lc_bytes_tx[lcid] += dlsch_total_bytes;
tx_req->PDU_length = TBS;
tx_req->PDU_index = pduindex;
tx_req->num_TLV = 1;
tx_req->TLVs[0].length = TBS + 2;
gNB_mac->TX_req[CC_id].Number_of_PDUs++;
gNB_mac->TX_req[CC_id].SFN = frame;
gNB_mac->TX_req[CC_id].Slot = slot;
retInfo->rbSize = sched_ctrl->rbSize; retInfo->rbSize = sched_ctrl->rbSize;
retInfo->time_domain_allocation = sched_ctrl->time_domain_allocation; retInfo->time_domain_allocation = sched_ctrl->time_domain_allocation;
...@@ -958,18 +914,6 @@ void nr_schedule_ue_spec(module_id_t module_id, ...@@ -958,18 +914,6 @@ void nr_schedule_ue_spec(module_id_t module_id,
T(T_GNB_MAC_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti), T(T_GNB_MAC_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti),
T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_BUFFER(buf, TBS)); T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_BUFFER(buf, TBS));
#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
if (frame%100 == 0) {
LOG_I(MAC,
"%d.%d, first 10 payload bytes, TBS size: %d \n",
frame,
slot,
TBS);
for(int i = 0; i < 10; i++)
LOG_I(MAC, "byte %d: %x\n", i, ((uint8_t *) buf)[i]);
}
#endif
} }
/* mark UE as scheduled */ /* mark UE as scheduled */
......
...@@ -64,17 +64,6 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB, ...@@ -64,17 +64,6 @@ void clear_nr_nfapi_information(gNB_MAC_INST * gNB,
void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
frame_t frame_rxP, sub_frame_t slot_rxP); frame_t frame_rxP, sub_frame_t slot_rxP);
int nr_generate_dlsch_pdu(module_id_t Mod_idP,
NR_UE_sched_ctrl_t *ue_sched_ctl,
unsigned char *sdus_payload,
unsigned char *mac_pdu,
unsigned char num_sdus,
unsigned short *sdu_lengths,
unsigned char *sdu_lcids,
unsigned char drx_cmd,
unsigned char *ue_cont_res_id,
unsigned short post_padding);
void nr_schedule_ue_spec(module_id_t module_id, void nr_schedule_ue_spec(module_id_t module_id,
frame_t frame, frame_t frame,
sub_frame_t slot); sub_frame_t slot);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment