From 8ba08032b5f439e6982ddee4bf5ce3453165423d Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 7 Dec 2021 17:16:57 +0000 Subject: [PATCH] nr,gnb,sched: implemented standalone PDSCH allocator class --- srsgnb/hdr/stack/mac/sched_nr_cfg.h | 19 ++- .../hdr/stack/mac/sched_nr_grant_allocator.h | 11 +- srsgnb/hdr/stack/mac/sched_nr_helpers.h | 2 +- srsgnb/hdr/stack/mac/sched_nr_pdsch.h | 81 ++++++++++ srsgnb/hdr/stack/mac/sched_nr_rb.h | 23 +++ srsgnb/src/stack/mac/CMakeLists.txt | 1 + srsgnb/src/stack/mac/sched_nr_bwp.cc | 4 +- srsgnb/src/stack/mac/sched_nr_cfg.cc | 16 +- .../src/stack/mac/sched_nr_grant_allocator.cc | 143 +++++++++--------- srsgnb/src/stack/mac/sched_nr_helpers.cc | 43 ------ srsgnb/src/stack/mac/sched_nr_pdcch.cc | 52 ++++++- srsgnb/src/stack/mac/sched_nr_pdsch.cc | 143 ++++++++++++++++++ srsgnb/src/stack/mac/sched_nr_signalling.cc | 23 +-- 13 files changed, 410 insertions(+), 151 deletions(-) create mode 100644 srsgnb/hdr/stack/mac/sched_nr_pdsch.h create mode 100644 srsgnb/src/stack/mac/sched_nr_pdsch.cc diff --git a/srsgnb/hdr/stack/mac/sched_nr_cfg.h b/srsgnb/hdr/stack/mac/sched_nr_cfg.h index 34634b55c..5d5a077cb 100644 --- a/srsgnb/hdr/stack/mac/sched_nr_cfg.h +++ b/srsgnb/hdr/stack/mac/sched_nr_cfg.h @@ -33,6 +33,7 @@ using pusch_t = mac_interface_phy_nr::pusch_t; using pucch_t = mac_interface_phy_nr::pucch_t; using pdcch_dl_list_t = srsran::bounded_vector; using pdcch_ul_list_t = srsran::bounded_vector; +using pdsch_list_t = srsran::bounded_vector; using pucch_list_t = srsran::bounded_vector; using pusch_list_t = srsran::bounded_vector; using nzp_csi_rs_list = srsran::bounded_vector; @@ -93,12 +94,12 @@ struct bwp_params_t { bwp_params_t(const cell_cfg_t& cell, const sched_args_t& sched_cfg_, uint32_t cc, uint32_t bwp_id); - const prb_bitmap& used_prbs(uint32_t ss_id, srsran_dci_format_nr_t dci_fmt) const + uint32_t coreset_bw(uint32_t cs_id) const { return coresets[cs_id].bw; } + + const bwp_rb_bitmap& coreset_prb_limits(uint32_t ss_id, srsran_dci_format_nr_t dci_fmt) const { - if (used_common_prb_masks.contains(ss_id)) { - if (dci_fmt == srsran_dci_format_nr_1_0) { - return used_common_prb_masks[ss_id]; - } + if (used_common_prb_masks.contains(ss_id) and dci_fmt == srsran_dci_format_nr_1_0) { + return used_common_prb_masks[ss_id]; } return cached_empty_prb_mask; } @@ -109,8 +110,12 @@ struct bwp_params_t { } private: - prb_bitmap cached_empty_prb_mask; - srsran::optional_vector used_common_prb_masks; + bwp_rb_bitmap cached_empty_prb_mask; + srsran::optional_vector used_common_prb_masks; + struct coreset_cached_params { + uint32_t bw = 0; + }; + srsran::optional_vector coresets; }; /// Structure packing a single cell config params, and sched args diff --git a/srsgnb/hdr/stack/mac/sched_nr_grant_allocator.h b/srsgnb/hdr/stack/mac/sched_nr_grant_allocator.h index 1afda0f40..6a4b0affc 100644 --- a/srsgnb/hdr/stack/mac/sched_nr_grant_allocator.h +++ b/srsgnb/hdr/stack/mac/sched_nr_grant_allocator.h @@ -17,6 +17,7 @@ #include "sched_nr_helpers.h" #include "sched_nr_interface.h" #include "sched_nr_pdcch.h" +#include "sched_nr_pdsch.h" #include "sched_nr_ue.h" #include "srsenb/hdr/stack/mac/sched_common.h" @@ -44,24 +45,20 @@ struct bwp_slot_grid { uint32_t slot_idx = 0; const bwp_params_t* cfg = nullptr; - bwp_rb_bitmap dl_prbs; bwp_rb_bitmap ul_prbs; dl_sched_res_t dl; ul_sched_t ul; harq_ack_list_t pending_acks; bwp_pdcch_allocator pdcchs; /// slot PDCCH resource allocator + pdsch_allocator pdschs; /// slot PDSCH resource allocator srsran::unique_pool_ptr rar_softbuffer; explicit bwp_slot_grid(const bwp_params_t& bwp_params, uint32_t slot_idx_); void reset(); - bool is_dl() const { return cfg->slots[slot_idx].is_dl; } - bool is_ul() const { return cfg->slots[slot_idx].is_ul; } - prb_bitmap used_prbs(uint32_t ss_id, srsran_dci_format_nr_t dci_fmt) const - { - return dl_prbs.prbs() | cfg->used_prbs(ss_id, dci_fmt); - } + bool is_dl() const { return cfg->slots[slot_idx].is_dl; } + bool is_ul() const { return cfg->slots[slot_idx].is_ul; } }; struct bwp_res_grid { diff --git a/srsgnb/hdr/stack/mac/sched_nr_helpers.h b/srsgnb/hdr/stack/mac/sched_nr_helpers.h index 95f159014..588fd33d6 100644 --- a/srsgnb/hdr/stack/mac/sched_nr_helpers.h +++ b/srsgnb/hdr/stack/mac/sched_nr_helpers.h @@ -38,7 +38,7 @@ inline bool is_rnti_type_valid_in_search_space(srsran_rnti_type_t rnti_type, srs case srsran_search_space_type_common_2: return rnti_type == srsran_rnti_type_p; case srsran_search_space_type_common_3: - return rnti_type == srsran_rnti_type_c or rnti_type == srsran_rnti_type_ra; // TODO: Fix + return rnti_type == srsran_rnti_type_c; // TODO: Fix case srsran_search_space_type_ue: return rnti_type == srsran_rnti_type_c or rnti_type == srsran_rnti_type_cs or rnti_type == srsran_rnti_type_sp_csi; diff --git a/srsgnb/hdr/stack/mac/sched_nr_pdsch.h b/srsgnb/hdr/stack/mac/sched_nr_pdsch.h new file mode 100644 index 000000000..2e6b9ec0a --- /dev/null +++ b/srsgnb/hdr/stack/mac/sched_nr_pdsch.h @@ -0,0 +1,81 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSRAN_SCHED_NR_PDSCH_H +#define SRSRAN_SCHED_NR_PDSCH_H + +#include "srsenb/hdr/stack/mac/sched_common.h" +#include "srsgnb/hdr/stack/mac/sched_nr_cfg.h" + +namespace srsenb { + +namespace sched_nr_impl { + +class pdsch_allocator +{ +public: + pdsch_allocator(const bwp_params_t& cfg_, uint32_t sl_index, pdsch_list_t& pdsch_lst); + + /// Get available RBGs for allocation + rbg_bitmap available_rbgs(uint32_t ss_id, srsran_dci_format_nr_t dci_fmt) const + { + return (dl_prbs | bwp_cfg.coreset_prb_limits(ss_id, dci_fmt)).rbgs(); + } + /// Get available PRBs for allocation + prb_bitmap available_prbs(uint32_t ss_id, srsran_dci_format_nr_t dci_fmt) const + { + return (dl_prbs | bwp_cfg.coreset_prb_limits(ss_id, dci_fmt)).prbs(); + } + + /// Checks if provided PDSCH arguments produce a valid PDSCH that fits into cell PRBs and does not collide with other + /// allocations + alloc_result is_grant_valid(uint32_t ss_id, + srsran_dci_format_nr_t dci_fmt, + const prb_grant& grant, + ue_carrier_params_t* ue = nullptr) const; + + /** + * @brief Tries to allocate PDSCH grant. Ensures that there are no collisions with other previous PDSCH allocations + * @param dci_ctx[in] PDCCH DL DCI context information + * @param ss_id[in] SearchSpaceId used for allocation + * @param grant[in] PRBs used for the grant + * @param pdcch[out] PDCCH where frequency_assignment and time_assignment get stored. + * @return pdsch_t object pointer in case of success. alloc_result error code in case of failure + */ + srsran::expected + alloc_pdsch(const srsran_dci_ctx_t& dci_ctx, uint32_t ss_id, const prb_grant& grant, pdcch_dl_t& pdcch); + + /** + * @brief Allocates PDSCH grant without verifying for collisions. Useful to avoid redundant is_grant_valid(...) calls + * @param dci_ctx[in] PDCCH DL DCI context information + * @param grant[in] PRBs used for the grant + * @param pdcch[out] PDCCH where frequency and time assignment get stored. + */ + pdsch_t& alloc_pdsch_unchecked(const srsran_dci_ctx_t& dci_ctx, const prb_grant& grant, pdcch_dl_t& pdcch); + + void cancel_last_pdsch(); + + void reset(); + +private: + const bwp_params_t& bwp_cfg; + uint32_t slot_idx = 0; + + pdsch_list_t& pdschs; + bwp_rb_bitmap dl_prbs; +}; + +} // namespace sched_nr_impl + +} // namespace srsenb + +#endif // SRSRAN_SCHED_NR_PDSCH_H diff --git a/srsgnb/hdr/stack/mac/sched_nr_rb.h b/srsgnb/hdr/stack/mac/sched_nr_rb.h index e7b19843b..175460d48 100644 --- a/srsgnb/hdr/stack/mac/sched_nr_rb.h +++ b/srsgnb/hdr/stack/mac/sched_nr_rb.h @@ -198,6 +198,23 @@ public: uint32_t prb_to_rbg_idx(uint32_t prb_idx) const; + bwp_rb_bitmap& operator|=(const bwp_rb_bitmap& other) + { + prbs_ |= other.prbs_; + rbgs_ |= other.rbgs_; + return *this; + } + bwp_rb_bitmap& operator|=(const rbg_bitmap& other) + { + add(other); + return *this; + } + bwp_rb_bitmap& operator|=(const prb_bitmap& other) + { + add(other); + return *this; + } + private: prb_bitmap prbs_; rbg_bitmap rbgs_; @@ -210,6 +227,12 @@ private: void add_rbgs_to_prbs(const rbg_bitmap& grant); }; +template +bwp_rb_bitmap operator|(const bwp_rb_bitmap& lhs, const Other& rhs) +{ + return bwp_rb_bitmap(lhs) |= rhs; +} + inline prb_interval find_next_empty_interval(const prb_bitmap& mask, size_t start_prb_idx = 0, size_t last_prb_idx = SRSRAN_MAX_PRB_NR) { diff --git a/srsgnb/src/stack/mac/CMakeLists.txt b/srsgnb/src/stack/mac/CMakeLists.txt index 1837a272d..eb21b0dd7 100644 --- a/srsgnb/src/stack/mac/CMakeLists.txt +++ b/srsgnb/src/stack/mac/CMakeLists.txt @@ -14,6 +14,7 @@ set(SOURCES mac_nr.cc sched_nr_grant_allocator.cc sched_nr_harq.cc sched_nr_pdcch.cc + sched_nr_pdsch.cc sched_nr_cfg.cc sched_nr_helpers.cc sched_nr_bwp.cc diff --git a/srsgnb/src/stack/mac/sched_nr_bwp.cc b/srsgnb/src/stack/mac/sched_nr_bwp.cc index 14b941a50..c04b2fa57 100644 --- a/srsgnb/src/stack/mac/sched_nr_bwp.cc +++ b/srsgnb/src/stack/mac/sched_nr_bwp.cc @@ -25,8 +25,8 @@ alloc_result ra_sched::allocate_pending_rar(bwp_slot_allocator& slot_grid, const pending_rar_t& rar, uint32_t& nof_grants_alloc) { const uint32_t rar_aggr_level = 2; - prb_bitmap prbs = slot_grid.res_grid()[slot_grid.get_pdcch_tti()].used_prbs(bwp_cfg->cfg.pdcch.ra_search_space.id, - srsran_dci_format_nr_1_0); + prb_bitmap prbs = slot_grid.res_grid()[slot_grid.get_pdcch_tti()].pdschs.available_prbs( + bwp_cfg->cfg.pdcch.ra_search_space.id, srsran_dci_format_nr_1_0); alloc_result ret = alloc_result::other_cause; srsran::const_span msg3_grants{rar.msg3_grant}; diff --git a/srsgnb/src/stack/mac/sched_nr_cfg.cc b/srsgnb/src/stack/mac/sched_nr_cfg.cc index bc89ebbc1..5c5efca20 100644 --- a/srsgnb/src/stack/mac/sched_nr_cfg.cc +++ b/srsgnb/src/stack/mac/sched_nr_cfg.cc @@ -44,14 +44,22 @@ bwp_params_t::bwp_params_t(const cell_cfg_t& cell, const sched_args_t& sched_cfg cc(cc_), bwp_id(bwp_id_), cfg(cell.bwps[bwp_id_]), - logger(srslog::fetch_basic_logger(sched_cfg_.logger_name)) + logger(srslog::fetch_basic_logger(sched_cfg_.logger_name)), + cached_empty_prb_mask(cell.bwps[bwp_id_].rb_width, + cell.bwps[bwp_id_].start_rb, + cell.bwps[bwp_id_].pdsch.rbg_size_cfg_1) { srsran_assert(cfg.pdcch.ra_search_space_present, "BWPs without RA search space not supported"); const uint32_t ra_coreset_id = cfg.pdcch.ra_search_space.coreset_id; P = get_P(cfg.rb_width, cfg.pdsch.rbg_size_cfg_1); N_rbg = get_nof_rbgs(cfg.rb_width, cfg.start_rb, cfg.pdsch.rbg_size_cfg_1); - cached_empty_prb_mask.resize(cfg.rb_width); + + for (const srsran_coreset_t& cs : view_active_coresets(cfg.pdcch)) { + coresets.emplace(cs.id); + auto& cached_coreset = coresets[cs.id]; + cached_coreset.bw = srsran_coreset_get_bw(&cs); + } // Derive params of individual slots uint32_t nof_slots = SRSRAN_NSLOTS_PER_FRAME_NR(cfg.numerology_idx); @@ -112,10 +120,10 @@ bwp_params_t::bwp_params_t(const cell_cfg_t& cell, const sched_args_t& sched_cfg if (SRSRAN_SEARCH_SPACE_IS_COMMON(ss.type)) { used_common_prb_masks.emplace(ss_id, cached_empty_prb_mask); uint32_t coreset_start = srsran_coreset_start_rb(&cfg.pdcch.coreset[ss.coreset_id]); - used_common_prb_masks[ss_id].fill(0, coreset_start, true); + used_common_prb_masks[ss_id] |= prb_interval(0, coreset_start); if (ss.coreset_id == 0) { uint32_t coreset0_bw = srsran_coreset_get_bw(&cfg.pdcch.coreset[0]); - used_common_prb_masks[ss_id].fill(coreset_start + coreset0_bw, cfg.rb_width, true); + used_common_prb_masks[ss_id] |= prb_interval(coreset_start + coreset0_bw, cfg.rb_width); } } } diff --git a/srsgnb/src/stack/mac/sched_nr_grant_allocator.cc b/srsgnb/src/stack/mac/sched_nr_grant_allocator.cc index 40b2414fb..fddd55eb2 100644 --- a/srsgnb/src/stack/mac/sched_nr_grant_allocator.cc +++ b/srsgnb/src/stack/mac/sched_nr_grant_allocator.cc @@ -76,24 +76,21 @@ candidate_ss_list_t find_ss(const srsran_pdcch_cfg_nr_t& pdcch, //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bwp_slot_grid::bwp_slot_grid(const bwp_params_t& bwp_cfg_, uint32_t slot_idx_) : - dl_prbs(bwp_cfg_.cfg.rb_width, bwp_cfg_.cfg.start_rb, bwp_cfg_.cfg.pdsch.rbg_size_cfg_1), ul_prbs(bwp_cfg_.cfg.rb_width, bwp_cfg_.cfg.start_rb, bwp_cfg_.cfg.pdsch.rbg_size_cfg_1), slot_idx(slot_idx_), cfg(&bwp_cfg_), pdcchs(bwp_cfg_, slot_idx_, dl.phy.pdcch_dl, dl.phy.pdcch_ul), + pdschs(bwp_cfg_, slot_idx_, dl.phy.pdsch), rar_softbuffer(harq_softbuffer_pool::get_instance().get_tx(bwp_cfg_.cfg.rb_width)) {} void bwp_slot_grid::reset() { pdcchs.reset(); - dl_prbs.reset(); + pdschs.reset(); ul_prbs.reset(); dl.phy.ssb.clear(); dl.phy.nzp_csi_rs.clear(); - dl.phy.pdcch_dl.clear(); - dl.phy.pdcch_ul.clear(); - dl.phy.pdsch.clear(); dl.data.clear(); dl.rar.clear(); dl.sib_idxs.clear(); @@ -121,25 +118,33 @@ alloc_result bwp_slot_allocator::alloc_si(uint32_t aggr_idx, const prb_interval& prbs, tx_harq_softbuffer& softbuffer) { + static const uint32_t ss_id = 0; + static const srsran_dci_format_nr_t dci_fmt = srsran_dci_format_nr_1_0; + bwp_slot_grid& bwp_pdcch_slot = bwp_grid[pdcch_slot]; alloc_result ret = verify_pdsch_space(bwp_pdcch_slot, bwp_pdcch_slot); if (ret != alloc_result::success) { return ret; } - if (bwp_pdcch_slot.dl_prbs.collides(prbs)) { - return alloc_result::sch_collision; + + // Verify there is space in PDSCH + ret = bwp_pdcch_slot.pdschs.is_grant_valid(ss_id, dci_fmt, prbs); + if (ret != alloc_result::success) { + return ret; } - const uint32_t ss_id = 0; - auto pdcch_result = bwp_pdcch_slot.pdcchs.alloc_si_pdcch(ss_id, aggr_idx); + auto pdcch_result = bwp_pdcch_slot.pdcchs.alloc_si_pdcch(ss_id, aggr_idx); if (pdcch_result.is_error()) { logger.warning("SCHED: Cannot allocate SIB1 due to lack of PDCCH space."); return pdcch_result.error(); } pdcch_dl_t* pdcch = pdcch_result.value(); - // RAR allocation successful. - bwp_pdcch_slot.dl_prbs |= prbs; + // SI allocation successful. + + // Allocate PDSCH + pdsch_t& pdsch = bwp_pdcch_slot.pdschs.alloc_pdsch_unchecked(pdcch->dci.ctx, prbs, *pdcch); + // Generate DCI for SIB pdcch->dci_cfg.coreset0_bw = srsran_coreset_get_bw(&cfg.cfg.pdcch.coreset[0]); if (not fill_dci_sib(prbs, si_idx, si_ntx, *bwp_grid.cfg, pdcch->dci)) { @@ -149,8 +154,6 @@ alloc_result bwp_slot_allocator::alloc_si(uint32_t aggr_idx, } // Generate PDSCH - bwp_pdcch_slot.dl.phy.pdsch.emplace_back(); - pdsch_t& pdsch = bwp_pdcch_slot.dl.phy.pdsch.back(); srsran_slot_cfg_t slot_cfg; slot_cfg.idx = pdcch_slot.to_uint(); int code = srsran_ra_dl_dci_to_grant_nr( @@ -174,12 +177,21 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t prb_interval interv, srsran::const_span pending_rachs) { - static const uint32_t msg3_nof_prbs = 3, m = 0; + static const uint32_t msg3_nof_prbs = 3, m = 0; + static const srsran_dci_format_nr_t dci_fmt = srsran_dci_format_nr_1_0; bwp_slot_grid& bwp_pdcch_slot = bwp_grid[pdcch_slot]; slot_point msg3_slot = pdcch_slot + cfg.pusch_ra_list[m].msg3_delay; bwp_slot_grid& bwp_msg3_slot = bwp_grid[msg3_slot]; - alloc_result ret = verify_pusch_space(bwp_msg3_slot); + + // Verify there is space in PDSCH + alloc_result ret = bwp_pdcch_slot.pdschs.is_grant_valid(cfg.cfg.pdcch.ra_search_space.id, dci_fmt, interv); + if (ret != alloc_result::success) { + return ret; + } + + // Verify there is space in PUSCH + ret = verify_pusch_space(bwp_msg3_slot); if (ret != alloc_result::success) { return ret; } @@ -205,12 +217,6 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t } } - // Check DL RB collision - if (bwp_pdcch_slot.dl_prbs.collides(interv)) { - logger.debug("SCHED: Provided RBG mask collides with allocation previously made."); - return alloc_result::sch_collision; - } - // Check Msg3 RB collision uint32_t total_ul_nof_prbs = msg3_nof_prbs * pending_rachs.size(); uint32_t total_ul_nof_rbgs = srsran::ceil_div(total_ul_nof_prbs, get_P(bwp_grid.nof_prbs(), false)); @@ -224,25 +230,25 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t auto pdcch_result = bwp_pdcch_slot.pdcchs.alloc_rar_pdcch(ra_rnti, aggr_idx); if (pdcch_result.is_error()) { // Could not find space in PDCCH - logger.debug("SCHED: No space in PDCCH for DL tx."); return pdcch_result.error(); } - pdcch_dl_t* pdcch = pdcch_result.value(); // RAR allocation successful. - bwp_pdcch_slot.dl_prbs |= interv; + pdcch_dl_t* pdcch = pdcch_result.value(); + auto& phy_cfg = slot_ues[pending_rachs[0].temp_crnti]->phy(); + pdcch->dci_cfg = phy_cfg.get_dci_cfg(); + + // Allocate PDSCH + pdsch_t& pdsch = bwp_pdcch_slot.pdschs.alloc_pdsch_unchecked(pdcch->dci.ctx, interv, *pdcch); + // Generate DCI for RAR with given RA-RNTI if (not fill_dci_rar(interv, ra_rnti, *bwp_grid.cfg, pdcch->dci)) { // Cancel on-going PDCCH allocation bwp_pdcch_slot.pdcchs.cancel_last_pdcch(); return alloc_result::invalid_coderate; } - auto& phy_cfg = slot_ues[pending_rachs[0].temp_crnti]->phy(); - pdcch->dci_cfg = phy_cfg.get_dci_cfg(); // Generate RAR PDSCH // TODO: Properly fill Msg3 grants - bwp_pdcch_slot.dl.phy.pdsch.emplace_back(); - pdsch_t& pdsch = bwp_pdcch_slot.dl.phy.pdsch.back(); srsran_slot_cfg_t slot_cfg; slot_cfg.idx = pdcch_slot.to_uint(); bool success = phy_cfg.get_pdsch_cfg(slot_cfg, pdcch->dci, pdsch.sch); @@ -287,12 +293,31 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, prb_grant dl_grant) { static const uint32_t aggr_idx = 2; - static const std::array dci_fmt_list{srsran_dci_format_nr_1_1, srsran_dci_format_nr_1_0}; + static const srsran_dci_format_nr_t dci_fmt = srsran_dci_format_nr_1_0; + static const std::array dci_fmt_list{srsran_dci_format_nr_1_0}; bwp_slot_grid& bwp_pdcch_slot = bwp_grid[ue.pdcch_slot]; bwp_slot_grid& bwp_pdsch_slot = bwp_grid[ue.pdsch_slot]; bwp_slot_grid& bwp_uci_slot = bwp_grid[ue.uci_slot]; // UCI : UL control info - alloc_result result = verify_pdsch_space(bwp_pdsch_slot, bwp_pdcch_slot, &bwp_uci_slot); + + // Choose SearchSpace + DCI format + srsran_rnti_type_t rnti_type = srsran_rnti_type_c; + // Choose the ss_id the highest number of candidates + candidate_ss_list_t ss_candidates = find_ss(ue->phy().pdcch, aggr_idx, rnti_type, dci_fmt_list); + if (ss_candidates.empty()) { + // Could not find space in PDCCH + logger.warning("SCHED: No PDCCH candidates for any of the rnti=0x%x search spaces", ue->rnti); + return alloc_result::no_cch_space; + } + const srsran_search_space_t& ss = *ss_candidates[0]; + + // Verify there is space in PDSCH + alloc_result ret = bwp_pdcch_slot.pdschs.is_grant_valid(ss.id, dci_fmt, dl_grant); + if (ret != alloc_result::success) { + return ret; + } + + alloc_result result = verify_pdsch_space(bwp_pdsch_slot, bwp_pdcch_slot, &bwp_uci_slot); if (result != alloc_result::success) { return result; } @@ -305,73 +330,56 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, prb_grant dl_grant) logger.debug("SCHED: skipping PDSCH allocation. Cause: concurrent PDSCH and SSB not yet supported"); return alloc_result::no_sch_space; } - if (bwp_pdsch_slot.dl_prbs.collides(dl_grant)) { - return alloc_result::sch_collision; - } // Find space in PUCCH // TODO - // Choose SearchSpace + DCI format - srsran_rnti_type_t rnti_type = srsran_rnti_type_c; - // Choose the ss_id the highest number of candidates - candidate_ss_list_t ss_candidates = find_ss(ue->phy().pdcch, aggr_idx, rnti_type, dci_fmt_list); - if (ss_candidates.empty()) { - // Could not find space in PDCCH - logger.warning("SCHED: No PDCCH candidates for any of the rnti=0x%x search spaces", ue->rnti); - return alloc_result::no_cch_space; - } - const srsran_search_space_t& ss = *ss_candidates[0]; - // Find space and allocate PDCCH auto pdcch_result = bwp_pdcch_slot.pdcchs.alloc_dl_pdcch(rnti_type, ss.id, aggr_idx, ue.cfg()); if (pdcch_result.is_error()) { // Could not find space in PDCCH return pdcch_result.error(); } - pdcch_dl_t* pdcch = pdcch_result.value(); - // Update PRB grant based on the start and end of CORESET RBs - reduce_to_dl_coreset_bw(cfg, ss.id, srsran_dci_format_nr_1_0, dl_grant); + // DL allocation successful. + pdcch_dl_t& pdcch = *pdcch_result.value(); + + // Allocate PDSCH + pdsch_t& pdsch = bwp_pdcch_slot.pdschs.alloc_pdsch_unchecked(pdcch.dci.ctx, dl_grant, pdcch); // Allocate HARQ int mcs = ue->fixed_pdsch_mcs(); if (ue.h_dl->empty()) { - bool ret = ue.h_dl->new_tx(ue.pdsch_slot, ue.uci_slot, dl_grant, mcs, 4); - srsran_assert(ret, "Failed to allocate DL HARQ"); + bool success = ue.h_dl->new_tx(ue.pdsch_slot, ue.uci_slot, dl_grant, mcs, 4); + srsran_assert(success, "Failed to allocate DL HARQ"); } else { - bool ret = ue.h_dl->new_retx(ue.pdsch_slot, ue.uci_slot, dl_grant); - mcs = ue.h_dl->mcs(); - srsran_assert(ret, "Failed to allocate DL HARQ retx"); + bool success = ue.h_dl->new_retx(ue.pdsch_slot, ue.uci_slot, dl_grant); + mcs = ue.h_dl->mcs(); + srsran_assert(success, "Failed to allocate DL HARQ retx"); } - // Allocation Successful - const static float max_R = 0.93; while (true) { // Generate PDCCH - fill_dl_dci_ue_fields(ue, *bwp_grid.cfg, ss.id, pdcch->dci.ctx.location, pdcch->dci); - pdcch->dci.pucch_resource = 0; - pdcch->dci.dai = std::count_if(bwp_uci_slot.pending_acks.begin(), - bwp_uci_slot.pending_acks.end(), - [&ue](const harq_ack_t& p) { return p.res.rnti == ue->rnti; }); - pdcch->dci.dai %= 4; - pdcch->dci_cfg = ue->phy().get_dci_cfg(); + fill_dl_dci_ue_fields(ue, *bwp_grid.cfg, ss.id, pdcch.dci.ctx.location, pdcch.dci); + pdcch.dci.pucch_resource = 0; + pdcch.dci.dai = std::count_if(bwp_uci_slot.pending_acks.begin(), + bwp_uci_slot.pending_acks.end(), + [&ue](const harq_ack_t& p) { return p.res.rnti == ue->rnti; }); + pdcch.dci.dai %= 4; + pdcch.dci_cfg = ue->phy().get_dci_cfg(); // Generate PUCCH bwp_uci_slot.pending_acks.emplace_back(); bwp_uci_slot.pending_acks.back().phy_cfg = &ue->phy(); - srsran_assert(ue->phy().get_pdsch_ack_resource(pdcch->dci, bwp_uci_slot.pending_acks.back().res), + srsran_assert(ue->phy().get_pdsch_ack_resource(pdcch.dci, bwp_uci_slot.pending_acks.back().res), "Error getting ack resource"); // Generate PDSCH - bwp_pdsch_slot.dl_prbs |= dl_grant; - bwp_pdsch_slot.dl.phy.pdsch.emplace_back(); - pdsch_t& pdsch = bwp_pdsch_slot.dl.phy.pdsch.back(); srsran_slot_cfg_t slot_cfg; slot_cfg.idx = ue.pdsch_slot.to_uint(); - bool ret = ue->phy().get_pdsch_cfg(slot_cfg, pdcch->dci, pdsch.sch); - srsran_assert(ret, "Error converting DCI to grant"); + bool success = ue->phy().get_pdsch_cfg(slot_cfg, pdcch.dci, pdsch.sch); + srsran_assert(success, "Error converting DCI to grant"); pdsch.sch.grant.tb[0].softbuffer.tx = ue.h_dl->get_softbuffer().get(); pdsch.data[0] = ue.h_dl->get_tx_pdu()->get(); @@ -386,7 +394,6 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, prb_grant dl_grant) // Decrease MCS if first tx and rate is too high mcs--; ue.h_dl->set_mcs(mcs); - bwp_pdsch_slot.dl.phy.pdsch.pop_back(); bwp_uci_slot.pending_acks.pop_back(); } if (mcs == 0) { diff --git a/srsgnb/src/stack/mac/sched_nr_helpers.cc b/srsgnb/src/stack/mac/sched_nr_helpers.cc index 73958562a..66e9ca250 100644 --- a/srsgnb/src/stack/mac/sched_nr_helpers.cc +++ b/srsgnb/src/stack/mac/sched_nr_helpers.cc @@ -70,26 +70,6 @@ void fill_dci_harq(const slot_ue& ue, DciDlOrUl& dci) dci.rv = rv_idx[h->nof_retx() % 4]; } -void fill_dci_grant(const bwp_params_t& bwp_cfg, const prb_grant& grant, srsran_dci_dl_nr_t& dci) -{ - dci.time_domain_assigment = 0; - if (grant.is_alloc_type0()) { - srsran_assert(not SRSRAN_SEARCH_SPACE_IS_COMMON(dci.ctx.ss_type), "AllocType0 for common search space"); - dci.freq_domain_assigment = grant.rbgs().to_uint64(); - } else { - uint32_t rb_start = 0, nof_prb = bwp_cfg.nof_prb(); - if (dci.ctx.format == srsran_dci_format_nr_1_0 && SRSRAN_SEARCH_SPACE_IS_COMMON(dci.ctx.ss_type)) { - rb_start = dci.ctx.coreset_start_rb; - } - if (dci.ctx.coreset_id == 0 and SRSRAN_SEARCH_SPACE_IS_COMMON(dci.ctx.ss_type)) { - nof_prb = dci.coreset0_bw; - } - srsran_assert(grant.prbs().start() >= rb_start, "Invalid PRB index=%d < %d", grant.prbs().start(), rb_start); - uint32_t grant_start = grant.prbs().start() - rb_start; - dci.freq_domain_assigment = srsran_ra_nr_type1_riv(nof_prb, grant_start, grant.prbs().length()); - } -} - void fill_dci_grant(const bwp_params_t& bwp_cfg, const prb_grant& grant, srsran_dci_ul_nr_t& dci) { dci.time_domain_assigment = 0; @@ -101,25 +81,9 @@ void fill_dci_grant(const bwp_params_t& bwp_cfg, const prb_grant& grant, srsran_ } } -void fill_rar_dci_context(const bwp_params_t& bwp_cfg, uint16_t ra_rnti, srsran_dci_ctx_t& dci_ctx) -{ - uint32_t cs_id = bwp_cfg.cfg.pdcch.ra_search_space.coreset_id; - - dci_ctx.format = srsran_dci_format_nr_1_0; - dci_ctx.ss_type = srsran_search_space_type_common_1; - dci_ctx.rnti_type = srsran_rnti_type_ra; - dci_ctx.rnti = ra_rnti; - dci_ctx.coreset_id = cs_id; - dci_ctx.coreset_start_rb = srsran_coreset_start_rb(&bwp_cfg.cfg.pdcch.coreset[cs_id]); -} - bool fill_dci_rar(prb_interval interv, uint16_t ra_rnti, const bwp_params_t& bwp_cfg, srsran_dci_dl_nr_t& dci) { - fill_rar_dci_context(bwp_cfg, ra_rnti, dci.ctx); - dci.mcs = 5; - fill_dci_common(bwp_cfg, dci); - fill_dci_grant(bwp_cfg, interv, dci); // TODO: Fill return true; @@ -152,14 +116,7 @@ void fill_dl_dci_ue_fields(const slot_ue& ue, srsran_dci_location_t dci_pos, srsran_dci_dl_nr_t& dci) { - // Note: DCI location may not be the final one, as scheduler may rellocate the UE PDCCH. However, the remaining DCI - // params are independent of the exact DCI location - bool ret = ue->phy().get_dci_ctx_pdsch_rnti_c(ss_id, dci_pos, ue->rnti, dci.ctx); - srsran_assert(ret, "Invalid DL DCI format"); - - fill_dci_common(bwp_cfg, dci); fill_dci_harq(ue, dci); - fill_dci_grant(bwp_cfg, ue.h_dl->prbs(), dci); if (dci.ctx.format == srsran_dci_format_nr_1_0) { dci.harq_feedback = (ue.uci_slot - ue.pdsch_slot) - 1; } else { diff --git a/srsgnb/src/stack/mac/sched_nr_pdcch.cc b/srsgnb/src/stack/mac/sched_nr_pdcch.cc index edcb4c592..33d7ba8ef 100644 --- a/srsgnb/src/stack/mac/sched_nr_pdcch.cc +++ b/srsgnb/src/stack/mac/sched_nr_pdcch.cc @@ -40,6 +40,23 @@ void log_pdcch_alloc_failure(srslog::log_channel& log_ch, log_ch("%s", srsran::to_c_str(fmtbuf)); } +void fill_dci_from_cfg(const bwp_params_t& bwp_cfg, srsran_dci_dl_nr_t& dci) +{ + dci.bwp_id = bwp_cfg.bwp_id; + dci.cc_id = bwp_cfg.cc; + dci.tpc = 1; + dci.coreset0_bw = bwp_cfg.cfg.pdcch.coreset_present[0] ? bwp_cfg.coreset_bw(0) : 0; +} + +void fill_dci_from_cfg(const bwp_params_t& bwp_cfg, srsran_dci_ul_nr_t& dci) +{ + dci.bwp_id = bwp_cfg.bwp_id; + dci.cc_id = bwp_cfg.cc; + dci.tpc = 1; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + coreset_region::coreset_region(const bwp_params_t& bwp_cfg_, uint32_t coreset_id_, uint32_t slot_idx_) : coreset_cfg(&bwp_cfg_.cfg.pdcch.coreset[coreset_id_]), coreset_id(coreset_id_), @@ -226,6 +243,7 @@ void bwp_pdcch_allocator::fill_dci_ctx_common(srsran_dci_ctx_t& dci, srsran_dci_format_nr_t dci_fmt, const ue_carrier_params_t* ue) { + // Note: Location is filled by coreset_region class. dci.ss_type = ss.type; dci.coreset_id = ss.coreset_id; const srsran_coreset_t* coreset = @@ -271,7 +289,10 @@ pdcch_dl_alloc_result bwp_pdcch_allocator::alloc_dl_pdcch_common(srsran_rnti_typ if (r != alloc_result::success) { return {r}; } - const srsran_search_space_t& ss = (user == nullptr) ? *bwp_cfg.get_ss(ss_id) : *user->get_ss(ss_id); + const srsran_search_space_t& ss = + (user == nullptr) + ? (rnti_type == srsran_rnti_type_ra ? bwp_cfg.cfg.pdcch.ra_search_space : *bwp_cfg.get_ss(ss_id)) + : *user->get_ss(ss_id); // Add new DL PDCCH to sched result pdcch_dl_list.emplace_back(); @@ -290,13 +311,19 @@ pdcch_dl_alloc_result bwp_pdcch_allocator::alloc_dl_pdcch_common(srsran_rnti_typ return {alloc_result::no_cch_space}; } + // PDCCH allocation was successful + pdcch_dl_t& pdcch = pdcch_dl_list.back(); + + // Fill DCI with semi-static config + fill_dci_from_cfg(bwp_cfg, pdcch.dci); + // Fill DCI context information - fill_dci_ctx_common(pdcch_dl_list.back().dci.ctx, rnti_type, rnti, ss, dci_fmt, user); + fill_dci_ctx_common(pdcch.dci.ctx, rnti_type, rnti, ss, dci_fmt, user); // register last PDCCH coreset, in case it needs to be aborted - pending_dci = &pdcch_dl_list.back().dci.ctx; + pending_dci = &pdcch.dci.ctx; - return {&pdcch_dl_list.back()}; + return {&pdcch}; } pdcch_ul_alloc_result @@ -325,13 +352,19 @@ bwp_pdcch_allocator::alloc_ul_pdcch(uint32_t ss_id, uint32_t aggr_idx, const ue_ return {alloc_result::no_cch_space}; } + // PDCCH allocation was successful + pdcch_ul_t& pdcch = pdcch_ul_list.back(); + + // Fill DCI with semi-static config + fill_dci_from_cfg(bwp_cfg, pdcch.dci); + // Fill DCI context information - fill_dci_ctx_common(pdcch_ul_list.back().dci.ctx, srsran_rnti_type_c, user.rnti, ss, dci_fmt, &user); + fill_dci_ctx_common(pdcch.dci.ctx, srsran_rnti_type_c, user.rnti, ss, dci_fmt, &user); // register last PDCCH coreset, in case it needs to be aborted - pending_dci = &pdcch_ul_list.back().dci.ctx; + pending_dci = &pdcch.dci.ctx; - return {&pdcch_ul_list.back()}; + return {&pdcch}; } void bwp_pdcch_allocator::cancel_last_pdcch() @@ -394,7 +427,10 @@ alloc_result bwp_pdcch_allocator::check_args_valid(srsran_rnti_type_t rn } // Verify SearchSpace validity - const srsran_search_space_t* ss = (user == nullptr) ? bwp_cfg.get_ss(ss_id) : user->get_ss(ss_id); + const srsran_search_space_t* ss = + (user == nullptr) + ? (rnti_type == srsran_rnti_type_ra ? &bwp_cfg.cfg.pdcch.ra_search_space : bwp_cfg.get_ss(ss_id)) + : user->get_ss(ss_id); if (ss == nullptr) { // Couldn't find SearchSpace log_pdcch_alloc_failure(logger.error, rnti_type, ss_id, rnti, "SearchSpace has not been configured"); diff --git a/srsgnb/src/stack/mac/sched_nr_pdsch.cc b/srsgnb/src/stack/mac/sched_nr_pdsch.cc new file mode 100644 index 000000000..3b374be0c --- /dev/null +++ b/srsgnb/src/stack/mac/sched_nr_pdsch.cc @@ -0,0 +1,143 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsgnb/hdr/stack/mac/sched_nr_pdsch.h" +#include "srsran/common/string_helpers.h" + +namespace srsenb { +namespace sched_nr_impl { + +template +void log_alloc_failure(srslog::log_channel& log_ch, uint32_t ss_id, const char* cause_fmt, Args&&... args) +{ + if (not log_ch.enabled()) { + return; + } + + // Log allocation failure + fmt::memory_buffer fmtbuf; + fmt::format_to(fmtbuf, "SCHED: Failure to allocate PDSCH in SS#{}. Cause: ", ss_id); + fmt::format_to(fmtbuf, cause_fmt, std::forward(args)...); + log_ch("%s", srsran::to_c_str(fmtbuf)); +} + +pdsch_allocator::pdsch_allocator(const bwp_params_t& cfg_, uint32_t slot_index, pdsch_list_t& pdsch_lst) : + bwp_cfg(cfg_), + slot_idx(slot_index), + pdschs(pdsch_lst), + dl_prbs(bwp_cfg.cfg.rb_width, bwp_cfg.cfg.start_rb, bwp_cfg.cfg.pdsch.rbg_size_cfg_1) +{} + +void pdsch_allocator::reset() +{ + pdschs.clear(); + dl_prbs.reset(); +} + +alloc_result pdsch_allocator::is_grant_valid(uint32_t ss_id, + srsran_dci_format_nr_t dci_fmt, + const prb_grant& grant, + ue_carrier_params_t* ue) const +{ + // DL must be active in given slot + if (not bwp_cfg.slots[slot_idx].is_dl) { + log_alloc_failure(bwp_cfg.logger.error, ss_id, "DL is disabled for slot={}", slot_idx); + return alloc_result::no_sch_space; + } + + // No space in Scheduler PDSCH output list + if (pdschs.full()) { + log_alloc_failure(bwp_cfg.logger.warning, ss_id, "SearchSpace has not been configured."); + return alloc_result::no_sch_space; + } + + // Verify SearchSpace validity + const srsran_search_space_t* ss = (ue == nullptr) ? bwp_cfg.get_ss(ss_id) : ue->get_ss(ss_id); + if (ss == nullptr) { + // Couldn't find SearchSpace + log_alloc_failure(bwp_cfg.logger.error, ss_id, "SearchSpace has not been configured."); + return alloc_result::invalid_grant_params; + } + + if (SRSRAN_SEARCH_SPACE_IS_COMMON(ss_id)) { + // In case of common SearchSpaces, the PRBs must be contiguous + if (grant.is_alloc_type0()) { + log_alloc_failure(bwp_cfg.logger.warning, ss_id, "AllocType0 not allowed in common SearchSpace."); + return alloc_result::invalid_grant_params; + } + + // Grant PRBs do not collide with CORESET PRB limits (in case of common SearchSpace) + if (bwp_cfg.coreset_prb_limits(ss_id, dci_fmt).collides(grant)) { + bwp_cfg.logger.debug("SCHED: Provided RBG mask falls outside common CORESET PRB boundaries."); + return alloc_result::sch_collision; + } + } + + // Grant PRBs do not collide with previous PDSCH allocations + if (dl_prbs.collides(grant)) { + bwp_cfg.logger.debug("SCHED: Provided RBG mask collides with allocation previously made."); + return alloc_result::sch_collision; + } + + return alloc_result::success; +} + +srsran::expected +pdsch_allocator::alloc_pdsch(const srsran_dci_ctx_t& dci_ctx, uint32_t ss_id, const prb_grant& grant, pdcch_dl_t& pdcch) +{ + alloc_result code = is_grant_valid(ss_id, dci_ctx.format, grant); + if (code != alloc_result::success) { + return code; + } + + return {&alloc_pdsch_unchecked(dci_ctx, grant, pdcch)}; +} + +pdsch_t& +pdsch_allocator::alloc_pdsch_unchecked(const srsran_dci_ctx_t& dci_ctx, const prb_grant& grant, pdcch_dl_t& pdcch) +{ + // Create new PDSCH entry in output PDSCH list + pdschs.emplace_back(); + pdsch_t& pdsch = pdschs.back(); + + // Register allocated PRBs in accumulated bitmap + dl_prbs |= grant; + + // Fill DCI with PDSCH freq/time allocation information + pdcch.dci.time_domain_assigment = 0; + if (grant.is_alloc_type0()) { + pdcch.dci.freq_domain_assigment = grant.rbgs().to_uint64(); + } else { + uint32_t rb_start = grant.prbs().start(), nof_prb = bwp_cfg.nof_prb(); + if (SRSRAN_SEARCH_SPACE_IS_COMMON(dci_ctx.ss_type)) { + if (dci_ctx.format == srsran_dci_format_nr_1_0) { + rb_start -= dci_ctx.coreset_start_rb; + } + if (dci_ctx.coreset_id == 0) { + nof_prb = bwp_cfg.coreset_bw(0); + } + } + srsran_sanity_check(rb_start + grant.prbs().length() <= nof_prb, "Invalid PRB grant"); + pdcch.dci.freq_domain_assigment = srsran_ra_nr_type1_riv(nof_prb, rb_start, grant.prbs().length()); + } + + return pdsch; +} + +void pdsch_allocator::cancel_last_pdsch() +{ + srsran_assert(not pdschs.empty(), "Trying to abort PDSCH allocation that does not exist"); + pdschs.pop_back(); +} + +} // namespace sched_nr_impl +} // namespace srsenb \ No newline at end of file diff --git a/srsgnb/src/stack/mac/sched_nr_signalling.cc b/srsgnb/src/stack/mac/sched_nr_signalling.cc index f87fb67b2..9fc545ca1 100644 --- a/srsgnb/src/stack/mac/sched_nr_signalling.cc +++ b/srsgnb/src/stack/mac/sched_nr_signalling.cc @@ -108,14 +108,14 @@ bool fill_dci_sib(prb_interval interv, const bwp_params_t& bwp_cfg, srsran_dci_dl_nr_t& dci) { - dci.mcs = 5; - dci.ctx.format = srsran_dci_format_nr_1_0; - dci.ctx.ss_type = srsran_search_space_type_common_0; - dci.ctx.rnti_type = srsran_rnti_type_si; - dci.ctx.rnti = SRSRAN_SIRNTI; - dci.ctx.coreset_id = 0; - dci.ctx.coreset_start_rb = bwp_cfg.cfg.pdcch.coreset[0].offset_rb; - dci.coreset0_bw = srsran_coreset_get_bw(&bwp_cfg.cfg.pdcch.coreset[0]); + dci.mcs = 5; + dci.ctx.format = srsran_dci_format_nr_1_0; + dci.ctx.ss_type = srsran_search_space_type_common_0; + dci.ctx.rnti_type = srsran_rnti_type_si; + dci.ctx.rnti = SRSRAN_SIRNTI; + dci.ctx.coreset_id = 0; + dci.ctx.coreset_start_rb = bwp_cfg.cfg.pdcch.coreset[0].offset_rb; + dci.coreset0_bw = srsran_coreset_get_bw(&bwp_cfg.cfg.pdcch.coreset[0]); dci.freq_domain_assigment = srsran_ra_nr_type1_riv(srsran_coreset_get_bw(&bwp_cfg.cfg.pdcch.coreset[0]), interv.start(), interv.length()); dci.time_domain_assigment = 0; @@ -149,9 +149,10 @@ void si_sched::run_slot(bwp_slot_allocator& bwp_alloc) // TODO: provide proper config return; } - const uint32_t si_aggr_level = 2; - slot_point sl_pdcch = bwp_alloc.get_pdcch_tti(); - const prb_bitmap& prbs = bwp_alloc.res_grid()[sl_pdcch].dl_prbs.prbs(); + const uint32_t si_aggr_level = 2; + const uint32_t ss_id = 0; + slot_point sl_pdcch = bwp_alloc.get_pdcch_tti(); + prb_bitmap prbs = bwp_alloc.res_grid()[sl_pdcch].pdschs.available_prbs(ss_id, srsran_dci_format_nr_1_0); // Update SI windows uint32_t N = bwp_cfg->slots.size();