<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/10455">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">trxcon/sched_prim.c: properly handle both TCH/H and FACCH/H prims<br><br>Initially it was assumed that FACCH prioritization should be done<br>in the same way for both TCH/F and TCH/H. Moreover, it was not<br>possible to confirm this, because TCH/H was (and still) not<br>implemented yet. But according to the specs:<br><br>  - unlike FACCH/F, FACCH/H transmissions shall be aligned<br>    within a multiframe, i.e. can only be initiated on<br>    particular frame numbers (see GSM 05.02, clause 7);<br><br>  - unlike FACCH/F, a FACCH/H frame steals two TCH/F frames;<br><br>so the TCH/H (including FACCH/H) primitives should be handled<br>separately from the TCH/F (including FACCH/F) primitives.<br><br>Change-Id: I9b59f60e1cbac8fb8fd557b6c67b5e376c0a6bbb<br>---<br>M src/host/trxcon/sched_prim.c<br>M src/host/trxcon/sched_trx.c<br>M src/host/trxcon/sched_trx.h<br>3 files changed, 86 insertions(+), 6 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/host/trxcon/sched_prim.c b/src/host/trxcon/sched_prim.c</span><br><span>index 4987379..acd08bf 100644</span><br><span>--- a/src/host/trxcon/sched_prim.c</span><br><span>+++ b/src/host/trxcon/sched_prim.c</span><br><span>@@ -223,25 +223,105 @@</span><br><span> }</span><br><span> </span><br><span> /**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Dequeues either a TCH/H, or a FACCH/H prim (preferred).</span><br><span style="color: hsl(120, 100%, 40%);">+ * If a FACCH/H prim is found, two TCH/H prims are being</span><br><span style="color: hsl(120, 100%, 40%);">+ * dropped (i.e. replaced).</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * According to GSM 05.02, the following blocks can be used</span><br><span style="color: hsl(120, 100%, 40%);">+ * to carry FACCH/H data (see clause 7, table 1 of 9):</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * UL FACCH/H0:</span><br><span style="color: hsl(120, 100%, 40%);">+ * B0(0,2,4,6,8,10), B1(8,10,13,15,17,19), B2(17,19,21,23,0,2)</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * UL FACCH/H1:</span><br><span style="color: hsl(120, 100%, 40%);">+ * B0(1,3,5,7,9,11), B1(9,11,14,16,18,20), B2(18,20,22,24,1,3)</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * where the numbers within brackets are fn % 26.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param  queue      transmit queue to take a prim from</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param  fn         the current frame number</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param  lchan_type required channel type of a primitive,</span><br><span style="color: hsl(120, 100%, 40%);">+ * @return            either a FACCH/H, or a TCH/H primitive,</span><br><span style="color: hsl(120, 100%, 40%);">+ *                    otherwise NULL</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct trx_ts_prim *prim_dequeue_tch_h(struct llist_head *queue,</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t fn, enum trx_lchan_type lchan_type)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct trx_ts_prim *facch;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct trx_ts_prim *tch;</span><br><span style="color: hsl(120, 100%, 40%);">+      bool facch_now = false;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t fn_mf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Traffic multiframe period */</span><br><span style="color: hsl(120, 100%, 40%);">+       fn_mf = fn % 26;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* FACCH/H0 frame alignment */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (lchan_type == TRXC_TCHH_0)</span><br><span style="color: hsl(120, 100%, 40%);">+                if (fn_mf == 0 || fn_mf == 8 || fn_mf == 17)</span><br><span style="color: hsl(120, 100%, 40%);">+                  facch_now = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* FACCH/H1 frame alignment */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (lchan_type == TRXC_TCHH_1)</span><br><span style="color: hsl(120, 100%, 40%);">+                if (fn_mf == 1 || fn_mf == 9 || fn_mf == 18)</span><br><span style="color: hsl(120, 100%, 40%);">+                  facch_now = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* If FACCH/H is not allowed for a given frame number */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!facch_now) /* Just dequeue a TCH/H prim */</span><br><span style="color: hsl(120, 100%, 40%);">+               goto no_facch;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* If there are no FACCH/H prims in the queue */</span><br><span style="color: hsl(120, 100%, 40%);">+      facch = prim_dequeue_tch(queue, lchan_type, true);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!facch) /* Just dequeue a TCH/H prim */</span><br><span style="color: hsl(120, 100%, 40%);">+           goto no_facch;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* FACCH/H prim replaces two TCH/F prims */</span><br><span style="color: hsl(120, 100%, 40%);">+   tch = prim_dequeue_tch(queue, lchan_type, false);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (tch) {</span><br><span style="color: hsl(120, 100%, 40%);">+            /* At least one TCH/H prim is dropped */</span><br><span style="color: hsl(120, 100%, 40%);">+              talloc_free(tch);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Attempt to find another */</span><br><span style="color: hsl(120, 100%, 40%);">+         tch = prim_dequeue_tch(queue, lchan_type, false);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (tch) /* Drop the second TCH/H prim */</span><br><span style="color: hsl(120, 100%, 40%);">+                     talloc_free(tch);</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%);">+   return facch;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+no_facch:</span><br><span style="color: hsl(120, 100%, 40%);">+    return prim_dequeue_tch(queue, lchan_type, false);</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>  * Dequeues a single primitive of required type</span><br><span>  * from a specified transmit queue.</span><br><span>  *</span><br><span>  * @param  queue      a transmit queue to take a prim from</span><br><span style="color: hsl(120, 100%, 40%);">+ * @param  fn         the current frame number (used for FACCH/H)</span><br><span>  * @param  lchan_type required primitive type</span><br><span>  * @return            a primitive or NULL if not found</span><br><span>  */</span><br><span> struct trx_ts_prim *sched_prim_dequeue(struct llist_head *queue,</span><br><span style="color: hsl(0, 100%, 40%);">-     enum trx_lchan_type lchan_type)</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t fn, enum trx_lchan_type lchan_type)</span><br><span> {</span><br><span>    /* There is nothing to dequeue */</span><br><span>    if (llist_empty(queue))</span><br><span>              return NULL;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        /* TCH requires FACCH prioritization, so handle it separately */</span><br><span style="color: hsl(0, 100%, 40%);">-        if (CHAN_IS_TCH(lchan_type))</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (lchan_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TCH/F requires FACCH/F prioritization */</span><br><span style="color: hsl(120, 100%, 40%);">+   case TRXC_TCHF:</span><br><span>              return prim_dequeue_tch_f(queue);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return prim_dequeue_one(queue, lchan_type);</span><br><span style="color: hsl(120, 100%, 40%);">+   /* FACCH/H prioritization is a bit more complex */</span><br><span style="color: hsl(120, 100%, 40%);">+    case TRXC_TCHH_0:</span><br><span style="color: hsl(120, 100%, 40%);">+     case TRXC_TCHH_1:</span><br><span style="color: hsl(120, 100%, 40%);">+             return prim_dequeue_tch_h(queue, fn, lchan_type);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Other kinds of logical channels */</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+              return prim_dequeue_one(queue, lchan_type);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span> }</span><br><span> </span><br><span> /**</span><br><span>diff --git a/src/host/trxcon/sched_trx.c b/src/host/trxcon/sched_trx.c</span><br><span>index c263ce7..fd43a56 100644</span><br><span>--- a/src/host/trxcon/sched_trx.c</span><br><span>+++ b/src/host/trxcon/sched_trx.c</span><br><span>@@ -95,7 +95,7 @@</span><br><span>                * attempt to obtain a new one from queue</span><br><span>             */</span><br><span>          if (lchan->prim == NULL)</span><br><span style="color: hsl(0, 100%, 40%);">-                     lchan->prim = sched_prim_dequeue(&ts->tx_prims, chan);</span><br><span style="color: hsl(120, 100%, 40%);">+                      lchan->prim = sched_prim_dequeue(&ts->tx_prims, fn, chan);</span><br><span> </span><br><span>             /* TODO: report TX buffers health to the higher layers */</span><br><span> </span><br><span>diff --git a/src/host/trxcon/sched_trx.h b/src/host/trxcon/sched_trx.h</span><br><span>index cd9c0e4..f3fa9df 100644</span><br><span>--- a/src/host/trxcon/sched_trx.h</span><br><span>+++ b/src/host/trxcon/sched_trx.h</span><br><span>@@ -302,7 +302,7 @@</span><br><span>         (CHAN_IS_TCH(prim->chan) && prim->payload_len == GSM_MACBLOCK_LEN)</span><br><span> </span><br><span> struct trx_ts_prim *sched_prim_dequeue(struct llist_head *queue,</span><br><span style="color: hsl(0, 100%, 40%);">-        enum trx_lchan_type lchan_type);</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t fn, enum trx_lchan_type lchan_type);</span><br><span> int sched_prim_dummy(struct trx_lchan_state *lchan);</span><br><span> void sched_prim_drop(struct trx_lchan_state *lchan);</span><br><span> void sched_prim_flush_queue(struct llist_head *list);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/10455">change 10455</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/10455"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmocom-bb </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I9b59f60e1cbac8fb8fd557b6c67b5e376c0a6bbb </div>
<div style="display:none"> Gerrit-Change-Number: 10455 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Vadim Yanitskiy <axilirator@gmail.com> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>