osmo-bts-trx: properly activate [CBCH/]BCCH/CCCH

The timeslot carrying BCCH/CCCH on C0 is a bit special in a way that
it's being activated implicitly - there is no explicit RSL CHANnel
ACTIVation for that.  This is why we have TRX_CHAN_FLAG_AUTO_ACTIVE,
which marks sub-channels of BCCH/CCCH in the trx_chan_desc[].

The upcoming patch changes the burst buffer allocation strategy, so
that the memory is allocated on channel activation and then free()d
on channel release.  This patch facilitates that by making the
activation/deactivation logic consistent for all sub-channels.

Change-Id: Id0c70d6a2b777a5117c85149bfa1b3a997299d1d
Related: OS#1572
This commit is contained in:
Vadim Yanitskiy 2023-03-07 08:52:25 +07:00 committed by fixeria
parent e7085d1699
commit 8e04613e4f
4 changed files with 101 additions and 58 deletions

View File

@ -58,6 +58,7 @@ struct gsm_network {
/* lchans 0..3 are SDCCH in combined channel configuration,
use 4 as magic number for BCCH hack - see osmo-bts-../oml.c:opstart_compl() */
#define CCCH_LCHAN 4
#define CBCH_LCHAN 2
#define TRX_NR_TS 8
#define TS_MAX_LCHAN 8

View File

@ -5,13 +5,6 @@
#include <osmo-bts/gsm_data.h>
/* Whether a logical channel must be activated automatically */
#define TRX_CHAN_FLAG_AUTO_ACTIVE (1 << 0)
/* FIXME: we should actually activate 'auto-active' channels */
#define TRX_CHAN_IS_ACTIVE(state, chan) \
(trx_chan_desc[chan].flags & TRX_CHAN_FLAG_AUTO_ACTIVE || (state)->active)
#define TRX_GMSK_NB_TSC(br) \
_sched_train_seq_gmsk_nb[(br)->tsc_set][(br)->tsc]
@ -192,6 +185,9 @@ int trx_sched_set_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pch
/*! \brief set all matching logical channels active/inactive */
int trx_sched_set_lchan(struct gsm_lchan *lchan, uint8_t chan_nr, uint8_t link_id, bool active);
/*! \brief set all logical channels of BCCH/CCCH active/inactive */
int trx_sched_set_bcch_ccch(struct gsm_lchan *lchan, bool active);
/*! \brief set mode of all matching logical channels to given mode(s) */
int trx_sched_set_mode(struct gsm_bts_trx_ts *ts, uint8_t chan_nr, uint8_t rsl_cmode,
uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1,

View File

@ -150,7 +150,6 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.desc = "Frequency correction channel",
/* Tx only, frequency correction bursts */
.flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
.dl_fn = tx_fcch_fn,
},
[TRXC_SCH] = {
@ -158,7 +157,6 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.desc = "Synchronization channel",
/* Tx only, synchronization bursts */
.flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
.dl_fn = tx_sch_fn,
},
[TRXC_BCCH] = {
@ -169,7 +167,6 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
/* Tx only, xCCH convolutional coding (3GPP TS 05.03, section 4.4),
* regular interleaving (3GPP TS 05.02, clause 7, table 3):
* a L2 frame is interleaved over 4 consecutive bursts. */
.flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
.rts_fn = rts_data_fn,
.dl_fn = tx_data_fn,
},
@ -179,7 +176,6 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.chan_nr = RSL_CHAN_RACH,
/* Rx only, RACH convolutional coding (3GPP TS 05.03, section 4.6). */
.flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
.ul_fn = rx_rach_fn,
},
[TRXC_CCCH] = {
@ -190,7 +186,6 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
/* Tx only, xCCH convolutional coding (3GPP TS 05.03, section 4.4),
* regular interleaving (3GPP TS 05.02, clause 7, table 3):
* a L2 frame is interleaved over 4 consecutive bursts. */
.flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
.rts_fn = rts_data_fn,
.dl_fn = tx_data_fn,
},
@ -575,7 +570,6 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
.chan_nr = RSL_CHAN_OSMO_CBCH4,
/* Tx only, same as for TRXC_BCCH (xCCH), see above. */
.flags = TRX_CHAN_FLAG_AUTO_ACTIVE,
.rts_fn = rts_data_fn,
.dl_fn = tx_data_fn,
},
@ -1062,6 +1056,52 @@ static void trx_sched_queue_filter(struct llist_head *q, uint8_t chan_nr, uint8_
}
}
static void _trx_sched_set_lchan(struct gsm_lchan *lchan,
enum trx_chan_type chan,
bool active)
{
struct l1sched_ts *l1ts = lchan->ts->priv;
struct l1sched_chan_state *chan_state;
OSMO_ASSERT(l1ts != NULL);
chan_state = &l1ts->chan_state[chan];
LOGPLCHAN(lchan, DL1C, LOGL_INFO, "%s %s\n",
(active) ? "Activating" : "Deactivating",
trx_chan_desc[chan].name);
/* free burst memory, to cleanly start with burst 0 */
if (chan_state->dl_bursts) {
talloc_free(chan_state->dl_bursts);
chan_state->dl_bursts = NULL;
}
if (chan_state->ul_bursts) {
talloc_free(chan_state->ul_bursts);
chan_state->ul_bursts = NULL;
}
if (chan_state->ul_bursts_prev) {
talloc_free(chan_state->ul_bursts_prev);
chan_state->ul_bursts_prev = NULL;
}
if (active) {
/* Clean up everything */
memset(chan_state, 0, sizeof(*chan_state));
/* Bind to generic 'struct gsm_lchan' */
chan_state->lchan = lchan;
} else {
chan_state->ho_rach_detect = 0;
/* Remove pending Tx prims belonging to this lchan */
trx_sched_queue_filter(&l1ts->dl_prims,
trx_chan_desc[chan].chan_nr,
trx_chan_desc[chan].link_id);
}
chan_state->active = active;
}
/* setting all logical channels given attributes to active/inactive */
int trx_sched_set_lchan(struct gsm_lchan *lchan, uint8_t chan_nr, uint8_t link_id, bool active)
{
@ -1069,7 +1109,6 @@ int trx_sched_set_lchan(struct gsm_lchan *lchan, uint8_t chan_nr, uint8_t link_i
uint8_t tn = L1SAP_CHAN2TS(chan_nr);
uint8_t ss = l1sap_chan2ss(chan_nr);
bool found = false;
int i;
if (!l1ts) {
LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "%s lchan with uninitialized scheduler structure\n",
@ -1083,48 +1122,15 @@ int trx_sched_set_lchan(struct gsm_lchan *lchan, uint8_t chan_nr, uint8_t link_i
chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;
/* look for all matching chan_nr/link_id */
for (i = 0; i < _TRX_CHAN_MAX; i++) {
struct l1sched_chan_state *chan_state = &l1ts->chan_state[i];
if (trx_chan_desc[i].chan_nr != (chan_nr & RSL_CHAN_NR_MASK))
for (enum trx_chan_type chan = 0; chan < _TRX_CHAN_MAX; chan++) {
if (trx_chan_desc[chan].chan_nr != (chan_nr & RSL_CHAN_NR_MASK))
continue;
if (trx_chan_desc[i].link_id != link_id)
if (trx_chan_desc[chan].link_id != link_id)
continue;
if (chan_state->active == active)
if (l1ts->chan_state[chan].active == active)
continue;
found = true;
LOGPLCHAN(lchan, DL1C, LOGL_INFO, "%s %s\n",
(active) ? "Activating" : "Deactivating",
trx_chan_desc[i].name);
/* free burst memory, to cleanly start with burst 0 */
if (chan_state->dl_bursts) {
talloc_free(chan_state->dl_bursts);
chan_state->dl_bursts = NULL;
}
if (chan_state->ul_bursts) {
talloc_free(chan_state->ul_bursts);
chan_state->ul_bursts = NULL;
}
if (chan_state->ul_bursts_prev) {
talloc_free(chan_state->ul_bursts_prev);
chan_state->ul_bursts_prev = NULL;
}
if (active) {
/* Clean up everything */
memset(chan_state, 0, sizeof(*chan_state));
/* Bind to generic 'struct gsm_lchan' */
chan_state->lchan = lchan;
} else {
chan_state->ho_rach_detect = 0;
/* Remove pending Tx prims belonging to this lchan */
trx_sched_queue_filter(&l1ts->dl_prims, chan_nr, link_id);
}
chan_state->active = active;
_trx_sched_set_lchan(lchan, chan, active);
}
/* disable handover detection (on deactivation) */
@ -1134,6 +1140,31 @@ int trx_sched_set_lchan(struct gsm_lchan *lchan, uint8_t chan_nr, uint8_t link_i
return found ? 0 : -EINVAL;
}
int trx_sched_set_bcch_ccch(struct gsm_lchan *lchan, bool active)
{
struct l1sched_ts *l1ts = lchan->ts->priv;
static const enum trx_chan_type chans[] = {
TRXC_FCCH,
TRXC_SCH,
TRXC_BCCH,
TRXC_RACH,
TRXC_CCCH,
};
if (!l1ts)
return -EINVAL;
for (unsigned int i = 0; i < ARRAY_SIZE(chans); i++) {
enum trx_chan_type chan = chans[i];
if (l1ts->chan_state[chan].active == active)
continue;
_trx_sched_set_lchan(lchan, chan, active);
}
return 0;
}
/* setting all logical channels given attributes to active/inactive */
int trx_sched_set_mode(struct gsm_bts_trx_ts *ts, uint8_t chan_nr, uint8_t rsl_cmode,
uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1,
@ -1277,7 +1308,7 @@ int _sched_rts(const struct l1sched_ts *l1ts, uint32_t fn)
return 0;
/* check if channel is active */
if (!TRX_CHAN_IS_ACTIVE(&l1ts->chan_state[chan], chan))
if (!l1ts->chan_state[chan].active)
return -EINVAL;
/* There is no burst, just for logging */
@ -1334,7 +1365,7 @@ void _sched_dl_burst(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
l1cs = &l1ts->chan_state[br->chan];
/* check if channel is active */
if (!TRX_CHAN_IS_ACTIVE(l1cs, br->chan))
if (!l1cs->active)
return;
/* Training Sequence Code and Set */
@ -1523,7 +1554,7 @@ int trx_sched_ul_burst(struct l1sched_ts *l1ts, struct trx_ul_burst_ind *bi)
func = trx_chan_desc[bi->chan].ul_fn;
/* check if channel is active */
if (!TRX_CHAN_IS_ACTIVE(l1cs, bi->chan)) {
if (!l1cs->active) {
/* handle noise measurements on dedicated and idle channels */
if (TRX_CHAN_IS_DEDIC(bi->chan) || bi->chan == TRXC_IDLE)
trx_sched_noise_meas(l1cs, bi);

View File

@ -270,11 +270,26 @@ static uint8_t trx_set_ts_as_pchan(struct gsm_bts_trx_ts *ts,
if (rc)
return NM_NACK_RES_NOTAVAIL;
/* activate lchan for CCCH */
if (pchan == GSM_PCHAN_CCCH || pchan == GSM_PCHAN_CCCH_SDCCH4 ||
pchan == GSM_PCHAN_CCCH_SDCCH4_CBCH) {
/* activate lchans for [CBCH/]BCCH/CCCH */
switch (pchan) {
case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
/* using RSL_CHAN_OSMO_CBCH4 is correct here, because the scheduler
* does not distinguish between SDCCH/4+CBCH abd SDCCH/8+CBCH. */
trx_sched_set_lchan(&ts->lchan[CBCH_LCHAN],
RSL_CHAN_OSMO_CBCH4, LID_DEDIC, true);
break;
case GSM_PCHAN_CCCH_SDCCH4_CBCH:
trx_sched_set_lchan(&ts->lchan[CBCH_LCHAN],
RSL_CHAN_OSMO_CBCH4, LID_DEDIC, true);
/* fall-through */
case GSM_PCHAN_CCCH_SDCCH4:
case GSM_PCHAN_CCCH:
trx_sched_set_bcch_ccch(&ts->lchan[CCCH_LCHAN], true);
ts->lchan[CCCH_LCHAN].rel_act_kind = LCHAN_REL_ACT_OML;
lchan_set_state(&ts->lchan[CCCH_LCHAN], LCHAN_S_ACTIVE);
break;
default:
break;
}
slottype = transceiver_chan_types[pchan];