sched,bugfix: fix nof_retx update when UL HARQs are resumed

master
Francisco 3 years ago committed by Francisco Paisana
parent d74f70289e
commit f7aef3ffc1

@ -19,8 +19,8 @@
#define srsran_unlikely(expr) __builtin_expect(!!(expr), 0)
#define srsran_terminate(fmt, ...) \
std::fprintf(stderr, "%s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
srslog::flush(); \
std::fprintf(stderr, "%s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
std::abort()
#ifdef ASSERTS_ENABLED

@ -106,14 +106,15 @@ public:
uint32_t get_pending_data() const;
bool has_pending_phich() const;
bool pop_pending_phich();
void phich_alloc_failed();
void request_pdcch();
void retx_skipped();
private:
prb_interval allocation;
int pending_data;
bool pending_phich = false;
bool is_msg3_ = false;
bool pdcch_required = false;
bool pending_phich = false;
bool is_msg3_ = false;
bool pdcch_requested = false;
};
class harq_entity

@ -637,17 +637,20 @@ alloc_result sf_sched::alloc_phich(sched_ue* user)
auto* ul_sf_result = &cc_results->get_cc(cc_cfg->enb_cc_idx)->ul_sched_result;
if (ul_sf_result->phich.full()) {
logger.warning("SCHED: Maximum number of PHICH allocations has been reached");
h->phich_alloc_failed();
logger.warning(
"SCHED: UL skipped retx rnti=0x%x, pid=%d. Cause: No PHICH space left", user->get_rnti(), h->get_id());
h->pop_pending_phich();
return alloc_result::no_grant_space;
}
if (not user->phich_enabled(get_tti_rx(), cc_cfg->enb_cc_idx)) {
// PHICH falls in measGap. PHICH hi=1 is assumed by UE. In case of NACK, the HARQ is going to be resumed later on.
logger.debug("SCHED: HARQ pid=%d for rnti=0x%x is being resumed due to PHICH - MeasGap collision",
h->get_id(),
user->get_rnti());
h->phich_alloc_failed();
logger.info(
"SCHED: UL skipped retx rnti=0x%x, pid=%d. Cause: PHICH-measGap collision", user->get_rnti(), h->get_id());
h->pop_pending_phich(); // empty pending PHICH
// Note: Given that the UE assumes PHICH hi=1, it is not expecting PUSCH grants for tti_tx_ul. Requesting PDCCH
// for the UL Harq has the effect of forbidding PUSCH grants, since phich_tti == pdcch_tti.
h->request_pdcch();
return alloc_result::no_cch_space;
}
@ -906,15 +909,23 @@ void sf_sched::generate_sched_results(sched_ue_list& ue_db)
/* Resume UL HARQs with pending retxs that did not get allocated */
using phich_t = sched_interface::ul_sched_phich_t;
auto& phich_list = cc_result->ul_sched_result.phich;
for (uint32_t i = 0; i < cc_result->ul_sched_result.phich.size(); ++i) {
auto& phich = phich_list[i];
if (phich.phich == phich_t::NACK) {
auto& ue = *ue_db[phich.rnti];
ul_harq_proc* h = ue.get_ul_harq(get_tti_tx_ul(), cc_cfg->enb_cc_idx);
if (not is_ul_alloc(ue.get_rnti()) and h != nullptr and not h->is_empty()) {
// There was a missed UL harq retx. Halt+Resume the HARQ
phich.phich = phich_t::ACK;
logger.debug("SCHED: rnti=0x%x UL harq pid=%d is being resumed", ue.get_rnti(), h->get_id());
for (auto& ue_pair : ue_db) {
auto& ue = *ue_pair.second;
uint16_t rnti = ue.get_rnti();
ul_harq_proc* h = ue.get_ul_harq(get_tti_tx_ul(), cc_cfg->enb_cc_idx);
if (h != nullptr and not h->is_empty() and not is_ul_alloc(rnti)) {
// There was a missed UL harq retx. Halt+Resume the HARQ
h->retx_skipped();
auto same_rnti = [rnti](const phich_t& p) { return p.rnti == rnti; };
phich_t* phich = std::find_if(phich_list.begin(), phich_list.end(), same_rnti);
if (phich != phich_list.end()) {
srsran_assert(phich->phich == phich_t::NACK, "Expected hi=0 in case of active UL HARQ that was not retx");
logger.info("SCHED: UL skipped retx rnti=0x%x, pid=%d. Cause: %s",
ue.get_rnti(),
h->get_id(),
ue.pusch_enabled(get_tti_rx(), cc_cfg->enb_cc_idx, false) ? "lack of PHY resources"
: "PUSCH-measGap collision");
phich->phich = phich_t::ACK;
}
}
}

@ -247,10 +247,10 @@ void ul_harq_proc::new_tx(tti_point tti_, int mcs, int tbs, prb_interval alloc,
{
allocation = alloc;
new_tx_common(0, tti_point{tti_}, mcs, tbs, max_retx_);
pending_data = tbs;
pending_phich = true;
is_msg3_ = is_msg3;
pdcch_required = false;
pending_data = tbs;
pending_phich = true;
is_msg3_ = is_msg3;
pdcch_requested = false;
}
void ul_harq_proc::new_retx(tti_point tti_, int* mcs, int* tbs, prb_interval alloc)
@ -258,15 +258,15 @@ void ul_harq_proc::new_retx(tti_point tti_, int* mcs, int* tbs, prb_interval all
// If PRBs changed, or there was no tx in last oportunity (e.g. HARQ is being resumed)
allocation = alloc;
new_retx_common(0, tti_point{tti_}, mcs, tbs);
pending_phich = true;
pdcch_required = false;
pending_phich = true;
pdcch_requested = false;
}
bool ul_harq_proc::retx_requires_pdcch(tti_point tti_, prb_interval alloc) const
{
// Adaptive retx if: (1) PRBs changed, (2) HARQ resumed due to last PUSCH retx being skipped (3) HARQ resumed due to
// last PHICH alloc being skipped (e.g. due to measGaps)
return alloc != allocation or tti_ != to_tx_ul(tti) or pdcch_required;
return alloc != allocation or pdcch_requested;
}
bool ul_harq_proc::set_ack(uint32_t tb_idx, bool ack_)
@ -283,13 +283,17 @@ bool ul_harq_proc::has_pending_phich() const
return pending_phich;
}
void ul_harq_proc::phich_alloc_failed()
void ul_harq_proc::request_pdcch()
{
pop_pending_phich();
if (not is_empty(0)) {
// HARQ needs to be resumed. This is signalled by pending_phich flag
pdcch_required = true;
}
pdcch_requested = true;
}
void ul_harq_proc::retx_skipped()
{
// Note: This function should be called in case of PHICH allocation is successful
// Flagging "PDCCH required" for next retx, as HARQ is being resumed
pdcch_requested = true;
n_rtx[0]++;
}
bool ul_harq_proc::pop_pending_phich()
@ -307,9 +311,9 @@ bool ul_harq_proc::pop_pending_phich()
void ul_harq_proc::reset_pending_data()
{
reset_pending_data_common();
pending_data = 0;
is_msg3_ = false;
pdcch_required = false;
pending_data = 0;
is_msg3_ = false;
pdcch_requested = false;
}
uint32_t ul_harq_proc::get_pending_data() const

@ -266,7 +266,9 @@ int test_dci_content_common(const sf_output_res_t& sf_out, uint32_t enb_cc_idx)
CONDERROR(pusch.tbs == 0, "Allocated PUSCH with invalid TBS=%d", pusch.tbs);
CONDERROR(alloc_rntis.count(rnti) > 0, "The user rnti=0x%x got allocated multiple times in UL", rnti);
alloc_rntis.insert(pusch.dci.rnti);
CONDERROR(not((pusch.current_tx_nb == 0) xor (pusch.dci.tb.rv != 0)), "Number of txs incorrectly set");
CONDERROR(not(((pusch.current_tx_nb % 4) == 0) xor (pusch.dci.tb.rv != 0)),
"[rnti=0x%x] Number of txs incorrectly set",
rnti);
if (not pusch.needs_pdcch) {
// In case of non-adaptive retx or Msg3
continue;

@ -116,6 +116,9 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out)
// Update UL harqs with PHICH info
bool found_phich = false;
bool is_msg3 = h.nof_txs == h.nof_retxs + 1 and ctxt.msg3_tti_rx.is_valid() and h.first_tti_rx == ctxt.msg3_tti_rx;
uint32_t max_retxs = is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ctxt.ue_cfg.maxharq_tx;
bool last_retx = h.nof_retxs + 1 >= max_retxs;
for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].phich.size(); ++i) {
const auto& phich = sf_out.ul_cc_result[cc].phich[i];
if (phich.rnti != ctxt.rnti) {
@ -124,25 +127,23 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out)
found_phich = true;
bool is_ack = phich.phich == phich_t::ACK;
bool is_msg3 =
h.nof_txs == h.nof_retxs + 1 and ctxt.msg3_tti_rx.is_valid() and h.first_tti_rx == ctxt.msg3_tti_rx;
bool last_retx = h.nof_retxs + 1 >= (is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ctxt.ue_cfg.maxharq_tx);
if (is_ack or last_retx) {
h.active = false;
}
}
if (h.active and not found_phich) {
// HARQ being resumed. Possibly due to measGap, PHICH may not be allocated.
logger.info("TESTER: rnti=0x%x, HARQ pid=%d being resumed.", ctxt.rnti, pid);
if (not found_phich and h.active) {
// There can be missing PHICH due to measGap collisions. In such case, we deactivate the harq and assume hi=1
h.active = false;
}
// Update UL harqs with PUSCH grants
bool pusch_found = false;
for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].pusch.size(); ++i) {
const auto& data = sf_out.ul_cc_result[cc].pusch[i];
if (data.dci.rnti != ctxt.rnti) {
continue;
}
pusch_found = true;
if (h.nof_txs == 0 or h.ndi != data.dci.tb.ndi) {
// newtx
@ -158,6 +159,11 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out)
h.riv = data.dci.type2_alloc.riv;
h.nof_txs++;
}
if (not pusch_found and h.nof_retxs < max_retxs) {
// PUSCH *may* be skipped due to measGap. nof_retxs keeps getting incremented
h.nof_retxs++;
h.nof_txs++;
}
}
}

@ -26,7 +26,7 @@ struct ue_harq_ctxt_t {
bool ndi = false;
uint32_t pid = 0;
uint32_t nof_txs = 0;
uint32_t nof_retxs = 0;
uint32_t nof_retxs = std::numeric_limits<uint32_t>::max();
uint32_t riv = 0;
srsran_dci_location_t dci_loc = {};
uint32_t tbs = 0;

@ -189,13 +189,16 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t&
continue;
}
const auto& h = ue.cc_list[ue_cc_idx].ul_harqs[pid];
bool phich_ack = phich_ptr != nullptr and phich_ptr->phich == phich_t::ACK;
bool is_msg3 = h.first_tti_rx == ue.msg3_tti_rx and h.nof_txs == h.nof_retxs + 1;
bool last_retx = h.nof_retxs + 1 >= (is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ue.ue_cfg.maxharq_tx);
tti_point tti_tx_phich = to_tx_dl(sf_out.tti_rx);
bool phich_in_meas_gap = is_in_measgap(tti_tx_phich, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset);
bool h_inactive_now = (not h.active) or (phich_ack or last_retx or phich_in_meas_gap);
const auto& h = ue.cc_list[ue_cc_idx].ul_harqs[pid];
bool phich_ack = phich_ptr != nullptr and phich_ptr->phich == phich_t::ACK;
bool is_msg3 = h.first_tti_rx == ue.msg3_tti_rx and h.nof_txs == h.nof_retxs + 1;
uint32_t max_nof_retxs = is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ue.ue_cfg.maxharq_tx;
bool last_retx = h.nof_retxs + 1 >= max_nof_retxs;
tti_point tti_tx_phich = to_tx_dl(sf_out.tti_rx);
bool phich_in_meas_gap = is_in_measgap(tti_tx_phich, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset);
bool pusch_in_meas_gap =
is_in_measgap(to_tx_ul(sf_out.tti_rx), ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset);
bool h_cleared = (not h.active) or (phich_ack or last_retx);
// TEST: Already active UL HARQs have to receive PHICH (unless MeasGap collision)
CONDERROR(h.active and phich_ptr == nullptr and not phich_in_meas_gap,
@ -209,7 +212,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t&
// TEST: absent PUSCH grants for active UL HARQs must be either ACKs, last retx, or interrupted HARQs
if (phich_ptr != nullptr) {
CONDERROR(not h_inactive_now and pusch_ptr == nullptr,
CONDERROR(not h_cleared and pusch_ptr == nullptr and not pusch_in_meas_gap,
"PHICH NACK received for rnti=0x%x but no PUSCH retx reallocated",
rnti);
}
@ -224,11 +227,13 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t&
// newtx
CONDERROR(nof_retx != 0, "Invalid rv index for new UL tx");
CONDERROR(pusch_ptr->current_tx_nb != 0, "UL HARQ retxs need to have been previously transmitted");
CONDERROR(not h_inactive_now, "New tx for already active UL HARQ");
CONDERROR(not h_cleared, "New tx for already active UL HARQ");
CONDERROR(not pusch_ptr->needs_pdcch and ue.msg3_tti_rx.is_valid() and sf_out.tti_rx > ue.msg3_tti_rx,
"In case of newtx, PDCCH allocation is required, unless it is Msg3");
} else {
CONDERROR(pusch_ptr->current_tx_nb == 0, "UL retx has to have nof tx > 0");
CONDERROR(h.nof_retxs >= max_nof_retxs, "UL max nof retxs exceeded");
CONDERROR(pusch_ptr->current_tx_nb != h.nof_retxs + 1, "UL HARQ nof_retx mismatch");
if (not h.active) {
// the HARQ is being resumed. PDCCH must be active with the exception of Msg3
CONDERROR(ue.msg4_tti_rx.is_valid() and not pusch_ptr->needs_pdcch,
@ -239,11 +244,11 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t&
} else {
// non-adaptive retx
CONDERROR(pusch_ptr->dci.type2_alloc.riv != h.riv, "Non-adaptive retx must keep the same riv");
CONDERROR(to_tx_ul(h.last_tti_rx) > sf_out.tti_rx, "UL harq pid=%d was reused too soon", h.pid);
}
}
CONDERROR(get_rvidx(h.nof_retxs + 1) != (uint32_t)pusch_ptr->dci.tb.rv, "Invalid rv index for retx");
CONDERROR(get_rvidx(h.nof_retxs + 1) != (uint32_t)pusch_ptr->dci.tb.rv, "Invalid rv index for UL retx");
CONDERROR(h.tbs != pusch_ptr->tbs, "TBS changed during HARQ retx");
CONDERROR(to_tx_ul(h.last_tti_rx) > sf_out.tti_rx, "UL harq pid=%d was reused too soon", h.pid);
}
}
}

Loading…
Cancel
Save