diff options
-rw-r--r-- | include/osmocom/bsc/gsm_data.h | 3 | ||||
-rw-r--r-- | src/osmo-bsc/abis_rsl.c | 17 | ||||
-rw-r--r-- | src/osmo-bsc/assignment_fsm.c | 1 | ||||
-rw-r--r-- | src/osmo-bsc/gsm_data.c | 69 | ||||
-rw-r--r-- | src/osmo-bsc/timeslot_fsm.c | 27 |
5 files changed, 105 insertions, 12 deletions
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h index fc6ce3077..88adb9ff5 100644 --- a/include/osmocom/bsc/gsm_data.h +++ b/include/osmocom/bsc/gsm_data.h @@ -1041,8 +1041,11 @@ uint8_t gsm_ts_tsc(const struct gsm_bts_trx_ts *ts); enum gsm_phys_chan_config ts_pchan(struct gsm_bts_trx_ts *ts); uint8_t pchan_subslots(enum gsm_phys_chan_config pchan); +uint8_t pchan_subslots_vamos(enum gsm_phys_chan_config pchan); bool ts_is_tch(struct gsm_bts_trx_ts *ts); +struct gsm_lchan *gsm_lchan_vamos_to_primary(const struct gsm_lchan *lchan_vamos); +struct gsm_lchan *gsm_lchan_primary_to_vamos(const struct gsm_lchan *lchan_primary); struct gsm_bts *conn_get_bts(struct gsm_subscriber_connection *conn); diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c index c20693785..1f7b639fb 100644 --- a/src/osmo-bsc/abis_rsl.c +++ b/src/osmo-bsc/abis_rsl.c @@ -1708,10 +1708,11 @@ static bool force_free_lchan_for_emergency(struct chan_rqd *rqd) * This will take a short amount of time. We need to come back and check regulary to see if we managed to * free up another lchan. */ if (!rqd->release_lchan) { + struct gsm_lchan *release_lchan; /* Pick any busy TCH/F or TCH/H lchan and inititate a channel * release to make room for the incoming emergency call */ - rqd->release_lchan = get_any_lchan(rqd->bts); - if (!rqd->release_lchan) { + rqd->release_lchan = release_lchan = get_any_lchan(rqd->bts); + if (!release_lchan) { /* It can not happen that we first find out that there * is no TCH/H or TCH/F available and at the same time * we ware unable to find any busy TCH/H or TCH/F. In @@ -1724,10 +1725,16 @@ static bool force_free_lchan_for_emergency(struct chan_rqd *rqd) LOG_BTS(rqd->bts, DRSL, LOGL_NOTICE, "CHAN RQD/EMERGENCY-PRIORITY: inducing termination of lchan %s (state:%s) in favor of incoming EMERGENCY CALL!\n", - gsm_lchan_name(rqd->release_lchan), osmo_fsm_inst_state_name(rqd->release_lchan->fi)); + gsm_lchan_name(release_lchan), osmo_fsm_inst_state_name(release_lchan->fi)); + + lchan_release(release_lchan, !!(release_lchan->conn), true, 0, + gscon_last_eutran_plmn(release_lchan->conn)); - lchan_release(rqd->release_lchan, !!(rqd->release_lchan->conn), true, 0, - gscon_last_eutran_plmn(rqd->release_lchan->conn)); + /* Also release any overlapping VAMOS multiplexes on this lchan */ + release_lchan = gsm_lchan_primary_to_vamos(release_lchan); + if (release_lchan) + lchan_release(release_lchan, !!(release_lchan->conn), true, 0, + gscon_last_eutran_plmn(release_lchan->conn)); } else { /* BTS is shutting down, give up... */ if (rqd->release_lchan->ts->fi->state == TS_ST_NOT_INITIALIZED) diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c index 65cd8a825..b6de29310 100644 --- a/src/osmo-bsc/assignment_fsm.c +++ b/src/osmo-bsc/assignment_fsm.c @@ -640,6 +640,7 @@ static void assignment_fsm_wait_lchan_active_onenter(struct osmo_fsm_inst *fi, u .ta_known = true, .tsc_set = req->tsc_set, .tsc = req->tsc, + .vamos = conn->assignment.new_lchan->vamos.is_secondary, }; lchan_activate(conn->assignment.new_lchan, &activ_info); } diff --git a/src/osmo-bsc/gsm_data.c b/src/osmo-bsc/gsm_data.c index b33b1c39d..4d2d81181 100644 --- a/src/osmo-bsc/gsm_data.c +++ b/src/osmo-bsc/gsm_data.c @@ -337,8 +337,9 @@ char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts) char *gsm_lchan_name_compute(void *ctx, const struct gsm_lchan *lchan) { struct gsm_bts_trx_ts *ts = lchan->ts; - return talloc_asprintf(ctx, "(bts=%d,trx=%d,ts=%d,ss=%d)", - ts->trx->bts->nr, ts->trx->nr, ts->nr, lchan->nr); + return talloc_asprintf(ctx, "(bts=%d,trx=%d,ts=%d,ss=%d%s)", + ts->trx->bts->nr, ts->trx->nr, ts->nr, lchan->nr, + lchan->vamos.is_secondary ? "-VAMOS" : ""); } /* obtain the MO structure for a given object instance */ @@ -545,9 +546,13 @@ uint8_t gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan, uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan) { - /* Note: non-standard Osmocom style dyn TS PDCH mode chan_nr is only used within - * rsl_tx_dyn_ts_pdch_act_deact(). */ - return gsm_pchan2chan_nr(lchan->ts->pchan_is, lchan->ts->nr, lchan->nr); + uint8_t lchan_nr = lchan->nr; + /* The VAMOS lchans are behind the primary ones in the ts->lchan[] array. They keep their lchan->nr as in the + * array, but on the wire they are the "shadow" lchans for the primary lchans. For example, for TCH/F, there is + * a primary ts->lchan[0] and a VAMOS ts->lchan[1]. Still, the VAMOS lchan should send chan_nr = 0. */ + if (lchan->vamos.is_secondary) + lchan_nr -= lchan->ts->max_primary_lchans; + return gsm_pchan2chan_nr(lchan->ts->pchan_is, lchan->ts->nr, lchan_nr); } static const uint8_t subslots_per_pchan[] = { @@ -574,6 +579,30 @@ uint8_t pchan_subslots(enum gsm_phys_chan_config pchan) return subslots_per_pchan[pchan]; } +static const uint8_t subslots_per_pchan_vamos[] = { + [GSM_PCHAN_NONE] = 0, + [GSM_PCHAN_CCCH] = 0, + [GSM_PCHAN_PDCH] = 0, + [GSM_PCHAN_CCCH_SDCCH4] = 0, + /* VAMOS: on a TCH/F, there may be a TCH/H shadow */ + [GSM_PCHAN_TCH_F] = 2, + [GSM_PCHAN_TCH_H] = 2, + [GSM_PCHAN_SDCCH8_SACCH8C] = 0, + [GSM_PCHAN_CCCH_SDCCH4_CBCH] = 0, + [GSM_PCHAN_SDCCH8_SACCH8C_CBCH] = 0, + [GSM_PCHAN_TCH_F_TCH_H_PDCH] = 2, + [GSM_PCHAN_TCH_F_PDCH] = 2, +}; + +/* Return the maximum number of VAMOS secondary lchans that may be used in a timeslot of the given physical channel + * configuration. */ +uint8_t pchan_subslots_vamos(enum gsm_phys_chan_config pchan) +{ + if (pchan < 0 || pchan >= ARRAY_SIZE(subslots_per_pchan_vamos)) + return 0; + return subslots_per_pchan_vamos[pchan]; +} + static bool pchan_is_tch(enum gsm_phys_chan_config pchan) { switch (pchan) { @@ -590,6 +619,36 @@ bool ts_is_tch(struct gsm_bts_trx_ts *ts) return pchan_is_tch(ts->pchan_is); } +/* For a VAMOS secondary shadow lchan, return its primary lchan. If the lchan is not a secondary lchan, return NULL. */ +struct gsm_lchan *gsm_lchan_vamos_to_primary(const struct gsm_lchan *lchan_vamos) +{ + struct gsm_lchan *lchan_primary; + if (!lchan_vamos || !lchan_vamos->vamos.is_secondary) + return NULL; + /* OsmoBSC currently does not support mixed TCH/F + TCH/H VAMOS multiplexes. Hence the primary <-> secondary + * relation is a simple index shift in the lchan array. If mixed multiplexes were allowed, a TCH/F primary might + * have two TCH/H VAMOS secondary lchans, etc. Fortunately, we don't need to care about that. */ + lchan_primary = (struct gsm_lchan*)lchan_vamos - lchan_vamos->ts->max_primary_lchans; + if (!lchan_primary->fi) + return NULL; + return lchan_primary; +} + +/* For a primary lchan, return its VAMOS secondary shadow lchan. If the lchan is not a primary lchan, return NULL. */ +struct gsm_lchan *gsm_lchan_primary_to_vamos(const struct gsm_lchan *lchan_primary) +{ + struct gsm_lchan *lchan_vamos; + if (!lchan_primary || lchan_primary->vamos.is_secondary) + return NULL; + /* OsmoBSC currently does not support mixed TCH/F + TCH/H VAMOS multiplexes. Hence the primary <-> secondary + * relation is a simple index shift in the lchan array. If mixed multiplexes were allowed, a TCH/F primary might + * have two TCH/H VAMOS secondary lchans, etc. Fortunately, we don't need to care about that. */ + lchan_vamos = (struct gsm_lchan*)lchan_primary + lchan_primary->ts->max_primary_lchans; + if (!lchan_vamos->fi) + return NULL; + return lchan_vamos; +} + struct gsm_bts *conn_get_bts(struct gsm_subscriber_connection *conn) { if (!conn || !conn->lchan) return NULL; diff --git a/src/osmo-bsc/timeslot_fsm.c b/src/osmo-bsc/timeslot_fsm.c index 047097280..64b98a67d 100644 --- a/src/osmo-bsc/timeslot_fsm.c +++ b/src/osmo-bsc/timeslot_fsm.c @@ -189,22 +189,45 @@ static void ts_fsm_err_ready_to_go_in_pdch(struct osmo_fsm_inst *fi, struct gsm_ void ts_set_pchan_is(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pchan_is) { + int i; + struct gsm_lchan *lchan; ts->pchan_is = pchan_is; ts->max_primary_lchans = pchan_subslots(ts->pchan_is); LOG_TS(ts, LOGL_DEBUG, "pchan_is=%s max_primary_lchans=%d max_lchans_possible=%d\n", gsm_pchan_name(ts->pchan_is), ts->max_primary_lchans, ts->max_lchans_possible); + switch (ts->pchan_is) { + case GSM_PCHAN_TCH_F: + case GSM_PCHAN_TCH_H: + for (i = 0; i < ts->max_lchans_possible; i++) { + lchan = &ts->lchan[i]; + if (i < ts->max_primary_lchans) + lchan->vamos.is_secondary = false; + else + lchan->vamos.is_secondary = true; + } + break; + default: + ts_for_n_lchans(lchan, ts, ts->max_lchans_possible) + lchan->vamos.is_secondary = false; + break; + } } static void ts_setup_lchans(struct gsm_bts_trx_ts *ts) { int i, max_lchans; + int max_lchans_vamos; ts->pchan_on_init = ts->pchan_from_config; ts_fsm_update_id(ts); max_lchans = pchan_subslots(ts->pchan_on_init); - LOG_TS(ts, LOGL_DEBUG, "max lchans: %d\n", max_lchans); - ts->max_lchans_possible = max_lchans; + if (osmo_bts_has_feature(&ts->trx->bts->features, BTS_FEAT_VAMOS)) + max_lchans_vamos = pchan_subslots_vamos(ts->pchan_on_init); + else + max_lchans_vamos = 0; + LOG_TS(ts, LOGL_DEBUG, "max lchans: %d + %d VAMOS secondaries\n", max_lchans, max_lchans_vamos); + ts->max_lchans_possible = max_lchans + max_lchans_vamos; ts->max_primary_lchans = 0; for (i = 0; i < ts->max_lchans_possible; i++) { |