diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 93db0d1945..4f55f73db1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -38,45 +38,58 @@ //#define SRS_IND_DEBUG -/* \brief Get the number of UL TDAs that could be used in frame and slot, reachable +/* \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 * suitable TDA, and the function returns the number of suitable TDAs, or 0. */ -int get_num_ul_tda(gNB_MAC_INST *nrmac, int frame, int slot, int k2, const NR_tda_info_t **first_idx) +int get_num_ul_tda(gNB_MAC_INST *nrmac, int slot, int k2, const NR_tda_info_t **first_idx) { /* we assume that this function is mutex-protected from outside */ NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock); - /* there is a mixed slot only when in TDD */ - frame_structure_t *fs = &nrmac->frame_structure; + const frame_structure_t *fs = &nrmac->frame_structure; + const int slot_period = slot % fs->numb_slots_period; + const tdd_bitmap_t *bm = &fs->period_cfg.tdd_slot_bitmap[slot_period]; + /* For some reason, we only store the number of symbols if it's mixed */ + const int num_ul_symbols = bm->slot_type == TDD_NR_MIXED_SLOT ? bm->num_ul_symbols : 14; + const uint16_t ul_bitmap = SL_to_bitmap(14 - num_ul_symbols, num_ul_symbols); - /* TODO: we assume currently that all UL TDA have same k2, check below */ - NR_tda_info_t *tda_info = seq_arr_at(&nrmac->ul_tda, 0); - if (!tda_info->valid_tda || tda_info->k2 != k2) + *first_idx = NULL; + FOR_EACH_SEQ_ARR(NR_tda_info_t *, tda, &nrmac->ul_tda) { + DevAssert(tda->valid_tda); + // nr_rrc_config_ul_tda() orders by k2, so skip smaller and return for + // bigger ones + if (tda->k2 < k2) + continue; + if (tda->k2 > k2) + break; // there won't be a suitable k2 anymore + + uint16_t tda_bitmap = SL_to_bitmap(tda->startSymbolIndex, tda->nrOfSymbols); + // nr_rrc_config_ul_tda() assures TDAs are from largest to smallest symbol number. + // check that this TDA fits entirely into this slot's mask (slot might be + // smaller in mixed slots)., A mixed slot TDA would be checked last, so a + // full slot TDA will be used for a full UL slot. + if ((tda_bitmap & ul_bitmap) == tda_bitmap) { // if TDA fits entiry + *first_idx = tda; + break; + } + } + if (*first_idx == NULL) /* nothing fit */ return 0; - if (fs->frame_type == TDD) { - // if there is uplink symbols in mixed slot - int s = get_slot_idx_in_period(slot, fs); - tdd_bitmap_t *tdd_slot_bitmap = fs->period_cfg.tdd_slot_bitmap; - if ((tdd_slot_bitmap[s].num_ul_symbols > 1) && is_mixed_slot(s, fs)) { - *first_idx = seq_arr_at(&nrmac->ul_tda, 2); // mixed slot, all symbols of mixed minus last - return 1; - } + NR_tda_info_t *end_it = seq_arr_next(&nrmac->ul_tda, *first_idx); + while (end_it != seq_arr_end(&nrmac->ul_tda) && end_it->k2 == k2) { + /* the following TDAs should all fit as long as the k2 is the same */ + uint16_t tda_bitmap = SL_to_bitmap(end_it->startSymbolIndex, end_it->nrOfSymbols); + AssertFatal((tda_bitmap & ul_bitmap) == tda_bitmap, + "TDA should fit inside slot, but is not the case for k2 %ld bitmap 0x%04x\n", + end_it->k2, + tda_bitmap); + end_it = seq_arr_next(&nrmac->ul_tda, end_it); } - // Avoid slots with the SRS - UE_iterator(nrmac->UE_info.connected_ue_list, UE) { - NR_sched_srs_t sched_srs = UE->UE_sched_ctrl.sched_srs; - if(sched_srs.srs_scheduled && sched_srs.frame == frame && sched_srs.slot == slot) { - *first_idx = seq_arr_at(&nrmac->ul_tda, 1); // symbols 0--12 - return 1; - } - } - - // symbols 0--13, if FDD or not mixed slot in TDD, for now use default TDA - // (TODO handle CSI-RS slots) - *first_idx = seq_arr_at(&nrmac->ul_tda, 0); - return 1; + ptrdiff_t diff = seq_arr_dist(&nrmac->ul_tda, *first_idx, end_it); + AssertFatal(diff > 0 && diff <= seq_arr_size(&nrmac->ul_tda), "dist %ld\n", diff); + return diff; } bwp_info_t get_pusch_bwp_start_size(NR_UE_info_t *UE) @@ -2607,7 +2620,7 @@ static void nr_ulsch_preprocessor(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp int k2 = fs_get_diff(fs, *next, current) - koffset; DevAssert(k2 > 0); const NR_tda_info_t *tda_info = NULL; - int n_tda = get_num_ul_tda(nr_mac, next->f, next->s, k2, &tda_info); + int n_tda = get_num_ul_tda(nr_mac, next->s, k2, &tda_info); if (n_tda == 0) /* no TDA fulfills this */ break; /* TODO: get_num_ul_tda() might indicate multiple TDAs to use (e.g., one diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 91c0969dde..9caa78bf7e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -417,7 +417,7 @@ void free_sched_pucch_list(NR_UE_sched_ctrl_t *sched_ctrl); bool add_UE_to_list(int list_size, NR_UE_info_t *list[list_size], NR_UE_info_t *UE); NR_UE_info_t *remove_UE_from_list(int list_size, NR_UE_info_t *list[list_size], rnti_t rnti); int get_dl_tda(const gNB_MAC_INST *nrmac, int slot); -int get_num_ul_tda(gNB_MAC_INST *nrmac, int frame, int slot, int k2, const NR_tda_info_t **first_idx); +int get_num_ul_tda(gNB_MAC_INST *nrmac, int slot, int k2, const NR_tda_info_t **first_idx); int get_cce_index(const gNB_MAC_INST *nrmac, const int CC_id, diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index d780cf4fe7..22d3b55fa4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -1058,6 +1058,29 @@ static struct NR_PUSCH_TimeDomainResourceAllocation *set_TimeDomainResourceAlloc return puschTdrAlloc; } +static int tda_cmp(const void *tda_a, const void *tda_b) +{ + const NR_PUSCH_TimeDomainResourceAllocation_t *a = *(const NR_PUSCH_TimeDomainResourceAllocation_t **)tda_a; + const NR_PUSCH_TimeDomainResourceAllocation_t *b = *(const NR_PUSCH_TimeDomainResourceAllocation_t **)tda_b; + DevAssert(a->k2 && b->k2); + if (*a->k2 < *b->k2) + return -1; // smaller first + if (*a->k2 > *b->k2) + return 1; + // same k2: order from big to small TDA number + int as, al, bs, bl; + SLIV2SL(a->startSymbolAndLength, &as, &al); + SLIV2SL(b->startSymbolAndLength, &bs, &bl); + if (al < bl) + return 1; // bigger first + if (al > bl) + return -1; + return 0; +} + +/* \brief Set up a list of time domain allocations as suitable for the TDD + * pattern. This will be used by get_num_ul_tda(), which requires a specific + * ordering, hence we qsort() the list at the end according to tda_cmp(). */ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay) { NR_PUSCH_TimeDomainResourceAllocationList_t *tda_list = @@ -1065,6 +1088,7 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay) AssertFatal(tda_list->list.count == 0, "already have pusch_TimeDomainAllocationList members\n"); const int k2 = min_fb_delay; + const int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; // UL TDA index 0 is basic slot configuration starting in symbol 0 til the last but one symbol NR_PUSCH_TimeDomainResourceAllocation_t *tda; @@ -1089,13 +1113,40 @@ void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay) } else if (p2) { ul_symb = p1->nrofUplinkSymbols; } - if (ul_symb>1) { + + DevAssert(p2 == NULL); + int N_dl = p1->nrofDownlinkSlots; + int N_ul = p1->nrofUplinkSlots; + 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; + + // make TDA for the mixed slot + if (ul_symb > 1 && k2 <= N_dl) { // UL TDA index 2 for mixed slot (TDD) long sliv = get_SLIV(NR_NUMBER_OF_SYMBOLS_PER_SLOT - ul_symb, ul_symb - 1); - tda = set_TimeDomainResourceAllocation(k2, sliv); + tda = set_TimeDomainResourceAllocation(k2, sliv); // to be reached from suitable DL slot + asn1cSeqAdd(&tda_list->list, tda); + } else if (ul_symb > 1) { // k2 > N_Dl + long sliv = get_SLIV(NR_NUMBER_OF_SYMBOLS_PER_SLOT - ul_symb, ul_symb - 1); + tda = set_TimeDomainResourceAllocation(nb_slots_per_period, sliv); // to be reached from last DL (mixed) slot, if any asn1cSeqAdd(&tda_list->list, tda); } + + // make TDA for UL slots that are not reachable within k2/min_rxtxtime + if (N_ul > k2) { + // enforce that with k2, we could reach all but one slot (which is mixed + // and taken into account above + AssertFatal(N_dl >= k2 - 1, "cannot fulfil TDD pattern: N_dl %d, k2 %d\n", N_dl, k2); + for (int i = k2 + 1; i <= N_ul; ++i) { + tda = set_TimeDomainResourceAllocation(i, get_SLIV(0, 13)); + asn1cSeqAdd(&tda_list->list, tda); + } + } } + + AssertFatal(tda_list->list.count <= 16, "cannot reach all UL slots with current TDD configuration\n"); + qsort(tda_list->list.array, tda_list->list.count, sizeof(tda_list->list.array), tda_cmp); } static void set_dl_DataToUL_ACK(NR_PUCCH_Config_t *pucch_Config, int min_feedback_time, NR_SubcarrierSpacing_t subcarrierSpacing)