diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 6bee9cad9a..6b86c8bfed 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -955,7 +955,23 @@ static void pf_dl(gNB_MAC_INST *mac, int partner_allocs[MAX_MU_MIMO_PARTNERS] = {-1, -1, -1}; int n_partners = 0; - if (mumimo_enabled() && remainUEs[beam.idx] > 0) { + /* nakaolab Phase 4: cap MU-MIMO group size to the active TX antenna count. + * When the antenna controller mutes some TX chains (e.g., 4->2 or 4->1), the + * effective number of orthogonal codewords in the codebook shrinks. Each + * co-scheduled UE consumes one spatial layer = one TX port. So: + * active_tx = 4 -> up to 4 UEs (3 partners), 4-way MU-MIMO + * active_tx = 2 -> up to 2 UEs (1 partner), 2-way MU-MIMO + * active_tx = 1 -> SU-MIMO only (0 partners) */ + int max_partners_now = MAX_MU_MIMO_PARTNERS; + if (mac->antenna_state) { + const uint8_t tx_mask = nr_get_tx_antenna_bitmask(mac->antenna_state); + int active_tx = __builtin_popcount(tx_mask); + if (active_tx < 1) active_tx = 1; + if (active_tx - 1 < max_partners_now) + max_partners_now = active_tx - 1; + } + + if (mumimo_enabled() && remainUEs[beam.idx] > 0 && max_partners_now > 0) { const uint8_t leader_x2 = iterator->UE->UE_sched_ctrl.CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2; uint8_t classes_used = 1 << leader_x2; static int diag_count = 0; @@ -970,8 +986,9 @@ static void pf_dl(gNB_MAC_INST *mac, LOG_W(NR_MAC, "[mumimo-diag] %4d.%2d ENTER partner-search after RNTI %04x leader_x2=%d; eligible_others=%d\n", frame, slot, iterator->UE->rnti, leader_x2, n_cand); } - /* Find up to MAX_MU_MIMO_PARTNERS partners, one per remaining x2 class. */ - while (n_partners < MAX_MU_MIMO_PARTNERS && remainUEs[beam.idx] > 0) { + /* Find up to max_partners_now partners, one per remaining x2 class. + * max_partners_now is capped by active TX antenna count (Phase 4). */ + while (n_partners < max_partners_now && remainUEs[beam.idx] > 0) { NR_UE_info_t *new_partner = NULL; int new_CCE = -1; int new_alloc = -1;