Skip to content

Commit e249f59

Browse files
committed
sched: integrate new HARQ manager in RA scheduler
1 parent fb48b39 commit e249f59

File tree

6 files changed

+101
-53
lines changed

6 files changed

+101
-53
lines changed

lib/scheduler/cell/cell_harq_manager.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,14 +206,17 @@ void cell_harq_repository<IsDl>::slot_indication(slot_point sl_tx)
206206
break;
207207
}
208208

209-
// HARQ is trapped. Remove it.
209+
// HARQ retransmission is trapped. Deallocate HARQ process.
210210
logger.warning(
211211
"rnti={} h_id={}: Discarding {} HARQ. Cause: Too much time has passed since the last HARQ "
212212
"transmission. The scheduler policy is likely not prioritizing retransmissions of old HARQ processes.",
213213
h.rnti,
214214
h.h_id,
215215
IsDl ? "DL" : "UL");
216216
dealloc_harq(h);
217+
218+
// Report timeout after the HARQ gets deleted to avoid reentrancy.
219+
timeout_notifier.on_harq_timeout(h.ue_idx, IsDl, false);
217220
}
218221
}
219222

@@ -222,9 +225,10 @@ void cell_harq_repository<IsDl>::handle_harq_ack_timeout(harq_type& h, slot_poin
222225
{
223226
srsran_sanity_check(h.status == harq_state_t::waiting_ack, "HARQ process in wrong state");
224227

228+
bool ack_val = h.ack_on_timeout;
225229
if (not is_ntn_mode()) {
226230
// Only in non-NTN case, we log a warning.
227-
if (h.ack_on_timeout) {
231+
if (ack_val) {
228232
// Case: Not all HARQ-ACKs were received, but at least one positive ACK was received.
229233
logger.debug("rnti={} h_id={}: Setting {} HARQ to \"ACKed\" state. Cause: HARQ-ACK wait timeout ({} slots) was "
230234
"reached with still missing PUCCH HARQ-ACKs. However, one positive ACK was received.",
@@ -242,13 +246,16 @@ void cell_harq_repository<IsDl>::handle_harq_ack_timeout(harq_type& h, slot_poin
242246
IsDl ? "DL" : "UL",
243247
h.slot_ack_timeout - h.slot_ack);
244248
}
245-
246-
// Report timeout with NACK.
247-
timeout_notifier.on_harq_timeout(h.ue_idx, IsDl, h.ack_on_timeout);
248249
}
249250

250251
// Deallocate HARQ.
251252
dealloc_harq(h);
253+
254+
if (max_ack_wait_in_slots != 1) {
255+
// Report timeout with NACK after we delete the HARQ to avoid reentrancy.
256+
// Only in non-NTN case.
257+
timeout_notifier.on_harq_timeout(h.ue_idx, IsDl, ack_val);
258+
}
252259
}
253260

254261
template <bool IsDl>
@@ -736,10 +743,11 @@ unique_ue_harq_entity::unique_ue_harq_entity(cell_harq_manager* mgr, du_ue_index
736743
}
737744

738745
unique_ue_harq_entity::unique_ue_harq_entity(unique_ue_harq_entity&& other) noexcept :
739-
cell_harq_mgr(other.cell_harq_mgr), ue_index(other.ue_index)
746+
cell_harq_mgr(other.cell_harq_mgr), ue_index(other.ue_index), crnti(other.crnti)
740747
{
741748
other.cell_harq_mgr = nullptr;
742749
other.ue_index = INVALID_DU_UE_INDEX;
750+
other.crnti = rnti_t::INVALID_RNTI;
743751
}
744752

745753
unique_ue_harq_entity& unique_ue_harq_entity::operator=(unique_ue_harq_entity&& other) noexcept
@@ -749,8 +757,10 @@ unique_ue_harq_entity& unique_ue_harq_entity::operator=(unique_ue_harq_entity&&
749757
}
750758
cell_harq_mgr = other.cell_harq_mgr;
751759
ue_index = other.ue_index;
760+
crnti = other.crnti;
752761
other.cell_harq_mgr = nullptr;
753762
other.ue_index = INVALID_DU_UE_INDEX;
763+
other.crnti = rnti_t::INVALID_RNTI;
754764
return *this;
755765
}
756766

lib/scheduler/common_scheduling/ra_scheduler.cpp

Lines changed: 70 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,23 @@ static crb_interval msg3_vrb_to_crb(const cell_configuration& cell_cfg, vrb_inte
6868
cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.start());
6969
}
7070

71+
class ra_scheduler::msg3_harq_timeout_notifier final : public harq_timeout_notifier
72+
{
73+
public:
74+
msg3_harq_timeout_notifier(std::vector<pending_msg3_t>& pending_msg3s_) : pending_msg3s(pending_msg3s_) {}
75+
76+
void on_harq_timeout(du_ue_index_t ue_idx, bool is_dl, bool ack) override
77+
{
78+
srsran_sanity_check(pending_msg3s[ue_idx].busy(), "timeout called but HARQ entity does not exist");
79+
80+
// Delete Msg3 HARQ entity to make it available again.
81+
pending_msg3s[ue_idx].msg3_harq_ent.reset();
82+
}
83+
84+
private:
85+
std::vector<pending_msg3_t>& pending_msg3s;
86+
};
87+
7188
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7289

7390
ra_scheduler::ra_scheduler(const scheduler_ra_expert_config& sched_cfg_,
@@ -87,6 +104,7 @@ ra_scheduler::ra_scheduler(const scheduler_ra_expert_config& sched_cfg_,
87104
band_helper::get_duplex_mode(cell_cfg.band),
88105
cell_cfg.ul_cfg_common.init_ul_bwp.rach_cfg_common->rach_cfg_generic.prach_config_index)
89106
.format)),
107+
msg3_harqs(MAX_NOF_MSG3, 1, std::make_unique<msg3_harq_timeout_notifier>(pending_msg3s)),
90108
pending_msg3s(MAX_NOF_MSG3)
91109
{
92110
// Precompute RAR PDSCH and DCI PDUs.
@@ -171,8 +189,7 @@ void ra_scheduler::precompute_msg3_pdus()
171189
crb_interval{0, prbs_tbs.nof_prbs},
172190
i,
173191
sched_cfg.msg3_mcs_index,
174-
msg3_rv,
175-
dummy_h_ul);
192+
msg3_rv);
176193

177194
// Note: RNTI will be overwritten later.
178195
build_pusch_f0_0_tc_rnti(msg3_data[i].pusch,
@@ -246,17 +263,19 @@ void ra_scheduler::handle_rach_indication_impl(const rach_indication_message& ms
246263
prach_preamble.time_advance.to_Ta(get_ul_bwp_cfg().scs)});
247264

248265
// Check if TC-RNTI value to be scheduled is already under use
249-
if (not pending_msg3s[to_value(prach_preamble.tc_rnti) % MAX_NOF_MSG3].harq.empty()) {
266+
unsigned msg3_ring_idx = to_value(prach_preamble.tc_rnti) % MAX_NOF_MSG3;
267+
auto& msg3_entry = pending_msg3s[msg3_ring_idx];
268+
if (msg3_entry.busy()) {
250269
logger.warning("PRACH ignored, as the allocated TC-RNTI={} is already under use", prach_preamble.tc_rnti);
251270
continue;
252271
}
253272

254273
// Store TC-RNTI of the preamble.
255274
rar_req->tc_rntis.emplace_back(prach_preamble.tc_rnti);
256275

257-
// Store Msg3 to allocate.
258-
pending_msg3s[to_value(prach_preamble.tc_rnti) % MAX_NOF_MSG3].preamble = prach_preamble;
259-
pending_msg3s[to_value(prach_preamble.tc_rnti) % MAX_NOF_MSG3].msg3_harq_logger.set_rnti(prach_preamble.tc_rnti);
276+
// Store Msg3 request and create a HARQ entity of 1 UL HARQ.
277+
msg3_entry.preamble = prach_preamble;
278+
msg3_entry.msg3_harq_ent = msg3_harqs.add_ue(to_du_ue_index(msg3_ring_idx), prach_preamble.tc_rnti, 1, 1);
260279
}
261280
}
262281
}
@@ -274,41 +293,51 @@ void ra_scheduler::handle_pending_crc_indications_impl(cell_resource_allocator&
274293

275294
for (const ul_crc_indication& crc_ind : new_crc_inds) {
276295
for (const ul_crc_pdu_indication& crc : crc_ind.crcs) {
277-
srsran_assert(crc.ue_index == INVALID_DU_UE_INDEX, "Msg3 HARQ CRCs cannot have a ueId assigned yet");
296+
srsran_assert(crc.ue_index == INVALID_DU_UE_INDEX, "Msg3 HARQ CRCs cannot have a ue index assigned yet");
278297
auto& pending_msg3 = pending_msg3s[to_value(crc.rnti) % MAX_NOF_MSG3];
279-
if (pending_msg3.preamble.tc_rnti != crc.rnti) {
280-
logger.warning("Invalid UL CRC, cell={}, rnti={}, h_id={}. Cause: Nonexistent rnti.",
298+
if (pending_msg3.preamble.tc_rnti != crc.rnti or pending_msg3.msg3_harq_ent.empty()) {
299+
logger.warning("Invalid UL CRC, cell={}, rnti={}, h_id={}. Cause: Nonexistent tc-rnti",
281300
cell_cfg.cell_index,
282301
crc.rnti,
283302
crc.harq_id);
284303
continue;
285304
}
286-
if (pending_msg3.harq.id != crc.harq_id) {
287-
logger.warning("Invalid UL CRC, cell={}, rnti={}, h_id={}. Cause: HARQ-Ids do not match ({} != {})",
305+
306+
// See TS38.321, 5.4.2.1 - "For UL transmission with UL grant in RA Response, HARQ process identifier 0 is used."
307+
harq_id_t h_id = to_harq_id(0);
308+
std::optional<ul_harq_process_handle> h_ul = pending_msg3.msg3_harq_ent.ul_harq(h_id);
309+
if (not h_ul.has_value() or crc.harq_id != h_id) {
310+
logger.warning("Invalid UL CRC, cell={}, rnti={}, h_id={}. Cause: HARQ-Id 0 must be used in Msg3",
288311
cell_cfg.cell_index,
289312
crc.rnti,
290-
crc.harq_id,
291-
crc.harq_id,
292-
pending_msg3.harq.id);
313+
crc.harq_id);
293314
continue;
294315
}
295-
pending_msg3.harq.crc_info(crc.tb_crc_success);
316+
317+
// Handle CRC info.
318+
h_ul->ul_crc_info(crc.tb_crc_success);
319+
if (h_ul->empty()) {
320+
// Deallocate Msg3 entry.
321+
pending_msg3.msg3_harq_ent.reset();
322+
}
296323
}
297324
}
298325

299326
// Allocate pending Msg3 retransmissions.
300-
for (auto& pending_msg3 : pending_msg3s) {
301-
if (not pending_msg3.harq.empty()) {
302-
pending_msg3.harq.slot_indication(res_alloc.slot_tx());
303-
if (pending_msg3.harq.has_pending_retx()) {
304-
schedule_msg3_retx(res_alloc, pending_msg3);
305-
}
306-
}
327+
// Note: pending_ul_retxs size will change in this iteration, so we prefetch the next iterator.
328+
auto pending_ul_retxs = msg3_harqs.pending_ul_retxs();
329+
for (auto it = pending_ul_retxs.begin(); it != pending_ul_retxs.end();) {
330+
ul_harq_process_handle h_ul = *it;
331+
++it;
332+
schedule_msg3_retx(res_alloc, pending_msg3s[h_ul.ue_index()]);
307333
}
308334
}
309335

310336
void ra_scheduler::run_slot(cell_resource_allocator& res_alloc)
311337
{
338+
// Update Msg3 HARQ state.
339+
msg3_harqs.slot_indication(res_alloc.slot_tx());
340+
312341
// Handle pending CRCs, which may lead to Msg3 reTxs.
313342
handle_pending_crc_indications_impl(res_alloc);
314343

@@ -648,10 +677,12 @@ void ra_scheduler::fill_rar_grant(cell_resource_allocator& res_alloc,
648677
const vrb_interval vrbs = msg3_crb_to_vrb(cell_cfg, msg3_candidate.crbs);
649678

650679
auto& pending_msg3 = pending_msg3s[to_value(rar_request.tc_rntis[i]) % MAX_NOF_MSG3];
651-
srsran_sanity_check(pending_msg3.harq.empty(), "Pending Msg3 should not have been added if HARQ is busy");
680+
srsran_sanity_check(pending_msg3.busy(), "Pending Msg3 entry should have been reserved when RACH was received");
652681

653682
// Allocate Msg3 UL HARQ
654-
pending_msg3.harq.new_tx(msg3_alloc.slot, sched_cfg.max_nof_msg3_harq_retxs);
683+
std::optional<ul_harq_process_handle> h_ul =
684+
pending_msg3.msg3_harq_ent.alloc_ul_harq(msg3_alloc.slot, sched_cfg.max_nof_msg3_harq_retxs);
685+
srsran_sanity_check(h_ul.has_value(), "Pending Msg3 HARQ must be available when RAR is allocated");
655686

656687
// Add MAC SDU with UL grant (Msg3) in RAR PDU.
657688
rar_ul_grant& msg3_info = rar.grants.emplace_back();
@@ -683,7 +714,7 @@ void ra_scheduler::fill_rar_grant(cell_resource_allocator& res_alloc,
683714
pusch.pusch_cfg.new_data = true;
684715

685716
// Store parameters used in HARQ.
686-
pending_msg3.harq.save_alloc_params(ul_harq_sched_context{dci_ul_rnti_config_type::tc_rnti_f0_0}, pusch.pusch_cfg);
717+
h_ul->save_grant_params(ul_harq_alloc_context{dci_ul_rnti_config_type::tc_rnti_f0_0}, pusch.pusch_cfg);
687718
}
688719
}
689720

@@ -703,6 +734,10 @@ void ra_scheduler::schedule_msg3_retx(cell_resource_allocator& res_alloc, pendin
703734
return;
704735
}
705736

737+
ul_harq_process_handle h_ul = msg3_ctx.msg3_harq_ent.ul_harq(to_harq_id(0)).value();
738+
srsran_sanity_check(h_ul.has_pending_retx(), "schedule_msg3_retx called when HARQ has no pending reTx");
739+
const ul_harq_process_handle::grant_params& last_harq_params = h_ul.get_grant_params();
740+
706741
const span<const pusch_time_domain_resource_allocation> pusch_td_alloc_list =
707742
get_pusch_time_domain_resource_table(get_pusch_cfg());
708743
for (unsigned pusch_td_res_index = 0; pusch_td_res_index != pusch_td_alloc_list.size(); ++pusch_td_res_index) {
@@ -713,8 +748,7 @@ void ra_scheduler::schedule_msg3_retx(cell_resource_allocator& res_alloc, pendin
713748
NOF_OFDM_SYM_PER_SLOT_NORMAL_CP - cell_cfg.get_nof_ul_symbol_per_slot(pusch_alloc.slot);
714749
// If it is a retx, we need to ensure we use a time_domain_resource with the same number of symbols as used for
715750
// the first transmission.
716-
const bool sym_length_match_prev_grant_for_retx =
717-
pusch_td_cfg.symbols.length() == msg3_ctx.harq.last_tx_params().nof_symbols;
751+
const bool sym_length_match_prev_grant_for_retx = pusch_td_cfg.symbols.length() == last_harq_params.nof_symbols;
718752
if (not cell_cfg.is_ul_enabled(pusch_alloc.slot) or pusch_td_cfg.symbols.start() < start_ul_symbols or
719753
!sym_length_match_prev_grant_for_retx) {
720754
// Not possible to schedule Msg3s in this TDD slot.
@@ -728,7 +762,7 @@ void ra_scheduler::schedule_msg3_retx(cell_resource_allocator& res_alloc, pendin
728762
}
729763

730764
// Try to reuse previous HARQ PRBs.
731-
const vrb_interval msg3_vrbs = msg3_ctx.harq.last_tx_params().rbs.type1();
765+
const vrb_interval msg3_vrbs = last_harq_params.rbs.type1();
732766
grant_info grant;
733767
grant.scs = bwp_ul_cmn.scs;
734768
grant.symbols = pusch_td_cfg.symbols;
@@ -764,7 +798,10 @@ void ra_scheduler::schedule_msg3_retx(cell_resource_allocator& res_alloc, pendin
764798
pusch_alloc.ul_res_grid.fill(grant);
765799

766800
// Allocate new retx in the HARQ.
767-
msg3_ctx.harq.new_retx(pusch_alloc.slot);
801+
if (not h_ul.new_retx(pusch_alloc.slot)) {
802+
logger.warning("tc-rnti={}: Failed to allocate reTx for Msg3", msg3_ctx.preamble.tc_rnti);
803+
continue;
804+
}
768805

769806
// Fill DCI.
770807
static constexpr uint8_t msg3_rv = 0;
@@ -773,24 +810,23 @@ void ra_scheduler::schedule_msg3_retx(cell_resource_allocator& res_alloc, pendin
773810
cell_cfg.ul_cfg_common.init_ul_bwp.generic_params,
774811
grant.crbs,
775812
pusch_td_res_index,
776-
msg3_ctx.harq.last_tx_params().mcs,
777-
msg3_rv,
778-
msg3_ctx.harq);
813+
last_harq_params.mcs,
814+
msg3_rv);
779815

780816
// Fill PUSCH.
781817
ul_sched_info& ul_info = pusch_alloc.result.ul.puschs.emplace_back();
782818
ul_info.context.ue_index = INVALID_DU_UE_INDEX;
783819
ul_info.context.ss_id = cell_cfg.dl_cfg_common.init_dl_bwp.pdcch_common.ra_search_space_id;
784820
ul_info.context.k2 = k2;
785-
ul_info.context.nof_retxs = msg3_ctx.harq.tb().nof_retxs;
821+
ul_info.context.nof_retxs = h_ul.nof_retxs();
786822
ul_info.pusch_cfg = msg3_data[pusch_td_res_index].pusch;
787823
ul_info.pusch_cfg.rnti = msg3_ctx.preamble.tc_rnti;
788824
ul_info.pusch_cfg.rbs = msg3_vrbs;
789825
ul_info.pusch_cfg.rv_index = pdcch->dci.tc_rnti_f0_0.redundancy_version;
790826
ul_info.pusch_cfg.new_data = false;
791827

792828
// Store parameters used in HARQ.
793-
msg3_ctx.harq.save_alloc_params(ul_harq_sched_context{dci_ul_rnti_config_type::tc_rnti_f0_0}, ul_info.pusch_cfg);
829+
h_ul.save_grant_params(ul_harq_alloc_context{dci_ul_rnti_config_type::tc_rnti_f0_0}, ul_info.pusch_cfg);
794830

795831
// successful allocation. Exit loop.
796832
break;

lib/scheduler/common_scheduling/ra_scheduler.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010

1111
#pragma once
1212

13+
#include "../cell/cell_harq_manager.h"
1314
#include "../cell/resource_grid.h"
1415
#include "../pdcch_scheduling/pdcch_resource_allocator.h"
1516
#include "../support/prbs_calculator.h"
1617
#include "../support/slot_event_list.h"
17-
#include "../ue_scheduling/harq_process.h"
1818
#include "srsran/ran/prach/prach_configuration.h"
1919
#include "srsran/scheduler/config/scheduler_expert_config.h"
2020
#include "srsran/srslog/srslog.h"
@@ -61,6 +61,8 @@ class ra_scheduler
6161
void run_slot(cell_resource_allocator& res_alloc);
6262

6363
private:
64+
class msg3_harq_timeout_notifier;
65+
6466
struct pending_rar_t {
6567
rnti_t ra_rnti = rnti_t::INVALID_RNTI;
6668
slot_point prach_slot_rx;
@@ -71,11 +73,12 @@ class ra_scheduler
7173
struct pending_msg3_t {
7274
/// Detected PRACH Preamble associated to this Msg3.
7375
rach_indication_message::preamble preamble{};
74-
harq_logger msg3_harq_logger{srslog::fetch_basic_logger("SCHED"), rnti_t::INVALID_RNTI, to_du_cell_index(0), false};
7576
/// UL Harq used to schedule Msg3.
7677
/// Note: [TS 38.321, 5.4.2.1] "For UL transmission with UL grant in RA Response, HARQ process identifier 0 is
7778
/// used".
78-
ul_harq_process harq{to_harq_id(0), msg3_harq_logger};
79+
unique_ue_harq_entity msg3_harq_ent;
80+
81+
bool busy() const { return not msg3_harq_ent.empty(); }
7982
};
8083
struct msg3_alloc_candidate {
8184
unsigned pusch_td_res_index;
@@ -170,6 +173,7 @@ class ra_scheduler
170173
sch_mcs_description msg3_mcs_config;
171174

172175
// variables
176+
cell_harq_manager msg3_harqs;
173177
slot_event_list<rach_indication_message> pending_rachs;
174178
slot_event_list<ul_crc_indication> pending_crcs;
175179
std::deque<pending_rar_t> pending_rars;

lib/scheduler/support/dci_builder.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
*/
99

1010
#include "dci_builder.h"
11+
#include "../cell/cell_harq_manager.h"
12+
#include "../ue_scheduling/harq_process.h"
1113
#include "srsran/adt/optional.h"
1214
#include "srsran/ran/pdcch/dci_packing.h"
1315
#include "srsran/ran/pdcch/search_space.h"
@@ -291,12 +293,8 @@ void srsran::build_dci_f0_0_tc_rnti(dci_ul_info& dci,
291293
const crb_interval& crbs,
292294
unsigned time_resource,
293295
sch_mcs_index mcs_index,
294-
uint8_t rv,
295-
const ul_harq_process& h_ul)
296+
uint8_t rv)
296297
{
297-
// See TS38.321, 5.4.2.1 - "For UL transmission with UL grant in RA Response, HARQ process identifier 0 is used."
298-
srsran_assert(h_ul.id == 0, "UL HARQ process used for Msg3 must have id=0");
299-
300298
dci.type = dci_ul_rnti_config_type::tc_rnti_f0_0;
301299
dci.tc_rnti_f0_0 = {};
302300
dci_0_0_tc_rnti_configuration& f0_0 = dci.tc_rnti_f0_0;

lib/scheduler/support/dci_builder.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@
1010
#pragma once
1111

1212
#include "../config/ue_configuration.h"
13-
#include "../ue_scheduling/harq_process.h"
1413
#include "srsran/ran/pdcch/search_space.h"
1514
#include "srsran/ran/resource_allocation/resource_allocation_frequency.h"
1615
#include "srsran/scheduler/config/bwp_configuration.h"
1716
#include "srsran/scheduler/scheduler_dci.h"
1817

1918
namespace srsran {
2019

20+
class dl_harq_process;
21+
class ul_harq_process;
22+
2123
/// Builds DCI f1_0 for SI-RNTI used in SIBs.
2224
void build_dci_f1_0_si_rnti(dci_dl_info& dci,
2325
const bwp_downlink_common& init_dl_bwp,
@@ -85,8 +87,7 @@ void build_dci_f0_0_tc_rnti(dci_ul_info& dci,
8587
const crb_interval& crbs,
8688
unsigned time_resource,
8789
sch_mcs_index mcs_index,
88-
uint8_t rv,
89-
const ul_harq_process& h_ul);
90+
uint8_t rv);
9091

9192
/// Builds DCI f0_0 for C-RNTI.
9293
void build_dci_f0_0_c_rnti(dci_ul_info& dci,

0 commit comments

Comments
 (0)