From 0773229b1a0c9ad61398692c3d1cc3624e648491 Mon Sep 17 00:00:00 2001 From: Robert Schmidt <robert.schmidt@eurecom.fr> Date: Wed, 23 Dec 2020 14:48:24 +0100 Subject: [PATCH] Implement UL HARQ using NR_list_t --- doc/SW_archi.md | 2 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c | 2 + .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 126 +++++++++--------- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 9 +- 4 files changed, 72 insertions(+), 67 deletions(-) diff --git a/doc/SW_archi.md b/doc/SW_archi.md index 412dad402d9..d92f8021488 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -186,7 +186,7 @@ development], for FR2 does not exist yet. 3) allocate a CCE for the UE (and return if it is not possible) 4) Calculate DMRS stuff (nr_save_pusch_fields()) and the TBS. 5) Mark used resources in vrb_map_UL. -* loop through all users: get a free HARQ PID using select_ul_harq_pid() and +* loop through all users: get a free HARQ PID and update statistics. Fill nFAPI structures directly for PUSCH, and call config_uldci() and fill_dci_pdu_rel15() for DCI filling and PDCCH messages. diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index d509aa33abb..e3532d94738 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -477,6 +477,8 @@ void nr_ul_preprocessor_phytest(module_id_t module_id, sched_pusch->mcs = mcs; sched_pusch->rbStart = rbStart; sched_pusch->rbSize = rbSize; + /* get the PID of a HARQ process awaiting retransmission, or -1 for "any new" */ + sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head; /* Calculate TBS from MCS */ sched_pusch->R = nr_get_code_rate_ul(mcs, ps->mcs_table); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index e2ecb9c38e0..be2a478b40e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -259,45 +259,47 @@ void handle_nr_ul_harq(module_id_t mod_id, NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info; NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl[UE_id]; - int max_harq_rounds = 4; // TODO define macro - uint8_t hrq_id = crc_pdu->harq_id; - NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[hrq_id]; - if (cur_harq->state==ACTIVE_SCHED) { - if (!crc_pdu->tb_crc_status) { - cur_harq->ndi ^= 1; - cur_harq->round = 0; - cur_harq->state = INACTIVE; // passed -> make inactive. can be used by scheduder for next grant - LOG_D(MAC, - "Ulharq id %d crc passed for RNTI %04x\n", - hrq_id, - crc_pdu->rnti); - } else { - cur_harq->round++; - cur_harq->state = ACTIVE_NOT_SCHED; - LOG_D(MAC, - "Ulharq id %d crc failed for RNTI %04x\n", - hrq_id, - crc_pdu->rnti); - } - - if (!(cur_harq->round<max_harq_rounds)) { - cur_harq->ndi ^= 1; - cur_harq->state = INACTIVE; // failed after 4 rounds -> make inactive - cur_harq->round = 0; - LOG_D(MAC, - "RNTI %04x: Ulharq id %d crc failed in all rounds\n", - crc_pdu->rnti, - hrq_id); - UE_info->mac_stats[UE_id].ulsch_errors++; - } - return; - } else + const int8_t harq_pid = sched_ctrl->feedback_ul_harq.head; + if (crc_pdu->harq_id != harq_pid && harq_pid < 0) { LOG_W(MAC, - "Incorrect ULSCH HARQ PID %d or invalid state %d for RNTI %04x " - "(ignore this warning for RA)\n", - hrq_id, - cur_harq->state, + "Unexpected ULSCH HARQ PID %d (have %d) for RNTI %04x (ignore this warning for RA)\n", + crc_pdu->harq_id, + harq_pid, + crc_pdu->rnti); + return; + } + DevAssert(harq_pid == crc_pdu->harq_id); + remove_front_nr_list(&sched_ctrl->feedback_ul_harq); + NR_UE_ul_harq_t *harq = &sched_ctrl->ul_harq_processes[harq_pid]; + DevAssert(harq->feedback_slot == slot - 1); + DevAssert(harq->is_waiting); + harq->feedback_slot = -1; + harq->is_waiting = false; + if (!crc_pdu->tb_crc_status) { + harq->ndi ^= 1; + harq->round = 0; + LOG_D(MAC, + "Ulharq id %d crc passed for RNTI %04x\n", + harq_pid, crc_pdu->rnti); + add_tail_nr_list(&sched_ctrl->available_ul_harq, harq_pid); + } else if (harq->round == MAX_HARQ_ROUNDS) { + harq->ndi ^= 1; + harq->round = 0; + LOG_D(MAC, + "RNTI %04x: Ulharq id %d crc failed in all rounds\n", + crc_pdu->rnti, + harq_pid); + UE_info->mac_stats[UE_id].ulsch_errors++; + add_tail_nr_list(&sched_ctrl->available_ul_harq, harq_pid); + } else { + harq->round++; + LOG_D(MAC, + "Ulharq id %d crc failed for RNTI %04x\n", + harq_pid, + crc_pdu->rnti); + add_tail_nr_list(&sched_ctrl->retrans_ul_harq, harq_pid); + } } /* @@ -432,29 +434,6 @@ long get_K2(NR_BWP_Uplink_t *ubwp, int time_domain_assignment, int mu) { return 3; } -int8_t select_ul_harq_pid(NR_UE_sched_ctrl_t *sched_ctrl) { - const uint8_t max_ul_harq_pids = 3; // temp: for testing - // schedule active harq processes - for (uint8_t hrq_id = 0; hrq_id < max_ul_harq_pids; hrq_id++) { - NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[hrq_id]; - if (cur_harq->state == ACTIVE_NOT_SCHED) { - LOG_D(MAC, "Found ulharq id %d, scheduling it for retransmission\n", hrq_id); - return hrq_id; - } - } - - // schedule new harq processes - for (uint8_t hrq_id=0; hrq_id < max_ul_harq_pids; hrq_id++) { - NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[hrq_id]; - if (cur_harq->state == INACTIVE) { - LOG_D(MAC, "Found new ulharq id %d, scheduling it\n", hrq_id); - return hrq_id; - } - } - LOG_E(MAC, "All UL HARQ processes are busy. Cannot schedule ULSCH\n"); - return -1; -} - void nr_simple_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot, @@ -502,6 +481,8 @@ void nr_simple_ulsch_preprocessor(module_id_t module_id, sched_ctrl->sched_pusch.slot = sched_slot; sched_ctrl->sched_pusch.frame = sched_frame; + /* get the PID of a HARQ process awaiting retransmission, or -1 otherwise */ + sched_ctrl->sched_pusch.ul_harq_pid = sched_ctrl->retrans_ul_harq.head; const int target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific; sched_ctrl->search_space = get_searchspace(sched_ctrl->active_bwp, target_ss); @@ -605,11 +586,28 @@ void nr_schedule_ulsch(module_id_t module_id, uint16_t rnti = UE_info->rnti[UE_id]; - int8_t harq_id = select_ul_harq_pid(sched_ctrl); - if (harq_id < 0) return; + int8_t harq_id = sched_pusch->ul_harq_pid; + if (harq_id < 0) { + /* PP has not selected a specific HARQ Process, get a new one */ + harq_id = sched_ctrl->available_ul_harq.head; + AssertFatal(harq_id >= 0, + "no free HARQ process available for UE %d\n", + UE_id); + remove_front_nr_list(&sched_ctrl->available_ul_harq); + } else { + /* PP selected a specific HARQ process. Check whether it will be a new + * transmission or a retransmission, and remove from the corresponding + * list */ + if (sched_ctrl->ul_harq_processes[harq_id].round == 0) + remove_nr_list(&sched_ctrl->available_ul_harq, harq_id); + else + remove_nr_list(&sched_ctrl->retrans_ul_harq, harq_id); + } NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[harq_id]; - cur_harq->state = ACTIVE_SCHED; - cur_harq->last_tx_slot = sched_pusch->slot; + DevAssert(!cur_harq->is_waiting); + add_tail_nr_list(&sched_ctrl->feedback_ul_harq, harq_id); + cur_harq->feedback_slot = sched_pusch->slot; + cur_harq->is_waiting = true; int rnti_types[2] = { NR_RNTI_C, 0 }; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 3e35cd7385a..10811d575b2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -336,6 +336,9 @@ typedef struct NR_sched_pusch { uint16_t R; uint8_t Qm; uint32_t tb_size; + + /// UL HARQ PID to use for this UE, or -1 for "any new" + int8_t ul_harq_pid; } NR_sched_pusch_t; typedef struct NR_UE_harq { @@ -360,10 +363,12 @@ typedef enum { } NR_UL_harq_states_t; typedef struct NR_UE_ul_harq { + bool is_waiting; uint8_t ndi; uint8_t round; - uint16_t last_tx_slot; - NR_UL_harq_states_t state; + uint16_t feedback_slot; + + /* TODO PUSCH of last transmission */ } NR_UE_ul_harq_t; -- GitLab