From 91fd4ddf7e22951c0deb8b4406d2aa021019336d Mon Sep 17 00:00:00 2001 From: Robert Schmidt <robert.schmidt@eurecom.fr> Date: Wed, 9 Dec 2020 17:31:02 +0100 Subject: [PATCH] rewrite nr_acknack_scheduling() --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 170 +++++++++++++----- 1 file changed, 122 insertions(+), 48 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 1e09f3777b..f1200f19de 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -430,79 +430,153 @@ bool nr_acknack_scheduling(int mod_id, frame_t frame, sub_frame_t slot) { + const NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon; + const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + const NR_TDD_UL_DL_Pattern_t *tdd_pattern = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; + const int nr_ulmix_slots = tdd_pattern->nrofUplinkSlots + (tdd_pattern->nrofUplinkSymbols != 0); + const int first_ul_slot_tdd = tdd_pattern->nrofDownlinkSlots; + const int CC_id = 0; + + AssertFatal(slot < first_ul_slot_tdd + (tdd_pattern->nrofUplinkSymbols != 0), + "cannot handle multiple TDD periods (yet): slot %d first_ul_slot_tdd %d nrofUplinkSlots %ld\n", + slot, + first_ul_slot_tdd, + tdd_pattern->nrofUplinkSlots); + /* FIXME: for the moment, we consider that - * * only pucch_sched[0] holds HARQ - * * a UE is not scheduled in more than two slots, and their ACKs come in the same slot! + * * only pucch_sched[0] holds HARQ (and SR) * * we do not multiplex with CSI - * * we do not mux two UEs in the same PUCCH slot (on the two symbols) * * we only use the first TDD period (5/10ms) */ NR_UE_sched_ctrl_t *sched_ctrl = &RC.nrmac[mod_id]->UE_info.UE_sched_ctrl[UE_id]; - NR_sched_pucch_t *curr_pucch = &sched_ctrl->sched_pucch[0]; - AssertFatal(curr_pucch->csi_bits == 0, + NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0]; + AssertFatal(pucch->csi_bits == 0, "%s(): csi_bits %d in sched_pucch[0]\n", __func__, - curr_pucch->csi_bits); + pucch->csi_bits); const int max_acknacks = 2; - AssertFatal(curr_pucch->dai_c <= max_acknacks, - "%s() called but already %d dai_c in sched_pucch[0]\n", - __func__, - curr_pucch->dai_c); - - const NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon; - const NR_TDD_UL_DL_Pattern_t *tdd_pattern = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; - //const int nr_ulmix_slots = tdd_pattern->nrofUplinkSlots + (tdd_pattern->nrofUplinkSymbols != 0); - const int first_ul_slot_tdd = tdd_pattern->nrofDownlinkSlots; - const int CC_id = 0; + AssertFatal(pucch->dai_c + pucch->sr_flag <= max_acknacks, + "illegal number of bits in PUCCH of UE %d\n", + UE_id); + /* if the currently allocated PUCCH of this UE is full, allocate it */ + if (pucch->sr_flag + pucch->dai_c == max_acknacks) { + /* advance the UL slot information in PUCCH by one so we won't schedule in + * the same slot again */ + const int f = pucch->frame; + const int s = pucch->ul_slot; + nr_fill_nfapi_pucch(mod_id, frame, slot, pucch, UE_id); + memset(pucch, 0, sizeof(*pucch)); + pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f; + pucch->ul_slot = (s + 1) % n_slots_frame; + } // this is hardcoded for now as ue specific NR_SearchSpace__searchSpaceType_PR ss_type = NR_SearchSpace__searchSpaceType_PR_ue_Specific; uint8_t pdsch_to_harq_feedback[8]; get_pdsch_to_harq_feedback(mod_id, UE_id, ss_type, pdsch_to_harq_feedback); + /* there is a scheduled SR or HARQ. Check whether we can use it for this + * ACKNACK */ + if (pucch->sr_flag + pucch->dai_c > 0) { + /* this UE already has a PUCCH occasion */ + DevAssert(pucch->frame == frame); + + // Find the right timing_indicator value. + int i = 0; + while (i < 8) { + if (pdsch_to_harq_feedback[i] == pucch->ul_slot - slot) + break; + ++i; + } + if (i >= 8) { + // we cannot reach this timing anymore, allocate and try again + const int f = pucch->frame; + const int s = pucch->ul_slot; + const int n_slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; + nr_fill_nfapi_pucch(mod_id, frame, slot, pucch, UE_id); + memset(pucch, 0, sizeof(*pucch)); + pucch->frame = s == n_slots_frame - 1 ? (f + 1) % 1024 : f; + pucch->ul_slot = (s + 1) % n_slots_frame; + return nr_acknack_scheduling(mod_id, UE_id, frame, slot); + } + + pucch->timing_indicator = i; + pucch->dai_c++; + // retain old resource indicator, and we are good + return true; + } + + /* we need to find a new PUCCH occasion */ + NR_PUCCH_Config_t *pucch_Config = sched_ctrl->active_ubwp->bwp_Dedicated->pucch_Config->choice.setup; DevAssert(pucch_Config->resourceToAddModList->list.count > 0); + DevAssert(pucch_Config->resourceSetToAddModList->list.count > 0); + const int n_res = pucch_Config->resourceSetToAddModList->list.array[0]->resourceList.list.count; + int *pucch_index_used = RC.nrmac[mod_id]->pucch_index_used[sched_ctrl->active_ubwp->bwp_Id]; - curr_pucch->frame = frame; - curr_pucch->dai_c++; + /* if time information is outdated (e.g., last PUCCH occasion in last frame), + * set to first possible UL occasion in this frame */ + if (frame != pucch->frame || pucch->ul_slot < first_ul_slot_tdd) { + DevAssert(pucch->sr_flag + pucch->dai_c == 0); + pucch->frame = frame; + pucch->ul_slot = first_ul_slot_tdd; + } - int *pucch_index_used = RC.nrmac[mod_id]->pucch_index_used[sched_ctrl->active_ubwp->bwp_Id]; - if (curr_pucch->dai_c == 1) { - /* FIXME for first allocation: find free resource, here assume first PUCCH - * resource and first_ul_slot_tdd */ - const int pucch_res = 0; - curr_pucch->resource_indicator = pucch_res; - curr_pucch->ul_slot = first_ul_slot_tdd; - DevAssert(pucch_index_used[first_ul_slot_tdd] == 0); - pucch_index_used[first_ul_slot_tdd] += 1; - - /* verify that at that slot and symbol, resources are free. - * Note: this does not handle potential mux of PUCCH in the same symbol! */ - const NR_PUCCH_Resource_t *resource = - pucch_Config->resourceToAddModList->list.array[pucch_res]; - DevAssert(resource->format.present == NR_PUCCH_Resource__format_PR_format0); - uint16_t *vrb_map_UL = - &RC.nrmac[mod_id]->common_channels[CC_id].vrb_map_UL[first_ul_slot_tdd * 275]; - const uint16_t symb = 1 << resource->format.choice.format0->startingSymbolIndex; - AssertFatal((vrb_map_UL[resource->startingPRB] & symb) == 0, - "symbol %x is not free for PUCCH alloc in vrb_map_UL at RB %ld and slot %d\n", - symb, resource->startingPRB, first_ul_slot_tdd); - vrb_map_UL[resource->startingPRB] |= symb; + // increase to first slot in which PUCCH resources are available + while (pucch_index_used[pucch->ul_slot] >= n_res) { + pucch->ul_slot++; + /* if there is no free resource anymore, abort search */ + if (pucch->ul_slot >= first_ul_slot_tdd + nr_ulmix_slots) { + LOG_E(MAC, + "%4d.%2d no free PUCCH resources anymore while searching for UE %d\n", + frame, + slot, + UE_id); + return false; + } } - /* Find the right timing_indicator value. FIXME: if previously ul_slot is not - * possible (anymore), we need to allocate previous HARQ feedback (since we - * cannot "reach" it anymore) and search a new one! */ + // advance ul_slot if it is not reachable by UE + pucch->ul_slot = max(pucch->ul_slot, slot + pdsch_to_harq_feedback[0]); + + // Find the right timing_indicator value. int i = 0; while (i < 8) { - if (pdsch_to_harq_feedback[i] == curr_pucch->ul_slot - slot) + if (pdsch_to_harq_feedback[i] == pucch->ul_slot - slot) break; ++i; } - AssertFatal(i < 8, - "could not find pdsch_to_harq_feedback: slot %d, ack slot %d\n", - slot, first_ul_slot_tdd); - curr_pucch->timing_indicator = i; // index in the list of timing indicators + if (i >= 8) { + LOG_W(MAC, + "%4d.%2d could not find pdsch_to_harq_feedback for UE %d: earliest " + "ack slot %d\n", + frame, + slot, + UE_id, + pucch->ul_slot); + return false; + } + pucch->timing_indicator = i; // index in the list of timing indicators + + pucch->dai_c++; + const int pucch_res = pucch_index_used[pucch->ul_slot]; + pucch->resource_indicator = pucch_res; + pucch_index_used[first_ul_slot_tdd] += 1; + + /* verify that at that slot and symbol, resources are free. We only do this + * for initialCyclicShift 0 (we assume it always has that one), so other + * initialCyclicShifts can overlap with ICS 0!*/ + const NR_PUCCH_Resource_t *resource = + pucch_Config->resourceToAddModList->list.array[pucch_res]; + DevAssert(resource->format.present == NR_PUCCH_Resource__format_PR_format0); + if (resource->format.choice.format0->initialCyclicShift == 0) { + uint16_t *vrb_map_UL = &RC.nrmac[mod_id]->common_channels[CC_id].vrb_map_UL[pucch->ul_slot * MAX_BWP_SIZE]; + const uint16_t symb = 1 << resource->format.choice.format0->startingSymbolIndex; + AssertFatal((vrb_map_UL[resource->startingPRB] & symb) == 0, + "symbol %x is not free for PUCCH alloc in vrb_map_UL at RB %ld and slot %d\n", + symb, resource->startingPRB, first_ul_slot_tdd); + vrb_map_UL[resource->startingPRB] |= symb; + } return true; } -- 2.26.2