<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bsc/+/21829">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  laforge: Looks good to me, approved
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">abis_om2000: keep OM2K FSMs around, don't terminate<br><br>The existing code uses short-lived FSMs which are allocated straight<br>before START, and which are free'd after DONE state is reached.<br><br>While that works, it makes state introspection a bit hard, as one<br>cannot show the FSM states, etc.<br><br>Let's change to a different model where the per-OM2k-MO FSMs are<br>always around (in state INIT after object creation).  While at it,<br>also introduce a RESET event that can reset each FSM instance back<br>to INIT state, i.e. in case of OML link failure.<br><br>Change-Id: Ia37cffff5c451e1d79a52ccae41ab5718b4661d4<br>---<br>M include/osmocom/bsc/abis_om2000.h<br>M include/osmocom/bsc/bts.h<br>M include/osmocom/bsc/bts_trx.h<br>M src/osmo-bsc/abis_om2000.c<br>M src/osmo-bsc/bts_ericsson_rbs2000.c<br>5 files changed, 241 insertions(+), 74 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/bsc/abis_om2000.h b/include/osmocom/bsc/abis_om2000.h</span><br><span>index 58c07c4..62aef9d 100644</span><br><span>--- a/include/osmocom/bsc/abis_om2000.h</span><br><span>+++ b/include/osmocom/bsc/abis_om2000.h</span><br><span>@@ -121,9 +121,26 @@</span><br><span> int abis_om2k_tx_tx_conf_req(struct gsm_bts_trx *trx);</span><br><span> int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct osmo_fsm_inst *om2k_bts_fsm_start(struct gsm_bts *bts);</span><br><span style="color: hsl(120, 100%, 40%);">+enum om2k_bts_state {</span><br><span style="color: hsl(120, 100%, 40%);">+       OM2K_BTS_S_INIT,</span><br><span style="color: hsl(120, 100%, 40%);">+      OM2K_BTS_S_WAIT_CF,</span><br><span style="color: hsl(120, 100%, 40%);">+   OM2K_BTS_S_WAIT_IS,</span><br><span style="color: hsl(120, 100%, 40%);">+   OM2K_BTS_S_WAIT_CON,</span><br><span style="color: hsl(120, 100%, 40%);">+  OM2K_BTS_S_WAIT_TF,</span><br><span style="color: hsl(120, 100%, 40%);">+   OM2K_BTS_S_WAIT_MCTR,</span><br><span style="color: hsl(120, 100%, 40%);">+ OM2K_BTS_S_WAIT_TRX_LAPD,</span><br><span style="color: hsl(120, 100%, 40%);">+     OM2K_BTS_S_WAIT_TRX,</span><br><span style="color: hsl(120, 100%, 40%);">+  OM2K_BTS_S_DONE,</span><br><span style="color: hsl(120, 100%, 40%);">+      OM2K_BTS_S_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void abis_om2k_bts_init(struct gsm_bts *bts);</span><br><span style="color: hsl(120, 100%, 40%);">+void om2k_bts_fsm_start(struct gsm_bts *bts);</span><br><span style="color: hsl(120, 100%, 40%);">+void om2k_bts_fsm_reset(struct gsm_bts *bts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void abis_om2k_trx_init(struct gsm_bts_trx *trx);</span><br><span style="color: hsl(120, 100%, 40%);">+void om2k_trx_fsm_start(struct gsm_bts_trx *trx);</span><br><span style="color: hsl(120, 100%, 40%);">+void om2k_trx_fsm_reset(struct gsm_bts_trx *trx);</span><br><span> </span><br><span> int abis_om2k_vty_init(void);</span><br><span> </span><br><span>diff --git a/include/osmocom/bsc/bts.h b/include/osmocom/bsc/bts.h</span><br><span>index aef0e03..c79e7f7 100644</span><br><span>--- a/include/osmocom/bsc/bts.h</span><br><span>+++ b/include/osmocom/bsc/bts.h</span><br><span>@@ -316,6 +316,7 @@</span><br><span>                  struct gsm_envabtse envabtse[4];</span><br><span>             } bs11;</span><br><span>              struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct osmo_fsm_inst *bts_fi;</span><br><span>                        struct {</span><br><span>                             struct om2k_mo om2k_mo;</span><br><span>                              struct gsm_abis_mo mo;</span><br><span>diff --git a/include/osmocom/bsc/bts_trx.h b/include/osmocom/bsc/bts_trx.h</span><br><span>index 5888c63..85adc9b 100644</span><br><span>--- a/include/osmocom/bsc/bts_trx.h</span><br><span>+++ b/include/osmocom/bsc/bts_trx.h</span><br><span>@@ -66,6 +66,7 @@</span><br><span>                  struct rxlev_stats rxlev_stat;</span><br><span>               } ipaccess;</span><br><span>          struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct osmo_fsm_inst *trx_fi;</span><br><span>                        struct {</span><br><span>                             struct om2k_mo om2k_mo;</span><br><span>                      } trxc;</span><br><span>diff --git a/src/osmo-bsc/abis_om2000.c b/src/osmo-bsc/abis_om2000.c</span><br><span>index 13d3a33..15c0431 100644</span><br><span>--- a/src/osmo-bsc/abis_om2000.c</span><br><span>+++ b/src/osmo-bsc/abis_om2000.c</span><br><span>@@ -1598,7 +1598,9 @@</span><br><span> #define S(x)    (1 << (x))</span><br><span> </span><br><span> enum om2k_event_name {</span><br><span style="color: hsl(120, 100%, 40%);">+        OM2K_MO_EVT_RESET,</span><br><span>   OM2K_MO_EVT_START,</span><br><span style="color: hsl(120, 100%, 40%);">+    OM2K_MO_EVT_CHILD_TERM,</span><br><span>      OM2K_MO_EVT_RX_CONN_COMPL,</span><br><span>   OM2K_MO_EVT_RX_RESET_COMPL,</span><br><span>  OM2K_MO_EVT_RX_START_REQ_ACCEPT,</span><br><span>@@ -1611,7 +1613,9 @@</span><br><span> };</span><br><span> </span><br><span> static const struct value_string om2k_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ { OM2K_MO_EVT_RESET,                    "RESET" },</span><br><span>         { OM2K_MO_EVT_START,                    "START" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { OM2K_MO_EVT_CHILD_TERM,               "CHILD-TERM" },</span><br><span>    { OM2K_MO_EVT_RX_CONN_COMPL,            "RX-CONN-COMPL" },</span><br><span>         { OM2K_MO_EVT_RX_RESET_COMPL,           "RX-RESET-COMPL" },</span><br><span>        { OM2K_MO_EVT_RX_START_REQ_ACCEPT,      "RX-RESET-REQ-ACCEPT" },</span><br><span>@@ -1643,6 +1647,7 @@</span><br><span>   struct gsm_bts_trx *trx;</span><br><span>     struct om2k_mo *mo;</span><br><span>  uint8_t ts_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t done_event;</span><br><span> };</span><br><span> </span><br><span> static void om2k_mo_st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -1832,8 +1837,9 @@</span><br><span> static void om2k_mo_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span> {</span><br><span>        struct om2k_mo_fsm_priv *omfp = fi->priv;</span><br><span style="color: hsl(0, 100%, 40%);">-    omfp->mo->fsm = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-     osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (fi->proc.parent)</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_dispatch(fi->proc.parent, omfp->done_event, NULL);</span><br><span> }</span><br><span> </span><br><span> static void om2k_mo_s_error_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span>@@ -1844,11 +1850,24 @@</span><br><span>      osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void om2k_mo_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case OM2K_MO_EVT_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_broadcast_children(fi, event, data);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_state_chg(fi, OM2K_ST_INIT, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static const struct osmo_fsm_state om2k_is_states[] = {</span><br><span>    [OM2K_ST_INIT] = {</span><br><span>           .name = "INIT",</span><br><span>            .in_event_mask = S(OM2K_MO_EVT_START),</span><br><span>               .out_state_mask = S(OM2K_ST_DONE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(OM2K_ST_INIT) |</span><br><span>                            S(OM2K_ST_ERROR) |</span><br><span>                                   S(OM2K_ST_WAIT_CONN_COMPL) |</span><br><span>                                 S(OM2K_ST_WAIT_START_ACCEPT) |</span><br><span>@@ -1859,6 +1878,7 @@</span><br><span>             .name = "WAIT-CONN-COMPL",</span><br><span>                 .in_event_mask = S(OM2K_MO_EVT_RX_CONN_COMPL),</span><br><span>               .out_state_mask = S(OM2K_ST_DONE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(OM2K_ST_INIT) |</span><br><span>                            S(OM2K_ST_ERROR) |</span><br><span>                                   S(OM2K_ST_WAIT_START_ACCEPT) |</span><br><span>                               S(OM2K_ST_WAIT_RES_COMPL),</span><br><span>@@ -1868,6 +1888,7 @@</span><br><span>                 .name = "WAIT-RES-COMPL",</span><br><span>          .in_event_mask = S(OM2K_MO_EVT_RX_RESET_COMPL),</span><br><span>              .out_state_mask = S(OM2K_ST_DONE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(OM2K_ST_INIT) |</span><br><span>                            S(OM2K_ST_ERROR) |</span><br><span>                                   S(OM2K_ST_WAIT_START_ACCEPT),</span><br><span>              .action = om2k_mo_st_wait_res_compl,</span><br><span>@@ -1876,6 +1897,7 @@</span><br><span>                 .name = "WAIT-START-ACCEPT",</span><br><span>               .in_event_mask = S(OM2K_MO_EVT_RX_START_REQ_ACCEPT),</span><br><span>                 .out_state_mask = S(OM2K_ST_DONE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(OM2K_ST_INIT) |</span><br><span>                            S(OM2K_ST_ERROR) |</span><br><span>                                   S(OM2K_ST_WAIT_START_RES),</span><br><span>                 .action =om2k_mo_st_wait_start_accept,</span><br><span>@@ -1884,6 +1906,7 @@</span><br><span>               .name = "WAIT-START-RES",</span><br><span>          .in_event_mask = S(OM2K_MO_EVT_RX_START_RES),</span><br><span>                .out_state_mask = S(OM2K_ST_DONE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(OM2K_ST_INIT) |</span><br><span>                            S(OM2K_ST_ERROR) |</span><br><span>                                   S(OM2K_ST_WAIT_CFG_ACCEPT) |</span><br><span>                                 S(OM2K_ST_WAIT_OPINFO_ACCEPT) |</span><br><span>@@ -1894,6 +1917,7 @@</span><br><span>            .name = "WAIT-CFG-ACCEPT",</span><br><span>                 .in_event_mask = S(OM2K_MO_EVT_RX_CFG_REQ_ACCEPT),</span><br><span>           .out_state_mask = S(OM2K_ST_DONE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(OM2K_ST_INIT) |</span><br><span>                            S(OM2K_ST_ERROR) |</span><br><span>                                   S(OM2K_ST_WAIT_CFG_RES),</span><br><span>           .action = om2k_mo_st_wait_cfg_accept,</span><br><span>@@ -1902,6 +1926,7 @@</span><br><span>                .name = "WAIT-CFG-RES",</span><br><span>            .in_event_mask = S(OM2K_MO_EVT_RX_CFG_RES),</span><br><span>          .out_state_mask = S(OM2K_ST_DONE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(OM2K_ST_INIT) |</span><br><span>                            S(OM2K_ST_ERROR) |</span><br><span>                                   S(OM2K_ST_WAIT_ENABLE_ACCEPT),</span><br><span>             .action = om2k_mo_st_wait_cfg_res,</span><br><span>@@ -1910,6 +1935,7 @@</span><br><span>           .name = "WAIT-ENABLE-ACCEPT",</span><br><span>              .in_event_mask = S(OM2K_MO_EVT_RX_ENA_REQ_ACCEPT),</span><br><span>           .out_state_mask = S(OM2K_ST_DONE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(OM2K_ST_INIT) |</span><br><span>                            S(OM2K_ST_ERROR) |</span><br><span>                                   S(OM2K_ST_WAIT_ENABLE_RES),</span><br><span>                .action = om2k_mo_st_wait_enable_accept,</span><br><span>@@ -1918,6 +1944,7 @@</span><br><span>             .name = "WAIT-ENABLE-RES",</span><br><span>                 .in_event_mask = S(OM2K_MO_EVT_RX_ENA_RES),</span><br><span>          .out_state_mask = S(OM2K_ST_DONE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(OM2K_ST_INIT) |</span><br><span>                            S(OM2K_ST_ERROR) |</span><br><span>                                   S(OM2K_ST_WAIT_OPINFO_ACCEPT),</span><br><span>             .action = om2k_mo_st_wait_enable_res,</span><br><span>@@ -1926,19 +1953,20 @@</span><br><span>              .name = "WAIT-OPINFO-ACCEPT",</span><br><span>              .in_event_mask = S(OM2K_MO_EVT_RX_OPINFO_ACC),</span><br><span>               .out_state_mask = S(OM2K_ST_DONE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(OM2K_ST_INIT) |</span><br><span>                            S(OM2K_ST_ERROR),</span><br><span>          .action = om2k_mo_st_wait_opinfo_accept,</span><br><span>     },</span><br><span>   [OM2K_ST_DONE] = {</span><br><span>           .name = "DONE",</span><br><span>            .in_event_mask = 0,</span><br><span style="color: hsl(0, 100%, 40%);">-             .out_state_mask = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+          .out_state_mask = S(OM2K_ST_INIT),</span><br><span>           .onenter = om2k_mo_s_done_onenter,</span><br><span>   },</span><br><span>   [OM2K_ST_ERROR] = {</span><br><span>          .name = "ERROR",</span><br><span>           .in_event_mask = 0,</span><br><span style="color: hsl(0, 100%, 40%);">-             .out_state_mask = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+          .out_state_mask = S(OM2K_ST_INIT),</span><br><span>           .onenter = om2k_mo_s_error_onenter,</span><br><span>  },</span><br><span> </span><br><span>@@ -1955,11 +1983,13 @@</span><br><span>     .states = om2k_is_states,</span><br><span>    .num_states = ARRAY_SIZE(om2k_is_states),</span><br><span>    .log_subsys = DNM,</span><br><span style="color: hsl(120, 100%, 40%);">+    .allstate_event_mask = S(OM2K_MO_EVT_RESET),</span><br><span style="color: hsl(120, 100%, 40%);">+  .allstate_action = om2k_mo_allstate,</span><br><span>         .event_names = om2k_event_names,</span><br><span>     .timer_cb = om2k_mo_timer_cb,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct osmo_fsm_inst *om2k_mo_fsm_start(struct osmo_fsm_inst *parent, uint32_t term_event,</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm_inst *om2k_mo_fsm_alloc(struct osmo_fsm_inst *parent, uint32_t done_event,</span><br><span>                                         struct gsm_bts_trx *trx, struct om2k_mo *mo)</span><br><span> {</span><br><span>     struct osmo_fsm_inst *fi;</span><br><span>@@ -1970,8 +2000,7 @@</span><br><span>             get_value_string(om2k_mo_class_short_vals, mo->addr.class),</span><br><span>               mo->addr.bts, mo->addr.assoc_so, mo->addr.inst);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  fi = osmo_fsm_inst_alloc_child_id(&om2k_mo_fsm, parent,</span><br><span style="color: hsl(0, 100%, 40%);">-                                       term_event, idbuf);</span><br><span style="color: hsl(120, 100%, 40%);">+ fi = osmo_fsm_inst_alloc_child_id(&om2k_mo_fsm, parent, OM2K_MO_EVT_CHILD_TERM, idbuf);</span><br><span>  if (!fi)</span><br><span>             return NULL;</span><br><span> </span><br><span>@@ -1979,13 +2008,17 @@</span><br><span>   omfp = talloc_zero(fi, struct om2k_mo_fsm_priv);</span><br><span>     omfp->mo = mo;</span><br><span>    omfp->trx = trx;</span><br><span style="color: hsl(120, 100%, 40%);">+   omfp->done_event = done_event;</span><br><span>    fi->priv = omfp;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- osmo_fsm_inst_dispatch(fi, OM2K_MO_EVT_START, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>         return fi;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void om2k_mo_fsm_start(struct om2k_mo *mo)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_inst_dispatch(mo->fsm, OM2K_MO_EVT_START, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int om2k_mo_fsm_recvmsg(struct gsm_bts *bts, struct om2k_mo *mo,</span><br><span>                        struct om2k_decoded_msg *odm)</span><br><span> {</span><br><span>@@ -2053,7 +2086,9 @@</span><br><span>  ***********************************************************************/</span><br><span> </span><br><span> enum om2k_trx_event {</span><br><span style="color: hsl(0, 100%, 40%);">-    OM2K_TRX_EVT_START,</span><br><span style="color: hsl(120, 100%, 40%);">+   OM2K_TRX_EVT_RESET = OM2K_MO_EVT_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+       OM2K_TRX_EVT_START = OM2K_MO_EVT_START,</span><br><span style="color: hsl(120, 100%, 40%);">+       OM2K_TRX_EVT_CHILD_TERM = OM2K_MO_EVT_CHILD_TERM,</span><br><span>    OM2K_TRX_EVT_TRXC_DONE,</span><br><span>      OM2K_TRX_EVT_TX_DONE,</span><br><span>        OM2K_TRX_EVT_RX_DONE,</span><br><span>@@ -2062,7 +2097,9 @@</span><br><span> };</span><br><span> </span><br><span> static struct value_string om2k_trx_events[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   { OM2K_TRX_EVT_RESET,           "RESET" },</span><br><span>         { OM2K_TRX_EVT_START,           "START" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { OM2K_TRX_EVT_CHILD_TERM,      "CHILD-TERM" },</span><br><span>    { OM2K_TRX_EVT_TRXC_DONE,       "TRXC-DONE" },</span><br><span>     { OM2K_TRX_EVT_TX_DONE,         "TX-DONE" },</span><br><span>       { OM2K_TRX_EVT_RX_DONE,         "RX-DONE" },</span><br><span>@@ -2085,6 +2122,7 @@</span><br><span> struct om2k_trx_fsm_priv {</span><br><span>         struct gsm_bts_trx *trx;</span><br><span>     uint8_t cur_ts_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t done_event;</span><br><span> };</span><br><span> </span><br><span> static void om2k_trx_s_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -2093,7 +2131,7 @@</span><br><span> </span><br><span>      /* First initialize TRXC */</span><br><span>  osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TRXC, TRX_FSM_TIMEOUT, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-  om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TRXC_DONE, otfp->trx, &otfp->trx->rbs2000.trxc.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+      om2k_mo_fsm_start(&otfp->trx->rbs2000.trxc.om2k_mo);</span><br><span> }</span><br><span> </span><br><span> static void om2k_trx_s_wait_trxc(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -2102,7 +2140,7 @@</span><br><span> </span><br><span>        /* Initialize TX after TRXC */</span><br><span>       osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TX, TRX_FSM_TIMEOUT, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TX_DONE, otfp->trx, &otfp->trx->rbs2000.tx.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+  om2k_mo_fsm_start(&otfp->trx->rbs2000.tx.om2k_mo);</span><br><span> }</span><br><span> </span><br><span> static void om2k_trx_s_wait_tx(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -2111,7 +2149,7 @@</span><br><span> </span><br><span>    /* Initialize RX after TX */</span><br><span>         osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_RX, TRX_FSM_TIMEOUT, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    om2k_mo_fsm_start(fi, OM2K_TRX_EVT_RX_DONE, otfp->trx, &otfp->trx->rbs2000.rx.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+  om2k_mo_fsm_start(&otfp->trx->rbs2000.rx.om2k_mo);</span><br><span> }</span><br><span> </span><br><span> static void om2k_trx_s_wait_rx(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -2123,7 +2161,7 @@</span><br><span>        osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TS, TRX_FSM_TIMEOUT, 0);</span><br><span>         otfp->cur_ts_nr = 0;</span><br><span>      ts = &otfp->trx->ts[otfp->cur_ts_nr];</span><br><span style="color: hsl(0, 100%, 40%);">-      om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TS_DONE, otfp->trx, &ts->rbs2000.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+       om2k_mo_fsm_start(&ts->rbs2000.om2k_mo);</span><br><span> }</span><br><span> </span><br><span> static void om2k_trx_s_wait_ts(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -2139,7 +2177,7 @@</span><br><span>     if (++otfp->cur_ts_nr < 8) {</span><br><span>           /* iterate to the next timeslot */</span><br><span>           ts = &otfp->trx->ts[otfp->cur_ts_nr];</span><br><span style="color: hsl(0, 100%, 40%);">-              om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TS_DONE, otfp->trx, &ts->rbs2000.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+               om2k_mo_fsm_start(&ts->rbs2000.om2k_mo);</span><br><span>      } else {</span><br><span>             /* only after all 8 TS */</span><br><span>            osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_SEND_SI, 0, 0);</span><br><span>@@ -2163,55 +2201,76 @@</span><br><span>     /* See e1_config:bts_isdn_sign_link() / OS#4914 */</span><br><span>   otfp->trx->mo.nm_state.administrative = NM_STATE_UNLOCKED;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (fi->proc.parent)</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_dispatch(fi->proc.parent, otfp->done_event, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void om2k_trx_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case OM2K_TRX_EVT_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_fsm_inst_broadcast_children(fi, event, data);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_INIT, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> }</span><br><span> </span><br><span> static const struct osmo_fsm_state om2k_trx_states[] = {</span><br><span>       [OM2K_TRX_S_INIT] = {</span><br><span>                .in_event_mask = S(OM2K_TRX_EVT_START),</span><br><span style="color: hsl(0, 100%, 40%);">-         .out_state_mask = S(OM2K_TRX_S_WAIT_TRXC),</span><br><span style="color: hsl(120, 100%, 40%);">+            .out_state_mask = S(OM2K_TRX_S_WAIT_TRXC) |</span><br><span style="color: hsl(120, 100%, 40%);">+                             S(OM2K_TRX_S_INIT),</span><br><span>                .name = "INIT",</span><br><span>            .action = om2k_trx_s_init,</span><br><span>   },</span><br><span>   [OM2K_TRX_S_WAIT_TRXC] = {</span><br><span>           .in_event_mask = S(OM2K_TRX_EVT_TRXC_DONE),</span><br><span>          .out_state_mask = S(OM2K_TRX_S_ERROR) |</span><br><span style="color: hsl(0, 100%, 40%);">-                           S(OM2K_TRX_S_WAIT_TX),</span><br><span style="color: hsl(120, 100%, 40%);">+                                S(OM2K_TRX_S_WAIT_TX) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(OM2K_TRX_S_INIT),</span><br><span>                .name = "WAIT-TRXC",</span><br><span>               .action = om2k_trx_s_wait_trxc,</span><br><span>      },</span><br><span>   [OM2K_TRX_S_WAIT_TX] = {</span><br><span>             .in_event_mask = S(OM2K_TRX_EVT_TX_DONE),</span><br><span>            .out_state_mask = S(OM2K_TRX_S_ERROR) |</span><br><span style="color: hsl(0, 100%, 40%);">-                           S(OM2K_TRX_S_WAIT_RX),</span><br><span style="color: hsl(120, 100%, 40%);">+                                S(OM2K_TRX_S_WAIT_RX) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(OM2K_TRX_S_INIT),</span><br><span>                .name = "WAIT-TX",</span><br><span>                 .action = om2k_trx_s_wait_tx,</span><br><span>        },</span><br><span>   [OM2K_TRX_S_WAIT_RX] = {</span><br><span>             .in_event_mask = S(OM2K_TRX_EVT_RX_DONE),</span><br><span>            .out_state_mask = S(OM2K_TRX_S_ERROR) |</span><br><span style="color: hsl(0, 100%, 40%);">-                           S(OM2K_TRX_S_WAIT_TS),</span><br><span style="color: hsl(120, 100%, 40%);">+                                S(OM2K_TRX_S_WAIT_TS) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(OM2K_TRX_S_INIT),</span><br><span>                .name = "WAIT-RX",</span><br><span>                 .action = om2k_trx_s_wait_rx,</span><br><span>        },</span><br><span>   [OM2K_TRX_S_WAIT_TS] = {</span><br><span>             .in_event_mask = S(OM2K_TRX_EVT_TS_DONE),</span><br><span>            .out_state_mask = S(OM2K_TRX_S_ERROR) |</span><br><span style="color: hsl(0, 100%, 40%);">-                           S(OM2K_TRX_S_SEND_SI),</span><br><span style="color: hsl(120, 100%, 40%);">+                                S(OM2K_TRX_S_SEND_SI) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(OM2K_TRX_S_INIT),</span><br><span>                .name = "WAIT-TS",</span><br><span>                 .action = om2k_trx_s_wait_ts,</span><br><span>        },</span><br><span>   [OM2K_TRX_S_SEND_SI] = {</span><br><span>             .out_state_mask = S(OM2K_TRX_S_ERROR) |</span><br><span style="color: hsl(0, 100%, 40%);">-                           S(OM2K_TRX_S_DONE),</span><br><span style="color: hsl(120, 100%, 40%);">+                           S(OM2K_TRX_S_DONE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                  S(OM2K_TRX_S_INIT),</span><br><span>                .name = "SEND-SI",</span><br><span>                 .onenter = om2k_trx_s_send_si,</span><br><span>       },</span><br><span>   [OM2K_TRX_S_DONE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .out_state_mask = S(OM2K_TRX_S_INIT),</span><br><span>                .name = "DONE",</span><br><span>            .onenter = om2k_trx_s_done_onenter,</span><br><span>  },</span><br><span>   [OM2K_TRX_S_ERROR] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask = S(OM2K_TRX_S_INIT),</span><br><span>                .name = "ERROR",</span><br><span>   },</span><br><span> };</span><br><span>@@ -2227,41 +2286,68 @@</span><br><span>   .states = om2k_trx_states,</span><br><span>   .num_states = ARRAY_SIZE(om2k_trx_states),</span><br><span>   .log_subsys = DNM,</span><br><span style="color: hsl(120, 100%, 40%);">+    .allstate_event_mask = S(OM2K_TRX_EVT_RESET),</span><br><span style="color: hsl(120, 100%, 40%);">+ .allstate_action = om2k_trx_allstate,</span><br><span>        .event_names = om2k_trx_events,</span><br><span>      .timer_cb = om2k_trx_timer_cb,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct osmo_fsm_inst *om2k_trx_fsm_start(struct osmo_fsm_inst *parent,</span><br><span style="color: hsl(0, 100%, 40%);">-                                   struct gsm_bts_trx *trx,</span><br><span style="color: hsl(0, 100%, 40%);">-                                        uint32_t term_event)</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm_inst *om2k_trx_fsm_alloc(struct osmo_fsm_inst *parent,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          struct gsm_bts_trx *trx, uint32_t done_event)</span><br><span> {</span><br><span>   struct osmo_fsm_inst *fi;</span><br><span>    struct om2k_trx_fsm_priv *otfp;</span><br><span>      char idbuf[32];</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(!trx->rbs2000.trx_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      snprintf(idbuf, sizeof(idbuf), "%u-%u", trx->bts->nr, trx->nr);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  fi = osmo_fsm_inst_alloc_child_id(&om2k_trx_fsm, parent, term_event,</span><br><span style="color: hsl(0, 100%, 40%);">-                                          idbuf);</span><br><span style="color: hsl(120, 100%, 40%);">+     fi = osmo_fsm_inst_alloc_child_id(&om2k_trx_fsm, parent, OM2K_MO_EVT_CHILD_TERM, idbuf);</span><br><span>         if (!fi)</span><br><span>             return NULL;</span><br><span> </span><br><span>     otfp = talloc_zero(fi, struct om2k_trx_fsm_priv);</span><br><span>    otfp->trx = trx;</span><br><span style="color: hsl(120, 100%, 40%);">+   otfp->done_event = done_event;</span><br><span>    fi->priv = otfp;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- osmo_fsm_inst_dispatch(fi, OM2K_TRX_EVT_START, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>        return fi;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void om2k_trx_fsm_start(struct gsm_bts_trx *trx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_fsm_inst *bts_fi = trx->bts->rbs2000.bts_fi;</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(trx->rbs2000.trx_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* suppress if BTS is not yet brought up */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (bts_fi->state == OM2K_BTS_S_DONE || bts_fi->state == OM2K_BTS_S_WAIT_TRX)</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_inst_dispatch(trx->rbs2000.trx_fi, OM2K_TRX_EVT_START, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void om2k_trx_fsm_reset(struct gsm_bts_trx *trx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_fsm_inst *bts_fi = trx->bts->rbs2000.bts_fi;</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(trx->rbs2000.trx_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(trx->rbs2000.trx_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* suppress if BTS is not yet brought up */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (bts_fi->state == OM2K_BTS_S_DONE || bts_fi->state == OM2K_BTS_S_WAIT_TRX)</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_inst_dispatch(trx->rbs2000.trx_fi, OM2K_TRX_EVT_RESET, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> /***********************************************************************</span><br><span>  * OM2000 BTS Finite State Machine, initializes CF and all siblings</span><br><span>  ***********************************************************************/</span><br><span> </span><br><span> enum om2k_bts_event {</span><br><span style="color: hsl(0, 100%, 40%);">-   OM2K_BTS_EVT_START,</span><br><span style="color: hsl(120, 100%, 40%);">+   OM2K_BTS_EVT_RESET = OM2K_MO_EVT_RESET,</span><br><span style="color: hsl(120, 100%, 40%);">+       OM2K_BTS_EVT_START = OM2K_MO_EVT_START,</span><br><span style="color: hsl(120, 100%, 40%);">+       OM2K_BTS_EVT_CHILD_TERM = OM2K_MO_EVT_CHILD_TERM,</span><br><span>    OM2K_BTS_EVT_CF_DONE,</span><br><span>        OM2K_BTS_EVT_IS_DONE,</span><br><span>        OM2K_BTS_EVT_CON_DONE,</span><br><span>@@ -2269,11 +2355,14 @@</span><br><span>     OM2K_BTS_EVT_MCTR_DONE,</span><br><span>      OM2K_BTS_EVT_TRX_LAPD_UP,</span><br><span>    OM2K_BTS_EVT_TRX_DONE,</span><br><span style="color: hsl(120, 100%, 40%);">+        OM2K_BTS_EVT_TRX_TERM,</span><br><span>       OM2K_BTS_EVT_STOP,</span><br><span> };</span><br><span> </span><br><span> static const struct value_string om2k_bts_events[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        { OM2K_BTS_EVT_RESET,           "RESET" },</span><br><span>         { OM2K_BTS_EVT_START,           "START" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { OM2K_BTS_EVT_CHILD_TERM,      "CHILD-TERM" },</span><br><span>    { OM2K_BTS_EVT_CF_DONE,         "CF-DONE" },</span><br><span>       { OM2K_BTS_EVT_IS_DONE,         "IS-DONE" },</span><br><span>       { OM2K_BTS_EVT_CON_DONE,        "CON-DONE" },</span><br><span>@@ -2285,19 +2374,6 @@</span><br><span>     { 0, NULL }</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-enum om2k_bts_state {</span><br><span style="color: hsl(0, 100%, 40%);">-      OM2K_BTS_S_INIT,</span><br><span style="color: hsl(0, 100%, 40%);">-        OM2K_BTS_S_WAIT_CF,</span><br><span style="color: hsl(0, 100%, 40%);">-     OM2K_BTS_S_WAIT_IS,</span><br><span style="color: hsl(0, 100%, 40%);">-     OM2K_BTS_S_WAIT_CON,</span><br><span style="color: hsl(0, 100%, 40%);">-    OM2K_BTS_S_WAIT_TF,</span><br><span style="color: hsl(0, 100%, 40%);">-     OM2K_BTS_S_WAIT_MCTR,</span><br><span style="color: hsl(0, 100%, 40%);">-   OM2K_BTS_S_WAIT_TRX_LAPD,</span><br><span style="color: hsl(0, 100%, 40%);">-       OM2K_BTS_S_WAIT_TRX,</span><br><span style="color: hsl(0, 100%, 40%);">-    OM2K_BTS_S_DONE,</span><br><span style="color: hsl(0, 100%, 40%);">-        OM2K_BTS_S_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> struct om2k_bts_fsm_priv {</span><br><span>    struct gsm_bts *bts;</span><br><span>         uint8_t next_trx_nr;</span><br><span>@@ -2310,7 +2386,7 @@</span><br><span> </span><br><span>     OSMO_ASSERT(event == OM2K_BTS_EVT_START);</span><br><span>    osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_CF, BTS_FSM_TIMEOUT, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    om2k_mo_fsm_start(fi, OM2K_BTS_EVT_CF_DONE, bts->c0, &bts->rbs2000.cf.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+     om2k_mo_fsm_start(&bts->rbs2000.cf.om2k_mo);</span><br><span> }</span><br><span> </span><br><span> static void om2k_bts_s_wait_cf(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -2321,7 +2397,7 @@</span><br><span>         OSMO_ASSERT(event == OM2K_BTS_EVT_CF_DONE);</span><br><span>  /* TF can take a long time to initialize, wait for 10min */</span><br><span>  osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TF, 600, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-        om2k_mo_fsm_start(fi, OM2K_BTS_EVT_TF_DONE, bts->c0, &bts->rbs2000.tf.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+     om2k_mo_fsm_start(&bts->rbs2000.tf.om2k_mo);</span><br><span> }</span><br><span> </span><br><span> static void om2k_bts_s_wait_tf(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -2334,10 +2410,10 @@</span><br><span>       if (!llist_count(&bts->rbs2000.con.conn_groups)) {</span><br><span>            /* skip CON object if we have no configuration for it */</span><br><span>             osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_IS, BTS_FSM_TIMEOUT, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-            om2k_mo_fsm_start(fi, OM2K_BTS_EVT_IS_DONE, bts->c0, &bts->rbs2000.is.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+             om2k_mo_fsm_start(&bts->rbs2000.is.om2k_mo);</span><br><span>  } else {</span><br><span>             osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_CON, BTS_FSM_TIMEOUT, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-           om2k_mo_fsm_start(fi, OM2K_BTS_EVT_CON_DONE, bts->c0, &bts->rbs2000.con.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+           om2k_mo_fsm_start(&bts->rbs2000.con.om2k_mo);</span><br><span>         }</span><br><span> }</span><br><span> </span><br><span>@@ -2349,7 +2425,7 @@</span><br><span>   OSMO_ASSERT(event == OM2K_BTS_EVT_CON_DONE);</span><br><span> </span><br><span>     osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_IS, BTS_FSM_TIMEOUT, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    om2k_mo_fsm_start(fi, OM2K_BTS_EVT_IS_DONE, bts->c0, &bts->rbs2000.is.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+     om2k_mo_fsm_start(&bts->rbs2000.is.om2k_mo);</span><br><span> }</span><br><span> </span><br><span> static void om2k_bts_s_wait_is(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -2362,7 +2438,7 @@</span><br><span>         /* If we're running OML >= G12R13, start MCTR, else skip directly to TRX */</span><br><span>   if (bts->rbs2000.om2k_version[0].active >= 0x0c0d) {</span><br><span>           osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_MCTR, BTS_FSM_TIMEOUT, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-          om2k_mo_fsm_start(fi, OM2K_BTS_EVT_MCTR_DONE, bts->c0, &bts->rbs2000.mctr.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+         om2k_mo_fsm_start(&bts->rbs2000.mctr.om2k_mo);</span><br><span>        } else {</span><br><span>             osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX_LAPD, TRX_LAPD_TIMEOUT, 0);</span><br><span>  }</span><br><span>@@ -2385,7 +2461,7 @@</span><br><span>    osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX, BTS_FSM_TIMEOUT, 0);</span><br><span>        obfp->next_trx_nr = 0;</span><br><span>    trx = gsm_bts_trx_num(obfp->bts, obfp->next_trx_nr++);</span><br><span style="color: hsl(0, 100%, 40%);">-    om2k_trx_fsm_start(fi, trx, OM2K_BTS_EVT_TRX_DONE);</span><br><span style="color: hsl(120, 100%, 40%);">+   om2k_trx_fsm_start(trx);</span><br><span> }</span><br><span> </span><br><span> static void om2k_bts_s_wait_trx(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -2397,7 +2473,7 @@</span><br><span>   if (obfp->next_trx_nr < obfp->bts->num_trx) {</span><br><span>            struct gsm_bts_trx *trx;</span><br><span>             trx = gsm_bts_trx_num(obfp->bts, obfp->next_trx_nr++);</span><br><span style="color: hsl(0, 100%, 40%);">-            om2k_trx_fsm_start(fi, trx, OM2K_BTS_EVT_TRX_DONE);</span><br><span style="color: hsl(120, 100%, 40%);">+           om2k_trx_fsm_start(trx);</span><br><span>     } else {</span><br><span>             osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_DONE, 0, 0);</span><br><span>  }</span><br><span>@@ -2405,20 +2481,33 @@</span><br><span> </span><br><span> static void om2k_bts_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-      osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void om2k_bts_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case OM2K_BTS_EVT_RESET:</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_fsm_inst_broadcast_children(fi, event, data);</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_INIT, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> }</span><br><span> </span><br><span> static const struct osmo_fsm_state om2k_bts_states[] = {</span><br><span>       [OM2K_BTS_S_INIT] = {</span><br><span>                .in_event_mask = S(OM2K_BTS_EVT_START),</span><br><span style="color: hsl(0, 100%, 40%);">-         .out_state_mask = S(OM2K_BTS_S_WAIT_CF),</span><br><span style="color: hsl(120, 100%, 40%);">+              .out_state_mask = S(OM2K_BTS_S_WAIT_CF) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(OM2K_BTS_S_INIT),</span><br><span>                .name = "INIT",</span><br><span>            .action = om2k_bts_s_init,</span><br><span>   },</span><br><span>   [OM2K_BTS_S_WAIT_CF] = {</span><br><span>             .in_event_mask = S(OM2K_BTS_EVT_CF_DONE),</span><br><span>            .out_state_mask = S(OM2K_BTS_S_ERROR) |</span><br><span style="color: hsl(0, 100%, 40%);">-                           S(OM2K_BTS_S_WAIT_TF),</span><br><span style="color: hsl(120, 100%, 40%);">+                                S(OM2K_BTS_S_WAIT_TF) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(OM2K_BTS_S_INIT),</span><br><span>                .name = "WAIT-CF",</span><br><span>                 .action = om2k_bts_s_wait_cf,</span><br><span>        },</span><br><span>@@ -2426,14 +2515,16 @@</span><br><span>                 .in_event_mask = S(OM2K_BTS_EVT_TF_DONE),</span><br><span>            .out_state_mask = S(OM2K_BTS_S_ERROR) |</span><br><span>                                S(OM2K_BTS_S_WAIT_CON) |</span><br><span style="color: hsl(0, 100%, 40%);">-                                S(OM2K_BTS_S_WAIT_IS),</span><br><span style="color: hsl(120, 100%, 40%);">+                                S(OM2K_BTS_S_WAIT_IS) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(OM2K_BTS_S_INIT),</span><br><span>                .name = "WAIT-TF",</span><br><span>                 .action = om2k_bts_s_wait_tf,</span><br><span>        },</span><br><span>   [OM2K_BTS_S_WAIT_CON] = {</span><br><span>            .in_event_mask = S(OM2K_BTS_EVT_CON_DONE),</span><br><span>           .out_state_mask = S(OM2K_BTS_S_ERROR) |</span><br><span style="color: hsl(0, 100%, 40%);">-                           S(OM2K_BTS_S_WAIT_IS),</span><br><span style="color: hsl(120, 100%, 40%);">+                                S(OM2K_BTS_S_WAIT_IS) |</span><br><span style="color: hsl(120, 100%, 40%);">+                               S(OM2K_BTS_S_INIT),</span><br><span>                .name = "WAIT-CON",</span><br><span>                .action = om2k_bts_s_wait_con,</span><br><span>       },</span><br><span>@@ -2441,35 +2532,41 @@</span><br><span>                 .in_event_mask = S(OM2K_BTS_EVT_IS_DONE),</span><br><span>            .out_state_mask = S(OM2K_BTS_S_ERROR) |</span><br><span>                                S(OM2K_BTS_S_WAIT_MCTR) |</span><br><span style="color: hsl(0, 100%, 40%);">-                               S(OM2K_BTS_S_WAIT_TRX_LAPD),</span><br><span style="color: hsl(120, 100%, 40%);">+                                  S(OM2K_BTS_S_WAIT_TRX_LAPD) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(OM2K_BTS_S_INIT),</span><br><span>                .name = "WAIT-IS",</span><br><span>                 .action = om2k_bts_s_wait_is,</span><br><span>        },</span><br><span>   [OM2K_BTS_S_WAIT_MCTR] = {</span><br><span>           .in_event_mask = S(OM2K_BTS_EVT_MCTR_DONE),</span><br><span>          .out_state_mask = S(OM2K_BTS_S_ERROR) |</span><br><span style="color: hsl(0, 100%, 40%);">-                           S(OM2K_BTS_S_WAIT_TRX_LAPD),</span><br><span style="color: hsl(120, 100%, 40%);">+                                  S(OM2K_BTS_S_WAIT_TRX_LAPD) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(OM2K_BTS_S_INIT),</span><br><span>                .name = "WAIT-MCTR",</span><br><span>               .action = om2k_bts_s_wait_mctr,</span><br><span>      },</span><br><span>   [OM2K_BTS_S_WAIT_TRX_LAPD] = {</span><br><span>               .in_event_mask = S(OM2K_BTS_EVT_TRX_LAPD_UP),</span><br><span style="color: hsl(0, 100%, 40%);">-           .out_state_mask = S(OM2K_BTS_S_WAIT_TRX),</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = S(OM2K_BTS_S_WAIT_TRX) |</span><br><span style="color: hsl(120, 100%, 40%);">+                              S(OM2K_BTS_S_INIT),</span><br><span>                .name = "WAIT-TRX-LAPD",</span><br><span>           .action = om2k_bts_s_wait_trx_lapd,</span><br><span>  },</span><br><span>   [OM2K_BTS_S_WAIT_TRX] = {</span><br><span>            .in_event_mask = S(OM2K_BTS_EVT_TRX_DONE),</span><br><span>           .out_state_mask = S(OM2K_BTS_S_ERROR) |</span><br><span style="color: hsl(0, 100%, 40%);">-                           S(OM2K_BTS_S_DONE),</span><br><span style="color: hsl(120, 100%, 40%);">+                           S(OM2K_BTS_S_DONE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                  S(OM2K_BTS_S_INIT),</span><br><span>                .name = "WAIT-TRX",</span><br><span>                .action = om2k_bts_s_wait_trx,</span><br><span>       },</span><br><span>   [OM2K_BTS_S_DONE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+         .out_state_mask = S(OM2K_BTS_S_INIT),</span><br><span>                .name = "DONE",</span><br><span>            .onenter = om2k_bts_s_done_onenter,</span><br><span>  },</span><br><span>   [OM2K_BTS_S_ERROR] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask = S(OM2K_BTS_S_INIT),</span><br><span>                .name = "ERROR",</span><br><span>   },</span><br><span> };</span><br><span>@@ -2492,30 +2589,44 @@</span><br><span>   .states = om2k_bts_states,</span><br><span>   .num_states = ARRAY_SIZE(om2k_bts_states),</span><br><span>   .log_subsys = DNM,</span><br><span style="color: hsl(120, 100%, 40%);">+    .allstate_event_mask = S(OM2K_BTS_EVT_RESET),</span><br><span style="color: hsl(120, 100%, 40%);">+ .allstate_action = om2k_bts_allstate,</span><br><span>        .event_names = om2k_bts_events,</span><br><span>      .timer_cb = om2k_bts_timer_cb,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct osmo_fsm_inst *</span><br><span style="color: hsl(0, 100%, 40%);">-om2k_bts_fsm_start(struct gsm_bts *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm_inst *</span><br><span style="color: hsl(120, 100%, 40%);">+om2k_bts_fsm_alloc(struct gsm_bts *bts)</span><br><span> {</span><br><span>   struct osmo_fsm_inst *fi;</span><br><span>    struct om2k_bts_fsm_priv *obfp;</span><br><span>      char idbuf[16];</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(!bts->rbs2000.bts_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      snprintf(idbuf, sizeof(idbuf), "%u", bts->nr);</span><br><span> </span><br><span>      fi = osmo_fsm_inst_alloc(&om2k_bts_fsm, bts, NULL, LOGL_DEBUG, idbuf);</span><br><span>   if (!fi)</span><br><span>             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       fi->priv = obfp = talloc_zero(fi, struct om2k_bts_fsm_priv);</span><br><span>      obfp->bts = bts;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- osmo_fsm_inst_dispatch(fi, OM2K_BTS_EVT_START, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>        return fi;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void om2k_bts_fsm_start(struct gsm_bts *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(bts->rbs2000.bts_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_fsm_inst_dispatch(bts->rbs2000.bts_fi, OM2K_BTS_EVT_START, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void om2k_bts_fsm_reset(struct gsm_bts *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(bts->rbs2000.bts_fi);</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_fsm_inst_dispatch(bts->rbs2000.bts_fi, OM2K_BTS_EVT_RESET, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> /***********************************************************************</span><br><span>  * OM2000 Negotiation</span><br><span>@@ -2955,17 +3066,27 @@</span><br><span> void abis_om2k_trx_init(struct gsm_bts_trx *trx)</span><br><span> {</span><br><span>     struct gsm_bts *bts = trx->bts;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_fsm_inst *trx_fi;</span><br><span>        unsigned int i;</span><br><span> </span><br><span>  OSMO_ASSERT(bts->type == GSM_BTS_TYPE_RBS2000);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        trx_fi = om2k_trx_fsm_alloc(trx->bts->rbs2000.bts_fi, trx, OM2K_BTS_EVT_TRX_DONE);</span><br><span style="color: hsl(120, 100%, 40%);">+      trx->rbs2000.trx_fi = trx_fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   om2k_mo_init(&trx->rbs2000.trxc.om2k_mo, OM2K_MO_CLS_TRXC, bts->nr, 255, trx->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+       om2k_mo_fsm_alloc(trx_fi, OM2K_TRX_EVT_TRXC_DONE, trx, &trx->rbs2000.trxc.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         om2k_mo_init(&trx->rbs2000.tx.om2k_mo, OM2K_MO_CLS_TX, bts->nr, 255, trx->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+   om2k_mo_fsm_alloc(trx_fi, OM2K_TRX_EVT_TX_DONE, trx, &trx->rbs2000.tx.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     om2k_mo_init(&trx->rbs2000.rx.om2k_mo, OM2K_MO_CLS_RX, bts->nr, 255, trx->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+   om2k_mo_fsm_alloc(trx_fi, OM2K_TRX_EVT_RX_DONE, trx, &trx->rbs2000.rx.om2k_mo);</span><br><span> </span><br><span>   for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {</span><br><span>            struct gsm_bts_trx_ts *ts = &trx->ts[i];</span><br><span>              om2k_mo_init(&ts->rbs2000.om2k_mo, OM2K_MO_CLS_TS, bts->nr, trx->nr, i);</span><br><span style="color: hsl(120, 100%, 40%);">+         om2k_mo_fsm_alloc(trx_fi, OM2K_TRX_EVT_TS_DONE, trx, &ts->rbs2000.om2k_mo);</span><br><span>           OSMO_ASSERT(ts->fi);</span><br><span>      }</span><br><span> }</span><br><span>@@ -2973,14 +3094,29 @@</span><br><span> /* initialize the OM2K_MO members of gsm_bts */</span><br><span> void abis_om2k_bts_init(struct gsm_bts *bts)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_fsm_inst *bts_fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      OSMO_ASSERT(bts->type == GSM_BTS_TYPE_RBS2000);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        bts_fi = om2k_bts_fsm_alloc(bts);</span><br><span style="color: hsl(120, 100%, 40%);">+     bts->rbs2000.bts_fi = bts_fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   om2k_mo_init(&bts->rbs2000.cf.om2k_mo, OM2K_MO_CLS_CF, bts->nr, 0xFF, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   om2k_mo_fsm_alloc(bts_fi, OM2K_BTS_EVT_CF_DONE, bts->c0, &bts->rbs2000.cf.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      om2k_mo_init(&bts->rbs2000.is.om2k_mo, OM2K_MO_CLS_IS, bts->nr, 0xFF, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   om2k_mo_fsm_alloc(bts_fi, OM2K_BTS_EVT_IS_DONE, bts->c0, &bts->rbs2000.is.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      om2k_mo_init(&bts->rbs2000.con.om2k_mo, OM2K_MO_CLS_CON, bts->nr, 0xFF, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ om2k_mo_fsm_alloc(bts_fi, OM2K_BTS_EVT_CON_DONE, bts->c0, &bts->rbs2000.con.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    om2k_mo_init(&bts->rbs2000.dp.om2k_mo, OM2K_MO_CLS_DP, bts->nr, 0xFF, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        om2k_mo_init(&bts->rbs2000.tf.om2k_mo, OM2K_MO_CLS_TF, bts->nr, 0xFF, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   om2k_mo_fsm_alloc(bts_fi, OM2K_BTS_EVT_TF_DONE, bts->c0, &bts->rbs2000.tf.om2k_mo);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      om2k_mo_init(&bts->rbs2000.mctr.om2k_mo, OM2K_MO_CLS_MCTR, bts->nr, 0xFF, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       om2k_mo_fsm_alloc(bts_fi, OM2K_BTS_EVT_MCTR_DONE, bts->c0, &bts->rbs2000.mctr.om2k_mo);</span><br><span>    // FIXME: There can be multiple MCTRs ...</span><br><span> }</span><br><span> </span><br><span>diff --git a/src/osmo-bsc/bts_ericsson_rbs2000.c b/src/osmo-bsc/bts_ericsson_rbs2000.c</span><br><span>index 1297b30..4fbf057 100644</span><br><span>--- a/src/osmo-bsc/bts_ericsson_rbs2000.c</span><br><span>+++ b/src/osmo-bsc/bts_ericsson_rbs2000.c</span><br><span>@@ -35,16 +35,8 @@</span><br><span> </span><br><span> static void bootstrap_om_bts(struct gsm_bts *bts)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct gsm_bts_trx *trx;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>     LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     /* Global init (not bootstrapping) */</span><br><span style="color: hsl(0, 100%, 40%);">-   abis_om2k_bts_init(bts);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        llist_for_each_entry(trx, &bts->trx_list, list)</span><br><span style="color: hsl(0, 100%, 40%);">-          abis_om2k_trx_init(trx);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>     /* TODO: Should we wait for a Failure report? */</span><br><span>     om2k_bts_fsm_start(bts);</span><br><span> }</span><br><span>@@ -53,7 +45,8 @@</span><br><span> {</span><br><span>       LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for TRX %u/%u\n",</span><br><span>             trx->bts->nr, trx->nr);</span><br><span style="color: hsl(0, 100%, 40%);">-   /* FIXME */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ om2k_trx_fsm_start(trx);</span><br><span> }</span><br><span> </span><br><span> static int shutdown_om(struct gsm_bts *bts)</span><br><span>@@ -145,6 +138,11 @@</span><br><span>              LOGP(DNM, LOGL_NOTICE, "Line-%u TS-%u TEI-%u SAPI-%u: Link "</span><br><span>                    "Lost for Ericsson RBS2000. Re-starting DL Establishment\n",</span><br><span>               isd->line->num, isd->ts_nr, isd->tei, isd->sapi);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (isd->tei == isd->trx->bts->oml_tei)</span><br><span style="color: hsl(120, 100%, 40%);">+                   om2k_bts_fsm_reset(isd->trx->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+              else</span><br><span style="color: hsl(120, 100%, 40%);">+                  om2k_trx_fsm_reset(isd->trx);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span>               /* Some datalink for a given TEI/SAPI went down, try to re-start it */</span><br><span>               e1i_ts = &isd->line->ts[isd->ts_nr-1];</span><br><span>          OSMO_ASSERT(e1i_ts->type == E1INP_TS_TYPE_SIGN);</span><br><span>@@ -184,10 +182,24 @@</span><br><span>  e1inp_line_bind_ops(line, &bts_isdn_e1inp_line_ops);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int bts_model_rbs2k_bts_init(struct gsm_bts *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        abis_om2k_bts_init(bts);</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int bts_model_rbs2k_trx_init(struct gsm_bts_trx *trx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       abis_om2k_trx_init(trx);</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct gsm_bts_model model_rbs2k = {</span><br><span>        .type = GSM_BTS_TYPE_RBS2000,</span><br><span>        .name = "rbs2000",</span><br><span>         .start = bts_model_rbs2k_start,</span><br><span style="color: hsl(120, 100%, 40%);">+       .bts_init = bts_model_rbs2k_bts_init,</span><br><span style="color: hsl(120, 100%, 40%);">+ .trx_init = bts_model_rbs2k_trx_init,</span><br><span>        .oml_rcvmsg = &abis_om2k_rcvmsg,</span><br><span>         .config_write_bts = &config_write_bts,</span><br><span>   .e1line_bind_ops = &bts_model_rbs2k_e1line_bind_ops,</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bsc/+/21829">change 21829</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-bsc/+/21829"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-bsc </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ia37cffff5c451e1d79a52ccae41ab5718b4661d4 </div>
<div style="display:none"> Gerrit-Change-Number: 21829 </div>
<div style="display:none"> Gerrit-PatchSet: 5 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-CC: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>