nr,gnb,sched: implemented standalone PDSCH allocator class

This commit is contained in:
Francisco 2021-12-07 17:16:57 +00:00 committed by Francisco Paisana
parent 20b327c320
commit 8ba08032b5
13 changed files with 414 additions and 155 deletions

View File

@ -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<pdcch_dl_t, MAX_GRANTS>;
using pdcch_ul_list_t = srsran::bounded_vector<pdcch_ul_t, MAX_GRANTS>;
using pdsch_list_t = srsran::bounded_vector<pdsch_t, MAX_GRANTS>;
using pucch_list_t = srsran::bounded_vector<pucch_t, MAX_GRANTS>;
using pusch_list_t = srsran::bounded_vector<pusch_t, MAX_GRANTS>;
using nzp_csi_rs_list = srsran::bounded_vector<srsran_csi_rs_nzp_resource_t, mac_interface_phy_nr::MAX_NZP_CSI_RS>;
@ -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<prb_bitmap> used_common_prb_masks;
bwp_rb_bitmap cached_empty_prb_mask;
srsran::optional_vector<bwp_rb_bitmap> used_common_prb_masks;
struct coreset_cached_params {
uint32_t bw = 0;
};
srsran::optional_vector<coreset_cached_params> coresets;
};
/// Structure packing a single cell config params, and sched args

View File

@ -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<tx_harq_softbuffer> 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 {

View File

@ -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;

View File

@ -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<pdsch_t*, alloc_result>
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

View File

@ -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 <typename Other>
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)
{

View File

@ -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

View File

@ -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<dl_sched_rar_info_t> msg3_grants{rar.msg3_grant};

View File

@ -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);
}
}
}

View File

@ -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<dl_sched_rar_info_t> 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,30 +293,12 @@ 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<srsran_dci_format_nr_t, 2> 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<srsran_dci_format_nr_t, 1> 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);
if (result != alloc_result::success) {
return result;
}
result = verify_ue_cfg(ue.cfg(), ue.h_dl);
if (result != alloc_result::success) {
return result;
}
if (not bwp_pdsch_slot.dl.phy.ssb.empty()) {
// TODO: support concurrent PDSCH and SSB
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;
@ -323,55 +311,75 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, prb_grant dl_grant)
}
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;
}
result = verify_ue_cfg(ue.cfg(), ue.h_dl);
if (result != alloc_result::success) {
return result;
}
if (not bwp_pdsch_slot.dl.phy.ssb.empty()) {
// TODO: support concurrent PDSCH and SSB
logger.debug("SCHED: skipping PDSCH allocation. Cause: concurrent PDSCH and SSB not yet supported");
return alloc_result::no_sch_space;
}
// Find space in PUCCH
// TODO
// 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) {

View File

@ -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 {

View File

@ -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");

View File

@ -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 <typename... Args>
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>(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_t*, alloc_result>
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

View File

@ -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();