Fix data race in NR UE MSG3 scheduling

Fixed a data race between DL processing of RAR and UL scheduler, which
might result in dropping MSG3.

It was possible that the UL scheduler for the UL slot which RAR
indicates as MSG3 slot was already run by the time the RAR was decoded.

Therefore when DCI for RAR is decoded, assume worst case and halt the
earliest corresponding UL scheduler call until RAR is decoded solving
the data race. This also in turn halts all later scheduling due to
sequential nature of the UL scheduler calls.
This commit is contained in:
Bartosz Podrygajlo
2025-06-03 14:41:06 +02:00
parent bab05384a4
commit 85f3e62caf
8 changed files with 36 additions and 25 deletions
+2 -1
View File
@@ -728,7 +728,8 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE,
}
sampleShift = pbch_pdcch_processing(UE, proc, phy_data);
if (phy_data->dlsch[0].active && phy_data->dlsch[0].rnti_type == TYPE_C_RNTI_) {
if (phy_data->dlsch[0].active
&& (phy_data->dlsch[0].rnti_type == TYPE_C_RNTI_ || phy_data->dlsch[0].rnti_type == TYPE_RA_RNTI_)) {
// indicate to tx thread to wait for DLSCH decoding
if (phy_data->dlsch[0].dlsch_config.k1_feedback) { // if feedback is 0 there is no HARQ associated with this DLSCH
const int ack_nack_slot = (proc->nr_slot_rx + phy_data->dlsch[0].dlsch_config.k1_feedback) % fp->slots_per_frame;
+1 -1
View File
@@ -815,7 +815,7 @@ static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
}
// DLSCH decoding finished! don't wait anymore in Tx process, we know if we should answer ACK/NACK PUCCH
if (dlsch[0].rnti_type == TYPE_C_RNTI_ && dlsch[0].dlsch_config.k1_feedback) {
if ((dlsch[0].rnti_type == TYPE_C_RNTI_ || dlsch[0].rnti_type == TYPE_RA_RNTI_) && dlsch[0].dlsch_config.k1_feedback) {
const int ack_nack_slot_and_frame =
(proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) + proc->frame_rx * ue->frame_parms.slots_per_frame;
dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]);
+17 -2
View File
@@ -368,8 +368,7 @@ NR_tda_info_t get_ul_tda_info(const NR_UE_UL_BWP_t *ul_bwp,
NR_PUSCH_TimeDomainResourceAllocationList_t *tdalist = get_ul_tdalist(ul_bwp, controlResourceSetId, ss_type, rnti_type);
// Definition of value j in Table 6.1.2.1.1-4 of 38.214
int scs = ul_bwp->scs;
AssertFatal(scs >= 0 && scs < 5, "Subcarrier spacing indicatior %d invalid value\n", scs);
int j = scs == 0 ? 1 : scs;
int j = get_j_for_k2(scs);
if (tdalist) {
tda_info.valid_tda = tda_index < tdalist->list.count;
if (!tda_info.valid_tda) {
@@ -5129,3 +5128,19 @@ int nr_get_prach_or_ul_mu(const NR_MsgA_ConfigCommon_r16_t *msgacc,
return mu;
}
int get_delta_for_k2(int mu)
{
// 38.214 Table 6.1.2.1.1-5: Definition of value Δ
int delta_table[] = {2, 3, 4, 6, 24, 48};
AssertFatal(mu >= 0 && mu < sizeofArray(delta_table), "Invalid numerology %d\n", mu);
return delta_table[mu];
}
int get_j_for_k2(int mu)
{
// 38.214 Table 6.1.2.1.1-4: Definition of value j
int j_table[] = {1, 1, 2, 3, 11, 21};
AssertFatal(mu >= 0 && mu < sizeofArray(j_table), "Invalid numerology %d\n", mu);
return j_table[mu];
}
@@ -318,4 +318,8 @@ int get_nrofHARQ_ProcessesForPUSCH(const NR_UE_ServingCell_Info_t *sc_info);
int nr_get_prach_or_ul_mu(const NR_MsgA_ConfigCommon_r16_t *msgacc, const NR_RACH_ConfigCommon_t *rach_ConfigCommon, const int ul_mu);
int get_delta_for_k2(int mu);
int get_j_for_k2(int mu);
#endif
@@ -933,6 +933,15 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac,
const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing);
uint16_t feedback_ti = 0;
if (rnti_type == TYPE_RA_RNTI_) {
// RA-RNTI indicates RAR. Ensure we can decode RAR before the earliest UL scheduler call
// that can process the MSG3. Also assume that RAR is sent in the same slot as DCI (k0 == 0)
// This is not perfect as the MSG3 might end up being scheduled later, so we could be
// halting the UL scheduler for a longer time than necessary.
feedback_ti = max(1 + GET_DURATION_RX_TO_TX(&mac->ntn_ta, dlsch_pdu->SubcarrierSpacing),
get_delta_for_k2(mac->current_UL_BWP->scs) + get_j_for_k2(mac->current_UL_BWP->scs));
}
if (rnti_type != TYPE_RA_RNTI_ && rnti_type != TYPE_SI_RNTI_) {
if (!get_FeedbackDisabled(mac->sc_info.downlinkHARQ_FeedbackDisabled_r17, dci->harq_pid.val)) {
feedback_ti = 1 + dci->pdsch_to_harq_feedback_timing_indicator.val + ntn_ue_koffset;
+1 -16
View File
@@ -1547,22 +1547,7 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac,
if (is_Msg3) {
switch (mu) {
case 0:
delta = 2;
break;
case 1:
delta = 3;
break;
case 2:
delta = 4;
break;
case 3:
delta = 6;
break;
default:
AssertFatal(1 == 0, "Invalid numerology %i\n", mu);
}
delta = get_delta_for_k2(mu);
AssertFatal((k2 + delta) > GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu),
"Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to "
@@ -58,8 +58,6 @@ static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu,
int fh);
static void nr_fill_rar(uint8_t Mod_idP, NR_UE_info_t *UE, uint8_t *dlsch_buffer, nfapi_nr_pusch_pdu_t *pusch_pdu);
static const uint8_t DELTA[4] = {2, 3, 4, 6};
static const float ssb_per_rach_occasion[8] = {0.125, 0.25, 0.5, 1, 2, 4, 8};
static int16_t ssb_index_from_prach(module_id_t module_idP,
@@ -1566,7 +1564,7 @@ static void nr_generate_Msg2(module_id_t module_idP,
const NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
bool ret = get_feasible_msg3_tda(scc,
DELTA[ul_bwp->scs],
get_delta_for_k2(ul_bwp->scs),
ul_bwp->tdaList_Common,
frameP,
slotP,
+1 -2
View File
@@ -1066,7 +1066,6 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay)
AssertFatal(tda->list.count == 0, "already have pusch_TimeDomainAllocationList members\n");
const int k2 = min_fb_delay;
uint8_t DELTA[4]= {2,3,4,6}; // Delta parameter for Msg3
int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing;
struct NR_SetupRelease_PUSCH_ConfigCommon *pusch_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon;
@@ -1099,7 +1098,7 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay)
int tdd_period_idx = get_tdd_period_idx(scc->tdd_UL_DL_ConfigurationCommon);
int nb_periods_per_frame = get_nb_periods_per_frame(tdd_period_idx);
int nb_slots_per_period = ((1 << mu) * 10) / nb_periods_per_frame;
int k2_msg3 = nb_slots_per_period - DELTA[mu];
int k2_msg3 = nb_slots_per_period - get_delta_for_k2(mu);
struct NR_PUSCH_TimeDomainResourceAllocation *puschTdrAllocMsg3 = set_TimeDomainResourceAllocation(k2_msg3, 3, ul_symb);
if (*puschTdrAllocMsg3->k2 < min_fb_delay)
*puschTdrAllocMsg3->k2 += nb_slots_per_period;