Skip to content

Commit d72e1e8

Browse files
committed
sched: fix handling of error indication and make it part of the ue event manager
1 parent f9b1047 commit d72e1e8

File tree

6 files changed

+148
-126
lines changed

6 files changed

+148
-126
lines changed

lib/scheduler/logging/scheduler_event_logger.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ void scheduler_event_logger::log_impl()
1818
if (mode == debug) {
1919
logger.debug("Processed slot events:{}", to_c_str(fmtbuf));
2020
fmtbuf.clear();
21+
} else if (mode == info) {
22+
logger.info("Processed slot events:{}", to_c_str(fmtbuf));
23+
fmtbuf.clear();
2124
}
2225
}
2326

@@ -92,6 +95,20 @@ void scheduler_event_logger::enqueue_impl(const sched_ue_delete_message& ue_requ
9295
}
9396
}
9497

98+
void scheduler_event_logger::enqueue_impl(const error_indication_event& err_ind)
99+
{
100+
if (mode == debug) {
101+
fmt::format_to(fmtbuf,
102+
"\n- ErrorIndication: slot={}{}{}{}",
103+
err_ind.sl_tx,
104+
err_ind.outcome.pdcch_discarded ? ", PDCCH discarded" : "",
105+
err_ind.outcome.pdsch_discarded ? ", PDSCH discarded" : "",
106+
err_ind.outcome.pusch_and_pucch_discarded ? ", PUSCH and PUCCH discarded" : "");
107+
} else if (mode == info) {
108+
fmt::format_to(fmtbuf, "{}ErrorIndication slot={}", separator(), err_ind.sl_tx);
109+
}
110+
}
111+
95112
void scheduler_event_logger::enqueue_impl(const sr_event& sr)
96113
{
97114
if (mode == debug) {

lib/scheduler/logging/scheduler_event_logger.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ class scheduler_event_logger
7777
ph_db_range ph;
7878
optional<p_cmax_dbm_range> p_cmax;
7979
};
80+
struct error_indication_event {
81+
slot_point sl_tx;
82+
scheduler_slot_handler::error_outcome outcome;
83+
};
8084

8185
scheduler_event_logger() :
8286
logger(srslog::fetch_basic_logger("SCHED")),
@@ -120,6 +124,8 @@ class scheduler_event_logger
120124
void enqueue_impl(const ue_reconf_event& ue_request);
121125
void enqueue_impl(const sched_ue_delete_message& ue_request);
122126

127+
void enqueue_impl(const error_indication_event& err_ind);
128+
123129
void enqueue_impl(const sr_event& sr);
124130
void enqueue_impl(const bsr_event& bsr);
125131
void enqueue_impl(const harq_ack_event& harq_ev);

lib/scheduler/ue_scheduling/ue_event_manager.cpp

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,114 @@ void ue_event_manager::handle_dl_buffer_state_indication(const dl_buffer_state_i
424424
dl_bo_mng->handle_dl_buffer_state_indication(bs);
425425
}
426426

427+
static void handle_discarded_pusch(const cell_slot_resource_allocator& prev_slot_result, ue_repository& ue_db)
428+
{
429+
for (const ul_sched_info& grant : prev_slot_result.result.ul.puschs) {
430+
ue* u = ue_db.find_by_rnti(grant.pusch_cfg.rnti);
431+
if (u == nullptr) {
432+
// UE has been removed.
433+
continue;
434+
}
435+
436+
// - The lower layers will not attempt to decode the PUSCH and will not send any CRC indication.
437+
ul_harq_process& h_ul = u->get_pcell().harqs.ul_harq(grant.pusch_cfg.harq_id);
438+
if (not h_ul.empty()) {
439+
if (h_ul.tb().nof_retxs == 0) {
440+
// Given that the PUSCH grant was discarded before it reached the PHY, the "new_data" flag was not handled
441+
// and the UL softbuffer was not reset. To avoid mixing different TBs in the softbuffer, it is important to
442+
// reset the UL HARQ process.
443+
h_ul.reset();
444+
} else {
445+
// To avoid a long UL HARQ timeout window (due to lack of CRC indication), it is important to force a NACK
446+
// in the UL HARQ process.
447+
h_ul.crc_info(false);
448+
}
449+
}
450+
451+
// - The lower layers will not attempt to decode any UCI in the PUSCH and will not send any UCI indication.
452+
if (grant.uci.has_value() and grant.uci->harq.has_value() and grant.uci->harq->harq_ack_nof_bits > 0) {
453+
// To avoid a long DL HARQ timeout window (due to lack of UCI indication), it is important to NACK the
454+
// DL HARQ processes with UCI falling in this slot.
455+
u->get_pcell().harqs.dl_ack_info_cancelled(prev_slot_result.slot);
456+
}
457+
}
458+
}
459+
460+
static void handle_discarded_pucch(const cell_slot_resource_allocator& prev_slot_result, ue_repository& ue_db)
461+
{
462+
for (const auto& pucch : prev_slot_result.result.ul.pucchs) {
463+
ue* u = ue_db.find_by_rnti(pucch.crnti);
464+
if (u == nullptr) {
465+
// UE has been removed.
466+
continue;
467+
}
468+
bool has_harq_ack = false;
469+
switch (pucch.format) {
470+
case pucch_format::FORMAT_1:
471+
has_harq_ack = pucch.format_1.harq_ack_nof_bits > 0;
472+
break;
473+
case pucch_format::FORMAT_2:
474+
has_harq_ack = pucch.format_2.harq_ack_nof_bits > 0;
475+
break;
476+
default:
477+
break;
478+
}
479+
480+
// - The lower layers will not attempt to decode the PUCCH and will not send any UCI indication.
481+
if (has_harq_ack) {
482+
// To avoid a long DL HARQ timeout window (due to lack of UCI indication), it is important to force a NACK in
483+
// the DL HARQ processes with UCI falling in this slot.
484+
u->get_pcell().harqs.dl_ack_info_cancelled(prev_slot_result.slot);
485+
}
486+
}
487+
}
488+
489+
void ue_event_manager::handle_error_indication(slot_point sl_tx,
490+
du_cell_index_t cell_index,
491+
scheduler_slot_handler::error_outcome event)
492+
{
493+
common_events.emplace(INVALID_DU_UE_INDEX, [this, sl_tx, cell_index, event]() {
494+
// Handle Error Indication.
495+
496+
const cell_slot_resource_allocator* prev_slot_result = du_cells[cell_index].res_grid->get_history(sl_tx);
497+
if (prev_slot_result == nullptr) {
498+
logger.warning("cell={}, slot={}: Discarding error indication. Cause: Scheduler results associated with the slot "
499+
"of the error indication have already been erased",
500+
cell_index,
501+
sl_tx);
502+
return;
503+
}
504+
505+
// In case DL PDCCHs were skipped, there will be the following consequences:
506+
// - The UE will not decode the PDSCH and will not send the respective UCI.
507+
// - The UE won't update the HARQ NDI, if new HARQ TB.
508+
// - The UCI indication coming later from the lower layers will likely contain a HARQ-ACK=DTX.
509+
// In case UL PDCCHs were skipped, there will be the following consequences:
510+
// - The UE will not decode the PUSCH.
511+
// - The UE won't update the HARQ NDI, if new HARQ TB.
512+
// - The CRC indication coming from the lower layers will likely be CRC=KO.
513+
// - Any UCI in the respective PUSCH will be likely reported as HARQ-ACK=DTX.
514+
// In neither of the cases, the HARQs will timeout, because we did not lose the UCI/CRC indications in the lower
515+
// layers. We do not need to cancel associated PUSCH grant (in UL PDCCH case) because it is important that
516+
// the PUSCH "new_data" flag reaches the lower layers, telling them whether the UL HARQ buffer needs to be reset or
517+
// not. Cancelling HARQ retransmissions is dangerous as it increases the chances of NDI ambiguity.
518+
519+
// In case of PDSCH grants being discarded, there will be the following consequences:
520+
// - If the PDCCH was not discarded,the UE will fail to decode the PDSCH and will send an HARQ-ACK=NACK. The
521+
// scheduler will retransmit the respective DL HARQ. No actions required.
522+
523+
// In case of PUCCH and PUSCH grants being discarded.
524+
if (event.pusch_and_pucch_discarded) {
525+
handle_discarded_pusch(*prev_slot_result, ue_db);
526+
527+
handle_discarded_pucch(*prev_slot_result, ue_db);
528+
}
529+
530+
// Log event.
531+
ev_logger.enqueue(scheduler_event_logger::error_indication_event{sl_tx, event});
532+
});
533+
}
534+
427535
void ue_event_manager::process_common(slot_point sl, du_cell_index_t cell_index)
428536
{
429537
bool new_slot_detected = last_sl != sl;
@@ -495,12 +603,14 @@ void ue_event_manager::run(slot_point sl, du_cell_index_t cell_index)
495603
process_cell_specific(cell_index);
496604
}
497605

498-
void ue_event_manager::add_cell(const cell_configuration& cell_cfg_, ue_srb0_scheduler& srb0_sched)
606+
void ue_event_manager::add_cell(cell_resource_allocator& cell_res_grid, ue_srb0_scheduler& srb0_sched)
499607
{
500-
srsran_assert(not cell_exists(cell_cfg_.cell_index), "Overwriting cell configurations not supported");
608+
const du_cell_index_t cell_index = cell_res_grid.cell_index();
609+
srsran_assert(not cell_exists(cell_index), "Overwriting cell configurations not supported");
501610

502-
du_cells[cell_cfg_.cell_index].cfg = &cell_cfg_;
503-
du_cells[cell_cfg_.cell_index].srb0_sched = &srb0_sched;
611+
du_cells[cell_index].cfg = &cell_res_grid.cfg;
612+
du_cells[cell_index].res_grid = &cell_res_grid;
613+
du_cells[cell_index].srb0_sched = &srb0_sched;
504614
}
505615

506616
bool ue_event_manager::cell_exists(du_cell_index_t cell_index) const

lib/scheduler/ue_scheduling/ue_event_manager.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class ue_event_manager final : public sched_ue_configuration_handler,
3535
ue_event_manager(ue_repository& ue_db, scheduler_metrics_handler& metrics_handler, scheduler_event_logger& ev_logger);
3636
~ue_event_manager();
3737

38-
void add_cell(const cell_configuration& cell_cfg_, ue_srb0_scheduler& srb0_sched);
38+
void add_cell(cell_resource_allocator& cell_res_grid, ue_srb0_scheduler& srb0_sched);
3939

4040
/// UE Add/Mod/Remove interface.
4141
void handle_ue_creation(ue_config_update_event ev) override;
@@ -52,6 +52,9 @@ class ue_event_manager final : public sched_ue_configuration_handler,
5252
/// Scheduler DL buffer state indication handler interface.
5353
void handle_dl_buffer_state_indication(const dl_buffer_state_indication_message& bs) override;
5454

55+
void
56+
handle_error_indication(slot_point sl_tx, du_cell_index_t cell_index, scheduler_slot_handler::error_outcome event);
57+
5558
/// Process events for a given slot and cell index.
5659
void run(slot_point sl, du_cell_index_t cell_index);
5760

@@ -106,6 +109,8 @@ class ue_event_manager final : public sched_ue_configuration_handler,
106109
struct du_cell {
107110
const cell_configuration* cfg = nullptr;
108111

112+
cell_resource_allocator* res_grid = nullptr;
113+
109114
/// Reference to SRB0 and other bearers scheduler
110115
ue_srb0_scheduler* srb0_sched = nullptr;
111116
};

lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp

Lines changed: 1 addition & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ void ue_scheduler_impl::add_cell(const ue_scheduler_cell_params& params)
2929
{
3030
ue_res_grid_view.add_cell(*params.cell_res_alloc);
3131
cells[params.cell_index] = std::make_unique<cell>(expert_cfg, params, ue_db);
32-
event_mng.add_cell(params.cell_res_alloc->cfg, cells[params.cell_index]->srb0_sched);
32+
event_mng.add_cell(*params.cell_res_alloc, cells[params.cell_index]->srb0_sched);
3333
ue_alloc.add_cell(params.cell_index, *params.pdcch_sched, *params.uci_alloc, *params.cell_res_alloc);
3434
}
3535

@@ -166,122 +166,3 @@ void ue_scheduler_impl::run_slot(slot_point slot_tx, du_cell_index_t cell_index)
166166
// TODO: remove this.
167167
puxch_grant_sanitizer(*cells[cell_index]->cell_res_alloc);
168168
}
169-
170-
void ue_scheduler_impl::handle_error_indication(slot_point sl_tx,
171-
du_cell_index_t cell_index,
172-
scheduler_slot_handler::error_outcome event)
173-
{
174-
if (cells[cell_index] == nullptr or cells[cell_index]->cell_res_alloc == nullptr) {
175-
logger.error("cell={}: Discarding error indication. Cause: cell with provided index is not configured", cell_index);
176-
return;
177-
}
178-
cell_resource_allocator& res_grid = *cells[cell_index]->cell_res_alloc;
179-
180-
const cell_slot_resource_allocator* prev_slot_result = res_grid.get_history(sl_tx);
181-
if (prev_slot_result == nullptr) {
182-
logger.warning("cell={}, slot={}: Discarding error indication. Cause: Scheduler results associated with the slot "
183-
"of the error indication have already been erased",
184-
cell_index,
185-
sl_tx);
186-
return;
187-
}
188-
189-
// In case DL PDCCHs were skipped, there will be the following consequences:
190-
// - The UE will not decode the PDSCH and send the respective UCI. The UCI indication coming later from the lower
191-
// layers will likely contain a HARQ-ACK=DTX. No action needed. We do not cancel the respective DL HARQ, because
192-
// doing so would likely increase the chance of NDI ambiguity on the UE side.
193-
194-
// In case UL PDCCHs were skipped, there will be the following consequences:
195-
// - The UE won't send the associated PUSCHs, which means that the lower layers will later forward CRC indications
196-
// with CRC=KO, and the respective UL HARQs will need to be retransmitted. No action needed. We do not cancel
197-
// the respective PUSCH grant, because it is important that the PUSCH "new_data" flag reaches the lower layers,
198-
// telling them whether the UL HARQ buffer needs to be reset or not.
199-
// - Any UCI in the respective PUSCH will be reported as DTX, and the DL HARQ will be retransmitted. No action
200-
// needed.
201-
202-
// In case of PDSCH grants being discarded, there will be the following consequences:
203-
// - The UE will fail to decode the PDSCH and will send an HARQ-ACK=NACK. The scheduler will retransmit the
204-
// respective DL HARQ. No actions required.
205-
206-
// In case of PUCCH and PUSCH grants being discarded.
207-
if (event.pusch_and_pucch_discarded) {
208-
for (const ul_sched_info& grant : prev_slot_result->result.ul.puschs) {
209-
ue* u = ue_db.find_by_rnti(grant.pusch_cfg.rnti);
210-
if (u == nullptr) {
211-
// UE has been removed.
212-
continue;
213-
}
214-
215-
// - The lower layers will not attempt to decode the PUSCH and will not send any CRC indication.
216-
ul_harq_process& h_ul = u->get_pcell().harqs.ul_harq(grant.pusch_cfg.harq_id);
217-
if (not h_ul.empty()) {
218-
if (h_ul.tb().nof_retxs == 0) {
219-
// Given that the PUSCH grant was discarded before it reached the PHY, the "new_data" flag was not handled
220-
// and the UL softbuffer was not reset. To avoid mixing different TBs in the softbuffer, it is important to
221-
// reset the UL HARQ process.
222-
h_ul.reset();
223-
} else {
224-
// To avoid a long UL HARQ timeout window (due to lack of CRC indication), it is important to force a NACK in
225-
// the UL HARQ process.
226-
h_ul.crc_info(false);
227-
}
228-
}
229-
230-
// - The lower layers will not attempt to decode any UCI in the PUSCH and will not send any UCI indication.
231-
if (grant.uci.has_value() and grant.uci->harq.has_value() and grant.uci->harq->harq_ack_nof_bits > 0) {
232-
// To avoid a long DL HARQ timeout window (due to lack of UCI indication), it is important to NACK the
233-
// DL HARQ processes with UCI falling in this slot.
234-
u->get_pcell().harqs.dl_ack_info_cancelled(sl_tx);
235-
}
236-
}
237-
for (const auto& pucch : prev_slot_result->result.ul.pucchs) {
238-
ue* u = ue_db.find_by_rnti(pucch.crnti);
239-
if (u == nullptr) {
240-
// UE has been removed.
241-
continue;
242-
}
243-
bool has_harq_ack = false;
244-
switch (pucch.format) {
245-
case pucch_format::FORMAT_1:
246-
has_harq_ack = pucch.format_1.harq_ack_nof_bits > 0;
247-
break;
248-
case pucch_format::FORMAT_2:
249-
has_harq_ack = pucch.format_2.harq_ack_nof_bits > 0;
250-
break;
251-
default:
252-
break;
253-
}
254-
255-
// - The lower layers will not attempt to decode the PUCCH and will not send any UCI indication.
256-
if (has_harq_ack) {
257-
// To avoid a long DL HARQ timeout window (due to lack of UCI indication), it is important to force a NACK in
258-
// the DL HARQ processes with UCI falling in this slot.
259-
u->get_pcell().harqs.dl_ack_info_cancelled(sl_tx);
260-
}
261-
}
262-
}
263-
264-
if (event.pdsch_discarded) {
265-
for (const dl_msg_alloc& grant : prev_slot_result->result.dl.ue_grants) {
266-
// Given that the PDSCH grant was discarded before it reached the PHY, the "new_data" flag was not handled
267-
// and the DL buffer was not reset. To avoid mixing different TBs in the buffer, it is important to
268-
// reset the DL HARQ process.
269-
ue* u = ue_db.find_by_rnti(grant.pdsch_cfg.rnti);
270-
if (u == nullptr) {
271-
// UE has been removed.
272-
continue;
273-
}
274-
ue_cell* ucell = u->find_cell(cell_index);
275-
if (ucell == nullptr) {
276-
// UE cell does not exist.
277-
continue;
278-
}
279-
dl_harq_process& h_dl = ucell->harqs.dl_harq(grant.pdsch_cfg.harq_id);
280-
for (unsigned cw = 0; cw != grant.pdsch_cfg.codewords.size(); ++cw) {
281-
if (h_dl.is_waiting_ack(cw)) {
282-
h_dl.cancel_harq_retxs(cw);
283-
}
284-
}
285-
}
286-
}
287-
}

lib/scheduler/ue_scheduling/ue_scheduler_impl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ class ue_scheduler_impl final : public ue_scheduler
4545

4646
void handle_error_indication(slot_point sl_tx,
4747
du_cell_index_t cell_index,
48-
scheduler_slot_handler::error_outcome event) override;
48+
scheduler_slot_handler::error_outcome event) override
49+
{
50+
event_mng.handle_error_indication(sl_tx, cell_index, event);
51+
}
4952

5053
sched_ue_configuration_handler& get_ue_configurator() override { return event_mng; }
5154

0 commit comments

Comments
 (0)