aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bsc/abis_om2000.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bsc/abis_om2000.c')
-rw-r--r--src/osmo-bsc/abis_om2000.c783
1 files changed, 480 insertions, 303 deletions
diff --git a/src/osmo-bsc/abis_om2000.c b/src/osmo-bsc/abis_om2000.c
index a3f689add..2a653bf97 100644
--- a/src/osmo-bsc/abis_om2000.c
+++ b/src/osmo-bsc/abis_om2000.c
@@ -44,9 +44,22 @@
#include <osmocom/bsc/abis_om2000.h>
#include <osmocom/bsc/signal.h>
#include <osmocom/bsc/timeslot_fsm.h>
+#include <osmocom/bsc/nm_common_fsm.h>
#include <osmocom/bsc/bts.h>
#include <osmocom/abis/e1_input.h>
+static inline void abis_om2000_fsm_transc_becomes_enabled(struct gsm_bts_trx *trx)
+{
+ nm_obj_fsm_becomes_enabled_disabled(trx->bts, trx, NM_OC_RADIO_CARRIER, true);
+ nm_obj_fsm_becomes_enabled_disabled(trx->bts, &trx->bb_transc, NM_OC_BASEB_TRANSC, true);
+}
+
+static inline void abis_om2000_fsm_transc_becomes_disabled(struct gsm_bts_trx *trx)
+{
+ nm_obj_fsm_becomes_enabled_disabled(trx->bts, trx, NM_OC_RADIO_CARRIER, false);
+ nm_obj_fsm_becomes_enabled_disabled(trx->bts, &trx->bb_transc, NM_OC_BASEB_TRANSC, false);
+}
+
/* FIXME: move to libosmocore */
struct osmo_fsm_inst *osmo_fsm_inst_alloc_child_id(struct osmo_fsm *fsm,
struct osmo_fsm_inst *parent,
@@ -310,6 +323,7 @@ enum abis_om2k_dei {
OM2K_DEI_MAX_ALLOWED_POWER = 0xa9,
OM2K_DEI_MAX_ALLOWED_NUM_TRXCS = 0xaa,
OM2K_DEI_MCTR_FEAT_STATUS_BMAP = 0xab,
+ OM2K_DEI_SEEN_UNKNOWN_D2 = 0xd2,
};
enum abis_om2k_mostate {
@@ -388,6 +402,7 @@ const struct tlv_definition om2k_att_tlvdef = {
[OM2K_DEI_FS_OFFSET] = { TLV_TYPE_FIXED, 5 },
[OM2K_DEI_EXT_COND_MAP_2_EXT] = { TLV_TYPE_FIXED, 4 },
[OM2K_DEI_TSS_MO_STATE] = { TLV_TYPE_FIXED, 4 },
+ [OM2K_DEI_SEEN_UNKNOWN_D2] = { TLV_TYPE_FIXED, 6 },
},
};
@@ -776,6 +791,9 @@ get_om2k_mo(struct gsm_bts *bts, const struct abis_om2k_mo *abis_mo)
struct gsm_bts_trx *trx;
switch (abis_mo->class) {
+ case OM2K_MO_CLS_DP:
+ mo = &bts->rbs2000.dp.om2k_mo;
+ break;
case OM2K_MO_CLS_CF:
mo = &bts->rbs2000.cf.om2k_mo;
break;
@@ -849,7 +867,7 @@ static int om2k_decode_msg(struct om2k_decoded_msg *odm, struct msgb *msg)
return abis_om2k_msg_tlv_parse(&odm->tp, o2h);
}
-static char *om2k_mo_name(const struct abis_om2k_mo *mo)
+const char *abis_om2k_mo_name(const struct abis_om2k_mo *mo)
{
static char mo_buf[64];
@@ -861,8 +879,7 @@ static char *om2k_mo_name(const struct abis_om2k_mo *mo)
}
/* resolve the gsm_nm_state data structure for a given MO */
-static struct gsm_nm_state *
-mo2nm_state(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
+static struct gsm_nm_state *mo2nm_state(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
{
struct gsm_bts_trx *trx;
struct gsm_nm_state *nm_state = NULL;
@@ -917,7 +934,7 @@ mo2nm_state(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
return nm_state;
}
-static void *mo2obj(struct gsm_bts *bts, struct abis_om2k_mo *mo)
+static void *mo2obj(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
{
struct gsm_bts_trx *trx;
@@ -945,17 +962,11 @@ static void *mo2obj(struct gsm_bts *bts, struct abis_om2k_mo *mo)
return NULL;
}
-static void update_mo_state(struct gsm_bts *bts, struct abis_om2k_mo *mo,
- uint8_t mo_state)
+/* Derive an OML Availability state from an OM2000 MO state */
+static enum abis_nm_avail_state abis_nm_av_state_from_om2k_av_state(struct abis_om2k_mo *mo, uint8_t mo_state)
{
- struct gsm_nm_state *nm_state = mo2nm_state(bts, mo);
- struct gsm_nm_state new_state;
- struct nm_statechg_signal_data nsd;
bool has_enabled_state;
- if (!nm_state)
- return;
-
switch (mo->class) {
case OM2K_MO_CLS_CF:
case OM2K_MO_CLS_TRXC:
@@ -966,61 +977,132 @@ static void update_mo_state(struct gsm_bts *bts, struct abis_om2k_mo *mo,
break;
}
- new_state = *nm_state;
switch (mo_state) {
case OM2K_MOSTATE_RESET:
- new_state.availability = NM_AVSTATE_POWER_OFF;
- break;
+ return NM_AVSTATE_POWER_OFF;
case OM2K_MOSTATE_STARTED:
- new_state.availability = has_enabled_state ? NM_AVSTATE_OFF_LINE : NM_AVSTATE_OK;
- break;
+ return has_enabled_state ? NM_AVSTATE_OFF_LINE : NM_AVSTATE_OK;
case OM2K_MOSTATE_ENABLED:
- new_state.availability = NM_AVSTATE_OK;
- break;
+ return NM_AVSTATE_OK;
case OM2K_MOSTATE_DISABLED:
- new_state.availability = NM_AVSTATE_POWER_OFF;
- break;
+ return NM_AVSTATE_POWER_OFF;
default:
- new_state.availability = NM_AVSTATE_DEGRADED;
- break;
+ return NM_AVSTATE_DEGRADED;
}
+}
+
+/* The OM2000 -> 12.21 mapping we do doesn't have a separate bb_transc MO,
+ * for compatibility reasons we pretend to have it anyway. */
+static void update_bb_trxc_mo_state(struct gsm_bts *bts, struct abis_om2k_mo *mo, uint8_t mo_state)
+{
+ struct nm_statechg_signal_data nsd;
+ struct gsm_bts_trx *trx;
+
+ trx = gsm_bts_trx_num(bts, mo->inst);
+ if (!trx)
+ return;
memset(&nsd, 0, sizeof(nsd));
nsd.bts = bts;
nsd.obj = mo2obj(bts, mo);
- nsd.old_state = nm_state;
- nsd.new_state = &new_state;
+ nsd.old_state = trx->bb_transc.mo.nm_state;
+ nsd.new_state = trx->bb_transc.mo.nm_state;
nsd.om2k_mo = mo;
- osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
-
- nm_state->availability = new_state.availability;
+ nsd.new_state.availability = abis_nm_av_state_from_om2k_av_state(mo, mo_state);
+ trx->bb_transc.mo.nm_state.availability = nsd.new_state.availability;
+ osmo_signal_dispatch(SS_NM, S_NM_STATECHG, &nsd);
}
-static void update_op_state(struct gsm_bts *bts, const struct abis_om2k_mo *mo,
- uint8_t op_state)
+static void update_mo_state(struct gsm_bts *bts, struct abis_om2k_mo *mo, uint8_t mo_state)
{
struct gsm_nm_state *nm_state = mo2nm_state(bts, mo);
- struct gsm_nm_state new_state;
+ struct nm_statechg_signal_data nsd;
if (!nm_state)
return;
- new_state = *nm_state;
+ memset(&nsd, 0, sizeof(nsd));
+
+ nsd.bts = bts;
+ nsd.obj = mo2obj(bts, mo);
+ nsd.old_state = *nm_state;
+ nsd.new_state = *nm_state;
+ nsd.om2k_mo = mo;
+
+ nsd.new_state.availability = abis_nm_av_state_from_om2k_av_state(mo, mo_state);
+
+ /* Update current state before emitting signal: */
+ nm_state->availability = nsd.new_state.availability;
+ osmo_signal_dispatch(SS_NM, S_NM_STATECHG, &nsd);
+
+ /* When the TRXC MO is updated, also update the BB TRXC accordingly. */
+ if (mo->class == OM2K_MO_CLS_TRXC)
+ update_bb_trxc_mo_state(bts, mo, mo_state);
+}
+
+/* Derive an OML Operational state from an OM2000 OP state */
+static enum abis_nm_op_state abis_nm_op_state_from_om2k_op_state(uint8_t op_state)
+{
switch (op_state) {
case 1:
- new_state.operational = NM_OPSTATE_ENABLED;
- break;
+ return NM_OPSTATE_ENABLED;
case 0:
- new_state.operational = NM_OPSTATE_DISABLED;
- break;
+ return NM_OPSTATE_DISABLED;
default:
- new_state.operational = NM_OPSTATE_NULL;
- break;
+ return NM_OPSTATE_NULL;
}
+}
+
+/* (see comment in update_bb_trxc_mo_state() above) */
+static void update_bb_trxc_op_state(struct gsm_bts *bts, const struct abis_om2k_mo *mo, uint8_t op_state)
+{
+ struct nm_statechg_signal_data nsd;
+ struct gsm_bts_trx *trx;
+
+ trx = gsm_bts_trx_num(bts, mo->inst);
+ if (!trx)
+ return;
+
+ memset(&nsd, 0, sizeof(nsd));
+
+ nsd.bts = bts;
+ nsd.obj = mo2obj(bts, mo);
+ nsd.old_state = trx->bb_transc.mo.nm_state;
+ nsd.new_state = trx->bb_transc.mo.nm_state;
+ nsd.om2k_mo = mo;
+
+ nsd.new_state.operational = abis_nm_op_state_from_om2k_op_state(op_state);
+ trx->bb_transc.mo.nm_state.operational = nsd.new_state.operational;
+ osmo_signal_dispatch(SS_NM, S_NM_STATECHG, &nsd);
+}
+
+static void update_op_state(struct gsm_bts *bts, const struct abis_om2k_mo *mo, uint8_t op_state)
+{
+ struct gsm_nm_state *nm_state = mo2nm_state(bts, mo);
+ struct nm_statechg_signal_data nsd;
- nm_state->operational = new_state.operational;
+ if (!nm_state)
+ return;
+
+ memset(&nsd, 0, sizeof(nsd));
+
+ nsd.bts = bts;
+ nsd.obj = mo2obj(bts, mo);
+ nsd.old_state = *nm_state;
+ nsd.new_state = *nm_state;
+ nsd.om2k_mo = mo;
+
+ nsd.new_state.operational = abis_nm_op_state_from_om2k_op_state(op_state);
+
+ /* Update current state before emitting signal: */
+ nm_state->operational = nsd.new_state.operational;
+ osmo_signal_dispatch(SS_NM, S_NM_STATECHG, &nsd);
+
+ /* When the TRXC MO is updated, also update the BB TRXC accordingly. */
+ if (mo->class == OM2K_MO_CLS_TRXC)
+ update_bb_trxc_op_state(bts, mo, op_state);
}
static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
@@ -1041,8 +1123,8 @@ static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
/* Route through per-TRX OML Link to the appropriate TRX */
trx = gsm_bts_trx_num(bts, o2h->mo.inst);
if (!trx) {
- LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to "
- "non-existing TRX\n", om2k_mo_name(&o2h->mo));
+ LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to non-existing TRX\n",
+ abis_om2k_mo_name(&o2h->mo));
return -ENODEV;
}
msg->dst = trx->oml_link;
@@ -1051,8 +1133,8 @@ static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
/* Route through per-TRX OML Link to the appropriate TRX */
trx = gsm_bts_trx_num(bts, o2h->mo.assoc_so);
if (!trx) {
- LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to "
- "non-existing TRX\n", om2k_mo_name(&o2h->mo));
+ LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to non-existing TRX\n",
+ abis_om2k_mo_name(&o2h->mo));
return -ENODEV;
}
msg->dst = trx->oml_link;
@@ -1066,8 +1148,7 @@ static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
return _abis_nm_sendmsg(msg);
}
-static void fill_om2k_hdr(struct abis_om2k_hdr *o2h, const struct abis_om2k_mo *mo,
- uint16_t msg_type)
+static void fill_om2k_hdr(struct abis_om2k_hdr *o2h, const struct abis_om2k_mo *mo, uint16_t msg_type)
{
o2h->om.mdisc = ABIS_OM_MDISC_FOM;
o2h->om.placement = ABIS_OM_PLACEMENT_ONLY;
@@ -1085,8 +1166,7 @@ static int abis_om2k_cal_time_resp(struct gsm_bts *bts)
struct tm *tm;
o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &bts->rbs2000.cf.om2k_mo.addr,
- OM2K_MSGT_CAL_TIME_RESP);
+ fill_om2k_hdr(o2k, &bts->rbs2000.cf.om2k_mo.addr, OM2K_MSGT_CAL_TIME_RESP);
tm_t = time(NULL);
tm = localtime(&tm_t);
@@ -1102,8 +1182,7 @@ static int abis_om2k_cal_time_resp(struct gsm_bts *bts)
return abis_om2k_sendmsg(bts, msg);
}
-static int abis_om2k_tx_simple(struct gsm_bts *bts, const struct abis_om2k_mo *mo,
- uint16_t msg_type)
+static int abis_om2k_tx_simple(struct gsm_bts *bts, const struct abis_om2k_mo *mo, uint16_t msg_type)
{
struct msgb *msg = om2k_msgb_alloc();
struct abis_om2k_hdr *o2k;
@@ -1111,8 +1190,7 @@ static int abis_om2k_tx_simple(struct gsm_bts *bts, const struct abis_om2k_mo *m
o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
fill_om2k_hdr(o2k, mo, msg_type);
- DEBUGP(DNM, "Tx MO=%s %s\n", om2k_mo_name(mo),
- get_value_string(om2k_msgcode_vals, msg_type));
+ DEBUGP(DNM, "Tx MO=%s %s\n", abis_om2k_mo_name(mo), get_value_string(om2k_msgcode_vals, msg_type));
return abis_om2k_sendmsg(bts, msg);
}
@@ -1157,8 +1235,7 @@ int abis_om2k_tx_disable_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_DISABLE_REQ);
}
-int abis_om2k_tx_op_info(struct gsm_bts *bts, const struct abis_om2k_mo *mo,
- uint8_t operational)
+int abis_om2k_tx_op_info(struct gsm_bts *bts, const struct abis_om2k_mo *mo, uint8_t operational)
{
struct msgb *msg = om2k_msgb_alloc();
struct abis_om2k_hdr *o2k;
@@ -1168,7 +1245,7 @@ int abis_om2k_tx_op_info(struct gsm_bts *bts, const struct abis_om2k_mo *mo,
msgb_tv_put(msg, OM2K_DEI_OP_INFO, operational);
- DEBUGP(DNM, "Tx MO=%s %s\n", om2k_mo_name(mo),
+ DEBUGP(DNM, "Tx MO=%s %s\n", abis_om2k_mo_name(mo),
get_value_string(om2k_msgcode_vals, OM2K_MSGT_OP_INFO));
/* we update the state here... and send the signal at ACK */
@@ -1228,19 +1305,16 @@ int abis_om2k_tx_is_conf_req(struct gsm_bts *bts)
om2k_fill_is_conn_grp(&cg[i++], grp->icp1, grp->icp2, grp->ci);
o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &bts->rbs2000.is.om2k_mo.addr,
- OM2K_MSGT_IS_CONF_REQ);
+ fill_om2k_hdr(o2k, &bts->rbs2000.is.om2k_mo.addr, OM2K_MSGT_IS_CONF_REQ);
msgb_tv_put(msg, OM2K_DEI_LIST_NR, 1);
msgb_tv_put(msg, OM2K_DEI_END_LIST_NR, 1);
- msgb_tlv_put(msg, OM2K_DEI_IS_CONN_LIST,
- num_grps * sizeof(*cg), (uint8_t *)cg);
+ msgb_tlv_put(msg, OM2K_DEI_IS_CONN_LIST, num_grps * sizeof(*cg), (uint8_t *)cg);
talloc_free(cg);
- DEBUGP(DNM, "Tx MO=%s %s\n",
- om2k_mo_name(&bts->rbs2000.is.om2k_mo.addr),
+ DEBUGP(DNM, "Tx MO=%s %s\n", abis_om2k_mo_name(&bts->rbs2000.is.om2k_mo.addr),
get_value_string(om2k_msgcode_vals, OM2K_MSGT_IS_CONF_REQ));
return abis_om2k_sendmsg(bts, msg);
@@ -1286,11 +1360,9 @@ int abis_om2k_tx_con_conf_req(struct gsm_bts *bts)
/* pre-pend the OM2K header */
o2k = (struct abis_om2k_hdr *) msgb_push(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &bts->rbs2000.con.om2k_mo.addr,
- OM2K_MSGT_CON_CONF_REQ);
+ fill_om2k_hdr(o2k, &bts->rbs2000.con.om2k_mo.addr, OM2K_MSGT_CON_CONF_REQ);
- DEBUGP(DNM, "Tx MO=%s %s\n",
- om2k_mo_name(&bts->rbs2000.con.om2k_mo.addr),
+ DEBUGP(DNM, "Tx MO=%s %s\n", abis_om2k_mo_name(&bts->rbs2000.con.om2k_mo.addr),
get_value_string(om2k_msgcode_vals, OM2K_MSGT_CON_CONF_REQ));
return abis_om2k_sendmsg(bts, msg);
@@ -1316,17 +1388,14 @@ int abis_om2k_tx_mctr_conf_req(struct gsm_bts *bts)
/* pre-pend the OM2K header */
o2k = (struct abis_om2k_hdr *) msgb_push(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &bts->rbs2000.mctr.om2k_mo.addr,
- OM2K_MSGT_MCTR_CONF_REQ);
- DEBUGP(DNM, "Tx MO=%s %s\n",
- om2k_mo_name(&bts->rbs2000.mctr.om2k_mo.addr),
+ fill_om2k_hdr(o2k, &bts->rbs2000.mctr.om2k_mo.addr, OM2K_MSGT_MCTR_CONF_REQ);
+ DEBUGP(DNM, "Tx MO=%s %s\n", abis_om2k_mo_name(&bts->rbs2000.mctr.om2k_mo.addr),
get_value_string(om2k_msgcode_vals, OM2K_MSGT_MCTR_CONF_REQ));
return abis_om2k_sendmsg(bts, msg);
}
-static void om2k_trx_to_mo(struct abis_om2k_mo *mo,
- const struct gsm_bts_trx *trx,
+static void om2k_trx_to_mo(struct abis_om2k_mo *mo, const struct gsm_bts_trx *trx,
enum abis_om2k_mo_cls cls)
{
mo->class = cls;
@@ -1335,8 +1404,7 @@ static void om2k_trx_to_mo(struct abis_om2k_mo *mo,
mo->assoc_so = 255;
}
-static void om2k_ts_to_mo(struct abis_om2k_mo *mo,
- const struct gsm_bts_trx_ts *ts)
+static void om2k_ts_to_mo(struct abis_om2k_mo *mo, const struct gsm_bts_trx_ts *ts)
{
mo->class = OM2K_MO_CLS_TS;
mo->bts = 0;
@@ -1358,7 +1426,7 @@ int abis_om2k_tx_rx_conf_req(struct gsm_bts_trx *trx)
/* OM2K_DEI_FREQ_SPEC_RX: Using trx_nr as "RX address" only works for single MCTR case */
msgb_tv16_put(msg, OM2K_DEI_FREQ_SPEC_RX, 0x8000 | ((uint16_t)trx->nr << 10));
- msgb_tv_put(msg, OM2K_DEI_RX_DIVERSITY, 0x02); /* A */
+ msgb_tv_put(msg, OM2K_DEI_RX_DIVERSITY, trx->rbs2000.rx_diversity);
return abis_om2k_sendmsg(trx->bts, msg);
}
@@ -1400,16 +1468,13 @@ int abis_om2k_tx_tf_conf_req(struct gsm_bts *bts)
struct abis_om2k_hdr *o2k;
o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &bts->rbs2000.tf.om2k_mo.addr,
- OM2K_MSGT_TF_CONF_REQ);
+ fill_om2k_hdr(o2k, &bts->rbs2000.tf.om2k_mo.addr, OM2K_MSGT_TF_CONF_REQ);
msgb_tv_put(msg, OM2K_DEI_TF_MODE, OM2K_TF_MODE_STANDALONE);
- msgb_tv_put(msg, OM2K_DEI_TF_SYNC_SRC, 0x00);
- msgb_tv_fixed_put(msg, OM2K_DEI_FS_OFFSET,
- sizeof(fs_offset_undef), fs_offset_undef);
+ msgb_tv_put(msg, OM2K_DEI_TF_SYNC_SRC, bts->rbs2000.sync_src);
+ msgb_tv_fixed_put(msg, OM2K_DEI_FS_OFFSET, sizeof(fs_offset_undef), fs_offset_undef);
- DEBUGP(DNM, "Tx MO=%s %s\n",
- om2k_mo_name(&bts->rbs2000.tf.om2k_mo.addr),
+ DEBUGP(DNM, "Tx MO=%s %s\n", abis_om2k_mo_name(&bts->rbs2000.tf.om2k_mo.addr),
get_value_string(om2k_msgcode_vals, OM2K_MSGT_TF_CONF_REQ));
return abis_om2k_sendmsg(bts, msg);
@@ -1428,7 +1493,7 @@ static uint8_t pchan2comb(enum gsm_phys_chan_config pchan)
case GSM_PCHAN_TCH_H:
case GSM_PCHAN_PDCH:
case GSM_PCHAN_TCH_F_PDCH:
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ case GSM_PCHAN_OSMO_DYN:
return 8;
default:
return 0;
@@ -1438,11 +1503,9 @@ static uint8_t pchan2comb(enum gsm_phys_chan_config pchan)
static uint8_t ts2comb(struct gsm_bts_trx_ts *ts)
{
if (ts->pchan_on_init == GSM_PCHAN_TCH_F_PDCH) {
- LOGP(DNM, LOGL_ERROR, "%s pchan %s not intended for use"
- " with OM2000, use %s instead\n",
- gsm_ts_and_pchan_name(ts),
- gsm_pchan_name(GSM_PCHAN_TCH_F_PDCH),
- gsm_pchan_name(GSM_PCHAN_TCH_F_TCH_H_PDCH));
+ LOGP(DNM, LOGL_ERROR, "%s pchan %s not intended for use with OM2000, use %s instead\n",
+ gsm_ts_and_pchan_name(ts), gsm_pchan_name(GSM_PCHAN_TCH_F_PDCH),
+ gsm_pchan_name(GSM_PCHAN_OSMO_DYN));
/* If we allowed initialization of TCH/F_PDCH, it would fail
* when we try to send the ip.access specific RSL PDCH Act
* message for it. Rather fail completely right now: */
@@ -1537,7 +1600,7 @@ int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts)
msgb_tv_put(msg, OM2K_DEI_HSN, ts->hopping.hsn);
msgb_tv_put(msg, OM2K_DEI_MAIO, ts->hopping.maio);
msgb_tv_put(msg, OM2K_DEI_BSIC, ts->trx->bts->bsic);
- msgb_tv_put(msg, OM2K_DEI_RX_DIVERSITY, 0x02); /* A */
+ msgb_tv_put(msg, OM2K_DEI_RX_DIVERSITY, ts->trx->rbs2000.rx_diversity);
msgb_tv16_put(msg, OM2K_DEI_FN_OFFSET, 0);
msgb_tv_put(msg, OM2K_DEI_EXT_RANGE, 0); /* Off */
/* Optional: Interference Rejection Combining */
@@ -1606,7 +1669,7 @@ int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts)
}
DEBUGP(DNM, "Tx MO=%s %s\n",
- om2k_mo_name(&mo),
+ abis_om2k_mo_name(&mo),
get_value_string(om2k_msgcode_vals, OM2K_MSGT_TS_CONF_REQ));
return abis_om2k_sendmsg(ts->trx->bts, msg);
@@ -1620,7 +1683,9 @@ int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts)
#define S(x) (1 << (x))
enum om2k_event_name {
+ OM2K_MO_EVT_RESET,
OM2K_MO_EVT_START,
+ OM2K_MO_EVT_CHILD_TERM,
OM2K_MO_EVT_RX_CONN_COMPL,
OM2K_MO_EVT_RX_RESET_COMPL,
OM2K_MO_EVT_RX_START_REQ_ACCEPT,
@@ -1633,7 +1698,9 @@ enum om2k_event_name {
};
static const struct value_string om2k_event_names[] = {
+ { OM2K_MO_EVT_RESET, "RESET" },
{ OM2K_MO_EVT_START, "START" },
+ { OM2K_MO_EVT_CHILD_TERM, "CHILD-TERM" },
{ OM2K_MO_EVT_RX_CONN_COMPL, "RX-CONN-COMPL" },
{ OM2K_MO_EVT_RX_RESET_COMPL, "RX-RESET-COMPL" },
{ OM2K_MO_EVT_RX_START_REQ_ACCEPT, "RX-RESET-REQ-ACCEPT" },
@@ -1665,6 +1732,7 @@ struct om2k_mo_fsm_priv {
struct gsm_bts_trx *trx;
struct om2k_mo *mo;
uint8_t ts_nr;
+ uint32_t done_event;
};
static void om2k_mo_st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -1676,20 +1744,17 @@ static void om2k_mo_st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data
switch (omfp->mo->addr.class) {
case OM2K_MO_CLS_CF:
/* no Connect required, is always connected */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_ACCEPT,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_ACCEPT, OM2K_TIMEOUT, 0);
abis_om2k_tx_start_req(omfp->trx->bts, &omfp->mo->addr);
break;
case OM2K_MO_CLS_TRXC:
/* no Connect required, start with Reset */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_RES_COMPL,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_RES_COMPL, OM2K_TIMEOUT, 0);
abis_om2k_tx_reset_cmd(omfp->trx->bts, &omfp->mo->addr);
break;
default:
/* start with Connect */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_CONN_COMPL,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_CONN_COMPL, OM2K_TIMEOUT, 0);
abis_om2k_tx_connect_cmd(omfp->trx->bts, &omfp->mo->addr);
break;
}
@@ -1703,14 +1768,12 @@ static void om2k_mo_st_wait_conn_compl(struct osmo_fsm_inst *fi, uint32_t event,
#if 0
case OM2K_MO_CLS_TF:
/* skip the reset, hope that helps */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_ACCEPT,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_ACCEPT, OM2K_TIMEOUT, 0);
abis_om2k_tx_start_req(omfp->trx->bts, &omfp->mo->addr);
break;
#endif
default:
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_RES_COMPL,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_RES_COMPL, OM2K_TIMEOUT, 0);
abis_om2k_tx_reset_cmd(omfp->trx->bts, &omfp->mo->addr);
break;
}
@@ -1720,8 +1783,7 @@ static void om2k_mo_st_wait_res_compl(struct osmo_fsm_inst *fi, uint32_t event,
{
struct om2k_mo_fsm_priv *omfp = fi->priv;
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_ACCEPT,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_ACCEPT, OM2K_TIMEOUT, 0);
abis_om2k_tx_start_req(omfp->trx->bts, &omfp->mo->addr);
}
@@ -1731,8 +1793,7 @@ static void om2k_mo_st_wait_start_accept(struct osmo_fsm_inst *fi, uint32_t even
switch (omd->msg_type) {
case OM2K_MSGT_START_REQ_ACK:
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_RES,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_RES, OM2K_TIMEOUT, 0);
break;
case OM2K_MSGT_START_REQ_REJ:
osmo_fsm_inst_state_chg(fi, OM2K_ST_ERROR, 0, 0);
@@ -1749,21 +1810,18 @@ static void om2k_mo_st_wait_start_res(struct osmo_fsm_inst *fi, uint32_t event,
case OM2K_MO_CLS_CF:
case OM2K_MO_CLS_TRXC:
/* Transition directly to Operational Info */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_OPINFO_ACCEPT,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_OPINFO_ACCEPT, OM2K_TIMEOUT, 0);
abis_om2k_tx_op_info(omfp->trx->bts, &omfp->mo->addr, 1);
return;
case OM2K_MO_CLS_DP:
/* Transition directory to WAIT_ENABLE_ACCEPT */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_ACCEPT,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_ACCEPT, OM2K_TIMEOUT, 0);
abis_om2k_tx_enable_req(omfp->trx->bts, &omfp->mo->addr);
return;
#if 0
case OM2K_MO_CLS_TF:
/* skip the config, hope that helps speeding things up */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_ACCEPT,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_ACCEPT, OM2K_TIMEOUT, 0);
abis_om2k_tx_enable_req(omfp->trx->bts, &omfp->mo->addr);
return;
#endif
@@ -1826,8 +1884,7 @@ static void om2k_mo_st_wait_cfg_res(struct osmo_fsm_inst *fi, uint32_t event, vo
return;
}
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_ACCEPT,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_ACCEPT, OM2K_TIMEOUT, 0);
abis_om2k_tx_enable_req(omfp->trx->bts, &omfp->mo->addr);
}
@@ -1841,11 +1898,9 @@ static void om2k_mo_st_wait_enable_accept(struct osmo_fsm_inst *fi, uint32_t eve
osmo_fsm_inst_state_chg(fi, OM2K_ST_ERROR, 0, 0);
break;
case OM2K_MSGT_ENABLE_REQ_ACK:
- if (omfp->mo->addr.class == OM2K_MO_CLS_IS &&
- omfp->trx->bts->rbs2000.use_superchannel)
+ if (omfp->mo->addr.class == OM2K_MO_CLS_IS && omfp->trx->bts->rbs2000.use_superchannel)
e1inp_ericsson_set_altc(omfp->trx->bts->oml_link->ts->line, 1);
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_RES,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_RES, OM2K_TIMEOUT, 0);
}
}
@@ -1855,8 +1910,7 @@ static void om2k_mo_st_wait_enable_res(struct osmo_fsm_inst *fi, uint32_t event,
//struct om2k_decoded_msg *omd = data;
/* TODO: check if state is actually enabled now? */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_OPINFO_ACCEPT,
- OM2K_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_OPINFO_ACCEPT, OM2K_TIMEOUT, 0);
abis_om2k_tx_op_info(omfp->trx->bts, &omfp->mo->addr, 1);
}
@@ -1868,8 +1922,9 @@ static void om2k_mo_st_wait_opinfo_accept(struct osmo_fsm_inst *fi, uint32_t eve
static void om2k_mo_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct om2k_mo_fsm_priv *omfp = fi->priv;
- omfp->mo->fsm = NULL;
- osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
+
+ if (fi->proc.parent)
+ osmo_fsm_inst_dispatch(fi->proc.parent, omfp->done_event, NULL);
}
static void om2k_mo_s_error_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
@@ -1880,11 +1935,24 @@ static void om2k_mo_s_error_onenter(struct osmo_fsm_inst *fi, uint32_t prev_stat
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
}
+static void om2k_mo_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch (event) {
+ case OM2K_MO_EVT_RESET:
+ osmo_fsm_inst_broadcast_children(fi, event, data);
+ osmo_fsm_inst_state_chg(fi, OM2K_ST_INIT, 0, 0);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
static const struct osmo_fsm_state om2k_is_states[] = {
[OM2K_ST_INIT] = {
.name = "INIT",
.in_event_mask = S(OM2K_MO_EVT_START),
.out_state_mask = S(OM2K_ST_DONE) |
+ S(OM2K_ST_INIT) |
S(OM2K_ST_ERROR) |
S(OM2K_ST_WAIT_CONN_COMPL) |
S(OM2K_ST_WAIT_START_ACCEPT) |
@@ -1895,6 +1963,7 @@ static const struct osmo_fsm_state om2k_is_states[] = {
.name = "WAIT-CONN-COMPL",
.in_event_mask = S(OM2K_MO_EVT_RX_CONN_COMPL),
.out_state_mask = S(OM2K_ST_DONE) |
+ S(OM2K_ST_INIT) |
S(OM2K_ST_ERROR) |
S(OM2K_ST_WAIT_START_ACCEPT) |
S(OM2K_ST_WAIT_RES_COMPL),
@@ -1904,6 +1973,7 @@ static const struct osmo_fsm_state om2k_is_states[] = {
.name = "WAIT-RES-COMPL",
.in_event_mask = S(OM2K_MO_EVT_RX_RESET_COMPL),
.out_state_mask = S(OM2K_ST_DONE) |
+ S(OM2K_ST_INIT) |
S(OM2K_ST_ERROR) |
S(OM2K_ST_WAIT_START_ACCEPT),
.action = om2k_mo_st_wait_res_compl,
@@ -1912,6 +1982,7 @@ static const struct osmo_fsm_state om2k_is_states[] = {
.name = "WAIT-START-ACCEPT",
.in_event_mask = S(OM2K_MO_EVT_RX_START_REQ_ACCEPT),
.out_state_mask = S(OM2K_ST_DONE) |
+ S(OM2K_ST_INIT) |
S(OM2K_ST_ERROR) |
S(OM2K_ST_WAIT_START_RES),
.action =om2k_mo_st_wait_start_accept,
@@ -1920,15 +1991,18 @@ static const struct osmo_fsm_state om2k_is_states[] = {
.name = "WAIT-START-RES",
.in_event_mask = S(OM2K_MO_EVT_RX_START_RES),
.out_state_mask = S(OM2K_ST_DONE) |
+ S(OM2K_ST_INIT) |
S(OM2K_ST_ERROR) |
S(OM2K_ST_WAIT_CFG_ACCEPT) |
- S(OM2K_ST_WAIT_OPINFO_ACCEPT),
+ S(OM2K_ST_WAIT_OPINFO_ACCEPT) |
+ S(OM2K_ST_WAIT_ENABLE_ACCEPT),
.action = om2k_mo_st_wait_start_res,
},
[OM2K_ST_WAIT_CFG_ACCEPT] = {
.name = "WAIT-CFG-ACCEPT",
.in_event_mask = S(OM2K_MO_EVT_RX_CFG_REQ_ACCEPT),
.out_state_mask = S(OM2K_ST_DONE) |
+ S(OM2K_ST_INIT) |
S(OM2K_ST_ERROR) |
S(OM2K_ST_WAIT_CFG_RES),
.action = om2k_mo_st_wait_cfg_accept,
@@ -1937,6 +2011,7 @@ static const struct osmo_fsm_state om2k_is_states[] = {
.name = "WAIT-CFG-RES",
.in_event_mask = S(OM2K_MO_EVT_RX_CFG_RES),
.out_state_mask = S(OM2K_ST_DONE) |
+ S(OM2K_ST_INIT) |
S(OM2K_ST_ERROR) |
S(OM2K_ST_WAIT_ENABLE_ACCEPT),
.action = om2k_mo_st_wait_cfg_res,
@@ -1945,6 +2020,7 @@ static const struct osmo_fsm_state om2k_is_states[] = {
.name = "WAIT-ENABLE-ACCEPT",
.in_event_mask = S(OM2K_MO_EVT_RX_ENA_REQ_ACCEPT),
.out_state_mask = S(OM2K_ST_DONE) |
+ S(OM2K_ST_INIT) |
S(OM2K_ST_ERROR) |
S(OM2K_ST_WAIT_ENABLE_RES),
.action = om2k_mo_st_wait_enable_accept,
@@ -1953,6 +2029,7 @@ static const struct osmo_fsm_state om2k_is_states[] = {
.name = "WAIT-ENABLE-RES",
.in_event_mask = S(OM2K_MO_EVT_RX_ENA_RES),
.out_state_mask = S(OM2K_ST_DONE) |
+ S(OM2K_ST_INIT) |
S(OM2K_ST_ERROR) |
S(OM2K_ST_WAIT_OPINFO_ACCEPT),
.action = om2k_mo_st_wait_enable_res,
@@ -1961,19 +2038,20 @@ static const struct osmo_fsm_state om2k_is_states[] = {
.name = "WAIT-OPINFO-ACCEPT",
.in_event_mask = S(OM2K_MO_EVT_RX_OPINFO_ACC),
.out_state_mask = S(OM2K_ST_DONE) |
+ S(OM2K_ST_INIT) |
S(OM2K_ST_ERROR),
.action = om2k_mo_st_wait_opinfo_accept,
},
[OM2K_ST_DONE] = {
.name = "DONE",
.in_event_mask = 0,
- .out_state_mask = 0,
+ .out_state_mask = S(OM2K_ST_INIT),
.onenter = om2k_mo_s_done_onenter,
},
[OM2K_ST_ERROR] = {
.name = "ERROR",
.in_event_mask = 0,
- .out_state_mask = 0,
+ .out_state_mask = S(OM2K_ST_INIT),
.onenter = om2k_mo_s_error_onenter,
},
@@ -1990,13 +2068,14 @@ static struct osmo_fsm om2k_mo_fsm = {
.states = om2k_is_states,
.num_states = ARRAY_SIZE(om2k_is_states),
.log_subsys = DNM,
+ .allstate_event_mask = S(OM2K_MO_EVT_RESET),
+ .allstate_action = om2k_mo_allstate,
.event_names = om2k_event_names,
.timer_cb = om2k_mo_timer_cb,
};
-struct osmo_fsm_inst *om2k_mo_fsm_start(struct osmo_fsm_inst *parent,
- uint32_t term_event,
- struct gsm_bts_trx *trx, struct om2k_mo *mo)
+static struct osmo_fsm_inst *om2k_mo_fsm_alloc(struct osmo_fsm_inst *parent, uint32_t done_event,
+ struct gsm_bts_trx *trx, struct om2k_mo *mo)
{
struct osmo_fsm_inst *fi;
struct om2k_mo_fsm_priv *omfp;
@@ -2006,8 +2085,7 @@ struct osmo_fsm_inst *om2k_mo_fsm_start(struct osmo_fsm_inst *parent,
get_value_string(om2k_mo_class_short_vals, mo->addr.class),
mo->addr.bts, mo->addr.assoc_so, mo->addr.inst);
- fi = osmo_fsm_inst_alloc_child_id(&om2k_mo_fsm, parent,
- term_event, idbuf);
+ fi = osmo_fsm_inst_alloc_child_id(&om2k_mo_fsm, parent, OM2K_MO_EVT_CHILD_TERM, idbuf);
if (!fi)
return NULL;
@@ -2015,38 +2093,38 @@ struct osmo_fsm_inst *om2k_mo_fsm_start(struct osmo_fsm_inst *parent,
omfp = talloc_zero(fi, struct om2k_mo_fsm_priv);
omfp->mo = mo;
omfp->trx = trx;
+ omfp->done_event = done_event;
fi->priv = omfp;
- osmo_fsm_inst_dispatch(fi, OM2K_MO_EVT_START, NULL);
-
return fi;
}
+static void om2k_mo_fsm_start(struct om2k_mo *mo)
+{
+ osmo_fsm_inst_dispatch(mo->fsm, OM2K_MO_EVT_START, NULL);
+}
+
int om2k_mo_fsm_recvmsg(struct gsm_bts *bts, struct om2k_mo *mo,
struct om2k_decoded_msg *odm)
{
switch (odm->msg_type) {
case OM2K_MSGT_CONNECT_COMPL:
case OM2K_MSGT_CONNECT_REJ:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_CONN_COMPL, odm);
+ osmo_fsm_inst_dispatch(mo->fsm, OM2K_MO_EVT_RX_CONN_COMPL, odm);
break;
case OM2K_MSGT_RESET_COMPL:
case OM2K_MSGT_RESET_REJ:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_RESET_COMPL, odm);
+ osmo_fsm_inst_dispatch(mo->fsm, OM2K_MO_EVT_RX_RESET_COMPL, odm);
break;
case OM2K_MSGT_START_REQ_ACK:
case OM2K_MSGT_START_REQ_REJ:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_START_REQ_ACCEPT, odm);
+ osmo_fsm_inst_dispatch(mo->fsm, OM2K_MO_EVT_RX_START_REQ_ACCEPT, odm);
break;
case OM2K_MSGT_START_RES:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_START_RES, odm);
+ osmo_fsm_inst_dispatch(mo->fsm, OM2K_MO_EVT_RX_START_RES, odm);
break;
case OM2K_MSGT_CON_CONF_REQ_ACK:
@@ -2056,8 +2134,7 @@ int om2k_mo_fsm_recvmsg(struct gsm_bts *bts, struct om2k_mo *mo,
case OM2K_MSGT_TF_CONF_REQ_ACK:
case OM2K_MSGT_TS_CONF_REQ_ACK:
case OM2K_MSGT_TX_CONF_REQ_ACK:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_CFG_REQ_ACCEPT, odm);
+ osmo_fsm_inst_dispatch(mo->fsm, OM2K_MO_EVT_RX_CFG_REQ_ACCEPT, odm);
break;
case OM2K_MSGT_CON_CONF_RES:
@@ -2067,24 +2144,20 @@ int om2k_mo_fsm_recvmsg(struct gsm_bts *bts, struct om2k_mo *mo,
case OM2K_MSGT_TF_CONF_RES:
case OM2K_MSGT_TS_CONF_RES:
case OM2K_MSGT_TX_CONF_RES:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_CFG_RES, odm);
+ osmo_fsm_inst_dispatch(mo->fsm, OM2K_MO_EVT_RX_CFG_RES, odm);
break;
case OM2K_MSGT_ENABLE_REQ_ACK:
case OM2K_MSGT_ENABLE_REQ_REJ:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_ENA_REQ_ACCEPT, odm);
+ osmo_fsm_inst_dispatch(mo->fsm, OM2K_MO_EVT_RX_ENA_REQ_ACCEPT, odm);
break;
case OM2K_MSGT_ENABLE_RES:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_ENA_RES, odm);
+ osmo_fsm_inst_dispatch(mo->fsm, OM2K_MO_EVT_RX_ENA_RES, odm);
break;
case OM2K_MSGT_OP_INFO_ACK:
case OM2K_MSGT_OP_INFO_REJ:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_OPINFO_ACC, odm);
+ osmo_fsm_inst_dispatch(mo->fsm, OM2K_MO_EVT_RX_OPINFO_ACC, odm);
break;
default:
return -1;
@@ -2098,7 +2171,9 @@ int om2k_mo_fsm_recvmsg(struct gsm_bts *bts, struct om2k_mo *mo,
***********************************************************************/
enum om2k_trx_event {
- OM2K_TRX_EVT_START,
+ OM2K_TRX_EVT_RESET = OM2K_MO_EVT_RESET,
+ OM2K_TRX_EVT_START = OM2K_MO_EVT_START,
+ OM2K_TRX_EVT_CHILD_TERM = OM2K_MO_EVT_CHILD_TERM,
OM2K_TRX_EVT_TRXC_DONE,
OM2K_TRX_EVT_TX_DONE,
OM2K_TRX_EVT_RX_DONE,
@@ -2107,7 +2182,9 @@ enum om2k_trx_event {
};
static struct value_string om2k_trx_events[] = {
+ { OM2K_TRX_EVT_RESET, "RESET" },
{ OM2K_TRX_EVT_START, "START" },
+ { OM2K_TRX_EVT_CHILD_TERM, "CHILD-TERM" },
{ OM2K_TRX_EVT_TRXC_DONE, "TRXC-DONE" },
{ OM2K_TRX_EVT_TX_DONE, "TX-DONE" },
{ OM2K_TRX_EVT_RX_DONE, "RX-DONE" },
@@ -2130,6 +2207,7 @@ enum om2k_trx_state {
struct om2k_trx_fsm_priv {
struct gsm_bts_trx *trx;
uint8_t cur_ts_nr;
+ uint32_t done_event;
};
static void om2k_trx_s_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -2137,10 +2215,8 @@ static void om2k_trx_s_init(struct osmo_fsm_inst *fi, uint32_t event, void *data
struct om2k_trx_fsm_priv *otfp = fi->priv;
/* First initialize TRXC */
- osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TRXC,
- TRX_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TRXC_DONE, otfp->trx,
- &otfp->trx->rbs2000.trxc.om2k_mo);
+ osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TRXC, TRX_FSM_TIMEOUT, 0);
+ om2k_mo_fsm_start(&otfp->trx->rbs2000.trxc.om2k_mo);
}
static void om2k_trx_s_wait_trxc(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -2148,10 +2224,8 @@ static void om2k_trx_s_wait_trxc(struct osmo_fsm_inst *fi, uint32_t event, void
struct om2k_trx_fsm_priv *otfp = fi->priv;
/* Initialize TX after TRXC */
- osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TX,
- TRX_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TX_DONE, otfp->trx,
- &otfp->trx->rbs2000.tx.om2k_mo);
+ osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TX, TRX_FSM_TIMEOUT, 0);
+ om2k_mo_fsm_start(&otfp->trx->rbs2000.tx.om2k_mo);
}
static void om2k_trx_s_wait_tx(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -2159,10 +2233,8 @@ static void om2k_trx_s_wait_tx(struct osmo_fsm_inst *fi, uint32_t event, void *d
struct om2k_trx_fsm_priv *otfp = fi->priv;
/* Initialize RX after TX */
- osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_RX,
- TRX_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_TRX_EVT_RX_DONE, otfp->trx,
- &otfp->trx->rbs2000.rx.om2k_mo);
+ osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_RX, TRX_FSM_TIMEOUT, 0);
+ om2k_mo_fsm_start(&otfp->trx->rbs2000.rx.om2k_mo);
}
static void om2k_trx_s_wait_rx(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -2171,12 +2243,10 @@ static void om2k_trx_s_wait_rx(struct osmo_fsm_inst *fi, uint32_t event, void *d
struct gsm_bts_trx_ts *ts;
/* Initialize Timeslots after TX */
- osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TS,
- TRX_FSM_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TS, TRX_FSM_TIMEOUT, 0);
otfp->cur_ts_nr = 0;
ts = &otfp->trx->ts[otfp->cur_ts_nr];
- om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TS_DONE, otfp->trx,
- &ts->rbs2000.om2k_mo);
+ om2k_mo_fsm_start(&ts->rbs2000.om2k_mo);
}
static void om2k_trx_s_wait_ts(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -2184,16 +2254,11 @@ static void om2k_trx_s_wait_ts(struct osmo_fsm_inst *fi, uint32_t event, void *d
struct om2k_trx_fsm_priv *otfp = fi->priv;
struct gsm_bts_trx_ts *ts;
- /* notify TS is ready */
- ts = &otfp->trx->ts[otfp->cur_ts_nr];
- osmo_fsm_inst_dispatch(ts->fi, TS_EV_OML_READY, NULL);
-
/* next ? */
if (++otfp->cur_ts_nr < 8) {
/* iterate to the next timeslot */
ts = &otfp->trx->ts[otfp->cur_ts_nr];
- om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TS_DONE, otfp->trx,
- &ts->rbs2000.om2k_mo);
+ om2k_mo_fsm_start(&ts->rbs2000.om2k_mo);
} else {
/* only after all 8 TS */
osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_SEND_SI, 0, 0);
@@ -2212,55 +2277,117 @@ static void om2k_trx_s_send_si(struct osmo_fsm_inst *fi, uint32_t prev_state)
static void om2k_trx_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
- osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
+ struct om2k_trx_fsm_priv *otfp = fi->priv;
+ struct nm_statechg_signal_data nsd;
+ struct nm_statechg_signal_data nsd_bb_transc;
+ struct gsm_bts_trx *trx = otfp->trx;
+ unsigned int i;
+
+ memset(&nsd, 0, sizeof(nsd));
+
+ nsd.bts = trx->bts;
+ nsd.obj = trx;
+ nsd.old_state = trx->mo.nm_state;
+ nsd.new_state = trx->mo.nm_state;
+ nsd.om2k_mo = &trx->rbs2000.trxc.om2k_mo.addr;
+
+ /* See e1_config:bts_isdn_sign_link() / OS#4914 */
+ nsd.new_state.administrative = NM_STATE_UNLOCKED;
+ trx->mo.nm_state.administrative = nsd.new_state.administrative;
+ osmo_signal_dispatch(SS_NM, S_NM_STATECHG, &nsd);
+
+ /* The OM2000 -> 12.21 mapping we do doesn't have separate bb_transc MO,
+ * for compatibility reasons we pretend to have it anyway and mirror the
+ * mo state of the TRXC on it. */
+ memset(&nsd_bb_transc, 0, sizeof(nsd));
+ nsd_bb_transc.bts = trx->bts;
+ nsd_bb_transc.obj = &trx->bb_transc;
+ nsd_bb_transc.old_state = trx->bb_transc.mo.nm_state;
+ nsd_bb_transc.new_state = trx->bb_transc.mo.nm_state;
+ nsd_bb_transc.om2k_mo = &trx->rbs2000.trxc.om2k_mo.addr;
+ nsd_bb_transc.new_state.administrative = NM_STATE_UNLOCKED;
+ trx->bb_transc.mo.nm_state.administrative = nsd_bb_transc.new_state.administrative;
+ osmo_signal_dispatch(SS_NM, S_NM_STATECHG, &nsd_bb_transc);
+
+ abis_om2000_fsm_transc_becomes_enabled(trx);
+
+ if (fi->proc.parent)
+ osmo_fsm_inst_dispatch(fi->proc.parent, otfp->done_event, NULL);
+
+ /* Notify the timeslot FSM that all TRX initialization steps are done. */
+ for (i = 0; i < ARRAY_SIZE(trx->ts); i++)
+ osmo_fsm_inst_dispatch(trx->ts[i].fi, TS_EV_OML_READY, NULL);
+}
+
+static void om2k_trx_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct om2k_trx_fsm_priv *otfp = fi->priv;
+
+ switch (event) {
+ case OM2K_TRX_EVT_RESET:
+ abis_om2000_fsm_transc_becomes_disabled(otfp->trx);
+ osmo_fsm_inst_broadcast_children(fi, event, data);
+ osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_INIT, 0, 0);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
}
static const struct osmo_fsm_state om2k_trx_states[] = {
[OM2K_TRX_S_INIT] = {
.in_event_mask = S(OM2K_TRX_EVT_START),
- .out_state_mask = S(OM2K_TRX_S_WAIT_TRXC),
+ .out_state_mask = S(OM2K_TRX_S_WAIT_TRXC) |
+ S(OM2K_TRX_S_INIT),
.name = "INIT",
.action = om2k_trx_s_init,
},
[OM2K_TRX_S_WAIT_TRXC] = {
.in_event_mask = S(OM2K_TRX_EVT_TRXC_DONE),
.out_state_mask = S(OM2K_TRX_S_ERROR) |
- S(OM2K_TRX_S_WAIT_TX),
+ S(OM2K_TRX_S_WAIT_TX) |
+ S(OM2K_TRX_S_INIT),
.name = "WAIT-TRXC",
.action = om2k_trx_s_wait_trxc,
},
[OM2K_TRX_S_WAIT_TX] = {
.in_event_mask = S(OM2K_TRX_EVT_TX_DONE),
.out_state_mask = S(OM2K_TRX_S_ERROR) |
- S(OM2K_TRX_S_WAIT_RX),
+ S(OM2K_TRX_S_WAIT_RX) |
+ S(OM2K_TRX_S_INIT),
.name = "WAIT-TX",
.action = om2k_trx_s_wait_tx,
},
[OM2K_TRX_S_WAIT_RX] = {
.in_event_mask = S(OM2K_TRX_EVT_RX_DONE),
.out_state_mask = S(OM2K_TRX_S_ERROR) |
- S(OM2K_TRX_S_WAIT_TS),
+ S(OM2K_TRX_S_WAIT_TS) |
+ S(OM2K_TRX_S_INIT),
.name = "WAIT-RX",
.action = om2k_trx_s_wait_rx,
},
[OM2K_TRX_S_WAIT_TS] = {
.in_event_mask = S(OM2K_TRX_EVT_TS_DONE),
.out_state_mask = S(OM2K_TRX_S_ERROR) |
- S(OM2K_TRX_S_SEND_SI),
+ S(OM2K_TRX_S_SEND_SI) |
+ S(OM2K_TRX_S_INIT),
.name = "WAIT-TS",
.action = om2k_trx_s_wait_ts,
},
[OM2K_TRX_S_SEND_SI] = {
.out_state_mask = S(OM2K_TRX_S_ERROR) |
- S(OM2K_TRX_S_DONE),
+ S(OM2K_TRX_S_DONE) |
+ S(OM2K_TRX_S_INIT),
.name = "SEND-SI",
.onenter = om2k_trx_s_send_si,
},
[OM2K_TRX_S_DONE] = {
+ .out_state_mask = S(OM2K_TRX_S_INIT),
.name = "DONE",
.onenter = om2k_trx_s_done_onenter,
},
[OM2K_TRX_S_ERROR] = {
+ .out_state_mask = S(OM2K_TRX_S_INIT),
.name = "ERROR",
},
};
@@ -2276,41 +2403,68 @@ static struct osmo_fsm om2k_trx_fsm = {
.states = om2k_trx_states,
.num_states = ARRAY_SIZE(om2k_trx_states),
.log_subsys = DNM,
+ .allstate_event_mask = S(OM2K_TRX_EVT_RESET),
+ .allstate_action = om2k_trx_allstate,
.event_names = om2k_trx_events,
.timer_cb = om2k_trx_timer_cb,
};
-struct osmo_fsm_inst *om2k_trx_fsm_start(struct osmo_fsm_inst *parent,
- struct gsm_bts_trx *trx,
- uint32_t term_event)
+static struct osmo_fsm_inst *om2k_trx_fsm_alloc(struct osmo_fsm_inst *parent,
+ struct gsm_bts_trx *trx, uint32_t done_event)
{
struct osmo_fsm_inst *fi;
struct om2k_trx_fsm_priv *otfp;
char idbuf[32];
+ OSMO_ASSERT(!trx->rbs2000.trx_fi);
+
snprintf(idbuf, sizeof(idbuf), "%u-%u", trx->bts->nr, trx->nr);
- fi = osmo_fsm_inst_alloc_child_id(&om2k_trx_fsm, parent, term_event,
- idbuf);
+ fi = osmo_fsm_inst_alloc_child_id(&om2k_trx_fsm, parent, OM2K_MO_EVT_CHILD_TERM, idbuf);
if (!fi)
return NULL;
otfp = talloc_zero(fi, struct om2k_trx_fsm_priv);
otfp->trx = trx;
+ otfp->done_event = done_event;
fi->priv = otfp;
- osmo_fsm_inst_dispatch(fi, OM2K_TRX_EVT_START, NULL);
-
return fi;
}
+void om2k_trx_fsm_start(struct gsm_bts_trx *trx)
+{
+ struct osmo_fsm_inst *bts_fi = trx->bts->rbs2000.bts_fi;
+ OSMO_ASSERT(trx->rbs2000.trx_fi);
+
+ /* suppress if BTS is not yet brought up */
+ if (bts_fi->state == OM2K_BTS_S_DONE || bts_fi->state == OM2K_BTS_S_WAIT_TRX)
+ return;
+
+ osmo_fsm_inst_dispatch(trx->rbs2000.trx_fi, OM2K_TRX_EVT_START, NULL);
+}
+
+void om2k_trx_fsm_reset(struct gsm_bts_trx *trx)
+{
+ struct osmo_fsm_inst *bts_fi = trx->bts->rbs2000.bts_fi;
+ OSMO_ASSERT(trx->rbs2000.trx_fi);
+ OSMO_ASSERT(trx->rbs2000.trx_fi);
+
+ /* suppress if BTS is not yet brought up */
+ if (bts_fi->state == OM2K_BTS_S_DONE || bts_fi->state == OM2K_BTS_S_WAIT_TRX)
+ return;
+
+ osmo_fsm_inst_dispatch(trx->rbs2000.trx_fi, OM2K_TRX_EVT_RESET, NULL);
+}
/***********************************************************************
* OM2000 BTS Finite State Machine, initializes CF and all siblings
***********************************************************************/
enum om2k_bts_event {
- OM2K_BTS_EVT_START,
+ OM2K_BTS_EVT_RESET = OM2K_MO_EVT_RESET,
+ OM2K_BTS_EVT_START = OM2K_MO_EVT_START,
+ OM2K_BTS_EVT_CHILD_TERM = OM2K_MO_EVT_CHILD_TERM,
OM2K_BTS_EVT_CF_DONE,
OM2K_BTS_EVT_IS_DONE,
OM2K_BTS_EVT_CON_DONE,
@@ -2318,11 +2472,14 @@ enum om2k_bts_event {
OM2K_BTS_EVT_MCTR_DONE,
OM2K_BTS_EVT_TRX_LAPD_UP,
OM2K_BTS_EVT_TRX_DONE,
+ OM2K_BTS_EVT_TRX_TERM,
OM2K_BTS_EVT_STOP,
};
static const struct value_string om2k_bts_events[] = {
+ { OM2K_BTS_EVT_RESET, "RESET" },
{ OM2K_BTS_EVT_START, "START" },
+ { OM2K_BTS_EVT_CHILD_TERM, "CHILD-TERM" },
{ OM2K_BTS_EVT_CF_DONE, "CF-DONE" },
{ OM2K_BTS_EVT_IS_DONE, "IS-DONE" },
{ OM2K_BTS_EVT_CON_DONE, "CON-DONE" },
@@ -2334,19 +2491,6 @@ static const struct value_string om2k_bts_events[] = {
{ 0, NULL }
};
-enum om2k_bts_state {
- OM2K_BTS_S_INIT,
- OM2K_BTS_S_WAIT_CF,
- OM2K_BTS_S_WAIT_IS,
- OM2K_BTS_S_WAIT_CON,
- OM2K_BTS_S_WAIT_TF,
- OM2K_BTS_S_WAIT_MCTR,
- OM2K_BTS_S_WAIT_TRX_LAPD,
- OM2K_BTS_S_WAIT_TRX,
- OM2K_BTS_S_DONE,
- OM2K_BTS_S_ERROR,
-};
-
struct om2k_bts_fsm_priv {
struct gsm_bts *bts;
uint8_t next_trx_nr;
@@ -2358,10 +2502,8 @@ static void om2k_bts_s_init(struct osmo_fsm_inst *fi, uint32_t event, void *data
struct gsm_bts *bts = obfp->bts;
OSMO_ASSERT(event == OM2K_BTS_EVT_START);
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_CF,
- BTS_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_BTS_EVT_CF_DONE, bts->c0,
- &bts->rbs2000.cf.om2k_mo);
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_CF, BTS_FSM_TIMEOUT, 0);
+ om2k_mo_fsm_start(&bts->rbs2000.cf.om2k_mo);
}
static void om2k_bts_s_wait_cf(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -2372,8 +2514,7 @@ static void om2k_bts_s_wait_cf(struct osmo_fsm_inst *fi, uint32_t event, void *d
OSMO_ASSERT(event == OM2K_BTS_EVT_CF_DONE);
/* TF can take a long time to initialize, wait for 10min */
osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TF, 600, 0);
- om2k_mo_fsm_start(fi, OM2K_BTS_EVT_TF_DONE, bts->c0,
- &bts->rbs2000.tf.om2k_mo);
+ om2k_mo_fsm_start(&bts->rbs2000.tf.om2k_mo);
}
static void om2k_bts_s_wait_tf(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -2383,10 +2524,14 @@ static void om2k_bts_s_wait_tf(struct osmo_fsm_inst *fi, uint32_t event, void *d
OSMO_ASSERT(event == OM2K_BTS_EVT_TF_DONE);
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_CON,
- BTS_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_BTS_EVT_CON_DONE, bts->c0,
- &bts->rbs2000.con.om2k_mo);
+ if (!llist_count(&bts->rbs2000.con.conn_groups)) {
+ /* skip CON object if we have no configuration for it */
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_IS, BTS_FSM_TIMEOUT, 0);
+ om2k_mo_fsm_start(&bts->rbs2000.is.om2k_mo);
+ } else {
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_CON, BTS_FSM_TIMEOUT, 0);
+ om2k_mo_fsm_start(&bts->rbs2000.con.om2k_mo);
+ }
}
static void om2k_bts_s_wait_con(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -2396,10 +2541,8 @@ static void om2k_bts_s_wait_con(struct osmo_fsm_inst *fi, uint32_t event, void *
OSMO_ASSERT(event == OM2K_BTS_EVT_CON_DONE);
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_IS,
- BTS_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_BTS_EVT_IS_DONE, bts->c0,
- &bts->rbs2000.is.om2k_mo);
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_IS, BTS_FSM_TIMEOUT, 0);
+ om2k_mo_fsm_start(&bts->rbs2000.is.om2k_mo);
}
static void om2k_bts_s_wait_is(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -2411,13 +2554,10 @@ static void om2k_bts_s_wait_is(struct osmo_fsm_inst *fi, uint32_t event, void *d
/* If we're running OML >= G12R13, start MCTR, else skip directly to TRX */
if (bts->rbs2000.om2k_version[0].active >= 0x0c0d) {
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_MCTR,
- BTS_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_BTS_EVT_MCTR_DONE, bts->c0,
- &bts->rbs2000.mctr.om2k_mo);
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_MCTR, BTS_FSM_TIMEOUT, 0);
+ om2k_mo_fsm_start(&bts->rbs2000.mctr.om2k_mo);
} else {
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX_LAPD,
- TRX_LAPD_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX_LAPD, TRX_LAPD_TIMEOUT, 0);
}
}
@@ -2425,8 +2565,7 @@ static void om2k_bts_s_wait_mctr(struct osmo_fsm_inst *fi, uint32_t event, void
{
OSMO_ASSERT(event == OM2K_BTS_EVT_MCTR_DONE);
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX_LAPD,
- TRX_LAPD_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX_LAPD, TRX_LAPD_TIMEOUT, 0);
}
static void om2k_bts_s_wait_trx_lapd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -2436,11 +2575,10 @@ static void om2k_bts_s_wait_trx_lapd(struct osmo_fsm_inst *fi, uint32_t event, v
OSMO_ASSERT(event == OM2K_BTS_EVT_TRX_LAPD_UP);
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX,
- BTS_FSM_TIMEOUT, 0);
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX, BTS_FSM_TIMEOUT, 0);
obfp->next_trx_nr = 0;
trx = gsm_bts_trx_num(obfp->bts, obfp->next_trx_nr++);
- om2k_trx_fsm_start(fi, trx, OM2K_BTS_EVT_TRX_DONE);
+ om2k_trx_fsm_start(trx);
}
static void om2k_bts_s_wait_trx(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -2452,7 +2590,7 @@ static void om2k_bts_s_wait_trx(struct osmo_fsm_inst *fi, uint32_t event, void *
if (obfp->next_trx_nr < obfp->bts->num_trx) {
struct gsm_bts_trx *trx;
trx = gsm_bts_trx_num(obfp->bts, obfp->next_trx_nr++);
- om2k_trx_fsm_start(fi, trx, OM2K_BTS_EVT_TRX_DONE);
+ om2k_trx_fsm_start(trx);
} else {
osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_DONE, 0, 0);
}
@@ -2460,34 +2598,50 @@ static void om2k_bts_s_wait_trx(struct osmo_fsm_inst *fi, uint32_t event, void *
static void om2k_bts_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
- osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
+}
+
+static void om2k_bts_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch (event) {
+ case OM2K_BTS_EVT_RESET:
+ osmo_fsm_inst_broadcast_children(fi, event, data);
+ osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_INIT, 0, 0);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
}
static const struct osmo_fsm_state om2k_bts_states[] = {
[OM2K_BTS_S_INIT] = {
.in_event_mask = S(OM2K_BTS_EVT_START),
- .out_state_mask = S(OM2K_BTS_S_WAIT_CF),
+ .out_state_mask = S(OM2K_BTS_S_WAIT_CF) |
+ S(OM2K_BTS_S_INIT),
.name = "INIT",
.action = om2k_bts_s_init,
},
[OM2K_BTS_S_WAIT_CF] = {
.in_event_mask = S(OM2K_BTS_EVT_CF_DONE),
.out_state_mask = S(OM2K_BTS_S_ERROR) |
- S(OM2K_BTS_S_WAIT_TF),
+ S(OM2K_BTS_S_WAIT_TF) |
+ S(OM2K_BTS_S_INIT),
.name = "WAIT-CF",
.action = om2k_bts_s_wait_cf,
},
[OM2K_BTS_S_WAIT_TF] = {
.in_event_mask = S(OM2K_BTS_EVT_TF_DONE),
.out_state_mask = S(OM2K_BTS_S_ERROR) |
- S(OM2K_BTS_S_WAIT_CON),
+ S(OM2K_BTS_S_WAIT_CON) |
+ S(OM2K_BTS_S_WAIT_IS) |
+ S(OM2K_BTS_S_INIT),
.name = "WAIT-TF",
.action = om2k_bts_s_wait_tf,
},
[OM2K_BTS_S_WAIT_CON] = {
.in_event_mask = S(OM2K_BTS_EVT_CON_DONE),
.out_state_mask = S(OM2K_BTS_S_ERROR) |
- S(OM2K_BTS_S_WAIT_IS),
+ S(OM2K_BTS_S_WAIT_IS) |
+ S(OM2K_BTS_S_INIT),
.name = "WAIT-CON",
.action = om2k_bts_s_wait_con,
},
@@ -2495,35 +2649,41 @@ static const struct osmo_fsm_state om2k_bts_states[] = {
.in_event_mask = S(OM2K_BTS_EVT_IS_DONE),
.out_state_mask = S(OM2K_BTS_S_ERROR) |
S(OM2K_BTS_S_WAIT_MCTR) |
- S(OM2K_BTS_S_WAIT_TRX_LAPD),
+ S(OM2K_BTS_S_WAIT_TRX_LAPD) |
+ S(OM2K_BTS_S_INIT),
.name = "WAIT-IS",
.action = om2k_bts_s_wait_is,
},
[OM2K_BTS_S_WAIT_MCTR] = {
.in_event_mask = S(OM2K_BTS_EVT_MCTR_DONE),
.out_state_mask = S(OM2K_BTS_S_ERROR) |
- S(OM2K_BTS_S_WAIT_TRX_LAPD),
+ S(OM2K_BTS_S_WAIT_TRX_LAPD) |
+ S(OM2K_BTS_S_INIT),
.name = "WAIT-MCTR",
.action = om2k_bts_s_wait_mctr,
},
[OM2K_BTS_S_WAIT_TRX_LAPD] = {
.in_event_mask = S(OM2K_BTS_EVT_TRX_LAPD_UP),
- .out_state_mask = S(OM2K_BTS_S_WAIT_TRX),
+ .out_state_mask = S(OM2K_BTS_S_WAIT_TRX) |
+ S(OM2K_BTS_S_INIT),
.name = "WAIT-TRX-LAPD",
.action = om2k_bts_s_wait_trx_lapd,
},
[OM2K_BTS_S_WAIT_TRX] = {
.in_event_mask = S(OM2K_BTS_EVT_TRX_DONE),
.out_state_mask = S(OM2K_BTS_S_ERROR) |
- S(OM2K_BTS_S_DONE),
+ S(OM2K_BTS_S_DONE) |
+ S(OM2K_BTS_S_INIT),
.name = "WAIT-TRX",
.action = om2k_bts_s_wait_trx,
},
[OM2K_BTS_S_DONE] = {
+ .out_state_mask = S(OM2K_BTS_S_INIT),
.name = "DONE",
.onenter = om2k_bts_s_done_onenter,
},
[OM2K_BTS_S_ERROR] = {
+ .out_state_mask = S(OM2K_BTS_S_INIT),
.name = "ERROR",
},
};
@@ -2546,31 +2706,44 @@ static struct osmo_fsm om2k_bts_fsm = {
.states = om2k_bts_states,
.num_states = ARRAY_SIZE(om2k_bts_states),
.log_subsys = DNM,
+ .allstate_event_mask = S(OM2K_BTS_EVT_RESET),
+ .allstate_action = om2k_bts_allstate,
.event_names = om2k_bts_events,
.timer_cb = om2k_bts_timer_cb,
};
-struct osmo_fsm_inst *
-om2k_bts_fsm_start(struct gsm_bts *bts)
+static struct osmo_fsm_inst *
+om2k_bts_fsm_alloc(struct gsm_bts *bts)
{
struct osmo_fsm_inst *fi;
struct om2k_bts_fsm_priv *obfp;
char idbuf[16];
+ OSMO_ASSERT(!bts->rbs2000.bts_fi);
+
snprintf(idbuf, sizeof(idbuf), "%u", bts->nr);
- fi = osmo_fsm_inst_alloc(&om2k_bts_fsm, bts, NULL,
- LOGL_DEBUG, idbuf);
+ fi = osmo_fsm_inst_alloc(&om2k_bts_fsm, bts, NULL, LOGL_DEBUG, idbuf);
if (!fi)
return NULL;
+
fi->priv = obfp = talloc_zero(fi, struct om2k_bts_fsm_priv);
obfp->bts = bts;
- osmo_fsm_inst_dispatch(fi, OM2K_BTS_EVT_START, NULL);
-
return fi;
}
+void om2k_bts_fsm_start(struct gsm_bts *bts)
+{
+ OSMO_ASSERT(bts->rbs2000.bts_fi);
+ osmo_fsm_inst_dispatch(bts->rbs2000.bts_fi, OM2K_BTS_EVT_START, NULL);
+}
+
+void om2k_bts_fsm_reset(struct gsm_bts *bts)
+{
+ OSMO_ASSERT(bts->rbs2000.bts_fi);
+ osmo_fsm_inst_dispatch(bts->rbs2000.bts_fi, OM2K_BTS_EVT_RESET, NULL);
+}
/***********************************************************************
* OM2000 Negotiation
@@ -2587,7 +2760,7 @@ static int abis_om2k_tx_negot_req_ack(struct gsm_bts *bts, const struct abis_om2
msgb_tlv_put(msg, OM2K_DEI_NEGOT_REC2, len, data);
- DEBUGP(DNM, "Tx MO=%s %s\n", om2k_mo_name(mo),
+ DEBUGP(DNM, "Tx MO=%s %s\n", abis_om2k_mo_name(mo),
get_value_string(om2k_msgcode_vals, OM2K_MSGT_NEGOT_REQ_ACK));
return abis_om2k_sendmsg(bts, msg);
@@ -2709,18 +2882,16 @@ static int om2k_rx_nack(struct msgb *msg)
uint16_t msg_type = ntohs(o2h->msg_type);
struct tlv_parsed tp;
- LOGP(DNM, LOGL_ERROR, "Rx MO=%s %s", om2k_mo_name(&o2h->mo),
+ LOGP(DNM, LOGL_ERROR, "Rx MO=%s %s", abis_om2k_mo_name(&o2h->mo),
get_value_string(om2k_msgcode_vals, msg_type));
abis_om2k_msg_tlv_parse(&tp, o2h);
if (TLVP_PRESENT(&tp, OM2K_DEI_REASON_CODE))
- LOGPC(DNM, LOGL_ERROR, ", Reason 0x%02x",
- *TLVP_VAL(&tp, OM2K_DEI_REASON_CODE));
+ LOGPC(DNM, LOGL_ERROR, ", Reason 0x%02x", *TLVP_VAL(&tp, OM2K_DEI_REASON_CODE));
if (TLVP_PRESENT(&tp, OM2K_DEI_RESULT_CODE))
LOGPC(DNM, LOGL_ERROR, ", Result %s",
- get_value_string(om2k_result_strings,
- *TLVP_VAL(&tp, OM2K_DEI_RESULT_CODE)));
+ get_value_string(om2k_result_strings, *TLVP_VAL(&tp, OM2K_DEI_RESULT_CODE)));
LOGPC(DNM, LOGL_ERROR, "\n");
return 0;
@@ -2734,8 +2905,7 @@ static int process_mo_state(struct gsm_bts *bts, struct om2k_decoded_msg *odm)
return -EIO;
mo_state = *TLVP_VAL(&odm->tp, OM2K_DEI_MO_STATE);
- LOGP(DNM, LOGL_DEBUG, "Rx MO=%s %s, MO State: %s\n",
- om2k_mo_name(&odm->o2h.mo),
+ LOGP(DNM, LOGL_DEBUG, "Rx MO=%s %s, MO State: %s\n", abis_om2k_mo_name(&odm->o2h.mo),
get_value_string(om2k_msgcode_vals, odm->msg_type),
get_value_string(om2k_mostate_vals, mo_state));
@@ -2743,10 +2913,8 @@ static int process_mo_state(struct gsm_bts *bts, struct om2k_decoded_msg *odm)
* not yield an enabled mo-state */
if (odm->msg_type == OM2K_MSGT_ENABLE_RES
&& mo_state != OM2K_MO_S_ENABLED) {
- LOGP(DNM, LOGL_ERROR,
- "Rx MO=%s %s Failed to enable MO State!\n",
- om2k_mo_name(&odm->o2h.mo),
- get_value_string(om2k_msgcode_vals, odm->msg_type));
+ LOGP(DNM, LOGL_ERROR, "Rx MO=%s %s Failed to enable MO State!\n",
+ abis_om2k_mo_name(&odm->o2h.mo), get_value_string(om2k_msgcode_vals, odm->msg_type));
}
update_mo_state(bts, &odm->o2h.mo, mo_state);
@@ -2786,7 +2954,7 @@ static bool display_fault_bits(const uint8_t *vect, uint16_t len,
}
sprintf(string + strlen(string), ")\n");
- DEBUGP(DNM, "Rx MO=%s %s", om2k_mo_name(mo), string);
+ DEBUGP(DNM, "Rx MO=%s %s", abis_om2k_mo_name(mo), string);
return true;
}
@@ -2816,8 +2984,7 @@ static void display_fault_maps(const uint8_t *src, unsigned int src_len,
src++;
src_len--;
if (msg_code != OM2K_MSGT_FAULT_REP) {
- LOGP(DNM, LOGL_ERROR, "Rx MO=%s Fault report: invalid message code!\n",
- om2k_mo_name(mo));
+ LOGP(DNM, LOGL_ERROR, "Rx MO=%s Fault report: invalid message code!\n", abis_om2k_mo_name(mo));
return;
}
@@ -2830,22 +2997,19 @@ static void display_fault_maps(const uint8_t *src, unsigned int src_len,
/* Bail if an the maximum number of TLV fields
* have been parsed */
- if (tlv_count >= 11) {
- LOGP(DNM, LOGL_ERROR,
- "Rx MO=%s Fault Report: too many tlv elements!\n",
- om2k_mo_name(mo));
+ if (tlv_count >= 20) {
+ LOGP(DNM, LOGL_ERROR, "Rx MO=%s Fault Report: too many tlv elements!\n",
+ abis_om2k_mo_name(mo));
return;
}
/* Parse TLV field */
- rc = tlv_parse_one(&tag, &tag_len, &val, &om2k_att_tlvdef,
- src + src_pos, src_len - src_pos);
+ rc = tlv_parse_one(&tag, &tag_len, &val, &om2k_att_tlvdef, src + src_pos, src_len - src_pos);
if (rc > 0)
src_pos += rc;
else {
- LOGP(DNM, LOGL_ERROR,
- "Rx MO=%s Fault Report: invalid tlv element!\n",
- om2k_mo_name(mo));
+ LOGP(DNM, LOGL_ERROR, "Rx MO=%s Fault Report: invalid tlv element!\n",
+ abis_om2k_mo_name(mo));
return;
}
@@ -2872,8 +3036,7 @@ static void display_fault_maps(const uint8_t *src, unsigned int src_len,
}
if (!faults_present) {
- DEBUGP(DNM, "Rx MO=%s Fault Report: All faults ceased!\n",
- om2k_mo_name(mo));
+ DEBUGP(DNM, "Rx MO=%s Fault Report: All faults ceased!\n", abis_om2k_mo_name(mo));
}
}
@@ -2890,28 +3053,24 @@ int abis_om2k_rcvmsg(struct msgb *msg)
/* Various consistency checks */
if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
- LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
- oh->placement);
+ LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n", oh->placement);
if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
return -EINVAL;
}
if (oh->sequence != 0) {
- LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
- oh->sequence);
+ LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n", oh->sequence);
return -EINVAL;
}
msg->l3h = (unsigned char *)o2h + sizeof(*o2h);
if (oh->mdisc != ABIS_OM_MDISC_FOM) {
- LOGP(DNM, LOGL_ERROR, "unknown ABIS OM2000 message discriminator 0x%x\n",
- oh->mdisc);
+ LOGP(DNM, LOGL_ERROR, "unknown ABIS OM2000 message discriminator 0x%x\n", oh->mdisc);
return -EINVAL;
}
- DEBUGP(DNM, "Rx MO=%s %s (%s)\n", om2k_mo_name(&o2h->mo),
- get_value_string(om2k_msgcode_vals, msg_type),
- osmo_hexdump(msg->l2h, msgb_l2len(msg)));
+ DEBUGP(DNM, "Rx MO=%s %s (%s)\n", abis_om2k_mo_name(&o2h->mo),
+ get_value_string(om2k_msgcode_vals, msg_type), osmo_hexdump(msg->l2h, msgb_l2len(msg)));
om2k_decode_msg(&odm, msg);
@@ -2920,11 +3079,13 @@ int abis_om2k_rcvmsg(struct msgb *msg)
switch (msg_type) {
case OM2K_MSGT_CAL_TIME_REQ:
rc = abis_om2k_cal_time_resp(bts);
- break;
+ /* we receive this from MOs without FSM (https://osmocom.org/issues/4670) */
+ goto no_mo;
case OM2K_MSGT_FAULT_REP:
display_fault_maps(msg->l2h, msgb_l2len(msg), &o2h->mo);
rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_FAULT_REP_ACK);
- break;
+ /* we receive this from MOs without FSM (https://osmocom.org/issues/4643) */
+ goto no_mo;
case OM2K_MSGT_NEGOT_REQ:
rc = om2k_rx_negot_req(msg);
break;
@@ -2996,26 +3157,24 @@ int abis_om2k_rcvmsg(struct msgb *msg)
mo = get_om2k_mo(bts, &o2h->mo);
if (!mo) {
LOGP(DNM, LOGL_ERROR, "Couldn't resolve MO for OM2K msg "
- "%s: %s\n", get_value_string(om2k_msgcode_vals, msg_type),
- msgb_hexdump(msg));
- return 0;
+ "%s: %s\n", get_value_string(om2k_msgcode_vals, msg_type), msgb_hexdump(msg));
+ goto no_mo;
}
if (!mo->fsm) {
LOGP(DNM, LOGL_ERROR, "MO object should not generate any message. fsm == NULL "
- "%s: %s\n", get_value_string(om2k_msgcode_vals, msg_type),
- msgb_hexdump(msg));
- return 0;
+ "%s: %s\n", get_value_string(om2k_msgcode_vals, msg_type), msgb_hexdump(msg));
+ goto no_mo;
}
/* Dispatch message to that MO */
om2k_mo_fsm_recvmsg(bts, mo, &odm);
+no_mo:
msgb_free(msg);
return rc;
}
-static void om2k_mo_init(struct om2k_mo *mo, uint8_t class,
- uint8_t bts_nr, uint8_t assoc_so, uint8_t inst)
+static void om2k_mo_init(struct om2k_mo *mo, uint8_t class, uint8_t bts_nr, uint8_t assoc_so, uint8_t inst)
{
mo->addr.class = class;
mo->addr.bts = bts_nr;
@@ -3027,21 +3186,28 @@ static void om2k_mo_init(struct om2k_mo *mo, uint8_t class,
void abis_om2k_trx_init(struct gsm_bts_trx *trx)
{
struct gsm_bts *bts = trx->bts;
+ struct osmo_fsm_inst *trx_fi;
unsigned int i;
OSMO_ASSERT(bts->type == GSM_BTS_TYPE_RBS2000);
- om2k_mo_init(&trx->rbs2000.trxc.om2k_mo, OM2K_MO_CLS_TRXC,
- bts->nr, 255, trx->nr);
- om2k_mo_init(&trx->rbs2000.tx.om2k_mo, OM2K_MO_CLS_TX,
- bts->nr, 255, trx->nr);
- om2k_mo_init(&trx->rbs2000.rx.om2k_mo, OM2K_MO_CLS_RX,
- bts->nr, 255, trx->nr);
+ trx_fi = om2k_trx_fsm_alloc(trx->bts->rbs2000.bts_fi, trx, OM2K_BTS_EVT_TRX_DONE);
+ trx->rbs2000.trx_fi = trx_fi;
+ trx->rbs2000.rx_diversity = OM2K_RX_DIVERSITY_A;
+
+ om2k_mo_init(&trx->rbs2000.trxc.om2k_mo, OM2K_MO_CLS_TRXC, bts->nr, 255, trx->nr);
+ om2k_mo_fsm_alloc(trx_fi, OM2K_TRX_EVT_TRXC_DONE, trx, &trx->rbs2000.trxc.om2k_mo);
+
+ om2k_mo_init(&trx->rbs2000.tx.om2k_mo, OM2K_MO_CLS_TX, bts->nr, 255, trx->nr);
+ om2k_mo_fsm_alloc(trx_fi, OM2K_TRX_EVT_TX_DONE, trx, &trx->rbs2000.tx.om2k_mo);
+
+ om2k_mo_init(&trx->rbs2000.rx.om2k_mo, OM2K_MO_CLS_RX, bts->nr, 255, trx->nr);
+ om2k_mo_fsm_alloc(trx_fi, OM2K_TRX_EVT_RX_DONE, trx, &trx->rbs2000.rx.om2k_mo);
for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
struct gsm_bts_trx_ts *ts = &trx->ts[i];
- om2k_mo_init(&ts->rbs2000.om2k_mo, OM2K_MO_CLS_TS,
- bts->nr, trx->nr, i);
+ om2k_mo_init(&ts->rbs2000.om2k_mo, OM2K_MO_CLS_TS, bts->nr, trx->nr, i);
+ om2k_mo_fsm_alloc(trx_fi, OM2K_TRX_EVT_TS_DONE, trx, &ts->rbs2000.om2k_mo);
OSMO_ASSERT(ts->fi);
}
}
@@ -3049,20 +3215,31 @@ void abis_om2k_trx_init(struct gsm_bts_trx *trx)
/* initialize the OM2K_MO members of gsm_bts */
void abis_om2k_bts_init(struct gsm_bts *bts)
{
+ struct osmo_fsm_inst *bts_fi;
+
OSMO_ASSERT(bts->type == GSM_BTS_TYPE_RBS2000);
- om2k_mo_init(&bts->rbs2000.cf.om2k_mo, OM2K_MO_CLS_CF,
- bts->nr, 0xFF, 0);
- om2k_mo_init(&bts->rbs2000.is.om2k_mo, OM2K_MO_CLS_IS,
- bts->nr, 0xFF, 0);
- om2k_mo_init(&bts->rbs2000.con.om2k_mo, OM2K_MO_CLS_CON,
- bts->nr, 0xFF, 0);
- om2k_mo_init(&bts->rbs2000.dp.om2k_mo, OM2K_MO_CLS_DP,
- bts->nr, 0xFF, 0);
- om2k_mo_init(&bts->rbs2000.tf.om2k_mo, OM2K_MO_CLS_TF,
- bts->nr, 0xFF, 0);
- om2k_mo_init(&bts->rbs2000.mctr.om2k_mo, OM2K_MO_CLS_MCTR,
- bts->nr, 0xFF, 0); // FIXME: There can be multiple MCTRs ...
+ bts_fi = om2k_bts_fsm_alloc(bts);
+ bts->rbs2000.bts_fi = bts_fi;
+ bts->rbs2000.sync_src = OM2K_SYNC_SRC_INTERNAL;
+
+ om2k_mo_init(&bts->rbs2000.cf.om2k_mo, OM2K_MO_CLS_CF, bts->nr, 0xFF, 0);
+ om2k_mo_fsm_alloc(bts_fi, OM2K_BTS_EVT_CF_DONE, bts->c0, &bts->rbs2000.cf.om2k_mo);
+
+ om2k_mo_init(&bts->rbs2000.is.om2k_mo, OM2K_MO_CLS_IS, bts->nr, 0xFF, 0);
+ om2k_mo_fsm_alloc(bts_fi, OM2K_BTS_EVT_IS_DONE, bts->c0, &bts->rbs2000.is.om2k_mo);
+
+ om2k_mo_init(&bts->rbs2000.con.om2k_mo, OM2K_MO_CLS_CON, bts->nr, 0xFF, 0);
+ om2k_mo_fsm_alloc(bts_fi, OM2K_BTS_EVT_CON_DONE, bts->c0, &bts->rbs2000.con.om2k_mo);
+
+ om2k_mo_init(&bts->rbs2000.dp.om2k_mo, OM2K_MO_CLS_DP, bts->nr, 0xFF, 0);
+
+ om2k_mo_init(&bts->rbs2000.tf.om2k_mo, OM2K_MO_CLS_TF, bts->nr, 0xFF, 0);
+ om2k_mo_fsm_alloc(bts_fi, OM2K_BTS_EVT_TF_DONE, bts->c0, &bts->rbs2000.tf.om2k_mo);
+
+ om2k_mo_init(&bts->rbs2000.mctr.om2k_mo, OM2K_MO_CLS_MCTR, bts->nr, 0xFF, 0);
+ om2k_mo_fsm_alloc(bts_fi, OM2K_BTS_EVT_MCTR_DONE, bts->c0, &bts->rbs2000.mctr.om2k_mo);
+ // FIXME: There can be multiple MCTRs ...
}
static __attribute__((constructor)) void abis_om2k_init(void)