fixeria has submitted this change. ( https://gerrit.osmocom.org/c/osmocom-bb/+/30239 )
Change subject: trxcon: rework l1sched_trigger(), split l1sched_pull_burst() ......................................................................
trxcon: rework l1sched_trigger(), split l1sched_pull_burst()
The key idea is to allow triggering the scheduler only for a specific timeslot of a frame, while keeping the API for triggering all together.
Split off the main part from l1sched_trigger() to l1sched_pull_burst(). While at it, rename l1sched_trigger() to l1sched_pull_send_frame().
Change-Id: Ibb7f9d7de26733f21b0753a2c655a250286bf1f0 Related: OS#5599 --- M src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h M src/host/trxcon/src/sched_clck.c M src/host/trxcon/src/sched_trx.c 3 files changed, 85 insertions(+), 81 deletions(-)
Approvals: laforge: Looks good to me, but someone else must approve fixeria: Looks good to me, approved pespin: Looks good to me, but someone else must approve Jenkins Builder: Verified
diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h index 3dfafb3..31d4b64 100644 --- a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h +++ b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h @@ -490,7 +490,9 @@ /* Clock and Downlink scheduling trigger */ int l1sched_clck_handle(struct l1sched_state *sched, uint32_t fn); void l1sched_clck_reset(struct l1sched_state *sched); -void l1sched_trigger(struct l1sched_state *sched); + +void l1sched_pull_burst(struct l1sched_state *sched, struct l1sched_burst_req *br); +void l1sched_pull_send_frame(struct l1sched_state *sched);
/* External L1 API, must be implemented by the API user */ int l1sched_handle_config_req(struct l1sched_state *sched, diff --git a/src/host/trxcon/src/sched_clck.c b/src/host/trxcon/src/sched_clck.c index ccafd7b..f9eadaf 100644 --- a/src/host/trxcon/src/sched_clck.c +++ b/src/host/trxcon/src/sched_clck.c @@ -82,7 +82,7 @@ GSM_TDMA_FN_INC(sched->fn_counter_proc);
/* Trigger the scheduler */ - l1sched_trigger(sched); + l1sched_pull_send_frame(sched); }
osmo_timer_schedule(&sched->clock_timer, 0, @@ -95,7 +95,7 @@ sched->fn_counter_proc = fn;
/* Trigger the scheduler */ - l1sched_trigger(sched); + l1sched_pull_send_frame(sched);
/* Schedule first FN clock */ sched->clock = *tv_now; @@ -176,7 +176,7 @@ GSM_TDMA_FN_INC(sched->fn_counter_proc);
/* Trigger the scheduler */ - l1sched_trigger(sched); + l1sched_pull_send_frame(sched); }
/* Schedule next FN to be transmitted */ diff --git a/src/host/trxcon/src/sched_trx.c b/src/host/trxcon/src/sched_trx.c index c36b7de..2ac6904 100644 --- a/src/host/trxcon/src/sched_trx.c +++ b/src/host/trxcon/src/sched_trx.c @@ -85,102 +85,104 @@ static void l1sched_a5_burst_enc(struct l1sched_lchan_state *lchan, struct l1sched_burst_req *br);
-void l1sched_trigger(struct l1sched_state *sched) +/* Pull an Uplink burst from the scheduler and store it to br->burst[]. + * The TDMA Fn advance must be applied by the caller (if needed). + * The given *br must be initialized by the caller. */ +void l1sched_pull_burst(struct l1sched_state *sched, struct l1sched_burst_req *br) { - struct l1sched_burst_req br[TRX_TS_COUNT]; + struct l1sched_ts *ts = sched->ts[br->tn]; const struct l1sched_tdma_frame *frame; struct l1sched_lchan_state *lchan; l1sched_lchan_tx_func *handler; enum l1sched_lchan_type chan; uint8_t offset; - struct l1sched_ts *ts; - unsigned int tn;
+ /* Timeslot is not allocated */ + if (ts == NULL) + return; + + /* Timeslot is not configured */ + if (ts->mf_layout == NULL) + return; + + /* Get frame from multiframe */ + offset = br->fn % ts->mf_layout->period; + frame = ts->mf_layout->frames + offset; + + /* Get required info from frame */ + br->bid = frame->ul_bid; + chan = frame->ul_chan; + handler = l1sched_lchan_desc[chan].tx_fn; + + /* Omit lchans without handler */ + if (!handler) + return; + + /* Make sure that lchan was allocated and activated */ + lchan = l1sched_find_lchan(ts, chan); + if (lchan == NULL) + return; + + /* Omit inactive lchans */ + if (!lchan->active) + return; + + /** + * If we aren't processing any primitive yet, + * attempt to obtain a new one from queue + */ + if (lchan->prim == NULL) + lchan->prim = l1sched_prim_dequeue(&ts->tx_prims, br->fn, lchan); + + /* TODO: report TX buffers health to the higher layers */ + + /* If CBTX (Continuous Burst Transmission) is assumed */ + if (l1sched_lchan_desc[chan].flags & L1SCHED_CH_FLAG_CBTX) { + /** + * Probably, a TX buffer is empty. Nevertheless, + * we shall continuously transmit anything on + * CBTX channels. + */ + if (lchan->prim == NULL) + l1sched_prim_dummy(lchan); + } + + /* If there is no primitive, do nothing */ + if (lchan->prim == NULL) + return; + + /* Handover RACH needs to be handled regardless of the + * current channel type and the associated handler. */ + if (L1SCHED_PRIM_IS_RACH(lchan->prim) && lchan->prim->chan != L1SCHED_RACH) + handler = l1sched_lchan_desc[L1SCHED_RACH].tx_fn; + + /* Poke lchan handler */ + handler(lchan, br); + + /* Perform A5/X burst encryption if required */ + if (lchan->a5.algo) + l1sched_a5_burst_enc(lchan, br); +} + +/* Pull *and send* Uplink bursts for all timeslots and the current TDMA Fn. */ +void l1sched_pull_send_frame(struct l1sched_state *sched) +{ /* Advance TDMA frame number in order to give the transceiver * more time to handle the burst before the actual transmission. */ const uint32_t fn = GSM_TDMA_FN_SUM(sched->fn_counter_proc, sched->fn_counter_advance);
/* Iterate over timeslot list */ - for (tn = 0; tn < ARRAY_SIZE(br); tn++) { - /* Initialize the buffer for this timeslot */ - br[tn] = (struct l1sched_burst_req) { + for (unsigned int tn = 0; tn < ARRAY_SIZE(sched->ts); tn++) { + struct l1sched_burst_req br = { .fn = fn, .tn = tn, .burst_len = 0, /* NOPE.ind */ };
- /* Timeslot is not allocated */ - ts = sched->ts[tn]; - if (ts == NULL) - continue; - - /* Timeslot is not configured */ - if (ts->mf_layout == NULL) - continue; - - /* Get frame from multiframe */ - offset = fn % ts->mf_layout->period; - frame = ts->mf_layout->frames + offset; - - /* Get required info from frame */ - br[tn].bid = frame->ul_bid; - chan = frame->ul_chan; - handler = l1sched_lchan_desc[chan].tx_fn; - - /* Omit lchans without handler */ - if (!handler) - continue; - - /* Make sure that lchan was allocated and activated */ - lchan = l1sched_find_lchan(ts, chan); - if (lchan == NULL) - continue; - - /* Omit inactive lchans */ - if (!lchan->active) - continue; - - /** - * If we aren't processing any primitive yet, - * attempt to obtain a new one from queue - */ - if (lchan->prim == NULL) - lchan->prim = l1sched_prim_dequeue(&ts->tx_prims, fn, lchan); - - /* TODO: report TX buffers health to the higher layers */ - - /* If CBTX (Continuous Burst Transmission) is assumed */ - if (l1sched_lchan_desc[chan].flags & L1SCHED_CH_FLAG_CBTX) { - /** - * Probably, a TX buffer is empty. Nevertheless, - * we shall continuously transmit anything on - * CBTX channels. - */ - if (lchan->prim == NULL) - l1sched_prim_dummy(lchan); - } - - /* If there is no primitive, do nothing */ - if (lchan->prim == NULL) - continue; - - /* Handover RACH needs to be handled regardless of the - * current channel type and the associated handler. */ - if (L1SCHED_PRIM_IS_RACH(lchan->prim) && lchan->prim->chan != L1SCHED_RACH) - handler = l1sched_lchan_desc[L1SCHED_RACH].tx_fn; - - /* Poke lchan handler */ - handler(lchan, &br[tn]); - - /* Perform A5/X burst encryption if required */ - if (lchan->a5.algo) - l1sched_a5_burst_enc(lchan, &br[tn]); + l1sched_pull_burst(sched, &br); + l1sched_handle_burst_req(sched, &br); } - - /* Send all bursts for this TDMA frame */ - for (tn = 0; tn < ARRAY_SIZE(br); tn++) - l1sched_handle_burst_req(sched, &br[tn]); }
void l1sched_logging_init(int log_cat_common, int log_cat_data)