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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">osmo-bts-trx/scheduler: implement baseband frequency hopping<br><br>The idea behind the baseband frequency hopping is quite simple: we<br>have several RF carriers (transceivers) transmitting and receiving<br>on fixed frequencies (just like in a regular multi-trx setup), and<br>an additional burst routing layer between the schedulear and the<br>transceiver interface (TRXD over UDP).<br><br>Speaking in terms of the proposed implementation:<br><br>  - on Downlink, dlfh_route_br() calculates the ARFCN corresponding<br>    to the current TDMA frame number according to the hopping sequence<br>    parametets, and picks the transceiver with matching ARFCN;<br><br>  - on Uplink, ulfh_route_bi() iterates over the transceiver list of<br>    of the BTS, calculating hopping ARFCNs for equivalent timeslots,<br>    and picks the one with ARFCN matching the received burst.<br><br>In order to avoid frequent transceiver lookups on the Downlink path,<br>dlfh_route_br() maintains a "cache" in the timeslot state structure.<br>Unfortunately, this "cache" seems to be useless on the Uplink path,<br>so ulfh_route_bi() always needs to lookup the matching transceiver<br>for each burst received over the TRXD interface.<br><br>It may also happen that the scheduler will be unable to route an<br>Uplink or Downlink burst, e.g. due to inconsistent / incorrect<br>hopping sequence parameters received from the BSC, or in case<br>if a transceiver gets RF-locked by the BTS operator.<br><br>Such events are logged as "FATAL" and aditionally signalled by the<br>following osmo-bts-trx specific rate counters:<br><br>  - trx_sched:dl_fh_no_carrier (Downlink), and<br>  - trx_sched:ul_fh_no_carrier (Uplink).<br><br>Change-Id: I68f4ae09fd0789ad0d8f1c1e17e17dfc4de8e462<br>Related: SYS#4868, OS#4546<br>---<br>M include/osmo-bts/gsm_data.h<br>M include/osmo-bts/scheduler.h<br>M src/osmo-bts-trx/l1_if.h<br>M src/osmo-bts-trx/main.c<br>M src/osmo-bts-trx/scheduler_trx.c<br>M src/osmo-bts-trx/trx_if.c<br>6 files changed, 117 insertions(+), 4 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h</span><br><span>index 0402f11..6b696b4 100644</span><br><span>--- a/include/osmo-bts/gsm_data.h</span><br><span>+++ b/include/osmo-bts/gsm_data.h</span><br><span>@@ -335,6 +335,9 @@</span><br><span>          uint8_t ma_len;</span><br><span>      } hopping;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        /* Transceiver "cache" for frequency hopping */</span><br><span style="color: hsl(120, 100%, 40%);">+     const struct gsm_bts_trx *fh_trx_list[64];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         struct gsm_lchan lchan[TS_MAX_LCHAN];</span><br><span> };</span><br><span> </span><br><span>diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h</span><br><span>index bc2fb69..47c0e9a 100644</span><br><span>--- a/include/osmo-bts/scheduler.h</span><br><span>+++ b/include/osmo-bts/scheduler.h</span><br><span>@@ -267,6 +267,7 @@</span><br><span> };</span><br><span> </span><br><span> /*! Handle an UL burst received by PHY */</span><br><span style="color: hsl(120, 100%, 40%);">+int trx_sched_route_burst_ind(struct trx_ul_burst_ind *bi, struct l1sched_trx *l1t);</span><br><span> int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi);</span><br><span> </span><br><span> #endif /* TRX_SCHEDULER_H */</span><br><span>diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h</span><br><span>index fb988a6..8c309db 100644</span><br><span>--- a/src/osmo-bts-trx/l1_if.h</span><br><span>+++ b/src/osmo-bts-trx/l1_if.h</span><br><span>@@ -29,6 +29,8 @@</span><br><span> /* bts-trx specific rate counters */</span><br><span> enum {</span><br><span>      BTSTRX_CTR_SCHED_DL_MISS_FN,</span><br><span style="color: hsl(120, 100%, 40%);">+  BTSTRX_CTR_SCHED_DL_FH_NO_CARRIER,</span><br><span style="color: hsl(120, 100%, 40%);">+    BTSTRX_CTR_SCHED_UL_FH_NO_CARRIER,</span><br><span> };</span><br><span> </span><br><span> /*! clock state of a given TRX */</span><br><span>diff --git a/src/osmo-bts-trx/main.c b/src/osmo-bts-trx/main.c</span><br><span>index e35f6fe..e2d9005 100644</span><br><span>--- a/src/osmo-bts-trx/main.c</span><br><span>+++ b/src/osmo-bts-trx/main.c</span><br><span>@@ -62,8 +62,18 @@</span><br><span> #include "trx_if.h"</span><br><span> </span><br><span> static const struct rate_ctr_desc btstrx_ctr_desc[] = {</span><br><span style="color: hsl(0, 100%, 40%);">- [BTSTRX_CTR_SCHED_DL_MISS_FN] = {"trx_clk:sched_dl_miss_fn",</span><br><span style="color: hsl(0, 100%, 40%);">-                                   "Downlink frames scheduled later than expected due to missed timerfd event (due to high system load)"},</span><br><span style="color: hsl(120, 100%, 40%);">+    [BTSTRX_CTR_SCHED_DL_MISS_FN] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             "trx_clk:sched_dl_miss_fn",</span><br><span style="color: hsl(120, 100%, 40%);">+         "Downlink frames scheduled later than expected due to missed timerfd event (due to high system load)"</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [BTSTRX_CTR_SCHED_DL_FH_NO_CARRIER] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               "trx_sched:dl_fh_no_carrier",</span><br><span style="color: hsl(120, 100%, 40%);">+               "Frequency hopping: no carrier found for a Downlink burst (check hopping parameters)"</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [BTSTRX_CTR_SCHED_UL_FH_NO_CARRIER] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               "trx_sched:ul_fh_no_carrier",</span><br><span style="color: hsl(120, 100%, 40%);">+               "Frequency hopping: no carrier found for an Uplink burst (check hopping parameters)"</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span> };</span><br><span> static const struct rate_ctr_group_desc btstrx_ctrg_desc = {</span><br><span>     "bts-trx",</span><br><span>diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c</span><br><span>index e617031..fd68f63 100644</span><br><span>--- a/src/osmo-bts-trx/scheduler_trx.c</span><br><span>+++ b/src/osmo-bts-trx/scheduler_trx.c</span><br><span>@@ -34,6 +34,7 @@</span><br><span> #include <osmocom/core/timer_compat.h></span><br><span> #include <osmocom/core/bits.h></span><br><span> #include <osmocom/gsm/a5.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm0502.h></span><br><span> </span><br><span> </span><br><span> #include <osmo-bts/gsm_data.h></span><br><span>@@ -47,6 +48,10 @@</span><br><span> #include "l1_if.h"</span><br><span> #include "trx_if.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define SCHED_FH_PARAMS_FMT "hsn=%u, maio=%u, ma_len=%u"</span><br><span style="color: hsl(120, 100%, 40%);">+#define SCHED_FH_PARAMS_VALS(ts) \</span><br><span style="color: hsl(120, 100%, 40%);">+  (ts)->hopping.hsn, (ts)->hopping.maio, (ts)->hopping.ma_len</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */</span><br><span> int tx_idle_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,</span><br><span>              uint8_t bid, struct trx_dl_burst_req *br)</span><br><span>@@ -55,6 +60,39 @@</span><br><span>        return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Find a route (PHY instance) for a given Downlink burst request */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct phy_instance *dlfh_route_br(const struct trx_dl_burst_req *br,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          struct gsm_bts_trx_ts *ts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct gsm_bts_trx *trx;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm_time time;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t idx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       gsm_fn2gsmtime(&time, br->fn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Check the "cache" first, so we eliminate frequent lookups */</span><br><span style="color: hsl(120, 100%, 40%);">+     idx = gsm0502_hop_seq_gen(&time, SCHED_FH_PARAMS_VALS(ts), NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ts->fh_trx_list[idx] != NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+          return ts->fh_trx_list[idx]->role_bts.l1h;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* The "cache" may not be filled yet, lookup the transceiver */</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_for_each_entry(trx, &ts->trx->bts->trx_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (trx->arfcn == ts->hopping.ma[idx]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        ts->fh_trx_list[idx] = trx;</span><br><span style="color: hsl(120, 100%, 40%);">+                        return trx->role_bts.l1h;</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 style="color: hsl(120, 100%, 40%);">+   LOGPTRX(ts->trx, DL1C, LOGL_FATAL, "Failed to find the transceiver (RF carrier) "</span><br><span style="color: hsl(120, 100%, 40%);">+                "for a Downlink burst (fn=%u, tn=%u, " SCHED_FH_PARAMS_FMT ")\n",</span><br><span style="color: hsl(120, 100%, 40%);">+         br->fn, br->tn, SCHED_FH_PARAMS_VALS(ts));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    struct bts_trx_priv *priv = (struct bts_trx_priv *) ts->trx->bts->model_priv;</span><br><span style="color: hsl(120, 100%, 40%);">+        rate_ctr_inc(&priv->ctrs->ctr[BTSTRX_CTR_SCHED_DL_FH_NO_CARRIER]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* schedule all frames of all TRX for given FN */</span><br><span> static void trx_sched_fn(struct gsm_bts *bts, const uint32_t fn)</span><br><span> {</span><br><span>@@ -100,8 +138,16 @@</span><br><span>                               continue;</span><br><span>                    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+                 /* resolve PHY instance if freq. hopping is enabled */</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (trx->ts[tn].hopping.enabled) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         pinst = dlfh_route_br(&br, &trx->ts[tn]);</span><br><span style="color: hsl(120, 100%, 40%);">+                          if (pinst == NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+                                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                             l1h = pinst->u.osmotrx.hdl;</span><br><span style="color: hsl(120, 100%, 40%);">+                        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                  /* update dummy burst mask for C0 */</span><br><span style="color: hsl(0, 100%, 40%);">-                    if (trx == bts->c0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (pinst->trx == bts->c0)</span><br><span>                             c0_mask |= (1 << tn);</span><br><span> </span><br><span>                      trx_if_send_burst(l1h, &br);</span><br><span>@@ -127,6 +173,57 @@</span><br><span>      }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Find a route (TRX instance) for a given Uplink burst indication */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gsm_bts_trx *ulfh_route_bi(const struct trx_ul_burst_ind *bi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         const struct gsm_bts_trx *src_trx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm_bts_trx *trx;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_time time;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t arfcn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     gsm_fn2gsmtime(&time, bi->fn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry(trx, &src_trx->bts->trx_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+          const struct gsm_bts_trx_ts *ts = &trx->ts[bi->tn];</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!ts->hopping.enabled)</span><br><span style="color: hsl(120, 100%, 40%);">+                  continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           arfcn = gsm0502_hop_seq_gen(&time, SCHED_FH_PARAMS_VALS(ts), ts->hopping.ma);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (src_trx->arfcn == arfcn)</span><br><span style="color: hsl(120, 100%, 40%);">+                       return trx;</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%);">+   LOGPTRX(src_trx, DL1C, LOGL_DEBUG, "Failed to find the transceiver (RF carrier) "</span><br><span style="color: hsl(120, 100%, 40%);">+           "for an Uplink burst (fn=%u, tn=%u, " SCHED_FH_PARAMS_FMT ")\n",</span><br><span style="color: hsl(120, 100%, 40%);">+          bi->fn, bi->tn, SCHED_FH_PARAMS_VALS(&src_trx->ts[bi->tn]));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bts_trx_priv *priv = (struct bts_trx_priv *) src_trx->bts->model_priv;</span><br><span style="color: hsl(120, 100%, 40%);">+   rate_ctr_inc(&priv->ctrs->ctr[BTSTRX_CTR_SCHED_UL_FH_NO_CARRIER]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 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%);">+/* Route a given Uplink burst indication to the scheduler depending on freq. hopping state */</span><br><span style="color: hsl(120, 100%, 40%);">+int trx_sched_route_burst_ind(struct trx_ul_burst_ind *bi, struct l1sched_trx *l1t)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct phy_instance *pinst;</span><br><span style="color: hsl(120, 100%, 40%);">+     const struct gsm_bts_trx *trx;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct trx_l1h *l1h;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* no frequency hopping => nothing to do */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!l1t->trx->ts[bi->tn].hopping.enabled)</span><br><span style="color: hsl(120, 100%, 40%);">+           return trx_sched_ul_burst(l1t, bi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ trx = ulfh_route_bi(bi, l1t->trx);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (trx == NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+              return -ENODEV;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     pinst = trx_phy_instance(trx);</span><br><span style="color: hsl(120, 100%, 40%);">+        l1h = pinst->u.osmotrx.hdl;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return trx_sched_ul_burst(&l1h->l1s, bi);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! maximum number of 'missed' frame periods we can tolerate of OS doesn't schedule us*/</span><br><span> #define MAX_FN_SKEW            50</span><br><span> /*! maximum number of frame periods we can tolerate without TRX Clock Indication*/</span><br><span>diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c</span><br><span>index ad6faad..875487a 100644</span><br><span>--- a/src/osmo-bts-trx/trx_if.c</span><br><span>+++ b/src/osmo-bts-trx/trx_if.c</span><br><span>@@ -1094,7 +1094,7 @@</span><br><span>            hdr_ver, trx_data_desc_msg(&bi));</span><br><span> </span><br><span>    /* feed received burst into scheduler code */</span><br><span style="color: hsl(0, 100%, 40%);">-   trx_sched_ul_burst(&l1h->l1s, &bi);</span><br><span style="color: hsl(120, 100%, 40%);">+        trx_sched_route_burst_ind(&bi, &l1h->l1s);</span><br><span> </span><br><span>    return 0;</span><br><span> }</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bts/+/19030">change 19030</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-bts/+/19030"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-bts </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I68f4ae09fd0789ad0d8f1c1e17e17dfc4de8e462 </div>
<div style="display:none"> Gerrit-Change-Number: 19030 </div>
<div style="display:none"> Gerrit-PatchSet: 6 </div>
<div style="display:none"> Gerrit-Owner: fixeria <vyanitskiy@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Hoernchen <ewild@sysmocom.de> </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>