replace ts_*_for_each_lchan() with ts_for_n_lchans()

So far we have a couple of macros iterating a specific number of lchans,
depending on dynamic timeslot state etc. With addition of VAMOS lchans,
this would become more complex and bloated.

Instead of separate iteration macros for each situation, only have one
that takes a number of lchans as argument. That allows to more clearly
pick the number of lchans, especially for non-trivial VAMOS scenarios.

Related: SYS#5315 OS#4940
Change-Id: Ib2c6baf73a81ba371143ba5adc912aef6f79238d
This commit is contained in:
Neels Hofmeyr 2021-05-19 02:28:26 +02:00
parent e262919892
commit 27c07690d9
10 changed files with 28 additions and 54 deletions

View File

@ -554,41 +554,20 @@ struct gsm_encr {
bsc_subscr_name(lchan && lchan->conn ? lchan->conn->bsub : NULL), \
## args)
/* Iterate lchans that have an FSM allocated based based on explicit pchan kind
* (GSM_PCHAN_* constant).
* Remark: PDCH related lchans are not handled in BSC but in PCU, so trying to
* iterate through GSM_PCHAN_PDCH is considered a void loop.
*/
#define ts_as_pchan_for_each_lchan(lchan, ts, as_pchan) \
for (lchan = (ts)->lchan; \
((lchan - (ts)->lchan) < ARRAY_SIZE((ts)->lchan)) \
&& lchan->fi \
&& lchan->nr < pchan_subslots(as_pchan); \
lchan++)
/* Iterate lchans that have an FSM allocated based on current PCHAN
* mode set in \ref ts.
/* Iterate at most N lchans of the given timeslot.
* usage:
* struct gsm_lchan *lchan;
* struct gsm_bts_trx_ts *ts = get_some_timeslot();
* ts_for_each_lchan(lchan, ts) {
* LOGPLCHAN(DMAIN, LOGL_DEBUG, "hello world\n");
* ts_for_n_lchans(lchan, ts, 3) {
* LOG_LCHAN(lchan, LOGL_DEBUG, "hello world\n");
* }
*/
#define ts_for_each_lchan(lchan, ts) ts_as_pchan_for_each_lchan(lchan, ts, (ts)->pchan_is)
/* Iterate over all possible lchans available that have an FSM allocated based
* on PCHAN \ref ts (dynamic) configuration.
* Iterate all lchan instances set up by this \ref ts type, including those
* lchans currently disabled or in process of being enabled (e.g. due to dynamic
* timeslot in switchover). Compare ts_for_each_lchan(), which iterates only the
* enabled lchans.
* For example, it is useful in case dynamic timeslot \ref ts is in process of
* switching from configuration PDCH (no lchans) to TCH_F (1 lchan), where
* pchan_is is still set to PDCH but \ref ts may contain already an \ref lchan
* of type TCH_F which initiated the request to switch the \ts configuration.
*/
#define ts_for_each_potential_lchan(lchan, ts) ts_as_pchan_for_each_lchan(lchan, ts, (ts)->pchan_on_init)
#define ts_for_n_lchans(lchan, ts, N) \
for (lchan = (ts)->lchan; \
((lchan - (ts)->lchan) < ARRAY_SIZE((ts)->lchan)) \
&& lchan->fi \
&& ((lchan - (ts)->lchan) < (N)); \
lchan++)
enum lchan_activate_for {
ACTIVATE_FOR_NONE,

View File

@ -1606,7 +1606,7 @@ static struct gsm_lchan *get_any_lchan(struct gsm_bts *bts)
trx = gsm_bts_trx_num(bts, trx_nr);
for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
ts = &trx->ts[ts_nr];
ts_for_each_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_primary_lchans) {
if (lchan->type == GSM_LCHAN_TCH_F || lchan->type == GSM_LCHAN_TCH_H) {
if (bts->chan_alloc_reverse) {
if (lchan->fi->state == LCHAN_ST_ESTABLISHED)

View File

@ -1691,7 +1691,7 @@ static int dump_lchan_trx_ts(struct gsm_bts_trx_ts *ts, struct vty *vty,
bool all)
{
struct gsm_lchan *lchan;
ts_for_each_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_lchans_possible) {
if (lchan_state_is(lchan, LCHAN_ST_UNUSED) && all == false)
continue;
dump_cb(vty, lchan);
@ -1997,7 +1997,7 @@ static struct gsm_lchan *find_used_voice_lchan(struct vty *vty, int random_idx)
if (ts->fi->state != TS_ST_IN_USE)
continue;
ts_for_each_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_lchans_possible) {
if (lchan_state_is(lchan, LCHAN_ST_ESTABLISHED)
&& (lchan->type == GSM_LCHAN_TCH_F
|| lchan->type == GSM_LCHAN_TCH_H)) {
@ -6160,7 +6160,7 @@ static int lchan_act_trx(struct vty *vty, struct gsm_bts_trx *trx, int activate)
for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
ts = &trx->ts[ts_nr];
ts_for_each_potential_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_lchans_possible) {
switch (ts->pchan_on_init) {
case GSM_PCHAN_SDCCH8_SACCH8C:
case GSM_PCHAN_CCCH_SDCCH4_CBCH:

View File

@ -267,7 +267,7 @@ int trx_count_free_ts(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan)
if (ts->pchan_is != pchan)
continue;
ts_for_each_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_primary_lchans) {
if (lchan_state_is(lchan, LCHAN_ST_UNUSED))
count++;
}

View File

@ -73,15 +73,7 @@ void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts)
pl->total++;
}
/* Count allocated logical channels.
* Note: A GSM_PCHAN_TCH_F_TCH_H_PDCH can be switched
* to a single TCH/F or to two TCH/H. So when it's in
* the TCH/H mode, total number of available channels
* is 1 more than when it's in the TCH/F mode.
* I.e. "total" count will fluctuate depending on
* whether GSM_PCHAN_TCH_F_TCH_H_PDCH timeslot is
* in TCH/F or TCH/H (or in NONE/PDCH) mode. */
ts_for_each_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_primary_lchans) {
/* don't even count CBCH slots in total */
if (lchan->type == GSM_LCHAN_CBCH)
continue;

View File

@ -171,7 +171,7 @@ static unsigned int ts_usage_count(struct gsm_bts_trx_ts *ts)
{
struct gsm_lchan *lchan;
unsigned int count = 0;
ts_for_each_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_lchans_possible) {
if (lchan_state_is(lchan, LCHAN_ST_ESTABLISHED))
count++;
}

View File

@ -112,7 +112,7 @@ int bts_handover_count(struct gsm_bts *bts, int ho_scopes)
if (!nm_is_running(&ts->mo.nm_state))
continue;
ts_for_each_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_lchans_possible) {
if (!lchan->conn)
continue;
if (!lchan->conn->ho.fi)

View File

@ -65,6 +65,7 @@ _lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan,
}
for (j = start; j != stop; j += dir) {
int lchans_as_pchan;
ts = &trx->ts[j];
if (!ts_is_usable(ts))
continue;
@ -84,7 +85,8 @@ _lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan,
}
/* TS is (going to be) in desired pchan mode. Go ahead and check for an available lchan. */
ts_as_pchan_for_each_lchan(lchan, ts, as_pchan) {
lchans_as_pchan = pchan_subslots(as_pchan);
ts_for_n_lchans(lchan, ts, lchans_as_pchan) {
if (lchan->fi->state == LCHAN_ST_UNUSED) {
LOGPLCHANALLOC("%s ss=%d is available%s\n",
gsm_ts_and_pchan_name(ts), lchan->nr,

View File

@ -112,7 +112,7 @@ static int ts_count_active_lchans(struct gsm_bts_trx_ts *ts)
struct gsm_lchan *lchan;
int count = 0;
ts_for_each_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_lchans_possible) {
if (lchan->fi->state == LCHAN_ST_UNUSED)
continue;
count++;
@ -125,7 +125,7 @@ static void ts_lchans_dispatch(struct gsm_bts_trx_ts *ts, int lchan_state, uint3
{
struct gsm_lchan *lchan;
ts_for_each_potential_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_lchans_possible) {
if (lchan_state >= 0
&& !lchan_state_is(lchan, lchan_state))
continue;
@ -137,7 +137,7 @@ static void ts_terminate_lchan_fsms(struct gsm_bts_trx_ts *ts)
{
struct gsm_lchan *lchan;
ts_for_each_potential_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_lchans_possible) {
osmo_fsm_inst_term(lchan->fi, OSMO_FSM_TERM_REQUEST, NULL);
}
}
@ -146,7 +146,7 @@ static int ts_lchans_waiting(struct gsm_bts_trx_ts *ts)
{
struct gsm_lchan *lchan;
int count = 0;
ts_for_each_potential_lchan(lchan, ts)
ts_for_n_lchans(lchan, ts, ts->max_lchans_possible)
if (lchan->fi->state == LCHAN_ST_WAIT_TS_READY)
count++;
return count;
@ -565,7 +565,7 @@ static void ts_fsm_in_use_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
ts->pdch_act_allowed = true;
/* For static TS, check validity. For dyn TS, figure out which PCHAN this should become. */
ts_for_each_potential_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_lchans_possible) {
if (lchan_state_is(lchan, LCHAN_ST_UNUSED))
continue;
@ -952,7 +952,7 @@ static struct osmo_fsm ts_fsm = {
bool ts_is_lchan_waiting_for_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config *target_pchan)
{
struct gsm_lchan *lchan;
ts_for_each_potential_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_lchans_possible) {
if (lchan->fi->state == LCHAN_ST_WAIT_TS_READY) {
if (target_pchan)
*target_pchan = gsm_pchan_by_lchan_type(lchan->type);

View File

@ -463,7 +463,8 @@ static void lchan_clear(struct gsm_lchan *lchan)
static void ts_clear(struct gsm_bts_trx_ts *ts)
{
struct gsm_lchan *lchan;
ts_for_each_lchan(lchan, ts) {
ts_for_n_lchans(lchan, ts, ts->max_lchans_possible) {
if (lchan_state_is(lchan, LCHAN_ST_UNUSED))
continue;
lchan_clear(lchan);