@@ -112,71 +112,59 @@ static unsigned compute_max_nof_rbs_per_ue_per_slot(const ue_repository&
112112 return (bwp_crb_limits.length () / nof_ues_to_be_scheduled_per_slot);
113113}
114114
115- // / \brief Algorithm to select next UE to allocate in a time-domain RR fashion
116- // / \param[in] ue_db map of "slot_ue"
117- // / \param[in] next_ue_index UE index with the highest priority to be allocated.
118- // / \param[in] alloc_ue callable with signature "alloc_outcome(ue&, pusch_time_domain_resource_index)" that returns the
119- // / UE allocation outcome.
120- // / \return Index of next UE to allocate.
121- template <typename AllocUEFunc>
122- du_ue_index_t round_robin_ul_apply (const ue_repository& ue_db, du_ue_index_t next_ue_index, const AllocUEFunc& alloc_ue)
115+ // / \brief Fetches a list of PUSCH Time Domain resource indexes based on cell, UE configuration and nof. symbols in
116+ // / PUSCH slot.
117+ // / \param[in] res_grid View of the current resource grid state to the PDSCH and PUSCH allocators.
118+ // / \param[in] ues map of ues.
119+ // / \return List of PUSCH Time Domain resource indexes.
120+ static static_vector<unsigned , pusch_constants::MAX_NOF_PUSCH_TD_RES_ALLOCS>
121+ get_pusch_td_resource_indexes (const ue_resource_grid_view& res_grid, const ue_repository& ues)
123122{
124- if (ue_db.empty ()) {
125- return next_ue_index;
126- }
127- auto it = ue_db.lower_bound (next_ue_index);
128- bool first_alloc = true ;
123+ // Compute list of PUSCH time domain resource index list relevant for the PUSCH slot.
124+ static_vector<unsigned , pusch_constants::MAX_NOF_PUSCH_TD_RES_ALLOCS> pusch_td_res_index_list;
129125
130126 // NOTE: All UEs use the same PUSCH Time Domain Resource configuration.
131- const ue& ref_u = **ue_db.begin ();
132-
133- unsigned max_pusch_time_domain_resource_index = 1 ;
134- if (ref_u.nof_cells () > 0 ) {
135- const ue_cell_configuration& ue_cfg = ref_u.get_pcell ().cfg ();
136- const auto * ss_info =
137- ue_cfg.find_search_space (ue_cfg.cfg_dedicated ().init_dl_bwp .pdcch_cfg ->search_spaces .back ().get_id ());
138- if (ss_info == nullptr ) {
139- return next_ue_index;
140- }
141-
142- // [Implementation-defined] For UL heavy TDD configuration we allow multiple UL PDCCH allocations in the same slot
143- // for same UE but with different k2 values. In other cases (DL heavy) k2 value which is less than or equal to
144- // minimum value of k1(s) is used. Assumes that first entry in the PUSCH Time Domain resource list contains the k2
145- // value which is less than or equal to minimum value of k1(s).
146- if (ue_cfg.cell_cfg_common .is_tdd () and
147- (nof_full_ul_slots_per_tdd_period (ue_cfg.cell_cfg_common .tdd_cfg_common .value ()) >
148- nof_full_dl_slots_per_tdd_period (ue_cfg.cell_cfg_common .tdd_cfg_common .value ()))) {
149- max_pusch_time_domain_resource_index = ss_info->pusch_time_domain_list .size ();
127+ const ue& ref_u = **ues.begin ();
128+ const ue_cell_configuration& ue_cfg = ref_u.get_pcell ().cfg ();
129+ const search_space_info* ss_info =
130+ ue_cfg.find_search_space (ue_cfg.cfg_dedicated ().init_dl_bwp .pdcch_cfg ->search_spaces .back ().get_id ());
131+ if (ss_info != nullptr ) {
132+ optional<unsigned > nof_full_ul_slots = nullopt ;
133+ optional<unsigned > nof_full_dl_slots = nullopt ;
134+ if (ue_cfg.cell_cfg_common .is_tdd ()) {
135+ nof_full_ul_slots = nof_full_ul_slots_per_tdd_period (ue_cfg.cell_cfg_common .tdd_cfg_common .value ());
136+ nof_full_dl_slots = nof_full_dl_slots_per_tdd_period (ue_cfg.cell_cfg_common .tdd_cfg_common .value ());
150137 }
151- }
152-
153- for (unsigned pusch_td_res_idx = 0 ; pusch_td_res_idx < max_pusch_time_domain_resource_index; ++pusch_td_res_idx) {
154- for (unsigned count = 0 ; count < ue_db.size (); ++count, ++it) {
155- if (it == ue_db.end ()) {
156- // wrap-around
157- it = ue_db.begin ();
158- }
159- const ue& u = **it;
160- const alloc_outcome alloc_result = alloc_ue (u, pusch_td_res_idx);
161- if (alloc_result == alloc_outcome::skip_slot) {
162- // Grid allocator directed policy to stop allocations for this slot.
163- return next_ue_index;
164- }
165-
166- if (alloc_result == alloc_outcome::success) {
167- if (first_alloc) {
168- // Mark the next UE to be the first UE to get allocated in the following slot.
169- // It is important that we equally distribute the opportunity to be the first UE being allocated in a slot for
170- // all UEs. Otherwise, we could end up in a situation, where a UE is always the last one to be allocated and
171- // can only use the RBs that were left from the previous UE allocations.
172- next_ue_index = to_du_ue_index ((unsigned )u.ue_index + 1U );
173- first_alloc = false ;
138+ const unsigned min_k1 = *std::min (ss_info->get_k1_candidates ().begin (), ss_info->get_k1_candidates ().end ());
139+ // [Implementation-defined] It is assumed that UE is not configured pusch-TimeDomainAllocationList in
140+ // pusch-Config and configured only in pusch-ConfigCommon (SIB1).
141+ for (const pusch_time_domain_resource_allocation& pusch_td_res : ss_info->pusch_time_domain_list ) {
142+ if (not ue_cfg.cell_cfg_common .is_tdd () or
143+ pusch_td_res.symbols .length () ==
144+ get_active_tdd_ul_symbols (
145+ ue_cfg.cell_cfg_common .tdd_cfg_common .value (),
146+ res_grid.get_pusch_slot (ref_u.get_pcell ().cell_index , pusch_td_res.k2 ).slot_index (),
147+ cyclic_prefix::NORMAL)
148+ .length ()) {
149+ if ((not ue_cfg.cell_cfg_common .is_tdd () or (*nof_full_dl_slots >= *nof_full_ul_slots)) and
150+ pusch_td_res.k2 <= min_k1) {
151+ // NOTE: Generated PUSCH time domain resources are sorted based on ascending order of k2 values and
152+ // descending order of nof. UL symbols for PUSCH.
153+ // [Implementation-defined] For DL heavy TDD configuration, only one entry in the PUSCH time domain
154+ // resources list with k2 value less than or equal to minimum value of k1(s) and, which matches nof. active
155+ // UL symbols in a slot is used.
156+ pusch_td_res_index_list.push_back (std::distance (ss_info->pusch_time_domain_list .begin (), &pusch_td_res));
157+ break ;
158+ }
159+ if (ue_cfg.cell_cfg_common .is_tdd () and (*nof_full_ul_slots > *nof_full_dl_slots)) {
160+ // [Implementation-defined] For UL heavy TDD configuration multiple k2 values are considered for scheduling
161+ // since it allows multiple UL PDCCH allocations in the same slot for same UE but with different k2 values.
162+ pusch_td_res_index_list.push_back (std::distance (ss_info->pusch_time_domain_list .begin (), &pusch_td_res));
174163 }
175164 }
176165 }
177166 }
178-
179- return next_ue_index;
167+ return pusch_td_res_index_list;
180168}
181169
182170// / \brief Algorithm to select next UE to allocate in a time-domain RR fashion
@@ -185,7 +173,7 @@ du_ue_index_t round_robin_ul_apply(const ue_repository& ue_db, du_ue_index_t nex
185173// / \param[in] alloc_ue callable with signature "bool(ue&)" that returns true if UE allocation was successful.
186174// / \return Index of next UE to allocate.
187175template <typename AllocUEFunc>
188- du_ue_index_t round_robin_dl_apply (const ue_repository& ue_db, du_ue_index_t next_ue_index, const AllocUEFunc& alloc_ue)
176+ du_ue_index_t round_robin_apply (const ue_repository& ue_db, du_ue_index_t next_ue_index, const AllocUEFunc& alloc_ue)
189177{
190178 if (ue_db.empty ()) {
191179 return next_ue_index;
@@ -321,13 +309,6 @@ static alloc_outcome alloc_ul_ue(const ue& u,
321309 srslog::basic_logger& logger,
322310 unsigned pusch_td_res_idx,
323311 optional<unsigned > ul_new_tx_max_nof_rbs_per_ue_per_slot = {})
324- // static alloc_outcome alloc_ul_ue(const ue& u,
325- // const ue_resource_grid_view& res_grid,
326- // ue_pusch_allocator& pusch_alloc,
327- // bool is_retx,
328- // bool schedule_sr_only,
329- // srslog::basic_logger& logger,
330- // optional<unsigned> ul_new_tx_max_nof_rbs_per_ue_per_slot = {})
331312{
332313 unsigned pending_newtx_bytes = 0 ;
333314 if (not is_retx) {
@@ -374,36 +355,38 @@ static alloc_outcome alloc_ul_ue(const ue& u,
374355 static_vector<const search_space_info*, MAX_NOF_SEARCH_SPACE_PER_BWP> search_spaces =
375356 ue_cc.get_active_ul_search_spaces (pdcch_slot, preferred_dci_rnti_type);
376357 for (const search_space_info* ss : search_spaces) {
377- if (ss->cfg ->is_search_space0 ()) {
358+ if (ss->cfg ->is_search_space0 () or
359+ ss->cfg ->get_id () != ue_cc.cfg ().cfg_dedicated ().init_dl_bwp .pdcch_cfg ->search_spaces .back ().get_id ()) {
378360 continue ;
379361 }
380362
381363 const pusch_time_domain_resource_allocation& pusch_td = ss->pusch_time_domain_list [pusch_td_res_idx];
382364
383- // UE is already allocated PUSCH.
384- if (res_grid. has_ue_ul_grant (ue_cc. cell_index , u. crnti , pusch_td. k2 )) {
365+ if (res_grid. has_ue_ul_grant (ue_cc. cell_index , ue_cc. rnti (), pusch_td. k2 + cell_cfg_common. ntn_cs_koffset )) {
366+ // Only one PUSCH per UE per slot.
385367 return alloc_outcome::skip_ue;
386368 }
387369
388370 const slot_point pusch_slot = pdcch_slot + pusch_td.k2 + cell_cfg_common.ntn_cs_koffset ;
389- const unsigned start_ul_symbols =
371+ if (not cell_cfg_common.is_ul_enabled (pusch_slot)) {
372+ // Try next PUSCH time domain resource value.
373+ return alloc_outcome::invalid_params;
374+ }
375+ const unsigned start_ul_symbols =
390376 NOF_OFDM_SYM_PER_SLOT_NORMAL_CP - cell_cfg_common.get_nof_ul_symbol_per_slot (pusch_slot);
391377 // If it is a retx, we need to ensure we use a time_domain_resource with the same number of symbols as used for
392378 // the first transmission.
393379 const bool sym_length_match_prev_grant_for_retx =
394380 is_retx ? pusch_td.symbols .length () != h->last_tx_params ().nof_symbols : true ;
395- if (not cell_cfg_common.is_ul_enabled (pusch_slot) or pusch_td.symbols .start () < start_ul_symbols or
381+ if (pusch_td.symbols .start () < start_ul_symbols or
382+ pusch_td.symbols .stop () > (start_ul_symbols + cell_cfg_common.get_nof_ul_symbol_per_slot (pusch_slot)) or
396383 !sym_length_match_prev_grant_for_retx) {
397- // UL needs to be active for PUSCH in this slot .
398- continue ;
384+ // Try next PUSCH time domain resource value .
385+ return alloc_outcome::invalid_params ;
399386 }
400387
401388 const cell_slot_resource_grid& grid =
402389 res_grid.get_pusch_grid (ue_cc.cell_index , pusch_td.k2 + cell_cfg_common.ntn_cs_koffset );
403- if (res_grid.has_ue_ul_grant (ue_cc.cell_index , ue_cc.rnti (), pusch_td.k2 + cell_cfg_common.ntn_cs_koffset )) {
404- // only one PUSCH per UE per slot.
405- continue ;
406- }
407390 const prb_bitmap used_crbs =
408391 grid.used_crbs (ss->bwp ->ul_common ->generic_params .scs , ss->ul_crb_lims , pusch_td.symbols );
409392 if (used_crbs.all ()) {
@@ -505,7 +488,7 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc,
505488 auto retx_ue_function = [this , &res_grid, &pdsch_alloc](const ue& u) {
506489 return alloc_dl_ue (u, res_grid, pdsch_alloc, true , logger);
507490 };
508- next_dl_ue_index = round_robin_dl_apply (ues, next_dl_ue_index, retx_ue_function);
491+ next_dl_ue_index = round_robin_apply (ues, next_dl_ue_index, retx_ue_function);
509492
510493 // Then, schedule new transmissions.
511494 const unsigned dl_new_tx_max_nof_rbs_per_ue_per_slot =
@@ -514,35 +497,53 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc,
514497 auto tx_ue_function = [this , &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) {
515498 return alloc_dl_ue (u, res_grid, pdsch_alloc, false , logger, dl_new_tx_max_nof_rbs_per_ue_per_slot);
516499 };
517- next_dl_ue_index = round_robin_dl_apply (ues, next_dl_ue_index, tx_ue_function);
500+ next_dl_ue_index = round_robin_apply (ues, next_dl_ue_index, tx_ue_function);
518501 }
519502}
520503
521504void scheduler_time_rr::ul_sched (ue_pusch_allocator& pusch_alloc,
522505 const ue_resource_grid_view& res_grid,
523506 const ue_repository& ues)
524507{
508+ if (ues.empty ()) {
509+ // No UEs to be scheduled.
510+ return ;
511+ }
512+
513+ // Fetch applicable PUSCH Time Domain resource index list.
514+ static_vector<unsigned , pusch_constants::MAX_NOF_PUSCH_TD_RES_ALLOCS> pusch_td_res_index_list =
515+ get_pusch_td_resource_indexes (res_grid, ues);
516+
525517 // First schedule UL data re-transmissions.
526- auto data_retx_ue_function = [this , &res_grid, &pusch_alloc](const ue& u, unsigned pusch_td_res_idx) {
527- return alloc_ul_ue (u, res_grid, pusch_alloc, true , false , logger, pusch_td_res_idx);
528- };
529- next_ul_ue_index = round_robin_ul_apply (ues, next_ul_ue_index, data_retx_ue_function);
518+ for (unsigned pusch_td_res_idx : pusch_td_res_index_list) {
519+ auto data_retx_ue_function = [this , &res_grid, &pusch_alloc, pusch_td_res_idx](const ue& u) {
520+ return alloc_ul_ue (u, res_grid, pusch_alloc, true , false , logger, pusch_td_res_idx);
521+ };
522+ next_ul_ue_index = round_robin_apply (ues, next_ul_ue_index, data_retx_ue_function);
523+ }
530524
531525 // Then, schedule all pending SR.
532- auto sr_ue_function = [this , &res_grid, &pusch_alloc](const ue& u, unsigned pusch_td_res_idx) {
533- return alloc_ul_ue (u, res_grid, pusch_alloc, false , true , logger, pusch_td_res_idx);
534- };
535- next_ul_ue_index = round_robin_ul_apply (ues, next_ul_ue_index, sr_ue_function);
526+ for (unsigned pusch_td_res_idx : pusch_td_res_index_list) {
527+ auto sr_ue_function = [this , &res_grid, &pusch_alloc, pusch_td_res_idx](const ue& u) {
528+ return alloc_ul_ue (u, res_grid, pusch_alloc, false , true , logger, pusch_td_res_idx);
529+ };
530+ next_ul_ue_index = round_robin_apply (ues, next_ul_ue_index, sr_ue_function);
531+ }
536532
537533 // Finally, schedule UL data new transmissions.
538534 const unsigned ul_new_tx_max_nof_rbs_per_ue_per_slot =
539535 compute_max_nof_rbs_per_ue_per_slot (ues, false , res_grid, expert_cfg);
540536 if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0 ) {
541- auto data_tx_ue_function =
542- [this , &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u, unsigned pusch_td_res_idx) {
543- return alloc_ul_ue (
544- u, res_grid, pusch_alloc, false , false , logger, pusch_td_res_idx, ul_new_tx_max_nof_rbs_per_ue_per_slot);
545- };
546- next_ul_ue_index = round_robin_ul_apply (ues, next_ul_ue_index, data_tx_ue_function);
537+ for (unsigned pusch_td_res_idx : pusch_td_res_index_list) {
538+ auto data_tx_ue_function = [this ,
539+ &res_grid,
540+ &pusch_alloc,
541+ ul_new_tx_max_nof_rbs_per_ue_per_slot,
542+ pusch_td_res_idx](const ue& u) {
543+ return alloc_ul_ue (
544+ u, res_grid, pusch_alloc, false , false , logger, pusch_td_res_idx, ul_new_tx_max_nof_rbs_per_ue_per_slot);
545+ };
546+ next_ul_ue_index = round_robin_apply (ues, next_ul_ue_index, data_tx_ue_function);
547+ }
547548 }
548549}
0 commit comments