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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Support multiplexing of GPRS and EGPRS TBFs in one PDCH<br><br>There are some restrictions to have both GPRS-only and EGPRS MS attached<br>to the same MS:<br>* Any MS needs to be able to successfully decode a DL block at least<br>  every 18 DL blocks (360 ms). That means a Dl block with CS1-4 must be<br>  sent at least once during that time.<br>* Any MS needs to be able to decode USF targeting it. GPRS-only MS can<br>  successfully decode USF from DL blocks using GMSK: CS1-4 and MCS1-4.<br><br>In this patch, if USF of a GPRS-only MS is selected, then all DL EGPRS<br>TBFs are discarded from data block selection. However, this logic can be<br>further improved later by still allowing selection of DL EGPRS TBFs and<br>then forcing construction of a DL EGPRS data block using MCS1-4.<br><br>Sources:<br>* 3GPP TS 03.64 version 8.12.0 "6.6.4.1.1.2 Multiplexing of GPRS and EGPRS MSs"<br>* 3GPP TS 05.08 version 8.23.0 "10.2.2 BTS output power"<br><br>Related: OS#4544<br>Change-Id: Ib4991c864eda6864533363443f76ae5d999532ae<br>---<br>M src/gprs_rlcmac_sched.cpp<br>M src/pdch.cpp<br>M src/pdch.h<br>3 files changed, 96 insertions(+), 29 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp</span><br><span>index 97806d9..537929b 100644</span><br><span>--- a/src/gprs_rlcmac_sched.cpp</span><br><span>+++ b/src/gprs_rlcmac_sched.cpp</span><br><span>@@ -89,11 +89,10 @@</span><br><span>  return poll_fn;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static uint8_t sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn,</span><br><span style="color: hsl(0, 100%, 40%);">-        uint8_t block_nr, struct gprs_rlcmac_pdch *pdch)</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gprs_rlcmac_ul_tbf *sched_select_uplink(uint8_t trx, uint8_t ts, uint32_t fn,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t block_nr, struct gprs_rlcmac_pdch *pdch, bool require_gprs_only)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   struct gprs_rlcmac_ul_tbf *tbf;</span><br><span style="color: hsl(0, 100%, 40%);">- uint8_t usf = 0x07;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_rlcmac_ul_tbf *tbf = NULL;</span><br><span>       uint8_t i, tfi;</span><br><span> </span><br><span>  /* select uplink resource */</span><br><span>@@ -110,18 +109,20 @@</span><br><span>                 if (tbf->state_is_not(GPRS_RLCMAC_FLOW))</span><br><span>                  continue;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+         if (require_gprs_only && tbf->is_egprs_enabled())</span><br><span style="color: hsl(120, 100%, 40%);">+                  continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          /* use this USF */</span><br><span style="color: hsl(0, 100%, 40%);">-              usf = tbf->m_usf[ts];</span><br><span>             LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "</span><br><span>                    "TS=%d FN=%d block_nr=%d scheduling USF=%d for "</span><br><span>                   "required uplink resource of UL TFI=%d\n", trx, ts, fn,</span><br><span style="color: hsl(0, 100%, 40%);">-                       block_nr, usf, tfi);</span><br><span style="color: hsl(120, 100%, 40%);">+                  block_nr, tbf->m_usf[ts], tfi);</span><br><span>           /* next TBF to handle resource is the next one */</span><br><span>            pdch->next_ul_tfi = (tfi + 1) & 31;</span><br><span>           break;</span><br><span>       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return usf;</span><br><span style="color: hsl(120, 100%, 40%);">+   return tbf;</span><br><span> }</span><br><span> </span><br><span> struct msgb *sched_app_info(struct gprs_rlcmac_tbf *tbf) {</span><br><span>@@ -273,7 +274,7 @@</span><br><span> </span><br><span> static struct msgb *sched_select_downlink(struct gprs_rlcmac_bts *bts,</span><br><span>                   uint8_t trx, uint8_t ts, uint32_t fn,</span><br><span style="color: hsl(0, 100%, 40%);">-                   uint8_t block_nr, struct gprs_rlcmac_pdch *pdch, bool *is_egprs)</span><br><span style="color: hsl(120, 100%, 40%);">+              uint8_t block_nr, struct gprs_rlcmac_pdch *pdch, enum mcs_kind req_mcs_kind, bool *is_egprs)</span><br><span> {</span><br><span>        struct msgb *msg = NULL;</span><br><span>     struct gprs_rlcmac_dl_tbf *tbf, *prio_tbf = NULL;</span><br><span>@@ -301,6 +302,13 @@</span><br><span>             if (tbf->m_wait_confirm)</span><br><span>                  continue;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+         /* If a GPRS (CS1-4) Dl block is required, skip EGPRS(_GSMK) tbfs: */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (req_mcs_kind == GPRS && tbf->is_egprs_enabled())</span><br><span style="color: hsl(120, 100%, 40%);">+                       continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* TODO: If a GPRS (CS1-4/MCS1-4) Dl block is required, downgrade MCS below instead of skipping */</span><br><span style="color: hsl(120, 100%, 40%);">+            if (req_mcs_kind == EGPRS_GMSK && (tbf->is_egprs_enabled() || tbf->ms()->mode() != GPRS))</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          age = tbf->frames_since_last_poll(fn);</span><br><span> </span><br><span>                /* compute priority */</span><br><span>@@ -385,12 +393,15 @@</span><br><span>       struct gprs_rlcmac_pdch *pdch;</span><br><span>       struct gprs_rlcmac_tbf *poll_tbf = NULL, *dl_ass_tbf = NULL,</span><br><span>                 *ul_ass_tbf = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gprs_rlcmac_ul_tbf *usf_tbf;</span><br><span>  struct gprs_rlcmac_ul_tbf *ul_ack_tbf = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t usf = 0x7;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t usf;</span><br><span>         struct msgb *msg = NULL;</span><br><span>     uint32_t poll_fn, sba_fn;</span><br><span>    enum pcu_gsmtap_category gsmtap_cat;</span><br><span style="color: hsl(0, 100%, 40%);">-    bool is_egprs = false;</span><br><span style="color: hsl(120, 100%, 40%);">+        bool tx_is_egprs = false;</span><br><span style="color: hsl(120, 100%, 40%);">+     bool require_gprs_only;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum mcs_kind req_mcs_kind; /* Restrict CS/MCS if DL Data block is to be sent */</span><br><span> </span><br><span>         if (trx >= 8 || ts >= 8)</span><br><span>               return -EINVAL;</span><br><span>@@ -405,47 +416,79 @@</span><br><span>      /* store last frame number of RTS */</span><br><span>         pdch->last_rts_fn = fn;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+        /* require_gprs_only: Prioritize USF for GPRS-only MS here,</span><br><span style="color: hsl(120, 100%, 40%);">+    * since anyway we'll need to tx a Dl block with CS1-4 due to</span><br><span style="color: hsl(120, 100%, 40%);">+      * synchronization requirements. See 3GPP TS 03.64 version</span><br><span style="color: hsl(120, 100%, 40%);">+     * 8.12.0</span><br><span style="color: hsl(120, 100%, 40%);">+      */</span><br><span style="color: hsl(120, 100%, 40%);">+   require_gprs_only = (pdch->fn_without_cs14 == MS_RESYNC_NUM_FRAMES - 1);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (require_gprs_only) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DRLCMACSCHED, LOGL_DEBUG, "TRX=%d TS=%d FN=%d "</span><br><span style="color: hsl(120, 100%, 40%);">+                     "synchronization frame (every 18 frames), only CS1-4 allowed",</span><br><span style="color: hsl(120, 100%, 40%);">+              trx, ts, fn);</span><br><span style="color: hsl(120, 100%, 40%);">+            req_mcs_kind = GPRS; /* only GPRS CS1-4 allowed, all MS need to be able to decode it */</span><br><span style="color: hsl(120, 100%, 40%);">+       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              req_mcs_kind = EGPRS; /* all kinds are fine */</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  poll_fn = sched_poll(bts->bts, trx, ts, fn, block_nr, &poll_tbf, &ul_ass_tbf,</span><br><span>             &dl_ass_tbf, &ul_ack_tbf);</span><br><span>   /* check uplink resource for polling */</span><br><span style="color: hsl(0, 100%, 40%);">- if (poll_tbf)</span><br><span style="color: hsl(120, 100%, 40%);">+ if (poll_tbf) {</span><br><span>              LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "</span><br><span>                    "TS=%d FN=%d block_nr=%d scheduling free USF for "</span><br><span>                         "polling at FN=%d of %s\n", trx, ts, fn,</span><br><span>                   block_nr, poll_fn,</span><br><span>                   tbf_name(poll_tbf));</span><br><span style="color: hsl(0, 100%, 40%);">-            /* use free USF */</span><br><span style="color: hsl(120, 100%, 40%);">+            usf = USF_UNUSED;</span><br><span>    /* else. check for sba */</span><br><span style="color: hsl(0, 100%, 40%);">-       else if ((sba_fn = bts->bts->sba()->sched(trx, ts, fn, block_nr) != 0xffffffff))</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if ((sba_fn = bts->bts->sba()->sched(trx, ts, fn, block_nr) != 0xffffffff)) {</span><br><span>                LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "</span><br><span>                    "TS=%d FN=%d block_nr=%d scheduling free USF for "</span><br><span>                         "single block allocation at FN=%d\n", trx, ts, fn,</span><br><span>                         block_nr, sba_fn);</span><br><span style="color: hsl(0, 100%, 40%);">-              /* use free USF */</span><br><span style="color: hsl(120, 100%, 40%);">+            usf = USF_UNUSED;</span><br><span>    /* else, we search for uplink resource */</span><br><span style="color: hsl(0, 100%, 40%);">-       else</span><br><span style="color: hsl(0, 100%, 40%);">-            usf = sched_select_uplink(trx, ts, fn, block_nr, pdch);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Prio 1: select control message */</span><br><span style="color: hsl(0, 100%, 40%);">-    msg = sched_select_ctrl_msg(trx, ts, fn, block_nr, pdch, ul_ass_tbf,</span><br><span style="color: hsl(0, 100%, 40%);">-            dl_ass_tbf, ul_ack_tbf);</span><br><span style="color: hsl(0, 100%, 40%);">-        gsmtap_cat = PCU_GSMTAP_C_DL_CTRL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* Prio 2: select data message for downlink */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!msg) {</span><br><span style="color: hsl(0, 100%, 40%);">-             msg = sched_select_downlink(bts, trx, ts, fn, block_nr, pdch, &is_egprs);</span><br><span style="color: hsl(0, 100%, 40%);">-           gsmtap_cat = is_egprs ? PCU_GSMTAP_C_DL_DATA_EGPRS : PCU_GSMTAP_C_DL_DATA_GPRS;</span><br><span style="color: hsl(120, 100%, 40%);">+       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              usf_tbf = sched_select_uplink(trx, ts, fn, block_nr, pdch, require_gprs_only);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (usf_tbf) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        usf = usf_tbf->m_usf[ts];</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* If MS selected for USF is GPRS-only, then it will</span><br><span style="color: hsl(120, 100%, 40%);">+                   * only be able to read USF if dl block uses GMSK</span><br><span style="color: hsl(120, 100%, 40%);">+                      * (CS1-4, MCS1-4)</span><br><span style="color: hsl(120, 100%, 40%);">+                     */</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (req_mcs_kind == EGPRS && usf_tbf->ms()->mode() != EGPRS)</span><br><span style="color: hsl(120, 100%, 40%);">+                            req_mcs_kind = EGPRS_GMSK;</span><br><span style="color: hsl(120, 100%, 40%);">+            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      usf = USF_UNUSED;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Prio 1: select control message */</span><br><span style="color: hsl(120, 100%, 40%);">+  if ((msg = sched_select_ctrl_msg(trx, ts, fn, block_nr, pdch, ul_ass_tbf,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      dl_ass_tbf, ul_ack_tbf))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  gsmtap_cat = PCU_GSMTAP_C_DL_CTRL;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Prio 2: select data message for downlink */</span><br><span style="color: hsl(120, 100%, 40%);">+        else if((msg = sched_select_downlink(bts, trx, ts, fn, block_nr, pdch, req_mcs_kind, &tx_is_egprs))) {</span><br><span style="color: hsl(120, 100%, 40%);">+            gsmtap_cat = tx_is_egprs ? PCU_GSMTAP_C_DL_DATA_EGPRS :</span><br><span style="color: hsl(120, 100%, 40%);">+                                          PCU_GSMTAP_C_DL_DATA_GPRS;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span>    /* Prio 3: send dummy contol message */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+   else if ((msg = sched_dummy())) {</span><br><span>            /* increase counter */</span><br><span>               msg = sched_dummy();</span><br><span>                 gsmtap_cat = PCU_GSMTAP_C_DL_DUMMY;</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              return -ENOMEM;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (!msg)</span><br><span style="color: hsl(0, 100%, 40%);">-               return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (tx_is_egprs && pdch->has_gprs_only_tbf_attached()) {</span><br><span style="color: hsl(120, 100%, 40%);">+           pdch->fn_without_cs14 += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+        } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              pdch->fn_without_cs14 = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  /* msg is now available */</span><br><span>   bts->bts->do_rate_ctr_add(CTR_RLC_DL_BYTES, msg->data_len);</span><br><span> </span><br><span>diff --git a/src/pdch.cpp b/src/pdch.cpp</span><br><span>index ff13477..a7dd2aa 100644</span><br><span>--- a/src/pdch.cpp</span><br><span>+++ b/src/pdch.cpp</span><br><span>@@ -944,6 +944,22 @@</span><br><span>                 m_assigned_usf, m_assigned_tfi[tbf->direction]);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+bool gprs_rlcmac_pdch::has_gprs_only_tbf_attached() const</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       unsigned int j;</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < sizeof(m_assigned_tfi[0]); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          for (j = 0; j < 2; j++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (m_assigned_tfi[j] & (1UL << i)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               gprs_rlcmac_tbf *tbf = m_tbfs[j][i];</span><br><span style="color: hsl(120, 100%, 40%);">+                          if (!tbf->is_egprs_enabled())</span><br><span style="color: hsl(120, 100%, 40%);">+                                      return true;</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%);">+     return false;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void gprs_rlcmac_pdch::reserve(enum gprs_rlcmac_tbf_direction dir)</span><br><span> {</span><br><span>        m_num_reserved[dir] += 1;</span><br><span>diff --git a/src/pdch.h b/src/pdch.h</span><br><span>index 1c0993f..5185045 100644</span><br><span>--- a/src/pdch.h</span><br><span>+++ b/src/pdch.h</span><br><span>@@ -40,6 +40,10 @@</span><br><span> #define PTCCH_TAI_NUM            16      /*!< Number of PTCCH/U slots and thus TA Indexes */</span><br><span> #define PTCCH_PADDING         0x2b    /*!< PTCCH/D messages need to be padded to 23 octets */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define USF_UNUSED 0x07</span><br><span style="color: hsl(120, 100%, 40%);">+/* 3GPP TS 05.08 version 8.23.0 "10.2.2 BTS output power". 360 ms */</span><br><span style="color: hsl(120, 100%, 40%);">+#define MS_RESYNC_NUM_FRAMES 18</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*</span><br><span>  * PDCH instance</span><br><span>  */</span><br><span>@@ -83,6 +87,8 @@</span><br><span> </span><br><span>  uint8_t assigned_usf() const;</span><br><span>        uint32_t assigned_tfi(enum gprs_rlcmac_tbf_direction dir) const;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    bool has_gprs_only_tbf_attached() const;</span><br><span> #endif</span><br><span> </span><br><span>       uint8_t m_is_enabled; /* TS is enabled */</span><br><span>@@ -92,6 +98,8 @@</span><br><span>        uint8_t next_ctrl_prio; /* next kind of ctrl message to schedule */</span><br><span>  struct llist_head paging_list; /* list of paging messages */</span><br><span>         uint32_t last_rts_fn; /* store last frame number of RTS */</span><br><span style="color: hsl(120, 100%, 40%);">+    /* store number of contiguous frame number where a DL block was transmitted which can be decoded by GPRS-only MS */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t fn_without_cs14;</span><br><span> </span><br><span>        /* PTCCH (Packet Timing Advance Control Channel) */</span><br><span>  uint8_t ptcch_msg[GSM_MACBLOCK_LEN]; /* 'ready to use' PTCCH/D message */</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-pcu/+/21178">change 21178</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-pcu/+/21178"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-pcu </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ib4991c864eda6864533363443f76ae5d999532ae </div>
<div style="display:none"> Gerrit-Change-Number: 21178 </div>
<div style="display:none"> Gerrit-PatchSet: 3 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>