Change in osmo-pcu[master]: Add new PDCH UL Controller, drop SBAllocator class

pespin gerrit-no-reply at lists.osmocom.org
Tue Mar 16 10:02:53 UTC 2021


pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-pcu/+/23291 )

Change subject: Add new PDCH UL Controller, drop SBAllocator class
......................................................................

Add new PDCH UL Controller, drop SBAllocator class

Right now we handle different types of UL allocations in different
classes like PollAllocator and SBAllocator, and they usually don't take
into account the other one in most cases. Furthermore, those objects are
usually per-BTS object, instead of per PDCH object.

This is a first step towards having a unified per-PDCH controller which
takes care of controlling what is scheduled and hence expected on the
uplink. Each PDCH has a UL Controller which keeps track of all reserved
uplink frame, be it SB, RRBP poll or USF assigned, all under the same
API.

As a first step, only the SBA part is fully implemented and used (being
it the easiest part to replace); TBF poll+usf will come in follow-up
patches later on. As a result, the SBAllocator per-BTS class dissappears
but some of its code is refactored/reused to provide more features to the
gprs_rlcmac_sba object, which is also further integrated into the new UL
Controller.

Related: OS#5020
Change-Id: I84b24beea4a1aa2c1528f41435f77bd16df2b947
---
M src/Makefile.am
M src/bts.cpp
M src/bts.h
M src/gprs_rlcmac_sched.cpp
M src/pcu_l1_if.cpp
M src/pcu_utils.h
M src/pdch.cpp
M src/pdch.h
A src/pdch_ul_controller.c
A src/pdch_ul_controller.h
M src/poll_controller.cpp
A src/sba.c
D src/sba.cpp
M src/sba.h
M src/tbf.cpp
M tests/tbf/TbfTest.cpp
M tests/tbf/TbfTest.err
17 files changed, 443 insertions(+), 225 deletions(-)

Approvals:
  Jenkins Builder: Verified
  osmith: Looks good to me, but someone else must approve
  pespin: Looks good to me, approved



diff --git a/src/Makefile.am b/src/Makefile.am
index eefbea1..ab9aeeb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -62,9 +62,10 @@
 	tbf_dl.cpp \
 	bts.cpp \
 	pdch.cpp \
+	pdch_ul_controller.c \
 	poll_controller.cpp \
 	encoding.cpp \
-	sba.cpp \
+	sba.c \
 	decoding.cpp \
 	llc.cpp \
 	rlc.cpp \
@@ -100,6 +101,7 @@
 	tbf_dl.h \
 	bts.h \
 	pdch.h \
+	pdch_ul_controller.h \
 	poll_controller.h \
 	encoding.h \
 	sba.h \
diff --git a/src/bts.cpp b/src/bts.cpp
index 1d3f690..a7d475c 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -212,7 +212,6 @@
 	 * m_ms_store's destructor */
 	bts->ms_store->cleanup();
 	delete bts->ms_store;
-	delete bts->sba;
 	delete bts->pollController;
 
 	if (bts->ratectrs) {
@@ -246,7 +245,6 @@
 	bts->nr = bts_nr;
 
 	bts->pollController = new PollController(*bts);
-	bts->sba = new SBAController(*bts);
 	bts->ms_store = new GprsMsStorage(bts);
 
 	bts->cur_fn = 0;
@@ -819,10 +817,43 @@
 	return 0;
 }
 
+struct gprs_rlcmac_sba *bts_alloc_sba(struct gprs_rlcmac_bts *bts, uint8_t ta)
+{
+	struct gprs_rlcmac_pdch *pdch;
+	struct gprs_rlcmac_sba *sba = NULL;
+	int8_t trx, ts;
+
+	if (!gsm48_ta_is_valid(ta))
+		return NULL;
+
+	for (trx = 0; trx < 8; trx++) {
+		for (ts = 7; ts >= 0; ts--) {
+			pdch = &bts->trx[trx].pdch[ts];
+			if (!pdch->is_enabled())
+				continue;
+			break;
+		}
+		if (ts >= 0)
+			break;
+	}
+	if (trx == 8) {
+		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n");
+		return NULL;
+	}
+
+	sba = sba_alloc(bts, pdch, ta);
+	if (!sba)
+		return NULL;
+
+	bts_do_rate_ctr_inc(bts, CTR_SBA_ALLOCATED);
+	return sba;
+}
+
 int bts_rcv_rach(struct gprs_rlcmac_bts *bts, const struct rach_ind_params *rip)
 {
 	struct chan_req_params chan_req = { 0 };
 	struct gprs_rlcmac_ul_tbf *tbf = NULL;
+	struct gprs_rlcmac_sba *sba;
 	uint8_t trx_no, ts_no;
 	uint32_t sb_fn = 0;
 	uint8_t usf = 7;
@@ -864,14 +895,18 @@
 
 	/* Should we allocate a single block or an Uplink TBF? */
 	if (chan_req.single_block) {
-		rc = bts_sba(bts)->alloc(&trx_no, &ts_no, &sb_fn, ta);
-		if (rc < 0) {
+		sba = bts_alloc_sba(bts, ta);
+		if (!sba) {
 			LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource for "
-			     "single block allocation: rc=%d\n", rc);
+			     "single block allocation\n");
+			rc = -EBUSY;
 			/* Send RR Immediate Assignment Reject */
 			goto send_imm_ass_rej;
 		}
 
+		trx_no = sba->pdch->trx_no();
+		ts_no = sba->pdch->ts_no;
+		sb_fn = sba->fn;
 		tsc = bts->trx[trx_no].pdch[ts_no].tsc;
 		LOGP(DRLCMAC, LOGL_DEBUG, "Allocated a single block at "
 		     "SBFn=%u TRX=%u TS=%u\n", sb_fn, trx_no, ts_no);
@@ -1076,11 +1111,6 @@
 	return ms;
 }
 
-struct SBAController *bts_sba(struct gprs_rlcmac_bts *bts)
-{
-	return bts->sba;
-}
-
 struct GprsMsStorage *bts_ms_store(struct gprs_rlcmac_bts *bts)
 {
 	return bts->ms_store;
diff --git a/src/bts.h b/src/bts.h
index 3ddf501..8070abb 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -196,7 +196,6 @@
 };
 
 struct PollController;
-struct SBAController;
 struct GprsMsStorage;
 struct pcu_l1_meas;
 
@@ -253,7 +252,6 @@
 	uint8_t max_cs_dl, max_cs_ul;
 	uint8_t max_mcs_dl, max_mcs_ul;
 	struct PollController *pollController;
-	struct SBAController *sba;
 	struct rate_ctr_group *ratectrs;
 	struct osmo_stat_item_group *statg;
 
@@ -308,8 +306,6 @@
 			  enum pcu_gsmtap_category categ, uint8_t channel,
 			  const struct rach_ind_params *rip);
 
-struct SBAController *bts_sba(struct gprs_rlcmac_bts *bts);
-
 struct GprsMsStorage *bts_ms_store(struct gprs_rlcmac_bts *bts);
 
 struct GprsMs *bts_ms_by_tlli(struct gprs_rlcmac_bts *bts, uint32_t tlli, uint32_t old_tlli);
@@ -339,6 +335,8 @@
 
 struct gprs_rlcmac_bts *bts_alloc(struct gprs_pcu *pcu, uint8_t bts_nr);
 
+struct gprs_rlcmac_sba *bts_alloc_sba(struct gprs_rlcmac_bts *bts, uint8_t ta);
+
 void bts_recalc_initial_cs(struct gprs_rlcmac_bts *bts);
 void bts_recalc_initial_mcs(struct gprs_rlcmac_bts *bts);
 void bts_recalc_max_cs(struct gprs_rlcmac_bts *bts);
diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp
index 51deb65..ce8fd02 100644
--- a/src/gprs_rlcmac_sched.cpp
+++ b/src/gprs_rlcmac_sched.cpp
@@ -482,11 +482,10 @@
 			block_nr, poll_fn, tbf_name(tbf_cand.poll));
 		usf = USF_UNUSED;
 	/* else. check for sba */
-	} else if ((sba_fn = bts_sba(bts)->sched(trx, ts, fn, block_nr)) != 0xffffffff) {
-		LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: TRX=%d "
-			"TS=%d FN=%d block_nr=%d scheduling free USF for "
-			"single block allocation at FN=%d\n", trx, ts, fn,
-			block_nr, sba_fn);
+	} else if ((sba_fn = find_sba_rts(pdch, fn, block_nr)) != 0xffffffff) {
+		LOGPDCH(pdch, DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: "
+			"FN=%d block_nr=%d scheduling free USF for "
+			"single block allocation at FN=%d\n", fn, block_nr, sba_fn);
 		usf = USF_UNUSED;
 	/* else, we search for uplink resource */
 	} else {
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index 970387d..f28c46f 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -285,7 +285,11 @@
 int pcu_rx_data_ind_pdtch(struct gprs_rlcmac_bts *bts, struct gprs_rlcmac_pdch *pdch, uint8_t *data,
 	uint8_t len, uint32_t fn, struct pcu_l1_meas *meas)
 {
-	return pdch->rcv_block(data, len, fn, meas);
+	int rc;
+
+	rc = pdch->rcv_block(data, len, fn, meas);
+	pdch_ulc_expire_fn(pdch->ulc, fn);
+	return rc;
 }
 
 static int pcu_rx_data_ind_bcch(struct gprs_rlcmac_bts *bts, uint8_t *data, uint8_t len)
diff --git a/src/pcu_utils.h b/src/pcu_utils.h
index 1d43045..a153ce7 100644
--- a/src/pcu_utils.h
+++ b/src/pcu_utils.h
@@ -25,6 +25,7 @@
 #endif
 
 #include <time.h>
+#include <stdint.h>
 
 static inline int msecs_to_frames(int msecs) {
 	return (msecs * (1024 * 1000 / 4615)) / 1024;
@@ -40,6 +41,15 @@
 	ts->tv_nsec = (csecs % 100) * 10000000;
 }
 
+static inline uint32_t rts_next_fn(uint32_t rts_fn, uint8_t block_nr)
+{
+	uint32_t fn = rts_fn + 4;
+	if ((block_nr % 3) == 2)
+		fn++;
+	fn = fn % GSM_MAX_FN;
+	return fn;
+}
+
 #ifdef __cplusplus
 template <typename T>
 inline unsigned int pcu_bitcount(T x)
diff --git a/src/pdch.cpp b/src/pdch.cpp
index 66afda7..1e54117 100644
--- a/src/pdch.cpp
+++ b/src/pdch.cpp
@@ -139,6 +139,7 @@
 	/*  Initialize the PTCCH/D message (Packet Timing Advance Control Channel) */
 	memset(pdch->ptcch_msg, PTCCH_TAI_FREE, PTCCH_TAI_NUM);
 	memset(pdch->ptcch_msg + PTCCH_TAI_NUM, PTCCH_PADDING, 7);
+	pdch->ulc = pdch_ulc_alloc(pdch, trx->bts);
 }
 
 void gprs_rlcmac_pdch::enable()
@@ -169,7 +170,7 @@
 	while ((pag = dequeue_paging()))
 		talloc_free(pag);
 
-	bts_sba(trx->bts)->free_resources(this);
+	talloc_free(this->ulc);
 }
 
 struct gprs_rlcmac_paging *gprs_rlcmac_pdch::dequeue_paging()
@@ -604,10 +605,10 @@
 		LOGPDCH(this, DRLCMAC, LOGL_DEBUG, "MS requests UL TBF "
 			"in packet resource request of single "
 			"block, so we provide one:\n");
-		sba = bts_sba(bts())->find(this, fn);
+		sba = pdch_ulc_get_sba(this->ulc, fn);
 		if (sba) {
 			ms_set_ta(ms, sba->ta);
-			bts_sba(bts())->free_sba(sba);
+			sba_free(sba);
 		} else if (!ul_tbf || !ul_tbf->state_is(GPRS_RLCMAC_FINISHED)) {
 			LOGPTBFUL(ul_tbf, LOGL_NOTICE,
 				  "MS requests UL TBF in PACKET RESOURCE REQ of "
@@ -702,9 +703,9 @@
 		ms = bts_alloc_ms(bts(), 0, 0);
 		ms_set_tlli(ms, report->TLLI);
 	}
-	if ((sba = bts_sba(bts())->find(this, fn))) {
+	if ((sba = pdch_ulc_get_sba(this->ulc, fn))) {
 		ms_set_ta(ms, sba->ta);
-		bts_sba(bts())->free_sba(sba);
+		sba_free(sba);
 	}
 	gprs_rlcmac_meas_rep(ms, report);
 }
diff --git a/src/pdch.h b/src/pdch.h
index fb28019..cfa0195 100644
--- a/src/pdch.h
+++ b/src/pdch.h
@@ -28,6 +28,7 @@
 #include <osmocom/core/linuxlist.h>
 #include "gsm_rlcmac.h"
 #include "coding_scheme.h"
+#include "pdch_ul_controller.h"
 }
 #endif
 
@@ -126,6 +127,7 @@
 	/* back pointers */
 	struct gprs_rlcmac_trx *trx;
 	uint8_t ts_no;
+	struct pdch_ulc *ulc;
 
 #ifdef __cplusplus
 private:
@@ -191,10 +193,9 @@
 void pdch_disable(struct gprs_rlcmac_pdch *pdch);
 #ifdef __cplusplus
 }
+#endif
 
 #define LOGPDCH(pdch, category, level, fmt, args...) \
 	LOGP(category, level, "PDCH(bts=%" PRIu8 ",trx=%" PRIu8 ",ts=%" PRIu8 ") " fmt, \
 	     (pdch)->trx->bts->nr, (pdch)->trx->trx_no, (pdch)->ts_no, \
 	     ## args)
-
-#endif
diff --git a/src/pdch_ul_controller.c b/src/pdch_ul_controller.c
new file mode 100644
index 0000000..ecd3691
--- /dev/null
+++ b/src/pdch_ul_controller.c
@@ -0,0 +1,186 @@
+/* pdch_ul_controller.c
+ *
+ * Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin at sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with it program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <unistd.h>
+#include <talloc.h>
+
+#include "pdch_ul_controller.h"
+#include "bts.h"
+#include "sba.h"
+#include "pdch.h"
+
+/* TS 44.060 Table 10.4.5.1 states maximum RRBP is N + 26. Give extra space for time diff between Tx and Rx? */
+#define MAX_FN_RESERVED (27 + 50)
+
+const struct value_string pdch_ul_node_names[] = {
+	{ PDCH_ULC_NODE_TBF_USF, "USF" },
+	{ PDCH_ULC_NODE_TBF_POLL, "POLL" },
+	{ PDCH_ULC_NODE_SBA, "SBA" },
+	{ 0, NULL }
+};
+
+struct pdch_ulc *pdch_ulc_alloc(struct gprs_rlcmac_pdch *pdch, void *ctx)
+{
+	struct pdch_ulc* ulc;
+	ulc = talloc_zero(ctx, struct pdch_ulc);
+	if (!ulc)
+		return ulc;
+
+	ulc->pdch = pdch;
+	ulc->pool_ctx = talloc_pool(ulc, sizeof(struct pdch_ulc_node) * MAX_FN_RESERVED);
+	return ulc;
+}
+
+struct pdch_ulc_node *pdch_ulc_get_node(struct pdch_ulc *ulc, uint32_t fn)
+{
+	struct rb_node *node;
+	struct pdch_ulc_node *it;
+	for (node = rb_first(&ulc->tree_root); node; node = rb_next(node)) {
+		it = container_of(node, struct pdch_ulc_node, node);
+		if (it->fn == fn)
+			return it;
+		if (it->fn > fn)
+			break;
+	}
+	return NULL;
+}
+struct pdch_ulc_node *pdch_ulc_pop_node(struct pdch_ulc *ulc, uint32_t fn)
+{
+	struct pdch_ulc_node *item = pdch_ulc_get_node(ulc, fn);
+	if (!item)
+		return NULL;
+	rb_erase(&item->node, &ulc->tree_root);
+	return item;
+}
+
+struct gprs_rlcmac_sba *pdch_ulc_get_sba(struct pdch_ulc *ulc, uint32_t fn)
+{
+	struct pdch_ulc_node *item = pdch_ulc_get_node(ulc, fn);
+	if (!item || item->type != PDCH_ULC_NODE_SBA)
+		return NULL;
+	return item->sba.sba;
+}
+
+bool pdch_ulc_fn_is_free(struct pdch_ulc *ulc, uint32_t fn)
+{
+	return !pdch_ulc_get_node(ulc, fn);
+}
+
+static struct pdch_ulc_node *_alloc_node(struct pdch_ulc *ulc, uint32_t fn)
+{
+	struct pdch_ulc_node *node;
+	node = talloc_zero(ulc->pool_ctx, struct pdch_ulc_node);
+	node->fn = fn;
+	return node;
+}
+
+static int pdch_ulc_add_node(struct pdch_ulc *ulc, struct pdch_ulc_node *item)
+{
+	struct rb_node **n = &(ulc->tree_root.rb_node);
+	struct rb_node *parent = NULL;
+
+	while (*n) {
+		struct pdch_ulc_node *it;
+
+		it = container_of(*n, struct pdch_ulc_node, node);
+
+		parent = *n;
+		if (item->fn < it->fn) {
+			n = &((*n)->rb_left);
+		} else if (item->fn > it->fn) {
+			n = &((*n)->rb_right);
+		} else {
+			LOGPDCH(ulc->pdch, DRLCMAC, LOGL_ERROR,
+				"Trying to reserve already reserved FN %u\n",
+				item->fn);
+			return -EEXIST;
+		}
+	}
+
+	rb_link_node(&item->node, parent, n);
+	rb_insert_color(&item->node, &ulc->tree_root);
+	return 0;
+}
+
+int pdch_ulc_reserve_tbf_usf(struct pdch_ulc *ulc, uint32_t fn, struct gprs_rlcmac_ul_tbf *ul_tbf)
+{
+	return 0; /* TODO: implement */
+}
+
+int pdch_ulc_reserve_tbf_poll(struct pdch_ulc *ulc, uint32_t fn, struct gprs_rlcmac_tbf *tbf)
+{
+	return 0; /* TODO: implement */
+}
+
+int pdch_ulc_reserve_sba(struct pdch_ulc *ulc, struct gprs_rlcmac_sba *sba)
+{
+	struct pdch_ulc_node *item = _alloc_node(ulc, sba->fn);
+	item->type = PDCH_ULC_NODE_SBA;
+	item->sba.sba = sba;
+	return pdch_ulc_add_node(ulc, item);
+}
+
+int pdch_ulc_release_fn(struct pdch_ulc *ulc, uint32_t fn)
+{
+	struct pdch_ulc_node *item = pdch_ulc_get_node(ulc, fn);
+	if (!item)
+		return -ENOKEY;
+	rb_erase(&item->node, &ulc->tree_root);
+	talloc_free(item);
+	return 0;
+}
+
+void pdch_ulc_expire_fn(struct pdch_ulc *ulc, uint32_t fn)
+{
+	struct gprs_rlcmac_sba *sba;
+	struct pdch_ulc_node *item;
+
+	struct rb_node *first;
+	while((first = rb_first(&ulc->tree_root))) {
+		item = container_of(first, struct pdch_ulc_node, node);
+		if (item->fn > fn)
+			break;
+		if (item->fn < fn) {
+			/* Sanity check: */
+			LOGPDCH(ulc->pdch, DRLCMAC, LOGL_ERROR,
+				"Expiring FN=%" PRIu32 " but previous FN=%" PRIu32 " is still reserved!\n",
+				fn, item->fn);
+		}
+		rb_erase(&item->node, &ulc->tree_root);
+
+		switch (item->type) {
+		case PDCH_ULC_NODE_TBF_USF:
+			/* TODO: increase N3...*/
+			break;
+		case PDCH_ULC_NODE_TBF_POLL:
+			/* TODO: increase N3...*/
+			break;
+		case PDCH_ULC_NODE_SBA:
+			sba = item->sba.sba;
+			LOGPDCH(sba->pdch, DRLCMAC, LOGL_NOTICE,
+				"Timeout for registered SBA (FN=%u, TA=%u)\n",
+				sba->fn, sba->ta);
+			sba_timeout(sba);
+			break;
+		}
+
+		talloc_free(item);
+	}
+}
diff --git a/src/pdch_ul_controller.h b/src/pdch_ul_controller.h
new file mode 100644
index 0000000..e86dbf5
--- /dev/null
+++ b/src/pdch_ul_controller.h
@@ -0,0 +1,79 @@
+/* pdch_ul_controller.h
+ *
+ * Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin at sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <osmocom/core/linuxrbtree.h>
+#include <osmocom/core/utils.h>
+
+struct gprs_rlcmac_pdch;
+struct gprs_rlcmac_tbf;
+struct gprs_rlcmac_ul_tbf;
+struct gprs_rlcmac_sba;
+
+struct pdch_ulc {
+	struct gprs_rlcmac_pdch *pdch; /* back pointer */
+	uint32_t last_fn; /* last FN rx from TDMA clock */
+	struct rb_root tree_root;
+	void *pool_ctx; /* talloc pool of struct pdch_ulc_node  */
+};
+
+enum PdchUlcNode {
+	PDCH_ULC_NODE_TBF_USF,
+	PDCH_ULC_NODE_TBF_POLL,
+	PDCH_ULC_NODE_SBA,
+};
+extern const struct value_string pdch_ul_node_names[];
+
+struct pdch_ulc_node {
+	struct rb_node node;	  /*! entry in pdch_ulc->tree_root */
+	uint32_t fn;
+	enum PdchUlcNode type;
+	union {
+		struct {
+			struct gprs_rlcmac_ul_tbf *ul_tbf;
+		} tbf_usf;
+		struct {
+			struct gprs_rlcmac_tbf *poll_tbf;
+		} tbf_poll;
+		struct {
+			struct gprs_rlcmac_sba *sba;
+		} sba;
+	};
+};
+
+
+struct pdch_ulc *pdch_ulc_alloc(struct gprs_rlcmac_pdch *pdch, void *ctx);
+
+int pdch_ulc_reserve_tbf_usf(struct pdch_ulc *ulc, uint32_t fn, struct gprs_rlcmac_ul_tbf *ul_tbf);
+int pdch_ulc_reserve_tbf_poll(struct pdch_ulc *ulc, uint32_t fn, struct gprs_rlcmac_tbf *tbf);
+int pdch_ulc_reserve_sba(struct pdch_ulc *ulc, struct gprs_rlcmac_sba *sba);
+
+bool pdch_ulc_fn_is_free(struct pdch_ulc *ulc, uint32_t fn);
+
+struct pdch_ulc_node *pdch_ulc_get_node(struct pdch_ulc *ulc, uint32_t fn);
+struct pdch_ulc_node *pdch_ulc_pop_node(struct pdch_ulc *ulc, uint32_t fn);
+struct gprs_rlcmac_sba *pdch_ulc_get_sba(struct pdch_ulc *ulc, uint32_t fn);
+
+int pdch_ulc_release_fn(struct pdch_ulc *ulc, uint32_t fn);
+
+void pdch_ulc_expire_fn(struct pdch_ulc *ulc, uint32_t fn);
diff --git a/src/poll_controller.cpp b/src/poll_controller.cpp
index 04ec4fd..fe10171 100644
--- a/src/poll_controller.cpp
+++ b/src/poll_controller.cpp
@@ -51,7 +51,6 @@
 {
 	struct gprs_rlcmac_dl_tbf *dl_tbf;
 	struct gprs_rlcmac_ul_tbf *ul_tbf;
-	struct gprs_rlcmac_sba *sba, *sba2;
 	struct llist_item *pos;
 
 	llist_for_each_entry(pos, &m_bts.ul_tbfs, list) {
@@ -68,11 +67,4 @@
 				dl_tbf->poll_timeout();
 		}
 	}
-	llist_for_each_entry_safe(sba, sba2, &bts_sba(&m_bts)->m_sbas, list) {
-		if (elapsed_fn_check(max_delay, frame_number, sba->fn)) {
-			/* sba will be freed here */
-			bts_sba(&m_bts)->timeout(sba);
-		}
-	}
-
 }
diff --git a/src/sba.c b/src/sba.c
new file mode 100644
index 0000000..2c3519d
--- /dev/null
+++ b/src/sba.c
@@ -0,0 +1,90 @@
+/* sba.c
+ *
+ * Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin at sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <sba.h>
+#include <gprs_debug.h>
+#include <bts.h>
+#include <pcu_utils.h>
+#include <pdch.h>
+#include <errno.h>
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/gsm_utils.h>
+
+#include "pdch.h"
+#include "pdch_ul_controller.h"
+
+/* starting time for assigning single slot
+ * This offset must be a multiple of 13. */
+#define AGCH_START_OFFSET 52
+
+
+struct gprs_rlcmac_sba *sba_alloc(void *ctx, struct gprs_rlcmac_pdch *pdch, uint8_t ta)
+{
+	struct gprs_rlcmac_sba *sba;
+	sba = talloc_zero(ctx, struct gprs_rlcmac_sba);
+	if (!sba)
+		return NULL;
+
+	sba->pdch = pdch;
+	sba->ta = ta;
+
+	/* TODO: request ULC for next available FN instead of hardcoded AGCH_START_OFFSET */
+	sba->fn = next_fn(pdch->last_rts_fn, AGCH_START_OFFSET);
+
+	pdch_ulc_reserve_sba(pdch->ulc, sba);
+	return sba;
+}
+
+/* Internal use */
+static void sba_free_norelease(struct gprs_rlcmac_sba *sba)
+{
+	bts_do_rate_ctr_inc(sba->pdch->trx->bts, CTR_SBA_FREED);
+	talloc_free(sba);
+}
+
+void sba_free(struct gprs_rlcmac_sba *sba)
+{
+	if (pdch_ulc_release_fn(sba->pdch->ulc, sba->fn) < 0)
+		LOGPDCH(sba->pdch, DRLCMAC, LOGL_NOTICE,
+			"Trying to release unregistered SBA (FN=%u, TA=%u)\n",
+			sba->fn, sba->ta);
+	sba_free_norelease(sba);
+}
+
+void sba_timeout(struct gprs_rlcmac_sba *sba)
+{
+	/* Upon timeout, the UL Controller node is already released */
+	sba_free_norelease(sba);
+}
+
+uint32_t find_sba_rts(struct gprs_rlcmac_pdch *pdch, uint32_t fn, uint8_t block_nr)
+{
+	uint32_t sba_fn = rts_next_fn(fn, block_nr);
+	struct gprs_rlcmac_sba *sba;
+
+	sba = pdch_ulc_get_sba(pdch->ulc, sba_fn);
+	if (sba)
+		return sba_fn;
+
+	return 0xffffffff;
+}
diff --git a/src/sba.cpp b/src/sba.cpp
deleted file mode 100644
index 53eb847..0000000
--- a/src/sba.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/* sba.cpp
- *
- * Copyright (C) 2012 Ivan Klyuchnikov
- * Copyright (C) 2012 Andreas Eversberg <jolly at eversberg.eu>
- * Copyright (C) 2013 by Holger Hans Peter Freyther
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-
-#include <sba.h>
-#include <gprs_debug.h>
-#include <bts.h>
-#include <pcu_utils.h>
-#include <pdch.h>
-
-extern "C" {
-#include <osmocom/core/logging.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/gsm/protocol/gsm_04_08.h>
-#include <osmocom/gsm/gsm_utils.h>
-}
-
-#include <errno.h>
-
-extern void *tall_pcu_ctx;
-
-/* starting time for assigning single slot
- * This offset must be a multiple of 13. */
-#define AGCH_START_OFFSET 52
-
-SBAController::SBAController(struct gprs_rlcmac_bts &bts)
-	: m_bts(bts)
-{
-	INIT_LLIST_HEAD(&m_sbas);
-}
-
-int SBAController::alloc(
-		uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta)
-{
-
-	struct gprs_rlcmac_pdch *pdch;
-	struct gprs_rlcmac_sba *sba;
-	int8_t trx, ts;
-	uint32_t fn;
-
-	if (!gsm48_ta_is_valid(ta))
-		return -EINVAL;
-
-	sba = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_sba);
-	if (!sba)
-		return -ENOMEM;
-
-	for (trx = 0; trx < 8; trx++) {
-		for (ts = 7; ts >= 0; ts--) {
-			pdch = &m_bts.trx[trx].pdch[ts];
-			if (!pdch->is_enabled())
-				continue;
-			break;
-		}
-		if (ts >= 0)
-			break;
-	}
-	if (trx == 8) {
-		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n");
-		talloc_free(sba);
-		return -EINVAL;
-	}
-
-	fn = next_fn(pdch->last_rts_fn, AGCH_START_OFFSET);
-
-	sba->trx_no = trx;
-	sba->ts_no = ts;
-	sba->fn = fn;
-	sba->ta = ta;
-
-	llist_add(&sba->list, &m_sbas);
-	bts_do_rate_ctr_inc(&m_bts, CTR_SBA_ALLOCATED);
-
-	*_trx = trx;
-	*_ts = ts;
-	*_fn = fn;
-	return 0;
-}
-
-gprs_rlcmac_sba *SBAController::find(uint8_t trx, uint8_t ts, uint32_t fn)
-{
-	struct gprs_rlcmac_sba *sba;
-
-	llist_for_each_entry(sba, &m_sbas, list) {
-		if (sba->trx_no == trx && sba->ts_no == ts && sba->fn == fn)
-			return sba;
-	}
-
-	return NULL;
-}
-
-gprs_rlcmac_sba *SBAController::find(const gprs_rlcmac_pdch *pdch, uint32_t fn)
-{
-	return find(pdch->trx_no(), pdch->ts_no, fn);
-}
-
-uint32_t SBAController::sched(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr)
-{
-	uint32_t sba_fn = fn + 4;
-	struct gprs_rlcmac_sba *sba;
-
-	/* check special TBF for events */
-	if ((block_nr % 3) == 2)
-		sba_fn++;
-	sba_fn = sba_fn % GSM_MAX_FN;
-	sba = find(trx, ts, sba_fn);
-	if (sba)
-		return sba_fn;
-
-	return 0xffffffff;
-}
-
-int SBAController::timeout(struct gprs_rlcmac_sba *sba)
-{
-	LOGP(DRLCMAC, LOGL_NOTICE,
-	     "Poll timeout for SBA (TRX=%u, TS=%u, FN=%u, TA=%u)\n", sba->trx_no,
-	     sba->ts_no, sba->fn, sba->ta);
-	bts_do_rate_ctr_inc(&m_bts, CTR_SBA_TIMEDOUT);
-	free_sba(sba);
-	return 0;
-}
-
-void SBAController::free_sba(gprs_rlcmac_sba *sba)
-{
-	bts_do_rate_ctr_inc(&m_bts, CTR_SBA_FREED);
-	llist_del(&sba->list);
-	talloc_free(sba);
-}
-
-void SBAController::free_resources(struct gprs_rlcmac_pdch *pdch)
-{
-	struct gprs_rlcmac_sba *sba, *sba2;
-	const uint8_t trx_no = pdch->trx->trx_no;
-	const uint8_t ts_no = pdch->ts_no;
-
-	llist_for_each_entry_safe(sba, sba2, &m_sbas, list) {
-		if (sba->trx_no == trx_no && sba->ts_no == ts_no)
-			free_sba(sba);
-	}
-}
diff --git a/src/sba.h b/src/sba.h
index a6e3f82..0f2fdc6 100644
--- a/src/sba.h
+++ b/src/sba.h
@@ -20,48 +20,31 @@
  */
 #pragma once
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include <stdint.h>
 
-extern "C" {
 #include <osmocom/core/linuxlist.h>
-}
 
-struct gprs_rlcmac_bts;
 struct gprs_rlcmac_pdch;
 
 /*
  * single block allocation entry
  */
 struct gprs_rlcmac_sba {
-	struct llist_head list;
-	uint8_t trx_no;
-	uint8_t ts_no;
+	struct gprs_rlcmac_pdch *pdch; /* PDCH where the SBA is allocated on*/
 	uint32_t fn;
 	uint8_t ta;
 };
 
-/**
- * I help to manage SingleBlockAssignment (SBA).
- *
- * TODO: Add a flush method..
- */
-struct SBAController {
-	friend class PollController;
-public:
-	SBAController(struct gprs_rlcmac_bts &bts);
+struct gprs_rlcmac_sba *sba_alloc(void *ctx, struct gprs_rlcmac_pdch *pdch, uint8_t ta);
+void sba_free(struct gprs_rlcmac_sba *sba);
+void sba_timeout(struct gprs_rlcmac_sba *sba);
 
-	int alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta);
-	gprs_rlcmac_sba *find(uint8_t trx, uint8_t ts, uint32_t fn);
-	gprs_rlcmac_sba *find(const gprs_rlcmac_pdch *pdch, uint32_t fn);
+uint32_t find_sba_rts(struct gprs_rlcmac_pdch *pdch, uint32_t fn, uint8_t block_nr);
 
-	uint32_t sched(uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr);
-
-	int timeout(struct gprs_rlcmac_sba *sba);
-	void free_resources(struct gprs_rlcmac_pdch *pdch);
-
-	void free_sba(gprs_rlcmac_sba *sba);
-
-private:
-	struct gprs_rlcmac_bts &m_bts;
-	llist_head m_sbas;
-};
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 70b3b12..87ca5bd 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -562,7 +562,7 @@
 		LOGPTBF(this, LOGL_DEBUG, "Polling is already scheduled\n");
 		return -EBUSY;
 	}
-	if (bts_sba(bts)->find(trx->trx_no, ts, new_poll_fn)) {
+	if (!pdch_ulc_fn_is_free(trx->pdch[ts].ulc, new_poll_fn)) {
 		LOGPTBF(this, LOGL_DEBUG, "Polling is already scheduled "
 			"for single block allocation at FN %d TS %d ...\n",
 			new_poll_fn, ts);
diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp
index d921cbe..f7524c9 100644
--- a/tests/tbf/TbfTest.cpp
+++ b/tests/tbf/TbfTest.cpp
@@ -1793,7 +1793,7 @@
 	 */
 	rc = bts_handle_rach(bts, 0x70, rach_fn, qta);
 
-	OSMO_ASSERT(rc == -EINVAL);
+	OSMO_ASSERT(rc == -EBUSY);
 
 	TALLOC_FREE(the_pcu);
 	fprintf(stderr, "=== end %s ===\n", __func__);
diff --git a/tests/tbf/TbfTest.err b/tests/tbf/TbfTest.err
index f483625..2f370d4 100644
--- a/tests/tbf/TbfTest.err
+++ b/tests/tbf/TbfTest.err
@@ -6232,7 +6232,7 @@
 MS requests Uplink resource on CCCH/RACH: ra=0x70 (8 bit) Fn=2654167 qta=31
 MS requests single block allocation
 No PDCH available.
-No PDCH resource for single block allocation: rc=-22
+No PDCH resource for single block allocation
 Tx Immediate Assignment Reject on AGCH
 === end test_immediate_assign_rej_single_block ===
 === start test_tbf_egprs_two_phase_puan ===

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

Gerrit-Project: osmo-pcu
Gerrit-Branch: master
Gerrit-Change-Id: I84b24beea4a1aa2c1528f41435f77bd16df2b947
Gerrit-Change-Number: 23291
Gerrit-PatchSet: 9
Gerrit-Owner: pespin <pespin at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann at sysmocom.de>
Gerrit-Reviewer: fixeria <vyanitskiy at sysmocom.de>
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-Reviewer: lynxis lazus <lynxis at fe80.eu>
Gerrit-Reviewer: osmith <osmith at sysmocom.de>
Gerrit-Reviewer: pespin <pespin at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20210316/cb8a316c/attachment.htm>


More information about the gerrit-log mailing list