pespin has submitted this change. ( 
https://gerrit.osmocom.org/c/osmocom-bb/+/33223 )

Change subject: l1gprs: implement TBF starting time support
......................................................................

l1gprs: implement TBF starting time support

Change-Id: I174e3c43d2f4c828a528710b284e62c9bb794122
Related: OS#5500
---
M include/l1gprs.h
M src/shared/l1gprs.c
2 files changed, 256 insertions(+), 20 deletions(-)

Approvals:
  Jenkins Builder: Verified
  pespin: Looks good to me, approved




diff --git a/include/l1gprs.h b/include/l1gprs.h
index 060366e..eb15726 100644
--- a/include/l1gprs.h
+++ b/include/l1gprs.h
@@ -9,6 +9,21 @@
 struct l1gprs_state;
 struct msgb;

+struct l1gprs_tbf_pending_req {
+       /*! Item in l1gprs_state->tbf_list_pending */
+       struct llist_head list;
+       /*! Uplink or Downlink */
+       bool uplink;
+       /*! TBF reference number (not index) */
+       uint8_t tbf_ref;
+       /*! PDCH timeslots used by this TBF */
+       uint8_t slotmask;
+       /*! (Downlink only) DL TFI (Temporary Flow Indentity): 0..31 */
+       uint8_t dl_tfi;
+       /*! TBF starting time (absolute TDMA Fn) */
+       uint32_t start_fn;
+};
+
 struct l1gprs_tbf {
        /*! Item in l1gprs_state->tbf_list */
        struct llist_head list;
@@ -33,11 +48,16 @@
        uint8_t dl_tbf_count;
        /*! DL TFI mask */
        uint32_t dl_tfi_mask;
+       /*! Pending UL TBF count */
+       uint8_t pending_ul_tbf_count;
+       /*! Pending DL TBF count */
+       uint8_t pending_dl_tbf_count;
 };

 static inline size_t l1gprs_pdch_use_count(const struct l1gprs_pdch *pdch)
 {
-       return pdch->ul_tbf_count + pdch->dl_tbf_count;
+       return pdch->ul_tbf_count + pdch->dl_tbf_count +
+              pdch->pending_ul_tbf_count + pdch->pending_dl_tbf_count;
 }


@@ -46,8 +66,10 @@
 struct l1gprs_state {
        /*! PDCH state for each timeslot */
        struct l1gprs_pdch pdch[8];
-       /*! Uplink and Downlink TBFs */
+       /*! Uplink and Downlink TBFs (active), struct l1gprs_pending_tbf */
        struct llist_head tbf_list;
+       /*! Uplink and Downlink TBFs (pending), struct l1gprs_tbf_pending_req */
+       struct llist_head tbf_list_pending;
        /*! Logging context (used as prefix for messages) */
        char *log_prefix;
        /*! Some private data for API user */
diff --git a/src/shared/l1gprs.c b/src/shared/l1gprs.c
index bae13d2..a9a6228 100644
--- a/src/shared/l1gprs.c
+++ b/src/shared/l1gprs.c
@@ -31,6 +31,7 @@

 #include <osmocom/gsm/protocol/gsm_04_08.h>
 #include <osmocom/gsm/protocol/gsm_44_060.h>
+#include <osmocom/gsm/gsm0502.h>

 #include <osmocom/bb/l1ctl_proto.h>
 #include <osmocom/bb/l1gprs.h>
@@ -43,10 +44,16 @@
        LOGP_GPRS((pdch)->gprs, level, "(PDCH-%u) " fmt, \
                  (pdch)->tn, ## args)

+#define LOG_TBF_CFG_REQ_FMT "tbf_ref=%u, slotmask=0x%02x, start_fn=%u"
+#define LOG_TBF_CFG_REQ_ARGS(req) \
+       (req)->tbf_ref, (req)->slotmask, ntohl((req)->start_fn)
+
 #define LOG_TBF_FMT "%cL-TBF#%03d"
 #define LOG_TBF_ARGS(tbf) \
        (tbf)->uplink ? 'U' : 'D', tbf->tbf_ref

+#define TDMA_FN_INVALID 0xffffffff
+
 static int l1gprs_log_cat = DLGLOBAL;

 enum gprs_rlcmac_block_type {
@@ -56,13 +63,39 @@
        GPRS_RLCMAC_RESERVED            = 0x03,
 };

-static struct l1gprs_tbf *l1gprs_tbf_alloc(struct l1gprs_state *gprs,
+static struct l1gprs_tbf_pending_req *l1gprs_tbf_pending_req_alloc(void 
*talloc_ctx,
+                                                      bool uplink, uint8_t 
tbf_ref,
+                                                      uint8_t slotmask, 
uint32_t start_fn)
+{
+       struct l1gprs_tbf_pending_req *preq;
+
+       preq = talloc(talloc_ctx, struct l1gprs_tbf_pending_req);
+       OSMO_ASSERT(preq != NULL);
+
+       preq->uplink = uplink;
+       preq->tbf_ref = tbf_ref;
+       preq->slotmask = slotmask;
+       preq->start_fn = start_fn;
+
+       return preq;
+}
+
+static void l1gprs_tbf_pending_req_free(struct l1gprs_tbf_pending_req *preq)
+{
+       if (preq == NULL)
+               return;
+       llist_del(&preq->list);
+       talloc_free(preq);
+}
+
+
+static struct l1gprs_tbf *l1gprs_tbf_alloc(void *talloc_ctx,
                                           bool uplink, uint8_t tbf_ref,
                                           uint8_t slotmask)
 {
        struct l1gprs_tbf *tbf;

-       tbf = talloc(gprs, struct l1gprs_tbf);
+       tbf = talloc(talloc_ctx, struct l1gprs_tbf);
        OSMO_ASSERT(tbf != NULL);

        tbf->uplink = uplink;
@@ -80,12 +113,12 @@
        talloc_free(tbf);
 }

-static struct l1gprs_tbf *l1gprs_find_tbf(struct l1gprs_state *gprs,
-                                         bool uplink, uint8_t tbf_ref)
+static struct l1gprs_tbf *_l1gprs_find_tbf(const struct llist_head *tbf_list,
+                                          bool uplink, uint8_t tbf_ref)
 {
        struct l1gprs_tbf *tbf;

-       llist_for_each_entry(tbf, &gprs->tbf_list, list) {
+       llist_for_each_entry(tbf, tbf_list, list) {
                if (tbf->uplink != uplink)
                        continue;
                if (tbf->tbf_ref != tbf_ref)
@@ -96,6 +129,16 @@
        return NULL;
 }

+static struct l1gprs_tbf *l1gprs_find_tbf(struct l1gprs_state *gprs,
+                                         bool uplink, uint8_t tbf_ref)
+{
+       struct l1gprs_tbf *tbf;
+
+       if ((tbf = _l1gprs_find_tbf(&gprs->tbf_list, uplink, tbf_ref)) != NULL)
+               return tbf;
+       return NULL;
+}
+
 static void l1gprs_register_tbf(struct l1gprs_state *gprs,
                                struct l1gprs_tbf *tbf)
 {
@@ -129,7 +172,7 @@
        llist_add_tail(&tbf->list, &gprs->tbf_list);

        LOGP_GPRS(gprs, LOGL_INFO,
-                 LOG_TBF_FMT " is registered\n",
+                 LOG_TBF_FMT " is registered as active\n",
                  LOG_TBF_ARGS(tbf));
 }

@@ -228,6 +271,122 @@
        l1gprs_tbf_free(tbf);
 }

+static void l1gprs_add_tbf_pending_req(struct l1gprs_state *gprs, struct 
l1gprs_tbf_pending_req *preq)
+{
+       OSMO_ASSERT(preq->slotmask != 0x00);
+
+       /* Update the PDCH states */
+       for (unsigned int tn = 0; tn < ARRAY_SIZE(gprs->pdch); tn++) {
+               struct l1gprs_pdch *pdch = &gprs->pdch[tn];
+
+               if (~preq->slotmask & (1 << pdch->tn))
+                       continue;
+
+               if (preq->uplink) {
+                       pdch->pending_ul_tbf_count++;
+               } else {
+                       pdch->pending_dl_tbf_count++;
+                       /* We don't care about DL_TFI here, we don't want to 
activate it */
+               }
+
+               LOGP_PDCH(pdch, LOGL_DEBUG,
+                         "Linked " LOG_TBF_FMT "\n",
+                         LOG_TBF_ARGS(preq));
+               /* If just got first use: */
+               if (l1gprs_pdch_use_count(pdch) == 1) {
+                       if (gprs->pdch_changed_cb)
+                               gprs->pdch_changed_cb(pdch, true);
+               }
+       }
+
+       llist_add_tail(&preq->list, &gprs->tbf_list_pending);
+
+       LOGP_GPRS(gprs, LOGL_INFO,
+                 LOG_TBF_FMT " is added as pending (fn=%u)\n",
+                 LOG_TBF_ARGS(preq), preq->start_fn);
+}
+
+static void l1gprs_remove_tbf_pending_req(struct l1gprs_state *gprs, struct 
l1gprs_tbf_pending_req *preq)
+{
+
+       OSMO_ASSERT(preq->slotmask != 0x00);
+
+       /* Update the PDCH states */
+       for (unsigned int tn = 0; tn < ARRAY_SIZE(gprs->pdch); tn++) {
+               struct l1gprs_pdch *pdch = &gprs->pdch[tn];
+
+               if (~preq->slotmask & (1 << pdch->tn))
+                       continue;
+
+               if (preq->uplink) {
+                       OSMO_ASSERT(pdch->pending_ul_tbf_count > 0);
+                       pdch->pending_ul_tbf_count--;
+               } else {
+                       OSMO_ASSERT(pdch->pending_dl_tbf_count > 0);
+                       pdch->pending_dl_tbf_count--;
+                       /* We don't care about DL_TFI here, we didn't activate 
them in first place */
+               }
+
+               LOGP_PDCH(pdch, LOGL_DEBUG,
+                         "Unlinked " LOG_TBF_FMT "\n",
+                         LOG_TBF_ARGS(preq));
+               /* Note: not calling gprs->pdch_changed_cb since no real
+                * activate / deactivate change can occur on lower layers as a
+                * consequence of moving a PDCH from pending to active, hence
+                * avoid triggering one active=false event here and immediately
+                * afterwards the opposite event when adding it as active: */
+       }
+
+       llist_del(&preq->list);
+
+       LOGP_GPRS(gprs, LOGL_INFO,
+                 LOG_TBF_FMT " is removed as pending (fn=%u)\n",
+                 LOG_TBF_ARGS(preq), preq->start_fn);
+}
+
+/* Check if the current TDMA Fn is past the start TDMA Fn.
+ * Based on fn_cmp() implementation from osmo-pcu.git, simplified. */
+static bool l1gprs_check_fn(uint32_t current, uint32_t start)
+{
+       const uint32_t thresh = GSM_TDMA_HYPERFRAME / 2;
+
+       if ((current < start && (start - current) < thresh) ||
+           (current > start && (current - start) > thresh))
+               return false;
+
+       return true;
+}
+
+/* Check the list of pending TBFs and move those with expired Fn to the active 
list */
+static void l1gprs_check_pending_tbfs(struct l1gprs_state *gprs, uint32_t fn)
+{
+       struct l1gprs_tbf_pending_req *preq, *tmp;
+       struct l1gprs_tbf *tbf;
+
+       llist_for_each_entry_safe(preq, tmp, &gprs->tbf_list_pending, list) {
+               if (!l1gprs_check_fn(fn, preq->start_fn))
+                       continue;
+
+               LOGP_GPRS(gprs, LOGL_INFO,
+                         LOG_TBF_FMT " becomes active (current_fn=%u, 
start_fn=%u)\n",
+                         LOG_TBF_ARGS(preq), fn, preq->start_fn);
+
+               l1gprs_remove_tbf_pending_req(gprs, preq);
+
+               /* If this tbf already exists in the main list, simply update 
its timeslot: */
+               tbf = _l1gprs_find_tbf(&gprs->tbf_list, preq->uplink, 
preq->tbf_ref);
+               if (tbf) {
+                       l1gprs_update_tbf(gprs, tbf, preq->slotmask);
+                       tbf->dl_tfi = preq->dl_tfi;
+               } else {
+                       tbf = l1gprs_tbf_alloc(gprs, preq->uplink, 
preq->tbf_ref, preq->slotmask);
+                       tbf->dl_tfi = preq->dl_tfi;
+                       l1gprs_register_tbf(gprs, tbf);
+               }
+               talloc_free(preq);
+       }
+}
+
 #define L1GPRS_L1CTL_MSGB_SIZE         256
 #define L1GPRS_L1CTL_MSGB_HEADROOM     32

@@ -302,6 +461,7 @@
        }

        INIT_LLIST_HEAD(&gprs->tbf_list);
+       INIT_LLIST_HEAD(&gprs->tbf_list_pending);

        if (log_prefix == NULL)
                gprs->log_prefix = talloc_asprintf(gprs, "l1gprs[0x%p]: ", 
gprs);
@@ -327,6 +487,16 @@
                l1gprs_tbf_free(tbf);
        }

+       while (!llist_empty(&gprs->tbf_list_pending)) {
+               struct l1gprs_tbf_pending_req *preq;
+
+               preq = llist_first_entry(&gprs->tbf_list_pending, struct 
l1gprs_tbf_pending_req, list);
+               LOGP_GPRS(gprs, LOGL_DEBUG,
+                         "%s(): " LOG_TBF_FMT " is free()d\n",
+                         __func__, LOG_TBF_ARGS(preq));
+               l1gprs_tbf_pending_req_free(preq);
+       }
+
        talloc_free(gprs->log_prefix);
        talloc_free(gprs);
 }
@@ -351,12 +521,23 @@
        }

        LOGP_GPRS(gprs, LOGL_INFO,
-                 "Rx Uplink TBF config: tbf_ref=%u, slotmask=0x%02x\n",
-                 req->tbf_ref, req->slotmask);
-
-       tbf = l1gprs_find_tbf(gprs, true, req->tbf_ref);
+                 "Rx UL TBF config: " LOG_TBF_CFG_REQ_FMT "\n",
+                 LOG_TBF_CFG_REQ_ARGS(req));

        if (req->slotmask != 0x00) {
+               uint32_t start_fn = ntohl(req->start_fn);
+               if (start_fn != TDMA_FN_INVALID) {
+                       /* Create a temporary tbf and keep it in a separate
+                        * list. It will be moved/merged into the main list at
+                        * start_fn time. */
+                       struct l1gprs_tbf_pending_req *preq;
+                       preq = l1gprs_tbf_pending_req_alloc(gprs, true, 
req->tbf_ref,
+                                                            req->slotmask, 
start_fn);
+                       l1gprs_add_tbf_pending_req(gprs, preq);
+                       return 0;
+               }
+
+               tbf = l1gprs_find_tbf(gprs, true, req->tbf_ref);
                if (tbf) {
                        l1gprs_update_tbf(gprs, tbf, req->slotmask);
                } else {
@@ -364,6 +545,7 @@
                        l1gprs_register_tbf(gprs, tbf);
                }
        } else {
+               tbf = l1gprs_find_tbf(gprs, true, req->tbf_ref);
                if (tbf == NULL) {
                        LOGP_GPRS(gprs, LOGL_ERROR, "%s(): " LOG_TBF_FMT " not 
found\n",
                                  __func__, 'U', req->tbf_ref);
@@ -390,8 +572,8 @@
        }

        LOGP_GPRS(gprs, LOGL_INFO,
-                 "Rx Downlink TBF config: tbf_ref=%u, slotmask=0x%02x, 
dl_tfi=%u\n",
-                 req->tbf_ref, req->slotmask, req->dl_tfi);
+                 "Rx DL TBF config: " LOG_TBF_CFG_REQ_FMT ", dl_tfi=%u\n",
+                 LOG_TBF_CFG_REQ_ARGS(req), req->dl_tfi);

        if (req->dl_tfi > 31) {
                LOGP_GPRS(gprs, LOGL_ERROR,
@@ -400,17 +582,31 @@
                return -EINVAL;
        }

-       tbf = l1gprs_find_tbf(gprs, false, req->tbf_ref);
-
        if (req->slotmask != 0x00) {
+               uint32_t start_fn = ntohl(req->start_fn);
+               if (start_fn != TDMA_FN_INVALID) {
+                       /* Create a temporary tbf and keep it in a separate
+                        * list. It will be moved/merged into the main list at
+                        * start_fn time. */
+                       struct l1gprs_tbf_pending_req *preq;
+                       preq = l1gprs_tbf_pending_req_alloc(gprs, false, 
req->tbf_ref,
+                                                           req->slotmask, 
start_fn);
+                       preq->dl_tfi = req->dl_tfi;
+                       l1gprs_add_tbf_pending_req(gprs, preq);
+                       return 0;
+               }
+
+               tbf = l1gprs_find_tbf(gprs, false, req->tbf_ref);
                if (tbf) {
                        l1gprs_update_tbf(gprs, tbf, req->slotmask);
                } else {
-                       tbf = l1gprs_tbf_alloc(gprs, false, req->tbf_ref, 
req->slotmask);
+                       tbf = l1gprs_tbf_alloc(gprs, false, req->tbf_ref,
+                                              req->slotmask);
                        tbf->dl_tfi = req->dl_tfi;
                        l1gprs_register_tbf(gprs, tbf);
                }
        } else {
+               tbf = l1gprs_find_tbf(gprs, false, req->tbf_ref);
                if (tbf == NULL) {
                        LOGP_GPRS(gprs, LOGL_ERROR, "%s(): " LOG_TBF_FMT " not 
found\n",
                                  __func__, 'D', req->tbf_ref);
@@ -496,9 +692,17 @@
                  BLOCK_IND_IS_PTCCH(ind) ? "PTCCH" : "PDTCH",
                  ind->hdr.fn, ind->data_len, osmo_hexdump(ind->data, 
ind->data_len));

-       if ((pdch->ul_tbf_count == 0) && (pdch->dl_tbf_count == 0)) {
-               LOGP_PDCH(pdch, LOGL_ERROR,
-                         "Rx DL BLOCK.ind, but this PDCH has no configured 
TBFs\n");
+       l1gprs_check_pending_tbfs(gprs, ind->hdr.fn);
+
+       if (pdch->ul_tbf_count + pdch->dl_tbf_count == 0) {
+               if (pdch->pending_ul_tbf_count + pdch->pending_dl_tbf_count > 0)
+                       LOGP_PDCH(pdch, LOGL_DEBUG,
+                                 "Rx DL BLOCK.ind (fn=%u), but this PDCH has 
no active TBFs yet\n",
+                                 ind->hdr.fn);
+               else
+                       LOGP_PDCH(pdch, LOGL_ERROR,
+                                 "Rx DL BLOCK.ind (fn=%u), but this PDCH has 
no configured TBFs\n",
+                                 ind->hdr.fn);
                return NULL;
        }


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

Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: I174e3c43d2f4c828a528710b284e62c9bb794122
Gerrit-Change-Number: 33223
Gerrit-PatchSet: 13
Gerrit-Owner: fixeria <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-MessageType: merged

Reply via email to