aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2014-02-14 16:42:49 +0100
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-03-10 08:54:54 +0100
commit4fbe06b3f27c678c2cba7339dc1ea3754ec0609e (patch)
tree201ff678404781ee04077bdefbb641ebbdb1d69d /src
parent20f542280330d1181d04ea34ef876358f710d6c8 (diff)
agch: Recalculate length limit of AGCH queue
This patch adds a function bts_update_agch_max_queue_length() to compute a limit of the AGCH queue. This is based on the idea, that the AGCH queue has a limited drain rate and that CHANNEL REQUESTs must be answered within a certain time frame, given by the minimum value of T3126 (see GSM 04.08). When the AGCH queue reaches that limit, the last message would be delivered in time if there were no other delays involved (which is not the case). The calculation is based on the ratio of the number RACH slots and CCCH blocks per time: Lmax = (T + 2*S) / R_RACH * R_CCCH where T3126_min = (T + 2*S) / R_RACH R_RACH is the RACH slot rate (e.g. RACHs per multiframe) R_CCCH is the CCCH block rate (same time base like R_RACH) The value depends control_channel_desc.ccch_conf and rach_control.tx_integer (both from SYSINFO_TYPE_3) and should therefore by called at least each time after one of these is changed. For this reason, a signal callback is registered under SS_GLOBAL/S_NEW_SYSINFO which invokes bts_update_agch_max_queue_length(). Sponsored-by: On-Waves ehf Based-On: "bts: Calculate length of agch queue" by Ivan Kluchnikov <kluchnikovi@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/common/bts.c90
1 files changed, 89 insertions, 1 deletions
diff --git a/src/common/bts.c b/src/common/bts.c
index 7bbf5870..e82656dd 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -42,6 +42,7 @@
#include <osmo-bts/bts_model.h>
#include <osmo-bts/rsl.h>
#include <osmo-bts/oml.h>
+#include <osmo-bts/signal.h>
struct gsm_network bts_gsmnet = {
@@ -51,11 +52,32 @@ struct gsm_network bts_gsmnet = {
void *tall_bts_ctx;
+/* Table 3.1 TS 04.08: Values of parameter S */
+static const uint8_t tx_integer[] = {
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 25, 32, 50,
+};
+
+static const uint8_t s_values[][2] = {
+ { 55, 41 }, { 76, 52 }, { 109, 58 }, { 163, 86 }, { 217, 115 },
+};
+
+static int bts_signal_cbfn(unsigned int subsys, unsigned int signal,
+ void *hdlr_data, void *signal_data)
+{
+ if (subsys == SS_GLOBAL && signal == S_NEW_SYSINFO) {
+ struct gsm_bts *bts = signal_data;
+
+ bts_update_agch_max_queue_length(bts);
+ }
+ return 0;
+}
+
int bts_init(struct gsm_bts *bts)
{
struct gsm_bts_role_bts *btsb;
struct gsm_bts_trx *trx;
int rc;
+ static int initialized = 0;
/* add to list of BTSs */
llist_add_tail(&bts->list, &bts_gsmnet.bts_list);
@@ -110,6 +132,11 @@ int bts_init(struct gsm_bts *bts)
bts_gsmnet.num_bts++;
+ if (!initialized) {
+ osmo_signal_register_handler(SS_GLOBAL, bts_signal_cbfn, NULL);
+ initialized = 1;
+ }
+
return rc;
}
@@ -209,11 +236,72 @@ int lchan_init_lapdm(struct gsm_lchan *lchan)
return 0;
}
+#define CCCH_RACH_RATIO_COMBINED256 (256*1/9)
+#define CCCH_RACH_RATIO_SEPARATE256 (256*10/55)
+
+int bts_agch_max_queue_length(int T, int bcch_conf)
+{
+ int S, ccch_rach_ratio256, i;
+ int T_group = 0;
+ int is_ccch_comb = 0;
+
+ if (bcch_conf == RSL_BCCH_CCCH_CONF_1_C)
+ is_ccch_comb = 1;
+
+ /*
+ * The calculation is based on the ratio of the number RACH slots and
+ * CCCH blocks per time:
+ * Lmax = (T + 2*S) / R_RACH * R_CCCH
+ * where
+ * T3126_min = (T + 2*S) / R_RACH, as defined in GSM 04.08, 11.1.1
+ * R_RACH is the RACH slot rate (e.g. RACHs per multiframe)
+ * R_CCCH is the CCCH block rate (same time base like R_RACH)
+ * S and T are defined in GSM 04.08, 3.3.1.1.2
+ * The ratio is mainly influenced by the downlink only channels
+ * (BCCH, FCCH, SCH, CBCH) that can not be used for CCCH.
+ * An estimation with an error of < 10% is used:
+ * ~ 1/9 if CCCH is combined with SDCCH, and
+ * ~ 1/5.5 otherwise.
+ */
+ ccch_rach_ratio256 = is_ccch_comb ?
+ CCCH_RACH_RATIO_COMBINED256 :
+ CCCH_RACH_RATIO_SEPARATE256;
+
+ for (i = 0; i < ARRAY_SIZE(tx_integer); i++) {
+ if (tx_integer[i] == T) {
+ T_group = i % 5;
+ break;
+ }
+ }
+ S = s_values[T_group][is_ccch_comb];
+
+ return (T + 2 * S) * ccch_rach_ratio256 / 256;
+}
+
+void bts_update_agch_max_queue_length(struct gsm_bts *bts)
+{
+ struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
+ struct gsm48_system_information_type_3 *si3;
+ int old_max_length = btsb->agch_max_queue_length;
+
+ if (!(bts->si_valid & (1<<SYSINFO_TYPE_3)))
+ return;
+
+ si3 = GSM_BTS_SI(bts, SYSINFO_TYPE_3);
+
+ btsb->agch_max_queue_length =
+ bts_agch_max_queue_length(si3->rach_control.tx_integer,
+ si3->control_channel_desc.ccch_conf);
+
+ if (btsb->agch_max_queue_length != old_max_length)
+ LOGP(DRSL, LOGL_INFO, "Updated AGCH max queue length to %d\n",
+ btsb->agch_max_queue_length);
+}
+
int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg)
{
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
- /* FIXME: implement max queue length */
msgb_enqueue(&btsb->agch_queue, msg);
btsb->agch_queue_length++;