aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2015-03-20 14:26:05 +0100
committerJacob Erlbeck <jerlbeck@sysmocom.de>2015-03-25 12:34:38 +0100
commit502bd1feea9441938498b92405220437dc3a91bf (patch)
tree2a90f0c6b8ff7d4158251f9040064a03b4e140c3 /src
parente25b5b91f60f20f61096bc6199a05b58ee6c6328 (diff)
tbf: Poll MS on idle DL TBFs
If an MS wants to open a new UL TBF, it can either use (P)RACH or request one in a Ack/Nack message for a DL TBF (PACCH). When a TBF becomes idle (LCC queue is empty but the TBF is kept open), there aren't any Ack/Nack requests that can be used by the MS to ask for an UL TBF, therefore it has to use the RACH. This leads to many RACH requests even for a single HTTP transaction, so it takes some time to retrieve even a simple web page. This commit modifies the scheduler to regularly send Ack/Nack requests on idle DL TBFs. It does so by extending the priority based scheduling algorithm to have 5 priority levels (highest priority first): - Control block is pending - High age (100%) threshold reached (-> request Ack/Nack) - Data is waiting or there are pending Nacks - Low age (200ms) threshold reached (-> request Ack/Nack) - Pending Nacks that have been resent already - None of the above (-> send DL dummy control block) The 'age' refers to the time since since the last control block has been sent on the TBF. This high age threshold is set to dl-tbf-idle-time or to 50% of T3190 (whichever is smaller), aiming for at least a poll (and TBF shutdown) after the TBF has expired and to safely prevent expiry of T3190. So if dl-tbf-idle-time > 200ms, there will be a poll every 200ms and a final poll after dl-tbf-idle-time. On high load, the interval between polls can get higher, but the 'high age' poll should be in place. This commit implements the scheduling with respect to GSM 44.060, 9.3.1a ("Delayed release of downlink TBF"). Ticket: #556 Sponsored-by: On-Waves ehf
Diffstat (limited to 'src')
-rw-r--r--src/bts.h4
-rw-r--r--src/gprs_rlcmac_sched.cpp41
-rw-r--r--src/tbf_dl.cpp1
3 files changed, 39 insertions, 7 deletions
diff --git a/src/bts.h b/src/bts.h
index 3d74b75..2b43736 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -178,6 +178,10 @@ public:
CTR_RACH_REQUESTS,
};
+ enum {
+ TIMER_T3190_MSEC = 5000,
+ };
+
BTS();
~BTS();
diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp
index c8977e4..dedea26 100644
--- a/src/gprs_rlcmac_sched.cpp
+++ b/src/gprs_rlcmac_sched.cpp
@@ -23,6 +23,8 @@
#include <bts.h>
#include <tbf.h>
+#include "pcu_utils.h"
+
static uint32_t sched_poll(struct gprs_rlcmac_bts *bts,
uint8_t trx, uint8_t ts, uint32_t fn, uint8_t block_nr,
struct gprs_rlcmac_tbf **poll_tbf,
@@ -168,8 +170,21 @@ static struct msgb *sched_select_downlink(struct gprs_rlcmac_bts *bts,
{
struct msgb *msg = NULL;
struct gprs_rlcmac_dl_tbf *tbf, *prio_tbf = NULL;
- int prio, max_prio = -1;
+ enum {
+ DL_PRIO_NONE,
+ DL_PRIO_SENT_DATA, /* the data has been sent and not (yet) nacked */
+ DL_PRIO_LOW_AGE, /* the age has reached the first threshold */
+ DL_PRIO_NEW_DATA, /* the data has not been sent yet or nacked */
+ DL_PRIO_HIGH_AGE, /* the age has reached the second threshold */
+ DL_PRIO_CONTROL, /* a control block needs to be sent */
+ } prio, max_prio = DL_PRIO_NONE;
+
uint8_t i, tfi, prio_tfi;
+ int age;
+ const int age_thresh1 = msecs_to_frames(200);
+ const int high_prio_msecs =
+ OSMO_MIN(BTS::TIMER_T3190_MSEC/2, bts->dl_tbf_idle_msec);
+ const int age_thresh2 = msecs_to_frames(high_prio_msecs);
/* select downlink resource */
for (i = 0, tfi = pdch->next_dl_tfi; i < 32;
@@ -190,13 +205,24 @@ static struct msgb *sched_select_downlink(struct gprs_rlcmac_bts *bts,
if (tbf->m_wait_confirm)
continue;
+ age = tbf->frames_since_last_poll(fn);
+
/* compute priority */
- if (tbf->state_is(GPRS_RLCMAC_FINISHED) &&
- tbf->m_window.resend_needed() < 0)
- /* would re-retransmit blocks */
- prio = 1;
+ if (tbf->is_control_ts(ts) && tbf->need_control_ts())
+ prio = DL_PRIO_CONTROL;
+ else if (tbf->is_control_ts(ts) &&
+ age > age_thresh2 && age_thresh2 > 0)
+ prio = DL_PRIO_HIGH_AGE;
+ else if ((tbf->state_is(GPRS_RLCMAC_FLOW) && tbf->have_data()) ||
+ tbf->m_window.resend_needed() >= 0)
+ prio = DL_PRIO_NEW_DATA;
+ else if (tbf->is_control_ts(ts) &&
+ age > age_thresh1 && tbf->keep_open(fn))
+ prio = DL_PRIO_LOW_AGE;
+ else if (!tbf->m_window.window_empty())
+ prio = DL_PRIO_SENT_DATA;
else
- prio = 2;
+ continue;
/* get the TBF with the highest priority */
if (prio > max_prio) {
@@ -208,7 +234,8 @@ static struct msgb *sched_select_downlink(struct gprs_rlcmac_bts *bts,
if (prio_tbf) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling data message at "
- "RTS for DL TFI=%d (TRX=%d, TS=%d)\n", prio_tfi, trx, ts);
+ "RTS for DL TFI=%d (TRX=%d, TS=%d) prio=%d\n",
+ prio_tfi, trx, ts, max_prio);
/* next TBF to handle resource is the next one */
pdch->next_dl_tfi = (prio_tfi + 1) & 31;
/* generate DL data block */
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index dab733e..7e0883b 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -75,6 +75,7 @@ int gprs_rlcmac_dl_tbf::append_data(const uint8_t ms_class,
reuse_tbf(data, len);
} else if (!have_data()) {
m_llc.put_frame(data, len);
+ m_last_dl_drained_fn = -1;
bts->llc_frame_sched();
/* it is no longer drained */
m_last_dl_drained_fn = -1;