Use spsc_q for PUCCH processing

Use the spsc queue to pass jobs from TX thread (scheduler) to RX thread
(handling those jobs), reducing the amount spent searching for PUCCH
jobs in an array, clarifying the design, and making it thread-safe.

Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
This commit is contained in:
Robert Schmidt
2026-04-16 11:53:19 +02:00
parent 85b4057bde
commit e8e3f60e73
5 changed files with 74 additions and 75 deletions
+1 -1
View File
@@ -1070,7 +1070,7 @@ add_library(PHY_NR_COMMON ${PHY_NR_SRC_COMMON})
target_link_libraries(PHY_NR_COMMON PUBLIC UTIL)
add_library(PHY_NR ${PHY_NR_SRC})
target_link_libraries(PHY_NR nr_phy_common nr_common nr_fapi_p5 polar smallblock)
target_link_libraries(PHY_NR nr_phy_common nr_common nr_fapi_p5 polar smallblock ds)
add_library(PHY_NR_NO_AVX_256 ${PHY_NR_SRC})
target_link_libraries(PHY_NR_NO_AVX_256 nr_phy_common nr_common)
+3 -6
View File
@@ -437,14 +437,11 @@ void init_nr_transport(PHY_VARS_gNB *gNB)
else
buffer_ul_slots = (nb_ul_slots_period < slot_ahead) ? nb_ul_slots_period : slot_ahead;
gNB->max_nb_pucch = buffer_ul_slots ? MAX_MOBILES_PER_GNB * buffer_ul_slots : 1;
gNB->max_nb_pusch = buffer_ul_slots ? MAX_MOBILES_PER_GNB * buffer_ul_slots : 1;
gNB->max_nb_srs = buffer_ul_slots ? buffer_ul_slots << 1 : 1; // assuming at most 2 SRS per slot
gNB->pucch = (NR_gNB_PUCCH_t *)malloc16(gNB->max_nb_pucch * sizeof(NR_gNB_PUCCH_t));
for (int i = 0; i < gNB->max_nb_pucch; i++) {
memset(&gNB->pucch[i], 0, sizeof(gNB->pucch[i]));
}
int max_nb_pucch = buffer_ul_slots ? MAX_MOBILES_PER_GNB * buffer_ul_slots : 1;
gNB->pucch_queue = spsc_q_alloc(max_nb_pucch, sizeof(NR_gNB_PUCCH_job_t));
gNB->srs = (NR_gNB_SRS_t *)malloc16(gNB->max_nb_srs * sizeof(NR_gNB_SRS_t));
for (int i = 0; i < gNB->max_nb_srs; i++)
@@ -465,7 +462,7 @@ void reset_nr_transport(PHY_VARS_gNB *gNB)
{
const NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
free(gNB->pucch);
spsc_q_free(&gNB->pucch_queue);
free(gNB->srs);
for (int i = 0; i < gNB->max_nb_pusch; i++)
+22 -30
View File
@@ -33,37 +33,29 @@
//#define DEBUG_NR_PUCCH_RX 1
void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pucch_pdu_t *pucch_pdu)
{
for (int i = 0; i < gNB->max_nb_pucch; i++) {
NR_gNB_PUCCH_t *pucch = &gNB->pucch[i];
if (pucch->active == false) {
pucch->frame = frame;
pucch->slot = slot;
pucch->active = true;
pucch->beam_nb = 0;
if (gNB->common_vars.beam_id) {
int fapi_beam_idx = pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx;
int bitmap = SL_to_bitmap(pucch_pdu->start_symbol_index, pucch_pdu->nr_of_symbols);
pucch->beam_nb = beam_index_allocation(gNB->enable_analog_das,
fapi_beam_idx,
&gNB->common_vars,
slot,
gNB->frame_parms.symbols_per_slot,
bitmap);
}
memcpy((void *)&pucch->pucch_pdu, (void *)pucch_pdu, sizeof(nfapi_nr_pucch_pdu_t));
LOG_D(PHY,
"Programming PUCCH[%d] for %d.%d, format %d, nb_harq %d, nb_sr %d, nb_csi %d\n",
i,
pucch->frame,
pucch->slot,
pucch->pucch_pdu.format_type,
pucch->pucch_pdu.bit_len_harq,
pucch->pucch_pdu.sr_flag,
pucch->pucch_pdu.bit_len_csi_part1);
return;
}
LOG_D(PHY,
"%4d.%2d UE %04x Programming PUCCH format %d, nb_harq %d, nb_sr %d, nb_csi %d\n",
frame,
slot,
pucch_pdu->rnti,
pucch_pdu->format_type,
pucch_pdu->bit_len_harq,
pucch_pdu->sr_flag,
pucch_pdu->bit_len_csi_part1);
NR_gNB_PUCCH_job_t pucch = {.frame = frame, .slot = slot, .pucch_pdu = *pucch_pdu};
if (gNB->common_vars.beam_id) {
int fapi_beam_idx = pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx;
int bitmap = SL_to_bitmap(pucch_pdu->start_symbol_index, pucch_pdu->nr_of_symbols);
pucch.beam_nb = beam_index_allocation(gNB->enable_analog_das,
fapi_beam_idx,
&gNB->common_vars,
slot,
gNB->frame_parms.symbols_per_slot,
bitmap);
}
LOG_W(PHY, "PUCCH list is full\n");
bool found = spsc_q_put(&gNB->pucch_queue, &pucch, sizeof(pucch));
if (!found)
LOG_W(NR_PHY, "PUCCH list is full: dropping PUCCH UE %04x\n", pucch_pdu->rnti);
}
int get_pucch0_cs_lut_index(PHY_VARS_gNB *gNB, const nfapi_nr_pucch_pdu_t *pucch_pdu)
+3 -4
View File
@@ -19,6 +19,7 @@
#include "nfapi_nr_interface_scf.h"
#include "common/utils/threadPool/task_ans.h"
#include "openair1/PHY/defs_RU.h"
#include "common/utils/ds/spsc_q.h"
#define MAX_NUM_RU_PER_gNB 8
#define MAX_PUCCH0_NID 8
@@ -190,7 +191,6 @@ typedef struct {
} NR_gNB_ULSCH_t;
typedef struct {
bool active;
// identifier for concurrent beams
int beam_nb;
/// Frame where current PUCCH pdu was sent
@@ -199,7 +199,7 @@ typedef struct {
uint32_t slot;
/// ULSCH PDU
nfapi_nr_pucch_pdu_t pucch_pdu;
} NR_gNB_PUCCH_t;
} NR_gNB_PUCCH_job_t;
typedef struct {
bool active;
@@ -369,7 +369,6 @@ typedef struct PHY_VARS_gNB_s {
nfapi_nr_ul_tti_request_t UL_tti_req;
int max_nb_pucch;
int max_nb_srs;
int max_nb_pdsch;
int max_nb_pusch;
@@ -380,7 +379,7 @@ typedef struct PHY_VARS_gNB_s {
NR_gNB_DLSCH_t *dlsch;
NR_gNB_PRS prs_vars;
NR_gNB_PUSCH *pusch_vars;
NR_gNB_PUCCH_t *pucch;
spsc_q_t pucch_queue;
NR_gNB_SRS_t *srs;
NR_gNB_ULSCH_t *ulsch;
NR_gNB_PHY_STATS_t phy_stats[MAX_MOBILES_PER_GNB];
+45 -34
View File
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
*/
#include "common/utils/fsn.h"
#include "PHY/defs_gNB.h"
#include "sched_nr.h"
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
@@ -613,10 +614,11 @@ static void nr_fill_indication(PHY_VARS_gNB *gNB,
// Function to fill UL RB mask to be used for N0 measurements
static void fill_ul_rb_mask(PHY_VARS_gNB *gNB,
int frame_rx,
int slot_rx,
fsn_t now,
uint32_t rb_mask_ul[14][9],
nfapi_nr_max_num_of_symbol_per_slot_t *slot_conf)
nfapi_nr_max_num_of_symbol_per_slot_t *slot_conf,
const NR_gNB_PUCCH_job_t *pucch,
int n_pucch)
{
for (int symbol = 0; symbol < 14; symbol++) {
for (int m = 0; m < 9; m++) {
@@ -630,20 +632,9 @@ static void fill_ul_rb_mask(PHY_VARS_gNB *gNB,
}
}
for (int i = 0; i < gNB->max_nb_pucch; i++){
const NR_gNB_PUCCH_t *pucch = gNB->pucch + i;
if (!(pucch && pucch->active && pucch->frame == frame_rx && pucch->slot == slot_rx))
continue;
const nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch->pucch_pdu;
for (int i = 0; i < n_pucch; ++i) {
const nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch[i].pucch_pdu;
const int start = pucch_pdu->start_symbol_index;
LOG_D(PHY,
"%d.%d pucch %d : start_symbol %d, nb_symbols %d, prb_size %d\n",
frame_rx,
slot_rx,
i,
start,
pucch_pdu->nr_of_symbols,
pucch_pdu->prb_size);
for (int symbol = start; symbol < (start + pucch_pdu->nr_of_symbols); symbol++) {
if (gNB->frame_parms.frame_type == FDD || (gNB->frame_parms.frame_type == TDD && slot_conf[symbol].slot_config.value == 1)) {
for (int rb = 0; rb < pucch_pdu->prb_size; rb++) {
@@ -661,7 +652,7 @@ static void fill_ul_rb_mask(PHY_VARS_gNB *gNB,
NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id];
NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process;
AssertFatal(ulsch_harq != NULL, "harq_pid %d is not allocated\n", ulsch->harq_pid);
if (!(ulsch->active && ulsch->frame == frame_rx && ulsch->slot == slot_rx && !ulsch->handled))
if (!(ulsch->active && ulsch->frame == now.f && ulsch->slot == now.s && !ulsch->handled))
continue;
uint8_t symbol_start = ulsch_harq->ulsch_pdu.start_symbol_index;
uint8_t symbol_end = symbol_start + ulsch_harq->ulsch_pdu.nr_of_symbols;
@@ -678,7 +669,7 @@ static void fill_ul_rb_mask(PHY_VARS_gNB *gNB,
for (int i = 0; i < gNB->max_nb_srs; i++) {
NR_gNB_SRS_t *srs = &gNB->srs[i];
if (!(srs && srs->active && srs->frame == frame_rx && srs->slot == slot_rx))
if (!(srs && srs->active && srs->frame == now.f && srs->slot == now.s))
continue;
nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu;
const uint8_t l0 = gNB->frame_parms.symbols_per_slot - 1 - srs_pdu->time_start_position;
@@ -989,7 +980,7 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB,
}
}
static void handle_pucch(PHY_VARS_gNB *gNB, c16_t **rxdataF, const NR_gNB_PUCCH_t *pucch, nfapi_nr_uci_t *uci)
static void handle_pucch(PHY_VARS_gNB *gNB, c16_t **rxdataF, const NR_gNB_PUCCH_job_t *pucch, nfapi_nr_uci_t *uci)
{
const nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch->pucch_pdu;
@@ -1011,16 +1002,41 @@ static void handle_pucch(PHY_VARS_gNB *gNB, c16_t **rxdataF, const NR_gNB_PUCCH_
}
}
static bool drop_old_pucch(const void *data, void *user)
{
const NR_gNB_PUCCH_job_t *pucch = data;
const fsn_t *now = user;
const fsn_t t = {pucch->frame, pucch->slot, now->mu};
bool drop = fsn_in_the_past(t, *now);
if (drop)
LOG_E(NR_PHY, "%4d.%2d PUCCH job for UE %04x is in the past (%4d.%2d)\n", now->f, now->s, pucch->pucch_pdu.rnti, t.f, t.s);
return drop;
}
static bool get_current_pucch(const void *data, void *user)
{
const NR_gNB_PUCCH_job_t *pucch = data;
const fsn_t *now = user;
const fsn_t t = {pucch->frame, pucch->slot, now->mu};
return fsn_equal(t, *now);
}
int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, NR_UL_IND_t *UL_INFO)
{
/* those variables to log T_GNB_PHY_PUCCH_PUSCH_IQ only when we try to decode */
int pucch_decode_done = 0;
int pusch_decode_done = 0;
int pusch_DTX = 0;
const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
const uint16_t ofdm_symbol_size = frame_parms->ofdm_symbol_size;
const uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx;
fsn_t now = {frame_rx, slot_rx, frame_parms->numerology_index};
spsc_q_drop_while(&gNB->pucch_queue, drop_old_pucch, &now);
NR_gNB_PUCCH_job_t pucch[MAX_NUM_NR_UCI_PDUS];
int n_pucch = spsc_q_get_while(&gNB->pucch_queue, get_current_pucch, &now, pucch, sizeof(*pucch), MAX_NUM_NR_UCI_PDUS);
LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d\n",frame_rx,slot_rx);
{
// Mask of occupied RBs, per symbol and PRB
@@ -1028,7 +1044,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
nfapi_nr_max_num_of_symbol_per_slot_t *slot_conf = NULL;
if (frame_parms->frame_type == TDD)
slot_conf = gNB->gNB_config.tdd_table.max_tdd_periodicity_list[slot_rx].max_num_of_symbol_per_slot_list;
fill_ul_rb_mask(gNB, frame_rx, slot_rx, rb_mask_ul, slot_conf);
fill_ul_rb_mask(gNB, now, rb_mask_ul, slot_conf, pucch, n_pucch);
int first_symb = 0, num_symb = 0;
if (frame_parms->frame_type == TDD)
@@ -1045,19 +1061,14 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
}
start_meas(&gNB->phy_proc_rx);
for (int i = 0; i < gNB->max_nb_pucch; i++) {
NR_gNB_PUCCH_t *pucch = &gNB->pucch[i];
if (!(pucch && pucch->active && pucch->frame == frame_rx && pucch->slot == slot_rx))
continue;
UL_INFO->uci_ind.uci_list = UL_INFO->uci_pdu_list;
UL_INFO->uci_ind.sfn = frame_rx;
UL_INFO->uci_ind.slot = slot_rx;
UL_INFO->uci_ind.num_ucis = n_pucch;
nfapi_nr_uci_t *uci = UL_INFO->uci_ind.uci_list;
for (int i = 0; i < n_pucch; ++i) {
c16_t **rxdataF = gNB->common_vars.rxdataF[pucch->beam_nb];
pucch_decode_done = 1;
UL_INFO->uci_ind.uci_list = UL_INFO->uci_pdu_list;
UL_INFO->uci_ind.sfn = frame_rx;
UL_INFO->uci_ind.slot = slot_rx;
nfapi_nr_uci_t *uci = UL_INFO->uci_ind.uci_list + UL_INFO->uci_ind.num_ucis;
handle_pucch(gNB, rxdataF, pucch, uci);
UL_INFO->uci_ind.num_ucis += 1;
pucch->active = false;
handle_pucch(gNB, rxdataF, &pucch[i], uci++);
}
UL_INFO->crc_ind.sfn = frame_rx;
@@ -1377,7 +1388,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
stop_meas(&gNB->phy_proc_rx);
if (pucch_decode_done || pusch_decode_done) {
if (n_pucch > 0 || pusch_decode_done) {
T(T_GNB_PHY_PUCCH_PUSCH_IQ,
T_INT(frame_rx),
T_INT(slot_rx),