Change in osmo-bsc[master]: abis_om2000: keep OM2K FSMs around, don't terminate

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

laforge gerrit-no-reply at lists.osmocom.org
Mon Dec 21 16:00:39 UTC 2020


laforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-bsc/+/21829 )


Change subject: abis_om2000: keep OM2K FSMs around, don't terminate
......................................................................

abis_om2000: keep OM2K FSMs around, don't terminate

The existing code uses short-lived FSMs which are allocated straight
before START, and which are free'd after DONE state is reached.

While that works, it makes state introspection a bit hard, as one
cannot show the FSM states, etc.

Let's change to a different model where the per-OM2k-MO FSMs are
always around (in state INIT after object creation).  While at it,
also introduce a RESET event that can reset each FSM instance back
to INIT state, i.e. in case of OML link failure.

Change-Id: Ia37cffff5c451e1d79a52ccae41ab5718b4661d4
---
M include/osmocom/bsc/abis_om2000.h
M include/osmocom/bsc/bts.h
M include/osmocom/bsc/bts_trx.h
M src/osmo-bsc/abis_om2000.c
M src/osmo-bsc/bts_ericsson_rbs2000.c
5 files changed, 232 insertions(+), 61 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-bsc refs/changes/29/21829/1

diff --git a/include/osmocom/bsc/abis_om2000.h b/include/osmocom/bsc/abis_om2000.h
index 58c07c4..2a83ffb 100644
--- a/include/osmocom/bsc/abis_om2000.h
+++ b/include/osmocom/bsc/abis_om2000.h
@@ -121,9 +121,13 @@
 int abis_om2k_tx_tx_conf_req(struct gsm_bts_trx *trx);
 int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts);
 
-struct osmo_fsm_inst *om2k_bts_fsm_start(struct gsm_bts *bts);
 void abis_om2k_bts_init(struct gsm_bts *bts);
+void om2k_bts_fsm_start(struct gsm_bts *bts);
+void om2k_bts_fsm_reset(struct gsm_bts *bts);
+
 void abis_om2k_trx_init(struct gsm_bts_trx *trx);
+void om2k_trx_fsm_start(struct gsm_bts_trx *trx);
+void om2k_trx_fsm_reset(struct gsm_bts_trx *trx);
 
 int abis_om2k_vty_init(void);
 
diff --git a/include/osmocom/bsc/bts.h b/include/osmocom/bsc/bts.h
index aef0e03..c79e7f7 100644
--- a/include/osmocom/bsc/bts.h
+++ b/include/osmocom/bsc/bts.h
@@ -316,6 +316,7 @@
 			struct gsm_envabtse envabtse[4];
 		} bs11;
 		struct {
+			struct osmo_fsm_inst *bts_fi;
 			struct {
 				struct om2k_mo om2k_mo;
 				struct gsm_abis_mo mo;
diff --git a/include/osmocom/bsc/bts_trx.h b/include/osmocom/bsc/bts_trx.h
index 5888c63..85adc9b 100644
--- a/include/osmocom/bsc/bts_trx.h
+++ b/include/osmocom/bsc/bts_trx.h
@@ -66,6 +66,7 @@
 			struct rxlev_stats rxlev_stat;
 		} ipaccess;
 		struct {
+			struct osmo_fsm_inst *trx_fi;
 			struct {
 				struct om2k_mo om2k_mo;
 			} trxc;
diff --git a/src/osmo-bsc/abis_om2000.c b/src/osmo-bsc/abis_om2000.c
index 13d3a33..96573ea 100644
--- a/src/osmo-bsc/abis_om2000.c
+++ b/src/osmo-bsc/abis_om2000.c
@@ -1598,7 +1598,9 @@
 #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,
@@ -1611,7 +1613,9 @@
 };
 
 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" },
@@ -1643,6 +1647,7 @@
 	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)
@@ -1832,8 +1837,9 @@
 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)
@@ -1844,11 +1850,24 @@
 	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) |
@@ -1859,6 +1878,7 @@
 		.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),
@@ -1868,6 +1888,7 @@
 		.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,
@@ -1876,6 +1897,7 @@
 		.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,
@@ -1884,6 +1906,7 @@
 		.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) |
@@ -1894,6 +1917,7 @@
 		.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,
@@ -1902,6 +1926,7 @@
 		.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,
@@ -1910,6 +1935,7 @@
 		.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,
@@ -1918,6 +1944,7 @@
 		.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,
@@ -1926,19 +1953,20 @@
 		.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,
 	},
 
@@ -1955,11 +1983,13 @@
 	.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,
 };
 
-static struct osmo_fsm_inst *om2k_mo_fsm_start(struct osmo_fsm_inst *parent, uint32_t term_event,
+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;
@@ -1970,8 +2000,7 @@
 		 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;
 
@@ -1979,13 +2008,17 @@
 	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)
 {
@@ -2053,7 +2086,9 @@
  ***********************************************************************/
 
 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,
@@ -2062,7 +2097,9 @@
 };
 
 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" },
@@ -2085,6 +2122,7 @@
 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)
@@ -2093,7 +2131,7 @@
 
 	/* 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);
+	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)
@@ -2102,7 +2140,7 @@
 
 	/* 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);
+	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)
@@ -2111,7 +2149,7 @@
 
 	/* 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);
+	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)
@@ -2123,7 +2161,7 @@
 	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)
@@ -2139,7 +2177,7 @@
 	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);
@@ -2163,55 +2201,76 @@
 	/* See e1_config:bts_isdn_sign_link() / OS#4914 */
 	otfp->trx->mo.nm_state.administrative = NM_STATE_UNLOCKED;
 
-	osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
+	if (fi->proc.parent)
+		osmo_fsm_inst_dispatch(fi->proc.parent, otfp->done_event, NULL);
+}
+
+static void om2k_trx_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+	switch (event) {
+	case OM2K_TRX_EVT_RESET:
+		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",
 	},
 };
@@ -2227,41 +2286,72 @@
 	.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;
 
+	trx->rbs2000.trx_fi = fi;
+
 	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 (strcmp(osmo_fsm_inst_state_name(bts_fi), "DONE") &&
+	    strcmp(osmo_fsm_inst_state_name(bts_fi), "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 (strcmp(osmo_fsm_inst_state_name(bts_fi), "DONE") &&
+	    strcmp(osmo_fsm_inst_state_name(bts_fi), "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,
@@ -2269,11 +2359,14 @@
 	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" },
@@ -2310,7 +2403,7 @@
 
 	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);
+	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)
@@ -2321,7 +2414,7 @@
 	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)
@@ -2334,10 +2427,10 @@
 	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(fi, OM2K_BTS_EVT_IS_DONE, bts->c0, &bts->rbs2000.is.om2k_mo);
+		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(fi, OM2K_BTS_EVT_CON_DONE, bts->c0, &bts->rbs2000.con.om2k_mo);
+		om2k_mo_fsm_start(&bts->rbs2000.con.om2k_mo);
 	}
 }
 
@@ -2349,7 +2442,7 @@
 	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);
+	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)
@@ -2362,7 +2455,7 @@
 	/* 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);
+		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);
 	}
@@ -2385,7 +2478,7 @@
 	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)
@@ -2397,7 +2490,7 @@
 	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);
 	}
@@ -2405,20 +2498,33 @@
 
 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,
 	},
@@ -2426,14 +2532,16 @@
 		.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_IS),
+				  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,
 	},
@@ -2441,35 +2549,41 @@
 		.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",
 	},
 };
@@ -2492,30 +2606,46 @@
 	.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);
 	if (!fi)
 		return NULL;
+
+	bts->rbs2000.bts_fi = fi;
+
 	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
@@ -2955,17 +3085,26 @@
 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);
 
+	trx_fi = om2k_trx_fsm_alloc(trx->bts->rbs2000.bts_fi, trx, OM2K_BTS_EVT_TRX_DONE);
+
 	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_fsm_alloc(trx_fi, OM2K_TRX_EVT_TS_DONE, trx, &ts->rbs2000.om2k_mo);
 		OSMO_ASSERT(ts->fi);
 	}
 }
@@ -2973,14 +3112,28 @@
 /* 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);
 
+	bts_fi = om2k_bts_fsm_alloc(bts);
+
 	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 ...
 }
 
diff --git a/src/osmo-bsc/bts_ericsson_rbs2000.c b/src/osmo-bsc/bts_ericsson_rbs2000.c
index 1297b30..4fbf057 100644
--- a/src/osmo-bsc/bts_ericsson_rbs2000.c
+++ b/src/osmo-bsc/bts_ericsson_rbs2000.c
@@ -35,16 +35,8 @@
 
 static void bootstrap_om_bts(struct gsm_bts *bts)
 {
-	struct gsm_bts_trx *trx;
-
 	LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr);
 
-	/* Global init (not bootstrapping) */
-	abis_om2k_bts_init(bts);
-
-	llist_for_each_entry(trx, &bts->trx_list, list)
-		abis_om2k_trx_init(trx);
-
 	/* TODO: Should we wait for a Failure report? */
 	om2k_bts_fsm_start(bts);
 }
@@ -53,7 +45,8 @@
 {
 	LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for TRX %u/%u\n",
 	     trx->bts->nr, trx->nr);
-	/* FIXME */
+
+	om2k_trx_fsm_start(trx);
 }
 
 static int shutdown_om(struct gsm_bts *bts)
@@ -145,6 +138,11 @@
 		LOGP(DNM, LOGL_NOTICE, "Line-%u TS-%u TEI-%u SAPI-%u: Link "
 		     "Lost for Ericsson RBS2000. Re-starting DL Establishment\n",
 		     isd->line->num, isd->ts_nr, isd->tei, isd->sapi);
+		if (isd->tei == isd->trx->bts->oml_tei)
+			om2k_bts_fsm_reset(isd->trx->bts);
+		else
+			om2k_trx_fsm_reset(isd->trx);
+		break;
 		/* Some datalink for a given TEI/SAPI went down, try to re-start it */
 		e1i_ts = &isd->line->ts[isd->ts_nr-1];
 		OSMO_ASSERT(e1i_ts->type == E1INP_TS_TYPE_SIGN);
@@ -184,10 +182,24 @@
 	e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops);
 }
 
+static int bts_model_rbs2k_bts_init(struct gsm_bts *bts)
+{
+	abis_om2k_bts_init(bts);
+	return 0;
+}
+
+static int bts_model_rbs2k_trx_init(struct gsm_bts_trx *trx)
+{
+	abis_om2k_trx_init(trx);
+	return 0;
+}
+
 static struct gsm_bts_model model_rbs2k = {
 	.type = GSM_BTS_TYPE_RBS2000,
 	.name = "rbs2000",
 	.start = bts_model_rbs2k_start,
+	.bts_init = bts_model_rbs2k_bts_init,
+	.trx_init = bts_model_rbs2k_trx_init,
 	.oml_rcvmsg = &abis_om2k_rcvmsg,
 	.config_write_bts = &config_write_bts,
 	.e1line_bind_ops = &bts_model_rbs2k_e1line_bind_ops,

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/21829
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Ia37cffff5c451e1d79a52ccae41ab5718b4661d4
Gerrit-Change-Number: 21829
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <laforge at osmocom.org>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20201221/d34f5cf3/attachment.htm>


More information about the gerrit-log mailing list