feat(nr): implement rank-8 PDSCH
This commit is contained in:
@@ -3034,7 +3034,10 @@ uint16_t nr_dci_size(const NR_UE_DL_BWP_t *DL_BWP,
|
||||
// TB2
|
||||
long *maxCWperDCI = pdsch_Config ? pdsch_Config->maxNrofCodeWordsScheduledByDCI : NULL;
|
||||
if (maxCWperDCI && (*maxCWperDCI == NR_PDSCH_Config__maxNrofCodeWordsScheduledByDCI_n2)) {
|
||||
size += 8;
|
||||
dci_pdu->mcs2.nbits = 5;
|
||||
dci_pdu->ndi2.nbits = 1;
|
||||
dci_pdu->rv2.nbits = 2;
|
||||
size += dci_pdu->mcs2.nbits + dci_pdu->ndi2.nbits + dci_pdu->rv2.nbits;
|
||||
}
|
||||
// HARQ process number – 5 bits if higher layer parameter harq-ProcessNumberSizeDCI-1-1 is configured;
|
||||
// otherwise 4 bits. Spec 38.212 Section 7.3.1.2.2
|
||||
|
||||
@@ -207,13 +207,16 @@ nfapi_nr_pm_list_t init_DL_MIMO_codebook(gNB_MAC_INST *gNB, nr_pdsch_AntennaPort
|
||||
int O2 = N2 > 1 ? 4 : 1; //Vertical beam oversampling (1 or 4)
|
||||
int O1 = num_antenna_ports > 2 ? 4 : 1; //Horizontal beam oversampling (1 or 4)
|
||||
|
||||
int max_mimo_layers = (num_antenna_ports < NR_MAX_NB_LAYERS) ? num_antenna_ports : NR_MAX_NB_LAYERS;
|
||||
AssertFatal(max_mimo_layers <= 4, "Max number of layers supported is 4\n");
|
||||
const int max_mimo_layers = min(num_antenna_ports, NR_MAX_NB_LAYERS);
|
||||
/* Type-I codebook generation below currently covers ranks 1--4. Rank
|
||||
* 5--8 is an explicit identity-PMI path and therefore needs no generated
|
||||
* codebook entries. */
|
||||
const int codebook_layers = min(max_mimo_layers, 4);
|
||||
AssertFatal(num_antenna_ports < 16, "Max number of antenna ports supported is currently 16\n");
|
||||
|
||||
int K1 = 0, K2 = 0;
|
||||
nfapi_nr_pm_list_t mat = {.num_pm_idx = 0};
|
||||
for (int i = 0; i < max_mimo_layers; i++) {
|
||||
for (int i = 0; i < codebook_layers; i++) {
|
||||
get_K1_K2(N1, N2, &K1, &K2, i + 1);
|
||||
int i2_size = i == 0 ? 4 : 2;
|
||||
gNB->precoding_matrix_size[i] = i2_size * N1 * O1 * N2 * O2 * K1 * K2;
|
||||
@@ -274,7 +277,7 @@ nfapi_nr_pm_list_t init_DL_MIMO_codebook(gNB_MAC_INST *gNB, nr_pdsch_AntennaPort
|
||||
}
|
||||
|
||||
int pmiq = 0;
|
||||
for (int layers = 1; layers <= max_mimo_layers; layers++)
|
||||
for (int layers = 1; layers <= codebook_layers; layers++)
|
||||
pmiq = precoding_weigths_generation(&mat, pmiq, layers, N1, N2, O1, O2, num_antenna_ports, theta_n, v_lm);
|
||||
|
||||
return mat;
|
||||
|
||||
@@ -404,6 +404,37 @@ bwp_info_t get_pdsch_bwp_start_size(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE)
|
||||
return bwp_info;
|
||||
}
|
||||
|
||||
static uint32_t compute_sched_pdsch_tbs(const NR_sched_pdsch_t *sched, uint16_t rb_size, uint8_t codeword)
|
||||
{
|
||||
const int cw_layers = nr_pdsch_layers_per_codeword(sched->nrOfLayers, codeword);
|
||||
return nr_compute_tbs(sched->Qm,
|
||||
sched->R,
|
||||
rb_size,
|
||||
sched->tda_info.nrOfSymbols,
|
||||
sched->dmrs_parms.N_PRB_DMRS * sched->dmrs_parms.N_DMRS_SLOT,
|
||||
0,
|
||||
0,
|
||||
cw_layers)
|
||||
>> 3;
|
||||
}
|
||||
|
||||
void update_sched_pdsch_codeword_tbs(NR_sched_pdsch_t *sched)
|
||||
{
|
||||
sched->tb_size = compute_sched_pdsch_tbs(sched, sched->rbSize, 0);
|
||||
sched->tb_size2 = nr_pdsch_num_codewords(sched->nrOfLayers) == 2 ? compute_sched_pdsch_tbs(sched, sched->rbSize, 1) : 0;
|
||||
}
|
||||
|
||||
static void fit_dual_codeword_tbs(NR_sched_pdsch_t *sched, uint32_t requested_bytes, uint16_t max_rb_size)
|
||||
{
|
||||
if (nr_pdsch_num_codewords(sched->nrOfLayers) == 1)
|
||||
return;
|
||||
update_sched_pdsch_codeword_tbs(sched);
|
||||
while ((uint64_t)sched->tb_size + sched->tb_size2 < requested_bytes && sched->rbSize < max_rb_size) {
|
||||
sched->rbSize++;
|
||||
update_sched_pdsch_codeword_tbs(sched);
|
||||
}
|
||||
}
|
||||
|
||||
static bool allocate_dl_retransmission(gNB_MAC_INST *nr_mac,
|
||||
post_process_pdsch_t *pp_pdsch,
|
||||
int *n_rb_sched,
|
||||
@@ -420,7 +451,7 @@ static bool allocate_dl_retransmission(gNB_MAC_INST *nr_mac,
|
||||
NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP;
|
||||
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
|
||||
NR_sched_pdsch_t new_sched = sched_ctrl->harq_processes[current_harq_pid].sched_pdsch;
|
||||
int layers = get_dl_nrOfLayers(sched_ctrl, dl_bwp->dci_format);
|
||||
int layers = get_dl_nrOfLayers(nr_mac, sched_ctrl, dl_bwp->dci_format);
|
||||
int pm_index = get_pm_index(nr_mac, UE, dl_bwp->dci_format, layers, nr_mac->radio_config.pdsch_AntennaPorts.XP);
|
||||
|
||||
// If the RI changed between current rtx and a previous transmission
|
||||
@@ -473,26 +504,43 @@ static bool allocate_dl_retransmission(gNB_MAC_INST *nr_mac,
|
||||
* that we have enough resources */
|
||||
NR_pdsch_dmrs_t temp_dmrs = get_dl_dmrs_params(scc, dl_bwp, &temp_tda, layers);
|
||||
|
||||
uint32_t new_tbs;
|
||||
uint16_t new_rbSize;
|
||||
bool success = nr_find_nb_rb(new_sched.Qm,
|
||||
new_sched.R,
|
||||
1, // no transform precoding for DL
|
||||
layers,
|
||||
temp_tda.nrOfSymbols,
|
||||
temp_dmrs.N_PRB_DMRS * temp_dmrs.N_DMRS_SLOT,
|
||||
new_sched.tb_size,
|
||||
1, /* minimum of 1RB: need to find exact TBS, don't preclude any number */
|
||||
bwp_size,
|
||||
&new_tbs,
|
||||
&new_rbSize);
|
||||
uint16_t new_rbSize = 0;
|
||||
if (nr_pdsch_num_codewords(layers) == 1) {
|
||||
uint32_t new_tbs = 0;
|
||||
bool success = nr_find_nb_rb(new_sched.Qm,
|
||||
new_sched.R,
|
||||
1, // no transform precoding for DL
|
||||
layers,
|
||||
temp_tda.nrOfSymbols,
|
||||
temp_dmrs.N_PRB_DMRS * temp_dmrs.N_DMRS_SLOT,
|
||||
new_sched.tb_size,
|
||||
1, /* find an exact retransmission TBS */
|
||||
bwp_size,
|
||||
&new_tbs,
|
||||
&new_rbSize);
|
||||
if (!success || new_tbs != new_sched.tb_size)
|
||||
new_rbSize = 0;
|
||||
} else {
|
||||
NR_sched_pdsch_t candidate = new_sched;
|
||||
candidate.nrOfLayers = layers;
|
||||
candidate.dmrs_parms = temp_dmrs;
|
||||
candidate.tda_info = temp_tda;
|
||||
for (uint16_t rb = 1; rb <= bwp_size; rb++) {
|
||||
candidate.rbSize = rb;
|
||||
update_sched_pdsch_codeword_tbs(&candidate);
|
||||
if (candidate.tb_size == new_sched.tb_size && candidate.tb_size2 == new_sched.tb_size2) {
|
||||
new_rbSize = rb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!success || new_tbs != new_sched.tb_size) {
|
||||
if (new_rbSize == 0) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] allocation of DL retransmission failed: new TBS %d of new TDA does not match old TBS %d\n",
|
||||
UE->rnti,
|
||||
frame,
|
||||
slot,
|
||||
new_tbs,
|
||||
0,
|
||||
new_sched.tb_size);
|
||||
return false; /* the maximum TBsize we might have is smaller than what we need */
|
||||
}
|
||||
@@ -505,13 +553,13 @@ static bool allocate_dl_retransmission(gNB_MAC_INST *nr_mac,
|
||||
|
||||
/* we can allocate it. Overwrite the time_domain_allocation, the number
|
||||
* of RBs, and the new TB size. The rest is done below */
|
||||
new_sched.tb_size = new_tbs;
|
||||
new_sched.rbSize = new_rbSize;
|
||||
new_sched.time_domain_allocation = tda;
|
||||
new_sched.nrOfLayers = layers;
|
||||
new_sched.pm_index = pm_index;
|
||||
new_sched.dmrs_parms = temp_dmrs;
|
||||
new_sched.tda_info = temp_tda;
|
||||
update_sched_pdsch_codeword_tbs(&new_sched);
|
||||
}
|
||||
|
||||
/* Find a free CCE */
|
||||
@@ -538,6 +586,11 @@ static bool allocate_dl_retransmission(gNB_MAC_INST *nr_mac,
|
||||
if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, current_harq_pid)) {
|
||||
int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex);
|
||||
alloc = nr_acknack_scheduling(nr_mac, UE, frame, slot, UE->UE_beam_index, r_pucch, 0);
|
||||
if (alloc >= 0 && nr_pdsch_num_codewords(new_sched.nrOfLayers) == 2) {
|
||||
const int second_alloc = nr_acknack_scheduling(nr_mac, UE, frame, slot, UE->UE_beam_index, r_pucch, 0);
|
||||
if (second_alloc != alloc)
|
||||
alloc = -1;
|
||||
}
|
||||
if (alloc < 0) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI retransmission\n", UE->rnti, frame, slot);
|
||||
return false;
|
||||
@@ -565,7 +618,6 @@ static bool allocate_dl_retransmission(gNB_MAC_INST *nr_mac,
|
||||
static void ack_reconfig(gNB_MAC_INST *mac, NR_UE_info_t *UE)
|
||||
{
|
||||
if (!UE->reconfigCellGroup) {
|
||||
LOG_W(NR_MAC, "Received ACK for RRCReconfiguration, but nothing to apply!\n");
|
||||
return;
|
||||
}
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
|
||||
@@ -700,7 +752,7 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
sched_ctrl->dl_bler_stats.mcs = selected_mcs;
|
||||
} else
|
||||
selected_mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame);
|
||||
int l = get_dl_nrOfLayers(sched_ctrl, current_BWP->dci_format);
|
||||
int l = get_dl_nrOfLayers(mac, sched_ctrl, current_BWP->dci_format);
|
||||
const uint8_t Qm = nr_get_Qm_dl(selected_mcs, current_BWP->mcsTableIdx);
|
||||
const uint16_t R = nr_get_code_rate_dl(selected_mcs, current_BWP->mcsTableIdx);
|
||||
uint32_t tbs = nr_compute_tbs(Qm,
|
||||
@@ -822,10 +874,17 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
/* Find PUCCH occasion: if it fails, undo CCE allocation (undoing PUCCH
|
||||
* allocation after CCE alloc fail would be more complex) */
|
||||
|
||||
const int l = get_dl_nrOfLayers(mac, sched_ctrl, dl_bwp->dci_format);
|
||||
int alloc = -1;
|
||||
if (!get_FeedbackDisabled(iterator->UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_ctrl->available_dl_harq.head)) {
|
||||
int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex);
|
||||
alloc = nr_acknack_scheduling(mac, iterator->UE, frame, slot, iterator->UE->UE_beam_index, r_pucch, 0);
|
||||
if (alloc >= 0 && nr_pdsch_num_codewords(l) == 2) {
|
||||
const int second_alloc =
|
||||
nr_acknack_scheduling(mac, iterator->UE, frame, slot, iterator->UE->UE_beam_index, r_pucch, 0);
|
||||
if (second_alloc != alloc)
|
||||
alloc = -1;
|
||||
}
|
||||
if (alloc < 0) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI\n", rnti, frame, slot);
|
||||
reset_beam_status(&mac->beam_info, frame, slot, iterator->UE->UE_beam_index, slots_per_frame, beam.new_beam);
|
||||
@@ -837,7 +896,6 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
sched_ctrl->cce_index = CCEIndex;
|
||||
fill_pdcch_vrb_map(mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam.idx);
|
||||
|
||||
int l = get_dl_nrOfLayers(sched_ctrl, dl_bwp->dci_format);
|
||||
NR_sched_pdsch_t sched_pdsch = {
|
||||
// rbSize below
|
||||
.rbStart = rbStart,
|
||||
@@ -877,6 +935,7 @@ static void pf_dl(gNB_MAC_INST *mac,
|
||||
max_rbSize,
|
||||
&sched_pdsch.tb_size,
|
||||
&sched_pdsch.rbSize);
|
||||
fit_dual_codeword_tbs(&sched_pdsch, sched_ctrl->num_total_bytes + oh, max_rbSize);
|
||||
|
||||
post_process_dlsch(mac, pp_pdsch, iterator->UE, &sched_pdsch);
|
||||
|
||||
@@ -943,13 +1002,15 @@ nfapi_nr_dl_tti_pdsch_pdu_rel15_t *prepare_pdsch_pdu(nfapi_nr_dl_tti_request_pdu
|
||||
pdsch_pdu->SubcarrierSpacing = dl_bwp ? dl_bwp->scs : *scc->ssbSubcarrierSpacing;
|
||||
pdsch_pdu->CyclicPrefix = dl_bwp && dl_bwp->cyclicprefix ? *dl_bwp->cyclicprefix : 0;
|
||||
// Codeword information
|
||||
pdsch_pdu->NrOfCodewords = 1;
|
||||
pdsch_pdu->targetCodeRate[0] = sched_pdsch->R;
|
||||
pdsch_pdu->qamModOrder[0] = sched_pdsch->Qm;
|
||||
pdsch_pdu->mcsIndex[0] = sched_pdsch->mcs;
|
||||
pdsch_pdu->mcsTable[0] = dl_bwp ? dl_bwp->mcsTableIdx : 0;
|
||||
pdsch_pdu->rvIndex[0] = nr_get_rv(harq_round % 4);
|
||||
pdsch_pdu->TBSize[0] = sched_pdsch->tb_size;
|
||||
pdsch_pdu->NrOfCodewords = nr_pdsch_num_codewords(sched_pdsch->nrOfLayers);
|
||||
for (int q = 0; q < pdsch_pdu->NrOfCodewords; q++) {
|
||||
pdsch_pdu->targetCodeRate[q] = sched_pdsch->R;
|
||||
pdsch_pdu->qamModOrder[q] = sched_pdsch->Qm;
|
||||
pdsch_pdu->mcsIndex[q] = sched_pdsch->mcs;
|
||||
pdsch_pdu->mcsTable[q] = dl_bwp ? dl_bwp->mcsTableIdx : 0;
|
||||
pdsch_pdu->rvIndex[q] = nr_get_rv(harq_round % 4);
|
||||
pdsch_pdu->TBSize[q] = q == 0 ? sched_pdsch->tb_size : sched_pdsch->tb_size2;
|
||||
}
|
||||
pdsch_pdu->dataScramblingId = pdsch_Config && pdsch_Config->dataScramblingIdentityPDSCH ? *pdsch_Config->dataScramblingIdentityPDSCH : *scc->physCellId;
|
||||
pdsch_pdu->nrOfLayers = sched_pdsch->nrOfLayers;
|
||||
pdsch_pdu->transmissionScheme = 0;
|
||||
@@ -961,7 +1022,7 @@ nfapi_nr_dl_tti_pdsch_pdu_rel15_t *prepare_pdsch_pdu(nfapi_nr_dl_tti_request_pdu
|
||||
pdsch_pdu->SCID = dmrs_parms->n_scid;
|
||||
pdsch_pdu->dlDmrsScramblingId = dmrs_parms->scrambling_id;
|
||||
pdsch_pdu->numDmrsCdmGrpsNoData = dmrs_parms->numDmrsCdmGrpsNoData;
|
||||
pdsch_pdu->dmrsPorts = (1 << sched_pdsch->nrOfLayers) - 1; // FIXME with a better implementation
|
||||
pdsch_pdu->dmrsPorts = dmrs_parms->dmrs_ports;
|
||||
// Pdsch Allocation in frequency domain
|
||||
pdsch_pdu->resourceAlloc = 1;
|
||||
pdsch_pdu->rbStart = sched_pdsch->rbStart;
|
||||
@@ -998,6 +1059,98 @@ nfapi_nr_dl_tti_pdsch_pdu_rel15_t *prepare_pdsch_pdu(nfapi_nr_dl_tti_request_pdu
|
||||
return pdsch_pdu;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int sdus;
|
||||
int sdu_bytes;
|
||||
} dlsch_fill_result_t;
|
||||
|
||||
static dlsch_fill_result_t fill_dlsch_transport_block(gNB_MAC_INST *mac,
|
||||
NR_UE_info_t *UE,
|
||||
uint8_t *tb,
|
||||
uint32_t tbs,
|
||||
frame_t frame,
|
||||
slot_t slot,
|
||||
bool include_ces)
|
||||
{
|
||||
const int module_id = mac->Mod_id;
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
dlsch_fill_result_t result = {0};
|
||||
uint8_t *buf = tb;
|
||||
|
||||
if (include_ces)
|
||||
buf += nr_write_ce_dlsch_pdu(module_id, sched_ctrl, buf, 255, NULL);
|
||||
DevAssert(buf < tb + tbs);
|
||||
uint8_t *buf_end = tb + tbs;
|
||||
|
||||
start_meas(&mac->rlc_data_req);
|
||||
if (sched_ctrl->num_total_bytes > 0) {
|
||||
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;
|
||||
if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0)
|
||||
continue;
|
||||
|
||||
tb_size_t pdu_siz[MAX_NUM_DATA_REQ];
|
||||
int num = nr_mac_rlc_multi_data_req(module_id,
|
||||
UE->rnti,
|
||||
true,
|
||||
lcid,
|
||||
buf_end - buf,
|
||||
(char *)buf,
|
||||
pdu_siz,
|
||||
sizeofArray(pdu_siz));
|
||||
DevAssert(num <= sizeofArray(pdu_siz));
|
||||
result.sdus += num;
|
||||
int lcid_bytes = 0;
|
||||
for (int j = 0; j < num; ++j) {
|
||||
NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *)buf;
|
||||
header->R = 0;
|
||||
header->F = 1;
|
||||
header->LCID = lcid;
|
||||
header->L = htons(pdu_siz[j]);
|
||||
buf += pdu_siz[j] + sizeof(NR_MAC_SUBHEADER_LONG);
|
||||
result.sdu_bytes += pdu_siz[j];
|
||||
lcid_bytes += pdu_siz[j];
|
||||
}
|
||||
T(T_GNB_MAC_LCID_DL,
|
||||
T_INT(UE->rnti),
|
||||
T_INT(frame),
|
||||
T_INT(slot),
|
||||
T_INT(lcid),
|
||||
T_INT(lcid_bytes),
|
||||
T_INT(nr_rlc_tx_list_occupancy(UE->rnti, lcid)));
|
||||
UE->mac_stats.dl.lc_bytes[lcid] += lcid_bytes;
|
||||
}
|
||||
} else if (get_softmodem_params()->phy_test || get_softmodem_params()->do_ra) {
|
||||
LOG_D(NR_MAC, "Configuring DL_TX in %d.%d: TBS %d of random data\n", frame, slot, tbs);
|
||||
if (buf_end - buf > sizeof(NR_MAC_SUBHEADER_LONG)) {
|
||||
NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *)buf;
|
||||
header->R = 0;
|
||||
header->F = 1;
|
||||
header->LCID = DL_SCH_LCID_PADDING;
|
||||
buf += sizeof(NR_MAC_SUBHEADER_LONG);
|
||||
header->L = htons(buf_end - buf);
|
||||
for (; ((intptr_t)buf) % 4; buf++)
|
||||
*buf = lrand48() & 0xff;
|
||||
for (; buf < buf_end - 3; buf += 4)
|
||||
*(uint32_t *)buf = lrand48();
|
||||
for (; buf < buf_end; buf++)
|
||||
*buf = lrand48() & 0xff;
|
||||
result.sdus++;
|
||||
}
|
||||
}
|
||||
stop_meas(&mac->rlc_data_req);
|
||||
|
||||
if (buf_end - buf > 0) {
|
||||
NR_MAC_SUBHEADER_FIXED *padding = (NR_MAC_SUBHEADER_FIXED *)buf;
|
||||
padding->R = 0;
|
||||
padding->LCID = DL_SCH_LCID_PADDING;
|
||||
buf++;
|
||||
memset(buf, 0, buf_end - buf);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE_info_t *UE, NR_sched_pdsch_t *sched_pdsch)
|
||||
{
|
||||
int CC_id = 0;
|
||||
@@ -1014,6 +1167,7 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE
|
||||
/* POST processing */
|
||||
const uint8_t nrOfLayers = sched_pdsch->nrOfLayers;
|
||||
const uint32_t TBS = sched_pdsch->tb_size;
|
||||
const uint32_t TBS2 = sched_pdsch->tb_size2;
|
||||
int8_t current_harq_pid = sched_pdsch->dl_harq_pid;
|
||||
|
||||
if (current_harq_pid < 0) {
|
||||
@@ -1208,11 +1362,15 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE
|
||||
harq->round,
|
||||
harq->ndi);
|
||||
if (!get_softmodem_params()->phy_test)
|
||||
AssertFatal(harq->sched_pdsch.tb_size == TBS,
|
||||
"UE %04x mismatch between scheduled TBS and buffered TB for HARQ PID %d\n",
|
||||
AssertFatal(harq->sched_pdsch.tb_size == TBS && harq->sched_pdsch.tb_size2 == TBS2,
|
||||
"UE %04x mismatch between scheduled TBS (%u,%u) and buffered TB (%u,%u) for HARQ PID %d\n",
|
||||
UE->rnti,
|
||||
TBS,
|
||||
TBS2,
|
||||
harq->sched_pdsch.tb_size,
|
||||
harq->sched_pdsch.tb_size2,
|
||||
current_harq_pid);
|
||||
else if (harq->sched_pdsch.tb_size != TBS)
|
||||
else if (harq->sched_pdsch.tb_size != TBS || harq->sched_pdsch.tb_size2 != TBS2)
|
||||
LOG_E(NR_MAC,
|
||||
"Mismatch between scheduled TBS and buffered TB for HARQ PID %d. No RTX control in phy-test mode. "
|
||||
"Possible causes: presence of CSI-RS or DLSCH scheduled in the mixed slot.\n",
|
||||
@@ -1225,94 +1383,24 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE
|
||||
LOG_D(NR_MAC, "Initial HARQ transmission in %d.%d\n", frame, slot);
|
||||
// Flag HARQ process to start TCI timer at ACK
|
||||
harq->start_tci_timer = sched_ctrl->UE_mac_ce_ctrl.tci_state_ind.is_scheduled;
|
||||
uint8_t *buf = allocate_transportBlock_buffer(&harq->transportBlock, TBS);
|
||||
/* 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;
|
||||
uint8_t *bufEnd = buf + TBS - written;
|
||||
DevAssert(TBS > written);
|
||||
int dlsch_total_bytes = 0;
|
||||
/* next, get RLC data */
|
||||
start_meas(&nr_mac->rlc_data_req);
|
||||
int sdus = 0;
|
||||
|
||||
if (sched_ctrl->num_total_bytes > 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;
|
||||
|
||||
if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0)
|
||||
continue; // no data for this LC tbs_size_t len = 0;
|
||||
|
||||
|
||||
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;
|
||||
header->R = 0;
|
||||
header->F = 1;
|
||||
header->LCID = lcid;
|
||||
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) {
|
||||
/* we will need the large header, phy-test typically allocates all
|
||||
* resources and fills to the last byte below */
|
||||
LOG_D(NR_MAC, "Configuring DL_TX in %d.%d: TBS %d of random data\n", frame, slot, TBS);
|
||||
|
||||
if (bufEnd-buf > sizeof(NR_MAC_SUBHEADER_LONG) ) {
|
||||
NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *) buf;
|
||||
// fill dlsch_buffer with random data
|
||||
header->R = 0;
|
||||
header->F = 1;
|
||||
header->LCID = DL_SCH_LCID_PADDING;
|
||||
buf += sizeof(NR_MAC_SUBHEADER_LONG);
|
||||
header->L = htons(bufEnd-buf);
|
||||
|
||||
for (; ((intptr_t)buf) % 4; buf++)
|
||||
*buf = lrand48() & 0xff;
|
||||
for (; buf < bufEnd - 3; buf += 4) {
|
||||
uint32_t *buf32 = (uint32_t *)buf;
|
||||
*buf32 = lrand48();
|
||||
}
|
||||
for (; buf < bufEnd; buf++)
|
||||
*buf = lrand48() & 0xff;
|
||||
sdus +=1;
|
||||
}
|
||||
for (int q = 0; q < nr_pdsch_num_codewords(nrOfLayers); q++) {
|
||||
const uint32_t cw_tbs = q == 0 ? TBS : sched_pdsch->tb_size2;
|
||||
byte_array_t *transport_block = q == 0 ? &harq->transportBlock : &harq->transportBlock2;
|
||||
uint8_t *buf = allocate_transportBlock_buffer(transport_block, cw_tbs);
|
||||
dlsch_fill_result_t fill = fill_dlsch_transport_block(nr_mac, UE, buf, cw_tbs, frame, slot, q == 0);
|
||||
sdus += fill.sdus;
|
||||
dlsch_total_bytes += fill.sdu_bytes;
|
||||
}
|
||||
|
||||
stop_meas(&nr_mac->rlc_data_req);
|
||||
|
||||
// Add padding header and zero rest out if there is space left
|
||||
if (bufEnd-buf > 0) {
|
||||
NR_MAC_SUBHEADER_FIXED *padding = (NR_MAC_SUBHEADER_FIXED *) buf;
|
||||
padding->R = 0;
|
||||
padding->LCID = DL_SCH_LCID_PADDING;
|
||||
buf += 1;
|
||||
memset(buf,0,bufEnd-buf);
|
||||
buf=bufEnd;
|
||||
}
|
||||
|
||||
UE->mac_stats.dl.total_bytes += TBS;
|
||||
UE->mac_stats.dl.current_bytes = TBS;
|
||||
const uint32_t total_tbs = TBS + sched_pdsch->tb_size2;
|
||||
UE->mac_stats.dl.total_bytes += total_tbs;
|
||||
UE->mac_stats.dl.current_bytes = total_tbs;
|
||||
UE->mac_stats.dl.total_rbs += sched_pdsch->rbSize;
|
||||
UE->mac_stats.dl.num_mac_sdu += sdus;
|
||||
UE->mac_stats.dl.current_rbs = sched_pdsch->rbSize;
|
||||
UE->mac_stats.dl.last_layers = sched_pdsch->nrOfLayers;
|
||||
UE->mac_stats.dl.total_sdu_bytes += dlsch_total_bytes;
|
||||
nr_mac->mac_stats.dl.used_prb_aggregate += sched_pdsch->rbSize;
|
||||
|
||||
@@ -1349,10 +1437,16 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE
|
||||
const int ntx_req = pdsch->TX_req->Number_of_PDUs;
|
||||
nfapi_nr_pdu_t *tx_req = &pdsch->TX_req->pdu_list[ntx_req];
|
||||
tx_req->PDU_index = pduindex;
|
||||
tx_req->num_TLV = 1;
|
||||
tx_req->TLVs[0].length = TBS;
|
||||
tx_req->PDU_length = compute_PDU_length(tx_req->num_TLV, tx_req->TLVs[0].length);
|
||||
memcpy(tx_req->TLVs[0].value.direct, harq->transportBlock.buf, TBS);
|
||||
tx_req->num_TLV = nr_pdsch_num_codewords(nrOfLayers);
|
||||
uint32_t total_tlv_length = 0;
|
||||
for (int q = 0; q < tx_req->num_TLV; q++) {
|
||||
const uint32_t cw_tbs = q == 0 ? TBS : TBS2;
|
||||
const byte_array_t *transport_block = q == 0 ? &harq->transportBlock : &harq->transportBlock2;
|
||||
tx_req->TLVs[q].length = cw_tbs;
|
||||
memcpy(tx_req->TLVs[q].value.direct, transport_block->buf, cw_tbs);
|
||||
total_tlv_length += cw_tbs;
|
||||
}
|
||||
tx_req->PDU_length = compute_PDU_length(tx_req->num_TLV, total_tlv_length);
|
||||
pdsch->TX_req->Number_of_PDUs++;
|
||||
pdsch->TX_req->SFN = frame;
|
||||
pdsch->TX_req->Slot = slot;
|
||||
|
||||
@@ -166,15 +166,7 @@ void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch)
|
||||
.tda_info = tda_info,
|
||||
};
|
||||
sched_ctrl->dl_bler_stats.mcs = target_dl_mcs; /* for logging output */
|
||||
sched_pdsch.tb_size = nr_compute_tbs(sched_pdsch.Qm,
|
||||
sched_pdsch.R,
|
||||
sched_pdsch.rbSize,
|
||||
tda_info.nrOfSymbols,
|
||||
sched_pdsch.dmrs_parms.N_PRB_DMRS * sched_pdsch.dmrs_parms.N_DMRS_SLOT,
|
||||
0 /* N_PRB_oh, 0 for initialBWP */,
|
||||
0 /* tb_scaling */,
|
||||
target_dl_Nl)
|
||||
>> 3;
|
||||
update_sched_pdsch_codeword_tbs(&sched_pdsch);
|
||||
|
||||
post_process_dlsch(mac, pp_pdsch, UE, &sched_pdsch);
|
||||
|
||||
|
||||
@@ -101,14 +101,13 @@ int get_ssbidx_from_beam(gNB_MAC_INST *mac, int beam_idx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format)
|
||||
uint8_t get_dl_nrOfLayers(const gNB_MAC_INST *mac, const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format)
|
||||
{
|
||||
// TODO check this but it should be enough for now
|
||||
// if there is not csi report activated RI is 0 from initialization
|
||||
if(dci_format == NR_DL_DCI_FORMAT_1_0)
|
||||
return 1;
|
||||
else
|
||||
return sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri + 1;
|
||||
int layers = (dci_format == NR_DL_DCI_FORMAT_1_0) ? 1
|
||||
: sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri + 1;
|
||||
if (mac && mac->antenna_state)
|
||||
return nr_get_effective_mimo_layers(mac->antenna_state, layers);
|
||||
return layers;
|
||||
}
|
||||
|
||||
int get_ul_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format)
|
||||
@@ -165,63 +164,88 @@ uint16_t get_pm_index(const gNB_MAC_INST *nrmac,
|
||||
int layers,
|
||||
int xp_pdsch_antenna_ports)
|
||||
{
|
||||
if (dci_format == NR_DL_DCI_FORMAT_1_0 || nrmac->identity_pm || xp_pdsch_antenna_ports == 1)
|
||||
return 0; //identity matrix (basic 5G configuration handled by PMI report is with XP antennas)
|
||||
const NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
const int report_id = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id;
|
||||
const nr_csi_report_t *csi_report = &UE->csi_report_template[report_id];
|
||||
const int N1 = csi_report->N1;
|
||||
const int N2 = csi_report->N2;
|
||||
const int antenna_ports = (N1 * N2) << 1;
|
||||
if (antenna_ports < 2)
|
||||
return 0; // single antenna port
|
||||
if (dci_format == NR_DL_DCI_FORMAT_1_0 || nrmac->identity_pm || xp_pdsch_antenna_ports == 1 || layers > 4)
|
||||
return 0; //identity matrix (basic 5G configuration handled by PMI report is with XP antennas)
|
||||
const NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
|
||||
int x1 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1;
|
||||
const int x2 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2;
|
||||
LOG_D(NR_MAC,"PMI report: x1 %d x2 %d layers: %d\n", x1, x2, layers);
|
||||
|
||||
int prev_layers_size = 0;
|
||||
for (int i = 1; i < layers; i++)
|
||||
prev_layers_size += nrmac->precoding_matrix_size[i - 1];
|
||||
|
||||
// need to return PM index to matrix initialized in init_DL_MIMO_codebook
|
||||
// index 0 is for identity matrix
|
||||
// order of matrices depends on layers to be transmitted
|
||||
// elements from 1 to n for 1 layer
|
||||
// elements from n+1 to m for 2 layers etc.
|
||||
if (antenna_ports == 2)
|
||||
return 1 + prev_layers_size + x2; // 0 for identity matrix
|
||||
else {
|
||||
int idx = layers - 1;
|
||||
// the order of i1x in X1 report needs to be verified
|
||||
// the standard is not very clear (Table 6.3.1.1.2-7 in 38.212)
|
||||
// it says: PMI wideband information fields X1 , from left to right
|
||||
int bitlen = csi_report->csi_meas_bitlen.pmi_i13_bitlen[idx];
|
||||
if (layers == 1 && bitlen != 0) {
|
||||
LOG_E(NR_MAC, "Invalid i13 bit length %d for single layer! It should be 0\n", bitlen);
|
||||
return 0;
|
||||
int reported_ri_layers = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri + 1;
|
||||
if (layers != reported_ri_layers) {
|
||||
LOG_D(NR_MAC, "PMI mismatch: using %d layers but RI report is for %d layers, using identity matrix\n",
|
||||
layers, reported_ri_layers);
|
||||
return 0;
|
||||
}
|
||||
const int i13 = x1 & ((1 << bitlen) - 1);
|
||||
x1 >>= bitlen;
|
||||
bitlen = csi_report->csi_meas_bitlen.pmi_i12_bitlen[idx];
|
||||
const int i12 = x1 & ((1 << bitlen) - 1);
|
||||
x1 >>= bitlen;
|
||||
bitlen = csi_report->csi_meas_bitlen.pmi_i11_bitlen[idx];
|
||||
const int i11 = x1 & ((1 << bitlen) - 1);
|
||||
const int i2 = x2;
|
||||
int k1, k2;
|
||||
get_k1_k2_indices(layers, N1, N2, i13, &k1, &k2); // get indices k1 and k2 for PHY matrix (not actual k1 and k2 values)
|
||||
const int O2 = N2 == 1 ? 1 : 4;
|
||||
int O1 = 4; //Horizontal beam oversampling = 4 for more than 2 antenna ports
|
||||
int max_i2 = 0;
|
||||
int lay_index = 0;
|
||||
max_i2 = layers == 1 ? 4 : 2;
|
||||
int K1, K2;
|
||||
get_K1_K2(N1, N2, &K1, &K2, layers);
|
||||
// computing precoding matrix index according to rule set in allocation function init_codebook_gNB
|
||||
lay_index = i2 + (i11 * max_i2) + (i12 * max_i2 * N1 * O1) + (k1 * max_i2 * N1 * O1 * N2 * O2) + (k2 * max_i2 * N1 * O1 * N2 * O2 * K1);
|
||||
return 1 + prev_layers_size + lay_index;
|
||||
}
|
||||
nr_antenna_state_t* ant_state = nrmac->antenna_state;
|
||||
if (ant_state) {
|
||||
if (nr_is_in_recovery_mode(ant_state)) {
|
||||
LOG_D(NR_MAC, "[ANTENNA_MUTE] Recovery mode active, using identity matrix\n");
|
||||
return 0;
|
||||
}
|
||||
// Don't fall back to identity matrix for muted antennas.
|
||||
// Antenna muting is handled at RU level (nr_feptx zeros muted antenna buffers).
|
||||
// Using proper precoding ensures data reaches all active antennas.
|
||||
}
|
||||
|
||||
const int report_id = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id;
|
||||
const nr_csi_report_t *csi_report = &UE->csi_report_template[report_id];
|
||||
const int N1 = csi_report->N1;
|
||||
const int N2 = csi_report->N2;
|
||||
const int antenna_ports = (N1 * N2) << 1;
|
||||
if (antenna_ports < 2) return 0; // single antenna port
|
||||
|
||||
int x1 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1;
|
||||
const int x2 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2;
|
||||
LOG_D(NR_MAC,"PMI report: x1 %d x2 %d layers: %d\n", x1, x2, layers);
|
||||
|
||||
int prev_layers_size = 0;
|
||||
for (int i = 1; i < layers; i++)
|
||||
prev_layers_size += nrmac->precoding_matrix_size[i - 1];
|
||||
|
||||
// need to return PM index to matrix initialized in init_DL_MIMO_codebook
|
||||
// index 0 is for identity matrix
|
||||
// order of matrices depends on layers to be transmitted
|
||||
// elements from 1 to n for 1 layer
|
||||
// elements from n+1 to m for 2 layers etc.
|
||||
int pm_index;
|
||||
if (antenna_ports == 2)
|
||||
pm_index = 1 + prev_layers_size + x2; // 0 for identity matrix
|
||||
else {
|
||||
int idx = layers - 1;
|
||||
// the order of i1x in X1 report needs to be verified
|
||||
// the standard is not very clear (Table 6.3.1.1.2-7 in 38.212)
|
||||
// it says: PMI wideband information fields X1 , from left to right
|
||||
int bitlen = csi_report->csi_meas_bitlen.pmi_i13_bitlen[idx];
|
||||
if (layers == 1 && bitlen != 0) {
|
||||
LOG_E(NR_MAC, "Invalid i13 bit length %d for single layer! It should be 0\n", bitlen);
|
||||
return 0;
|
||||
}
|
||||
const int i13 = x1 & ((1 << bitlen) - 1);
|
||||
x1 >>= bitlen;
|
||||
bitlen = csi_report->csi_meas_bitlen.pmi_i12_bitlen[idx];
|
||||
const int i12 = x1 & ((1 << bitlen) - 1);
|
||||
x1 >>= bitlen;
|
||||
bitlen = csi_report->csi_meas_bitlen.pmi_i11_bitlen[idx];
|
||||
const int i11 = x1 & ((1 << bitlen) - 1);
|
||||
const int i2 = x2;
|
||||
int k1, k2;
|
||||
get_k1_k2_indices(layers, N1, N2, i13, &k1, &k2); // get indices k1 and k2 for PHY matrix (not actual k1 and k2 values)
|
||||
const int O2 = N2 == 1 ? 1 : 4;
|
||||
int O1 = 4; //Horizontal beam oversampling = 4 for more than 2 antenna ports
|
||||
int max_i2 = 0;
|
||||
int lay_index = 0;
|
||||
max_i2 = layers == 1 ? 4 : 2;
|
||||
int K1, K2;
|
||||
get_K1_K2(N1, N2, &K1, &K2, layers);
|
||||
// computing precoding matrix index according to rule set in allocation function init_codebook_gNB
|
||||
lay_index = i2 + (i11 * max_i2) + (i12 * max_i2 * N1 * O1) + (k1 * max_i2 * N1 * O1 * N2 * O2) + (k2 * max_i2 * N1 * O1 * N2 * O2 * K1);
|
||||
pm_index = 1 + prev_layers_size + lay_index;
|
||||
}
|
||||
int max_valid_pm = prev_layers_size + nrmac->precoding_matrix_size[layers - 1];
|
||||
if (pm_index < 1 || pm_index > max_valid_pm) {
|
||||
LOG_W(NR_MAC, "PM index %d out of range [1, %d] for %d layers, using identity matrix\n",
|
||||
pm_index, max_valid_pm, layers);
|
||||
return 0;
|
||||
}
|
||||
return pm_index;
|
||||
}
|
||||
|
||||
// look-up table for AMC. Based on BLER vs SNR curves from the nr_dlsim simulation
|
||||
@@ -304,6 +328,11 @@ NR_pdsch_dmrs_t get_dl_dmrs_params(const NR_ServingCellConfigCommon_t *scc,
|
||||
{
|
||||
NR_pdsch_dmrs_t dmrs = {0};
|
||||
int frontloaded_symb = 1; // default value
|
||||
NR_PDSCH_Config_t *pdsch_Config = dl_bwp ? dl_bwp->pdsch_Config : NULL;
|
||||
NR_DMRS_DownlinkConfig_t *dmrs_Config = NULL;
|
||||
if (pdsch_Config)
|
||||
dmrs_Config = tda_info->mapping_type == typeB ? pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup
|
||||
: pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup;
|
||||
nr_dci_format_t dci_format = dl_bwp ? dl_bwp->dci_format : NR_DL_DCI_FORMAT_1_0;
|
||||
if (dci_format == NR_DL_DCI_FORMAT_1_0) {
|
||||
dmrs.numDmrsCdmGrpsNoData = tda_info->nrOfSymbols <= 2 ? 1 : 2;
|
||||
@@ -338,19 +367,29 @@ NR_pdsch_dmrs_t get_dl_dmrs_params(const NR_ServingCellConfigCommon_t *scc,
|
||||
dmrs.numDmrsCdmGrpsNoData = 2;
|
||||
frontloaded_symb = 1;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
AssertFatal(dmrs_Config && dmrs_Config->dmrs_Type == NULL && dmrs_Config->maxLength,
|
||||
"Rank %d PDSCH requires DMRS type 1 with maxLength len2\n",
|
||||
Layers);
|
||||
/* TS 38.212 Table 7.3.1.2.2-2, two-codeword rows 0--3. */
|
||||
dmrs.dmrs_ports_id = Layers - 5;
|
||||
dmrs.numDmrsCdmGrpsNoData = 2;
|
||||
frontloaded_symb = 2;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1==0,"Number of layers %d\n not supported or not valid\n",Layers);
|
||||
}
|
||||
}
|
||||
|
||||
dmrs.n_scid = 0;
|
||||
static const uint16_t two_cw_dmrs_ports[] = {0x1f, 0x5f, 0x7f, 0xff};
|
||||
dmrs.dmrs_ports = Layers > 4 ? two_cw_dmrs_ports[Layers - 5] : (1U << Layers) - 1;
|
||||
long *scramblingID = NULL;
|
||||
NR_PDSCH_Config_t *pdsch_Config = dl_bwp ? dl_bwp->pdsch_Config : NULL;
|
||||
if (pdsch_Config) {
|
||||
NR_DMRS_DownlinkConfig_t *dmrs_Config = tda_info->mapping_type == typeB ?
|
||||
pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup :
|
||||
pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup;
|
||||
dmrs.phaseTrackingRS = dmrs_Config->phaseTrackingRS ? dmrs_Config->phaseTrackingRS->choice.setup : NULL;
|
||||
dmrs.phaseTrackingRS = Layers > 4 ? NULL : (dmrs_Config->phaseTrackingRS ? dmrs_Config->phaseTrackingRS->choice.setup : NULL);
|
||||
dmrs.dmrsConfigType = dmrs_Config->dmrs_Type != NULL;
|
||||
scramblingID = dmrs.n_scid ? dmrs_Config->scramblingID1 : dmrs_Config->scramblingID0;
|
||||
} else {
|
||||
@@ -930,6 +969,11 @@ dci_pdu_rel15_t prepare_dci_dl_payload(const gNB_MAC_INST *gNB_mac,
|
||||
AssertFatal(harq, "HARQ process should be available for DCI with RNTI %s\n", rnti_types(rnti_type));
|
||||
dci_payload.harq_pid.val = harq_pid;
|
||||
dci_payload.ndi = harq->ndi;
|
||||
if (pdsch_pdu->NrOfCodewords == 2) {
|
||||
dci_payload.mcs2.val = sched_pdsch->mcs;
|
||||
dci_payload.ndi2.val = harq->ndi;
|
||||
dci_payload.rv2.val = pdsch_pdu->rvIndex[1];
|
||||
}
|
||||
dci_payload.pucch_resource_indicator = pucch ? pucch->resource_indicator : 0;
|
||||
dci_payload.pdsch_to_harq_feedback_timing_indicator.val = pucch ? pucch->timing_indicator : 0; // PDSCH to HARQ TI
|
||||
dci_payload.dai[0].val = pucch ? (pucch->dai_c - 1) & 3 : 0;
|
||||
@@ -2518,8 +2562,10 @@ void delete_nr_ue_data(NR_UE_info_t *UE, uid_allocator_t *uia)
|
||||
destroy_nr_list(&sched_ctrl->available_ul_harq);
|
||||
destroy_nr_list(&sched_ctrl->feedback_ul_harq);
|
||||
destroy_nr_list(&sched_ctrl->retrans_ul_harq);
|
||||
for (int i = 0; i < NR_MAX_HARQ_PROCESSES; ++i)
|
||||
for (int i = 0; i < NR_MAX_HARQ_PROCESSES; ++i) {
|
||||
free_transportBlock_buffer(&sched_ctrl->harq_processes[i].transportBlock);
|
||||
free_transportBlock_buffer(&sched_ctrl->harq_processes[i].transportBlock2);
|
||||
}
|
||||
free_sched_pucch_list(sched_ctrl);
|
||||
uid_linear_allocator_free(uia, UE->uid);
|
||||
LOG_I(NR_MAC, "Remove NR rnti 0x%04x\n", UE->rnti);
|
||||
@@ -3614,9 +3660,16 @@ void nr_mac_update_timers(module_id_t module_id)
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
|
||||
if (nr_mac_check_release(sched_ctrl)) {
|
||||
// trigger release first as nr_mac_release_ue() invalidates UE ptr
|
||||
nr_mac_trigger_release_complete(mac, UE->rnti);
|
||||
nr_mac_release_ue(mac, UE->rnti);
|
||||
// nakaolab UE release race fix:
|
||||
// Save rnti before nr_mac_trigger_release_complete — that call drops
|
||||
// the scheduler lock briefly (to send F1AP UE Context Release Complete),
|
||||
// and another thread (e.g., RRC DL handler) can free this UE during
|
||||
// that window, leaving UE->rnti pointing at freed memory.
|
||||
rnti_t rnti = UE->rnti;
|
||||
nr_mac_trigger_release_complete(mac, rnti);
|
||||
// Re-validate after lock re-acquired: skip release if already gone.
|
||||
if (find_nr_UE(&mac->UE_info, rnti) != NULL)
|
||||
nr_mac_release_ue(mac, rnti);
|
||||
// go back to examine the next UE, which is at the position the
|
||||
// current UE was
|
||||
UE--;
|
||||
|
||||
@@ -497,7 +497,9 @@ static void evaluate_sinr_report(NR_UE_info_t *UE,
|
||||
stats->num_sinr_meas++;
|
||||
|
||||
const int mcs_table = UE->current_DL_BWP.mcsTableIdx;
|
||||
const int nrOfLayers = get_dl_nrOfLayers(sched_ctrl, UE->current_DL_BWP.dci_format);
|
||||
/* NULL mac arg: SINR-based MCS estimation skips antenna-state rank cap
|
||||
(caller doesn't have nrmac in scope; this is only for max-MCS hint). */
|
||||
const int nrOfLayers = get_dl_nrOfLayers(NULL, sched_ctrl, UE->current_DL_BWP.dci_format);
|
||||
sched_ctrl->dl_max_mcs = get_mcs_from_SINRx10(mcs_table, sinr_report->r[0].SINRx10, nrOfLayers);
|
||||
|
||||
LOG_D(MAC, "Reported SSB-SINR = %01f, dl_max_mcs %d\n", sinr_report->r[0].SINRx10 / 10.0, sched_ctrl->dl_max_mcs);
|
||||
@@ -716,6 +718,7 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
|
||||
int cumul_bits = 0;
|
||||
int r_index = -1;
|
||||
int new_bf_index = -1;
|
||||
bool link_csi_decoded = false;
|
||||
for (int csi_report_id = 0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++) {
|
||||
nr_csi_report_t *csi_report = &UE->csi_report_template[csi_report_id];
|
||||
csi_report->nb_of_csi_ssb_report = 0;
|
||||
@@ -761,12 +764,25 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
|
||||
evaluate_cri_report(payload, cri_bitlen, cumul_bits, sched_ctrl);
|
||||
cumul_bits += cri_bitlen;
|
||||
ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen;
|
||||
if (ri_bitlen)
|
||||
if (ri_bitlen) {
|
||||
r_index = evaluate_ri_report(payload, ri_bitlen, csi_report->csi_meas_bitlen.ri_restriction, cumul_bits, sched_ctrl);
|
||||
} else {
|
||||
/* nakaolab: ri_bitlen=0 (single RI allowed via ri_restriction).
|
||||
* Pick that RI directly — without this, r_index stays -1 and trips
|
||||
* the DevAssert(ri>=0) in evaluate_cqi_report. */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if ((csi_report->csi_meas_bitlen.ri_restriction >> i) & 0x01) {
|
||||
r_index = i;
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cumul_bits += ri_bitlen;
|
||||
if (r_index != -1)
|
||||
skip_zero_padding(&cumul_bits, csi_report, r_index, bitlen);
|
||||
evaluate_cqi_report(payload, csi_report, cumul_bits, r_index, UE, cqi_table);
|
||||
link_csi_decoded |= r_index >= 0;
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI:
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true;
|
||||
@@ -775,8 +791,20 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
|
||||
evaluate_cri_report(payload, cri_bitlen, cumul_bits, sched_ctrl);
|
||||
cumul_bits += cri_bitlen;
|
||||
ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen;
|
||||
if (ri_bitlen)
|
||||
if (ri_bitlen) {
|
||||
r_index = evaluate_ri_report(payload, ri_bitlen, csi_report->csi_meas_bitlen.ri_restriction, cumul_bits, sched_ctrl);
|
||||
} else {
|
||||
/* nakaolab: ri_bitlen=0 (single RI allowed via ri_restriction).
|
||||
* Pick that RI directly — without this, r_index stays -1 and trips
|
||||
* the DevAssert(ri>=0) in evaluate_cqi_report. */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if ((csi_report->csi_meas_bitlen.ri_restriction >> i) & 0x01) {
|
||||
r_index = i;
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cumul_bits += ri_bitlen;
|
||||
if (r_index != -1)
|
||||
skip_zero_padding(&cumul_bits, csi_report, r_index, bitlen);
|
||||
@@ -784,6 +812,7 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id;
|
||||
cumul_bits += pmi_bitlen;
|
||||
evaluate_cqi_report(payload, csi_report, cumul_bits, r_index, UE, cqi_table);
|
||||
link_csi_decoded |= r_index >= 0;
|
||||
break;
|
||||
case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI:
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true;
|
||||
@@ -792,8 +821,20 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
|
||||
evaluate_cri_report(payload, cri_bitlen, cumul_bits, sched_ctrl);
|
||||
cumul_bits += cri_bitlen;
|
||||
ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen;
|
||||
if (ri_bitlen)
|
||||
if (ri_bitlen) {
|
||||
r_index = evaluate_ri_report(payload, ri_bitlen, csi_report->csi_meas_bitlen.ri_restriction, cumul_bits, sched_ctrl);
|
||||
} else {
|
||||
/* nakaolab: ri_bitlen=0 (single RI allowed via ri_restriction).
|
||||
* Pick that RI directly — without this, r_index stays -1 and trips
|
||||
* the DevAssert(ri>=0) in evaluate_cqi_report. */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if ((csi_report->csi_meas_bitlen.ri_restriction >> i) & 0x01) {
|
||||
r_index = i;
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cumul_bits += ri_bitlen;
|
||||
li_bitlen = evaluate_li_report(payload, csi_report, cumul_bits, r_index, sched_ctrl);
|
||||
cumul_bits += li_bitlen;
|
||||
@@ -803,6 +844,7 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id;
|
||||
cumul_bits += pmi_bitlen;
|
||||
evaluate_cqi_report(payload, csi_report, cumul_bits, r_index, UE, cqi_table);
|
||||
link_csi_decoded |= r_index >= 0;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1 == 0, "Invalid or not supported CSI measurement report\n");
|
||||
@@ -810,6 +852,10 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (link_csi_decoded) {
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.report_frame = frame;
|
||||
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.report_slot = slot;
|
||||
}
|
||||
if ((new_bf_index !=-1) && !nrmac->radio_config.do_TCI)
|
||||
// Trigger RRCReconfiguration. Need to be out of the for loop as it may modify csi_MeasConfig
|
||||
beam_switching_procedure(nrmac, UE, new_bf_index);
|
||||
@@ -882,8 +928,7 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, slot_t slot, con
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
if (((uci_01->pduBitmap >> 1) & 0x01)) {
|
||||
// iterate over received harq bits
|
||||
for (int harq_bit = 0; harq_bit < uci_01->harq.num_harq; harq_bit++) {
|
||||
const uint8_t harq_value = uci_01->harq.harq_list[harq_bit].harq_value;
|
||||
for (int harq_bit = 0; harq_bit < uci_01->harq.num_harq;) {
|
||||
const uint8_t harq_confidence = uci_01->harq.harq_confidence_level;
|
||||
NR_UE_harq_t *harq = find_harq(frame, slot, UE, nrmac->dl_bler.harq_round_max);
|
||||
if (!harq) {
|
||||
@@ -891,11 +936,16 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, slot_t slot, con
|
||||
break;
|
||||
}
|
||||
DevAssert(harq->is_waiting);
|
||||
const int n_ack_bits = harq->sched_pdsch.nrOfLayers > 4 ? 2 : 1;
|
||||
const int8_t pid = sched_ctrl->feedback_dl_harq.head;
|
||||
remove_front_nr_list(&sched_ctrl->feedback_dl_harq);
|
||||
LOG_D(NR_MAC,"%4d.%2d bit %d pid %d ack/nack %d\n",frame, slot, harq_bit,pid,harq_value);
|
||||
bool success = harq_confidence == 0 && harq_bit + n_ack_bits <= uci_01->harq.num_harq;
|
||||
for (int q = 0; q < n_ack_bits && harq_bit + q < uci_01->harq.num_harq; q++) {
|
||||
const uint8_t harq_value = uci_01->harq.harq_list[harq_bit + q].harq_value;
|
||||
LOG_D(NR_MAC, "%4d.%2d bit %d pid %d cw %d ack/nack %d\n", frame, slot, harq_bit + q, pid, q, harq_value);
|
||||
success &= harq_value == 0;
|
||||
}
|
||||
nr_mac_update_pdcch_closed_loop_adjust(sched_ctrl, harq_confidence != 0);
|
||||
bool success = harq_value == 0 && harq_confidence == 0;
|
||||
// TCI state switch occurs at the first slot that is after slot n_+ T_HARQ + 3N_sf_slot (8.10.3 of 38.133)
|
||||
if (success && harq->start_tci_timer) {
|
||||
int slots = 3 * nrmac->frame_structure.numb_slots_frame / 10;
|
||||
@@ -919,6 +969,7 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, slot_t slot, con
|
||||
// DTX for each _bit_, but maybe once for PUCCH is enough? not sure
|
||||
nr_mac_signal_dtx(&sched_ctrl->pucch_pc);
|
||||
}
|
||||
harq_bit += n_ack_bits;
|
||||
}
|
||||
|
||||
// tpc (power control) only if we received AckNack
|
||||
@@ -984,19 +1035,24 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, frame_t frame, slot_t slot, c
|
||||
|
||||
if ((uci_234->pduBitmap >> 1) & 0x01) {
|
||||
// iterate over received harq bits
|
||||
for (int harq_bit = 0; harq_bit < uci_234->harq.harq_bit_len; harq_bit++) {
|
||||
const int acknack = ((uci_234->harq.harq_payload[harq_bit >> 3]) >> harq_bit) & 0x01;
|
||||
for (int harq_bit = 0; harq_bit < uci_234->harq.harq_bit_len;) {
|
||||
NR_UE_harq_t *harq = find_harq(frame, slot, UE, RC.nrmac[mod_id]->dl_bler.harq_round_max);
|
||||
if (!harq) {
|
||||
LOG_E(NR_MAC, "UE %04x: Could not find a HARQ process at %4d.%2d!\n", UE->rnti, frame, slot);
|
||||
break;
|
||||
}
|
||||
DevAssert(harq->is_waiting);
|
||||
const int n_ack_bits = harq->sched_pdsch.nrOfLayers > 4 ? 2 : 1;
|
||||
const int8_t pid = sched_ctrl->feedback_dl_harq.head;
|
||||
remove_front_nr_list(&sched_ctrl->feedback_dl_harq);
|
||||
LOG_D(NR_MAC,"%4d.%2d bit %d pid %d ack/nack %d\n",frame, slot, harq_bit, pid, acknack);
|
||||
bool success = uci_234->harq.harq_crc != 1 && harq_bit + n_ack_bits <= uci_234->harq.harq_bit_len;
|
||||
for (int q = 0; q < n_ack_bits && harq_bit + q < uci_234->harq.harq_bit_len; q++) {
|
||||
const int bit = harq_bit + q;
|
||||
const int acknack = (uci_234->harq.harq_payload[bit >> 3] >> (bit & 7)) & 0x01;
|
||||
LOG_D(NR_MAC, "%4d.%2d bit %d pid %d cw %d ack/nack %d\n", frame, slot, bit, pid, q, acknack);
|
||||
success &= acknack;
|
||||
}
|
||||
// TCI state switch occurs at the first slot that is after slot n_+ T_HARQ + 3N_sf_slot (8.10.3 of 38.133)
|
||||
bool success = uci_234->harq.harq_crc != 1 && acknack;
|
||||
if (success && harq->start_tci_timer) {
|
||||
int slots = 3 * nrmac->frame_structure.numb_slots_frame / 10;
|
||||
nr_timer_setup(&sched_ctrl->tci_beam_switch, slots, 1);
|
||||
@@ -1004,6 +1060,7 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, frame_t frame, slot_t slot, c
|
||||
harq->start_tci_timer = false;
|
||||
}
|
||||
handle_dl_harq(nrmac, UE, pid, success, nrmac->dl_bler.harq_round_max);
|
||||
harq_bit += n_ack_bits;
|
||||
}
|
||||
free(uci_234->harq.harq_payload);
|
||||
}
|
||||
@@ -1353,4 +1410,3 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, slot_t slot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -373,7 +373,7 @@ uint16_t get_pm_index(const gNB_MAC_INST *nrmac,
|
||||
int get_mcs_from_SINRx10(int mcs_table, int SINRx10, int Nl);
|
||||
uint8_t get_mcs_from_cqi(int mcs_table, int cqi_table, int cqi_idx);
|
||||
|
||||
uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format);
|
||||
uint8_t get_dl_nrOfLayers(const gNB_MAC_INST *mac, const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format);
|
||||
int get_ul_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format);
|
||||
|
||||
void free_sched_pucch_list(NR_UE_sched_ctrl_t *sched_ctrl);
|
||||
@@ -464,6 +464,7 @@ bool prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE);
|
||||
void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_len, void *data);
|
||||
|
||||
void finish_nr_dl_harq(NR_UE_sched_ctrl_t *sched_ctrl, int harq_pid);
|
||||
void update_sched_pdsch_codeword_tbs(NR_sched_pdsch_t *sched);
|
||||
void abort_nr_dl_harq(NR_UE_info_t* UE, int8_t harq_pid);
|
||||
|
||||
void nr_mac_trigger_release_timer(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing);
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#include "LAYER2/NR_MAC_COMMON/nr_mac_common.h"
|
||||
#include "LAYER2/NR_MAC_gNB/mac_config.h"
|
||||
#include "NR_TAG.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_antenna_state.h"
|
||||
|
||||
/* Defs */
|
||||
#define MAX_NUM_BWP 5
|
||||
@@ -459,6 +460,7 @@ typedef struct NR_sched_pusch {
|
||||
|
||||
typedef struct NR_pdsch_dmrs {
|
||||
uint8_t dmrs_ports_id;
|
||||
uint16_t dmrs_ports;
|
||||
uint8_t N_PRB_DMRS;
|
||||
uint8_t N_DMRS_SLOT;
|
||||
uint16_t dl_dmrs_symb_pos;
|
||||
@@ -484,6 +486,8 @@ typedef struct NR_sched_pdsch {
|
||||
uint16_t R;
|
||||
uint8_t Qm;
|
||||
uint32_t tb_size;
|
||||
/// Second transport block for rank 5--8 (same MCS/R/Qm for bundled HARQ)
|
||||
uint32_t tb_size2;
|
||||
|
||||
/// DL HARQ PID to use for this UE, or -1 for "any new"
|
||||
int8_t dl_harq_pid;
|
||||
@@ -510,6 +514,7 @@ typedef struct NR_UE_harq {
|
||||
|
||||
/* Transport block to be sent using this HARQ process */
|
||||
byte_array_t transportBlock;
|
||||
byte_array_t transportBlock2;
|
||||
uint32_t tb_size; // size of currently stored TB
|
||||
bool start_tci_timer;
|
||||
/// sched_pdsch keeps information on MCS etc used for the initial transmission
|
||||
@@ -546,6 +551,8 @@ struct CRI_RI_LI_PMI_CQI {
|
||||
uint8_t wb_cqi_2tb;
|
||||
uint8_t cqi_table;
|
||||
uint8_t csi_report_id;
|
||||
uint16_t report_frame;
|
||||
uint16_t report_slot;
|
||||
bool print_report;
|
||||
};
|
||||
|
||||
@@ -714,6 +721,9 @@ typedef struct NR_mac_dir_stats {
|
||||
uint32_t total_rbs_retx;
|
||||
uint32_t num_mac_sdu;
|
||||
uint32_t current_rbs;
|
||||
// Most recently scheduled spatial layer count. Unlike current_rbs this is
|
||||
// intentionally persistent so asynchronous E2 sampling does not miss it.
|
||||
uint8_t last_layers;
|
||||
} NR_mac_dir_stats_t;
|
||||
|
||||
typedef struct NR_mac_stats {
|
||||
@@ -965,6 +975,10 @@ typedef struct gNB_MAC_INST_s {
|
||||
nr_mac_config_t radio_config;
|
||||
nr_rlc_configuration_t rlc_config;
|
||||
|
||||
/// Pointer to PHY antenna state (port mute mask) — set in nr-gnb init,
|
||||
/// used by get_dl_nrOfLayers to cap MIMO rank to active TX port count.
|
||||
nr_antenna_state_t *antenna_state;
|
||||
|
||||
NR_sched_ctrl_sib1_t *sched_ctrlSIB1;
|
||||
NR_sched_pdcch_t *sched_pdcch_otherSI;
|
||||
uint16_t cset0_bwp_start;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "utils.h"
|
||||
#include "xer_encoder.h"
|
||||
|
||||
#define NR_MAX_SUPPORTED_DL_LAYERS 4
|
||||
#define NR_MAX_SUPPORTED_DL_LAYERS NR_MAX_NB_LAYERS
|
||||
|
||||
/* Default values for measurement gap configuration */
|
||||
#define DEFAULT_MGRP NR_GapConfig__mgrp_ms160
|
||||
@@ -655,10 +655,18 @@ static void set_dl_maxmimolayers(NR_PDSCH_ServingCellConfig_t *pdsch_servingcell
|
||||
pdsch_servingcellconfig->ext1->maxMIMO_Layers = calloc(1, sizeof(*pdsch_servingcellconfig->ext1->maxMIMO_Layers));
|
||||
|
||||
long l = ue_supported_dl_layers(scc, uecap);
|
||||
long ue_supported_layers = l > 1 ? l : 2; // min UE supported layers = 2
|
||||
if (maxMIMO_layers == -1)
|
||||
// nakaolab Patch 6: when called with NULL uecap (initial config before
|
||||
// capability exchange), ue_supported_dl_layers returns -1. Fall back to
|
||||
// maxMIMO_layers from config directly instead of clamping to 2.
|
||||
long ue_supported_layers;
|
||||
if (l < 1) {
|
||||
ue_supported_layers = (maxMIMO_layers > 0) ? maxMIMO_layers : NR_MAX_SUPPORTED_DL_LAYERS;
|
||||
} else {
|
||||
ue_supported_layers = l;
|
||||
}
|
||||
if (maxMIMO_layers == -1)
|
||||
*pdsch_servingcellconfig->ext1->maxMIMO_Layers = min(NR_MAX_SUPPORTED_DL_LAYERS, ue_supported_layers);
|
||||
else
|
||||
else
|
||||
*pdsch_servingcellconfig->ext1->maxMIMO_Layers = min(maxMIMO_layers, ue_supported_layers);
|
||||
}
|
||||
|
||||
@@ -1282,7 +1290,9 @@ static void config_pucch_resset1(const NR_ServingCellConfigCommon_t *scc,
|
||||
pucchfmt2->interslotFrequencyHopping = NULL;
|
||||
pucchfmt2->additionalDMRS = NULL;
|
||||
pucchfmt2->maxCodeRate = calloc(1,sizeof(*pucchfmt2->maxCodeRate));
|
||||
*pucchfmt2->maxCodeRate = NR_PUCCH_MaxCodeRate_zeroDot15;
|
||||
// nakaolab Patch 5: bump from zeroDot15 (19.2 bit capacity) to zeroDot25
|
||||
// (32 bit capacity) so 4-port CSI report (20 bits) fits in PUCCH.
|
||||
*pucchfmt2->maxCodeRate = NR_PUCCH_MaxCodeRate_zeroDot25;
|
||||
pucchfmt2->nrofSlots = NULL;
|
||||
pucchfmt2->pi2BPSK = NULL;
|
||||
|
||||
@@ -1691,8 +1701,14 @@ static NR_PTRS_DownlinkConfig_t *config_dlptrs(const nr_ptrs_config_t *ptrs)
|
||||
return ptrs_config;
|
||||
}
|
||||
|
||||
static NR_SetupRelease_PDSCH_Config_t *config_pdsch(uint64_t ssb_bitmap, int bwp_Id, bool do_TCI, nr_ptrs_config_t *ptrs)
|
||||
static NR_SetupRelease_PDSCH_Config_t *config_pdsch(uint64_t ssb_bitmap,
|
||||
int bwp_Id,
|
||||
const nr_mac_config_t *configuration)
|
||||
{
|
||||
const int antenna_ports = configuration->pdsch_AntennaPorts.N1 * configuration->pdsch_AntennaPorts.N2
|
||||
* configuration->pdsch_AntennaPorts.XP;
|
||||
const int configured_layers = configuration->maxMIMO_layers > 0 ? configuration->maxMIMO_layers : antenna_ports;
|
||||
const bool two_codewords = min(configured_layers, NR_MAX_SUPPORTED_DL_LAYERS) > 4;
|
||||
NR_SetupRelease_PDSCH_Config_t *setup_pdsch_Config = calloc(1,sizeof(*setup_pdsch_Config));
|
||||
setup_pdsch_Config->present = NR_SetupRelease_PDSCH_Config_PR_setup;
|
||||
NR_PDSCH_Config_t *pdsch_Config = calloc(1, sizeof(*pdsch_Config));
|
||||
@@ -1701,15 +1717,20 @@ static NR_SetupRelease_PDSCH_Config_t *config_pdsch(uint64_t ssb_bitmap, int bwp
|
||||
pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->present = NR_SetupRelease_DMRS_DownlinkConfig_PR_setup;
|
||||
pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup = calloc(1, sizeof(*pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup));
|
||||
NR_DMRS_DownlinkConfig_t *dmrs_DownlinkForPDSCH_MappingTypeA = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup;
|
||||
if (ptrs) {
|
||||
NR_PTRS_DownlinkConfig_t *ptrs_config = config_dlptrs(ptrs);
|
||||
if (configuration->ptrs && !two_codewords) {
|
||||
NR_PTRS_DownlinkConfig_t *ptrs_config = config_dlptrs(configuration->ptrs);
|
||||
NR_SetupRelease_PTRS_DownlinkConfig_t *phaseTrackingRS = calloc(1, sizeof(*phaseTrackingRS));
|
||||
phaseTrackingRS->present = NR_SetupRelease_PTRS_DownlinkConfig_PR_setup;
|
||||
phaseTrackingRS->choice.setup = ptrs_config;
|
||||
dmrs_DownlinkForPDSCH_MappingTypeA->phaseTrackingRS = phaseTrackingRS;
|
||||
}
|
||||
if (configuration->ptrs && two_codewords)
|
||||
LOG_W(NR_MAC, "PDSCH PTRS is disabled for rank 5--8 until two-codeword PTRS is supported\n");
|
||||
dmrs_DownlinkForPDSCH_MappingTypeA->dmrs_Type = NULL;
|
||||
dmrs_DownlinkForPDSCH_MappingTypeA->maxLength = NULL;
|
||||
if (two_codewords)
|
||||
asn1cCallocOne(dmrs_DownlinkForPDSCH_MappingTypeA->maxLength, NR_DMRS_DownlinkConfig__maxLength_len2);
|
||||
else
|
||||
dmrs_DownlinkForPDSCH_MappingTypeA->maxLength = NULL;
|
||||
dmrs_DownlinkForPDSCH_MappingTypeA->scramblingID0 = NULL;
|
||||
dmrs_DownlinkForPDSCH_MappingTypeA->scramblingID1 = NULL;
|
||||
dmrs_DownlinkForPDSCH_MappingTypeA->dmrs_AdditionalPosition = calloc(1, sizeof(*dmrs_DownlinkForPDSCH_MappingTypeA->dmrs_AdditionalPosition));
|
||||
@@ -1718,13 +1739,16 @@ static NR_SetupRelease_PDSCH_Config_t *config_pdsch(uint64_t ssb_bitmap, int bwp
|
||||
|
||||
pdsch_Config->dataScramblingIdentityPDSCH = NULL;
|
||||
pdsch_Config->resourceAllocation = NR_PDSCH_Config__resourceAllocation_resourceAllocationType1;
|
||||
if (two_codewords)
|
||||
asn1cCallocOne(pdsch_Config->maxNrofCodeWordsScheduledByDCI,
|
||||
NR_PDSCH_Config__maxNrofCodeWordsScheduledByDCI_n2);
|
||||
|
||||
pdsch_Config->prb_BundlingType.present = NR_PDSCH_Config__prb_BundlingType_PR_staticBundling;
|
||||
pdsch_Config->prb_BundlingType.choice.staticBundling = calloc(1, sizeof(*pdsch_Config->prb_BundlingType.choice.staticBundling));
|
||||
pdsch_Config->prb_BundlingType.choice.staticBundling->bundleSize = calloc(1, sizeof(*pdsch_Config->prb_BundlingType.choice.staticBundling->bundleSize));
|
||||
*pdsch_Config->prb_BundlingType.choice.staticBundling->bundleSize = NR_PDSCH_Config__prb_BundlingType__staticBundling__bundleSize_wideband;
|
||||
|
||||
if (do_TCI) {
|
||||
if (configuration->do_TCI) {
|
||||
int n_ssb = 0;
|
||||
if (!pdsch_Config->tci_StatesToAddModList)
|
||||
pdsch_Config->tci_StatesToAddModList=calloc(1,sizeof(*pdsch_Config->tci_StatesToAddModList));
|
||||
@@ -1840,7 +1864,7 @@ static NR_BWP_Downlink_t *config_downlinkBWP(const NR_ServingCellConfigCommon_t
|
||||
asn1cSeqAdd(&bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss3);
|
||||
|
||||
bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToReleaseList = NULL;
|
||||
bwp->bwp_Dedicated->pdsch_Config = config_pdsch(ssb_bitmap, bwp->bwp_Id, configuration->do_TCI, configuration->ptrs);
|
||||
bwp->bwp_Dedicated->pdsch_Config = config_pdsch(ssb_bitmap, bwp->bwp_Id, configuration);
|
||||
|
||||
set_dl_mcs_table(bwp->bwp_Common->genericParameters.subcarrierSpacing,
|
||||
force_256qam_off ? NULL : uecap,
|
||||
@@ -3389,7 +3413,7 @@ static NR_BWP_DownlinkDedicated_t *configure_initial_dl_bwp(const NR_ServingCell
|
||||
asn1cSeqAdd(&pdcch_Config->searchSpacesToAddModList->list, ss2);
|
||||
bwp_Dedicated->pdcch_Config->choice.setup = pdcch_Config;
|
||||
|
||||
bwp_Dedicated->pdsch_Config = config_pdsch(bitmap, 0, configuration->do_TCI, configuration->ptrs);
|
||||
bwp_Dedicated->pdsch_Config = config_pdsch(bitmap, 0, configuration);
|
||||
// we might call configuration of initial BWP for BWP switch when we already have UE capabilities
|
||||
set_dl_mcs_table(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing,
|
||||
configuration->force_256qam_off ? NULL : uecap,
|
||||
@@ -4062,7 +4086,7 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC
|
||||
|
||||
configDedicated->initialDownlinkBWP = calloc(1, sizeof(*configDedicated->initialDownlinkBWP));
|
||||
configDedicated->initialDownlinkBWP->pdcch_Config = NULL;
|
||||
configDedicated->initialDownlinkBWP->pdsch_Config = config_pdsch(bitmap, 0, configuration->do_TCI, configuration->ptrs);
|
||||
configDedicated->initialDownlinkBWP->pdsch_Config = config_pdsch(bitmap, 0, configuration);
|
||||
configDedicated->initialDownlinkBWP->sps_Config = NULL; // calloc(1,sizeof(struct NR_SetupRelease_SPS_Config));
|
||||
|
||||
configDedicated->initialDownlinkBWP->radioLinkMonitoringConfig = NULL;
|
||||
|
||||
Reference in New Issue
Block a user