Fix scheduler for long prach

Long PRACH extends beyond a slot. Changes necessary to mark future slots
that may contain prach in ru, phy and mac functions.

In RU, the PRACH IDFT is done only after receiving last slot and marks
for L1 to start processing. The L1 processes at the last prach slot and
reports to MAC with the first slot index.

In MAC scheduler, the VRB for future slots are also marked as used.
PRACH scheduler is called in advance one frame minus num prach slots.
This commit is contained in:
Sakthivel Velumani
2025-02-25 11:58:41 -05:00
parent 94c74f4a1d
commit cf0206e7c6
13 changed files with 132 additions and 59 deletions
+23 -10
View File
@@ -475,7 +475,8 @@ static void config_common(gNB_MAC_INST *nrmac,
}
}
frame_type_t frame_type = get_frame_type(*frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing);
NR_FreqBandIndicatorNR_t band = *frequencyInfoDL->frequencyBandList.list.array[0];
frame_type_t frame_type = get_frame_type(band, *scc->ssbSubcarrierSpacing);
nrmac->common_channels[0].frame_type = frame_type;
// Cell configuration
@@ -511,18 +512,26 @@ static void config_common(gNB_MAC_INST *nrmac,
cfg->prach_config.prach_sequence_length.tl.tag = NFAPI_NR_CONFIG_PRACH_SEQUENCE_LENGTH_TAG;
cfg->num_tlv++;
cfg->prach_config.prach_ConfigurationIndex.value = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
cfg->prach_config.prach_ConfigurationIndex.tl.tag = NFAPI_NR_CONFIG_PRACH_CONFIG_INDEX_TAG;
cfg->num_tlv++;
if (rach_ConfigCommon->msg1_SubcarrierSpacing)
cfg->prach_config.prach_sub_c_spacing.value = *rach_ConfigCommon->msg1_SubcarrierSpacing;
else
cfg->prach_config.prach_sub_c_spacing.value = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
else {
// If absent, use SCS as derived from the prach-ConfigurationIndex (for 839)
int config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
int frame_type = get_frame_type(band, frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing);
const int64_t *prach_config_info_p = get_prach_config_info(frequency_range, config_index, frame_type);
int format = prach_config_info_p[0];
cfg->prach_config.prach_sub_c_spacing.value = get_delta_f_RA_long(format);
}
cfg->prach_config.prach_sub_c_spacing.tl.tag = NFAPI_NR_CONFIG_PRACH_SUB_C_SPACING_TAG;
cfg->num_tlv++;
cfg->prach_config.restricted_set_config.value = rach_ConfigCommon->restrictedSetConfig;
cfg->prach_config.restricted_set_config.tl.tag = NFAPI_NR_CONFIG_RESTRICTED_SET_CONFIG_TAG;
cfg->num_tlv++;
cfg->prach_config.prach_ConfigurationIndex.value = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
cfg->prach_config.prach_ConfigurationIndex.tl.tag = NFAPI_NR_CONFIG_PRACH_CONFIG_INDEX_TAG;
cfg->num_tlv++;
switch (rach_ConfigCommon->rach_ConfigGeneric.msg1_FDM) {
case 0:
@@ -543,10 +552,6 @@ static void config_common(gNB_MAC_INST *nrmac,
cfg->prach_config.num_prach_fd_occasions.tl.tag = NFAPI_NR_CONFIG_NUM_PRACH_FD_OCCASIONS_TAG;
cfg->num_tlv++;
cfg->prach_config.prach_ConfigurationIndex.value = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
cfg->prach_config.prach_ConfigurationIndex.tl.tag = NFAPI_NR_CONFIG_PRACH_CONFIG_INDEX_TAG;
cfg->num_tlv++;
cfg->prach_config.num_prach_fd_occasions_list = (nfapi_nr_num_prach_fd_occasions_t *)malloc(
cfg->prach_config.num_prach_fd_occasions.value * sizeof(nfapi_nr_num_prach_fd_occasions_t));
for (int i = 0; i < cfg->prach_config.num_prach_fd_occasions.value; i++) {
@@ -588,6 +593,14 @@ static void config_common(gNB_MAC_INST *nrmac,
cfg->prach_config.ssb_per_rach.tl.tag = NFAPI_NR_CONFIG_SSB_PER_RACH_TAG;
cfg->num_tlv++;
// compute and store prach duration in slots from rach_ConfigCommon
NR_RACH_ConfigGeneric_t *rachConfig =
&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric;
NR_COMMON_channels_t *cc = nrmac->common_channels;
const uint32_t pointA = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA;
const int prach_fmt = (get_nr_prach_format_from_index(rachConfig->prach_ConfigurationIndex, pointA, cc->frame_type) & 0xff);
cc->prach_len = (prach_fmt < 4) ? get_long_prach_dur(prach_fmt, *scc->ssbSubcarrierSpacing) : 1;
// SSB Table Configuration
cfg->ssb_table.ssb_offset_point_a.value =
+3 -3
View File
@@ -223,11 +223,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, sub_frame_
if (get_softmodem_params()->phy_test == 0) {
/* we need to make sure that resources for PRACH are free. To avoid that
e.g. PUSCH has already been scheduled, make sure we schedule before
anything else: below, we simply assume an advance one frame (minus one
slot, because otherwise we would allocate the current slot in
anything else: below, we simply assume an advance one frame (minus
prach duration, because otherwise we would allocate the current slot in
UL_tti_req_ahead), but be aware that, e.g., K2 is allowed to be larger
(schedule_nr_prach will assert if resources are not free). */
const sub_frame_t n_slots_ahead = slots_frame - 1 + get_NTN_Koffset(scc);
const int n_slots_ahead = slots_frame - cc->prach_len + get_NTN_Koffset(scc);
const frame_t f = (frame + (slot + n_slots_ahead) / slots_frame) % 1024;
const sub_frame_t s = (slot + n_slots_ahead) % slots_frame;
schedule_nr_prach(module_idP, f, s);
+44 -7
View File
@@ -356,6 +356,27 @@ static void schedule_nr_MsgA_pusch(NR_UplinkConfigCommon_t *uplinkConfigCommon,
UL_tti_req->n_pdus += 1;
}
static void fill_vrb(const frame_t frame,
const sub_frame_t slot,
int nb_rb,
int beam_idx,
int vrb_size,
int slots_frame,
int rb_start,
int start_symb,
int num_symb,
NR_COMMON_channels_t *cc)
{
const int index = ul_buffer_index(frame, slot, slots_frame, vrb_size);
uint16_t *vrb_map_UL = &cc->vrb_map_UL[beam_idx][index * MAX_BWP_SIZE];
for (int i = 0; i < nb_rb; ++i) {
AssertFatal(
!(vrb_map_UL[rb_start + i] & SL_to_bitmap(start_symb, num_symb)),
"PRACH resources are already occupied!\n");
vrb_map_UL[rb_start + i] |= SL_to_bitmap(start_symb, num_symb);
}
}
void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
{
gNB_MAC_INST *gNB = RC.nrmac[module_idP];
@@ -557,13 +578,29 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP
// block resources in vrb_map_UL
const int mu_pusch = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
const int16_t n_ra_rb = get_N_RA_RB(cfg->prach_config.prach_sub_c_spacing.value, mu_pusch);
index = ul_buffer_index(frameP, slotP, slots_frame, gNB->vrb_map_UL_size);
uint16_t *vrb_map_UL = &cc->vrb_map_UL[beam.idx][index * MAX_BWP_SIZE];
for (int i = 0; i < n_ra_rb * fdm; ++i) {
AssertFatal(
!(vrb_map_UL[bwp_start + rach_ConfigGeneric->msg1_FrequencyStart + i] & SL_to_bitmap(start_symbol, N_t_slot * N_dur)),
"PRACH resources are already occupied!\n");
vrb_map_UL[bwp_start + rach_ConfigGeneric->msg1_FrequencyStart + i] |= SL_to_bitmap(start_symbol, N_t_slot * N_dur);
// mark PRBs as occupied for current and future slots if prach extends beyond current slot
int total_prach_slots;
if (format0 < 4) {
N_dur = 14; // number of PRACH symbols in PRACH slot
total_prach_slots = get_long_prach_dur(format0, mu_pusch);
AssertFatal(slotP + total_prach_slots - 1 < slots_frame, "PRACH cannot extend across frames\n");
} else {
// TODO: to be revisited for format B4 (also extends beyond current slot for FR1 30kHz SCS and FR2)
AssertFatal((format != 0xb4) || (mu_pusch < 1), "Format B4 not supported for this PUSCH SCS\n");
total_prach_slots = 1;
}
// reserve PRBs occupied by PRACH in all PRACH slot.
for (int i = 0; i < total_prach_slots; i++) {
fill_vrb(frameP,
slotP + i,
n_ra_rb * fdm,
beam.idx,
gNB->vrb_map_UL_size,
slots_frame,
bwp_start + rach_ConfigGeneric->msg1_FrequencyStart,
start_symbol,
N_t_slot * N_dur,
cc);
}
}
}
+2
View File
@@ -301,6 +301,8 @@ typedef struct {
uint8_t ssb_index[MAX_NUM_OF_SSB];
//CB preambles for each SSB
int cb_preambles_per_ssb;
/// Max prach length in slots
int prach_len;
} NR_COMMON_channels_t;
// SP ZP CSI-RS Resource Set Activation/Deactivation MAC CE