aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bts.cpp158
-rw-r--r--src/bts.h28
-rw-r--r--src/gprs_rlcmac_ts_alloc.cpp10
-rw-r--r--src/sba.cpp42
-rw-r--r--src/tbf.cpp2
5 files changed, 203 insertions, 37 deletions
diff --git a/src/bts.cpp b/src/bts.cpp
index cfccec9..c116eed 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -188,11 +188,13 @@ BTS::BTS()
{
memset(&m_bts, 0, sizeof(m_bts));
m_bts.bts = this;
-
+ m_total_pdch = 0;
/* initialize back pointers */
for (size_t trx_no = 0; trx_no < ARRAY_SIZE(m_bts.trx); ++trx_no) {
struct gprs_rlcmac_trx *trx = &m_bts.trx[trx_no];
trx->trx_no = trx_no;
+ trx->num_pdch = 0;
+ trx->current_load = 0;
trx->bts = this;
for (size_t ts_no = 0; ts_no < ARRAY_SIZE(trx->pdch); ++ts_no) {
@@ -417,9 +419,82 @@ int BTS::tfi_find_free(enum gprs_rlcmac_tbf_direction dir,
uint8_t *_trx, int8_t use_trx)
{
struct gprs_rlcmac_pdch *pdch;
+ uint32_t free_tfis = 0xffffffff;
+ uint8_t ts, tfi;
+ bool possible_trx[8];
+ int ret;
+
+ /* This function will get list of possible TRXs */
+ ret = get_possible_trxs(dir, possible_trx, use_trx);
+ if (ret < 0)
+ return -EBUSY;
+
+
+ if (use_trx >= 0)
+ *_trx = use_trx;
+ else
+ *_trx = get_suitable_trx(possible_trx);
+
+ LOGP(DRLCMAC, LOGL_DEBUG,
+ "Searching for first unallocated TFI: TRX=%d\n", *_trx);
+
+ for (ts = 0; ts < 8; ts++) {
+ pdch = &m_bts.trx[*_trx].pdch[ts];
+ free_tfis &= ~pdch->assigned_tfi(dir);
+ }
+ /* find the first */
+ for (tfi = 0; tfi < 32; tfi++) {
+ if (free_tfis & 1 << tfi)
+ break;
+ }
+
+ OSMO_ASSERT(tfi < 32);
+
+ LOGP(DRLCMAC, LOGL_DEBUG, " Found TFI=%d.\n", tfi);
+
+ return tfi;
+}
+
+/*
+ * Search for free TFI and return TFI, TRX.
+ * This method returns the first TFI that is currently not used in any PDCH of
+ * a TRX. The first TRX that contains such an TFI is returned. Negative values
+ * indicate errors.
+ */
+int BTS::get_possible_trxs_sba(
+ bool *_trx)
+{
+ uint8_t trx;
+ bool has_pdch = false;
+
+ for (trx = 0; trx < 8; trx++) {
+ if (bts_data()->trx[trx].num_pdch) {
+ _trx[trx] = true;
+ has_pdch = true;
+ LOGP(DRLCMAC, LOGL_DEBUG, " Valid TRX=%d.\n", trx);
+ } else {
+ _trx[trx] = false;
+ LOGP(DRLCMAC, LOGL_DEBUG, " Not valid TRX=%d.\n", trx);
+ }
+ }
+ if (has_pdch)
+ return 0;
+
+ return -EINVAL;
+}
+
+/*
+ * This method loops through all possible TRX and
+ * returns subset of possible TRXs based on availability.
+ */
+int BTS::get_possible_trxs(enum gprs_rlcmac_tbf_direction dir,
+ bool *_trx, int8_t use_trx)
+{
+ struct gprs_rlcmac_pdch *pdch;
uint32_t free_tfis;
+ uint32_t is_tfis_available = false;
bool has_pdch = false;
- uint8_t trx_from, trx_to, trx, ts, tfi;
+ uint8_t trx_from, trx_to, trx, ts;
if (use_trx >= 0 && use_trx < 8)
trx_from = trx_to = use_trx;
@@ -442,8 +517,12 @@ int BTS::tfi_find_free(enum gprs_rlcmac_tbf_direction dir,
trx_has_pdch = true;
has_pdch = true;
}
- if (trx_has_pdch && free_tfis)
- break;
+ if (trx_has_pdch && free_tfis) {
+ _trx[trx] = true;
+ is_tfis_available = true;
+ } else {
+ _trx[trx] = false;
+ }
free_tfis = 0;
}
@@ -452,26 +531,69 @@ int BTS::tfi_find_free(enum gprs_rlcmac_tbf_direction dir,
return -EINVAL;
}
- if (!free_tfis) {
+ if (!is_tfis_available) {
LOGP(DRLCMAC, LOGL_NOTICE, "No TFI available.\n");
return -EBUSY;
}
+ return 0;
+}
+/*
+ * This method loops through all subset of TRXs provided by
+ * get_possible_trxs and does the load balancing algorithm. and
+ * selects best TRX possible based on load and capacity
+ */
+int BTS::get_suitable_trx(bool *avail_trx)
+{
+ uint8_t trx_from, trx_to, trx;
+ uint32_t select_probability = 0;
+ uint32_t temp_probability = 0;
+ int selected_trx = -1;
+ bool is_better_trx = false;
- LOGP(DRLCMAC, LOGL_DEBUG,
- "Searching for first unallocated TFI: TRX=%d\n", trx);
+ trx_from = 0;
+ trx_to = 7;
- /* find the first */
- for (tfi = 0; tfi < 32; tfi++) {
- if (free_tfis & 1 << tfi)
- break;
- }
+ for (trx = trx_from; trx <= trx_to; trx++) {
+ /* Check if this TRX is in possible list */
+ if (!avail_trx[trx])
+ continue;
- OSMO_ASSERT(tfi < 32);
+ is_better_trx = false;
+
+ temp_probability = MAX_LOAD_PROBABILITY -
+ (get_num_pdch() * 100 *
+ m_bts.trx[trx].current_load)
+ / m_bts.trx[trx].num_pdch;
+
+ LOGP(DRLCMAC, LOGL_DEBUG, "trx(%d) cur load(%d)"
+ " numpdch(%d) prob1(%u) seleprob(%u)"
+ " btsnumpdch(%d)\n", trx,
+ m_bts.trx[trx].current_load,
+ m_bts.trx[trx].num_pdch,
+ temp_probability, select_probability,
+ get_num_pdch());
+
+ if (temp_probability >= select_probability) {
+ if (temp_probability > select_probability)
+ is_better_trx = true;
+ else if (temp_probability == select_probability)
+ if (selected_trx >= 0 || selected_trx < 8)
+ if (m_bts.trx[selected_trx].num_pdch
+ < m_bts.trx[trx].num_pdch)
+ is_better_trx = true;
+ }
+ if (is_better_trx) {
+ selected_trx = trx;
+ select_probability =
+ temp_probability;
+ LOGP(DRLCMAC, LOGL_DEBUG, "selected pro(%u)"
+ "selected_trx(%d)\n",
+ select_probability, selected_trx);
+ }
+ }
- LOGP(DRLCMAC, LOGL_DEBUG, " Found TFI=%d.\n", tfi);
- *_trx = trx;
- return tfi;
+ return selected_trx;
}
int BTS::rcv_imm_ass_cnf(const uint8_t *data, uint32_t fn)
@@ -783,13 +905,17 @@ void gprs_rlcmac_pdch::enable()
{
/* TODO: Check if there are still allocated resources.. */
INIT_LLIST_HEAD(&paging_list);
+ trx->num_pdch++;
m_is_enabled = 1;
+ bts()->increment_num_pdch();
}
void gprs_rlcmac_pdch::disable()
{
/* TODO.. kick free_resources once we know the TRX/TS we are on */
m_is_enabled = 0;
+ trx->num_pdch--;
+ bts()->decrement_num_pdch();
}
void gprs_rlcmac_pdch::free_resources()
diff --git a/src/bts.h b/src/bts.h
index 2932154..f022e5b 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -44,6 +44,7 @@ extern "C" {
#define LLC_CODEL_USE_DEFAULT (-1)
#define MAX_GPRS_CS 9
+#define MAX_LOAD_PROBABILITY 0xffffffff
struct BTS;
struct GprsMs;
@@ -136,7 +137,8 @@ struct gprs_rlcmac_trx {
/* back pointers */
struct BTS *bts;
uint8_t trx_no;
-
+ uint8_t current_load;
+ uint8_t num_pdch;
#ifdef __cplusplus
void reserve_slots(enum gprs_rlcmac_tbf_direction dir, uint8_t slots);
void unreserve_slots(enum gprs_rlcmac_tbf_direction dir, uint8_t slots);
@@ -345,6 +347,9 @@ public:
gprs_rlcmac_ul_tbf *ul_tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts);
int tfi_find_free(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, int8_t use_trx);
+ int get_possible_trxs(enum gprs_rlcmac_tbf_direction dir,
+ bool *_trx, int8_t use_trx);
+ int get_suitable_trx(bool *suitable_trx);
int rcv_imm_ass_cnf(const uint8_t *data, uint32_t fn);
uint8_t is_single_block(uint16_t ra, enum ph_burst_type burst_type,
@@ -451,6 +456,10 @@ public:
void ms_present(int32_t n);
int32_t ms_present_get();
+ void increment_num_pdch();
+ void decrement_num_pdch();
+ uint8_t get_num_pdch() const;
+ int get_possible_trxs_sba(bool *_trx);
/*
* Below for C interface for the VTY
@@ -476,6 +485,8 @@ private:
/* list of downlink TBFs */
LListHead<gprs_rlcmac_tbf> m_dl_tbfs;
+ /* The summation of all the PDCH across all TRX for this BTS*/
+ uint8_t m_total_pdch;
private:
/* disable copying to avoid slicing */
BTS(const BTS&);
@@ -487,6 +498,21 @@ inline int BTS::current_frame_number() const
return m_cur_fn;
}
+inline void BTS::increment_num_pdch()
+{
+ m_total_pdch++;
+}
+
+inline void BTS::decrement_num_pdch()
+{
+ m_total_pdch--;
+}
+
+inline uint8_t BTS::get_num_pdch() const
+{
+ return m_total_pdch;
+}
+
inline SBAController *BTS::sba()
{
return &m_sba;
diff --git a/src/gprs_rlcmac_ts_alloc.cpp b/src/gprs_rlcmac_ts_alloc.cpp
index 57197b2..df65767 100644
--- a/src/gprs_rlcmac_ts_alloc.cpp
+++ b/src/gprs_rlcmac_ts_alloc.cpp
@@ -383,8 +383,11 @@ static int tfi_find_free(BTS *bts, const GprsMs *ms,
int tfi;
uint8_t trx_no;
- if (use_trx == -1 && ms->current_trx())
+ LOGP(DRLCMAC, LOGL_DEBUG, " USE trx = %d \n",use_trx);
+ if (use_trx == -1 && ms->current_trx()) {
use_trx = ms->current_trx()->trx_no;
+ LOGP(DRLCMAC, LOGL_DEBUG, " MS alive = %d \n",use_trx);
+ }
tfi = bts->tfi_find_free(dir, &trx_no, use_trx);
if (tfi < 0)
@@ -393,6 +396,8 @@ static int tfi_find_free(BTS *bts, const GprsMs *ms,
if (trx_no_)
*trx_no_ = trx_no;
+ LOGP(DRLCMAC, LOGL_DEBUG, " TREE trx = %d TFI = %d\n", *trx_no_, tfi);
+
return tfi;
}
@@ -479,6 +484,7 @@ int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
}
tbf_->trx = trx;
+ trx->current_load++;
/* the only one TS is the common TS */
tbf_->first_ts = tbf_->first_common_ts = ts;
ms_->set_reserved_slots(trx, 1 << ts, 1 << ts);
@@ -1000,6 +1006,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
if (!(dl_slots & (1 << ts)))
continue;
+ trx->current_load++;
LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning DL TS "
"%d\n", ts);
assign_dlink_tbf(&trx->pdch[ts], dl_tbf, tfi);
@@ -1012,6 +1019,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
continue;
OSMO_ASSERT(usf[ts] >= 0);
+ trx->current_load++;
LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning UL TS "
"%d\n", ts);
diff --git a/src/sba.cpp b/src/sba.cpp
index 46c1431..117aa34 100644
--- a/src/sba.cpp
+++ b/src/sba.cpp
@@ -49,8 +49,27 @@ int SBAController::alloc(
struct gprs_rlcmac_pdch *pdch;
struct gprs_rlcmac_sba *sba;
- int8_t trx, ts;
+ int8_t ts;
uint32_t fn;
+ bool trxs[8];
+ int selected_trx;
+ int ret;
+
+ ret = m_bts.get_possible_trxs_sba(trxs);
+
+ if (ret == -EINVAL)
+ return -EINVAL;
+
+ selected_trx = m_bts.get_suitable_trx(trxs);
+
+ for (ts = 7; ts >= 0; ts--) {
+ pdch = &m_bts.bts_data()->trx[selected_trx].pdch[ts];
+ if (!pdch->is_enabled())
+ continue;
+ break;
+ }
+ if (ts < 0)
+ return -EINVAL;
sba = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_sba);
if (!sba)
@@ -59,25 +78,10 @@ int SBAController::alloc(
if (!gsm48_ta_is_valid(ta))
return -EINVAL;
- for (trx = 0; trx < 8; trx++) {
- for (ts = 7; ts >= 0; ts--) {
- pdch = &m_bts.bts_data()->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 = (pdch->last_rts_fn + AGCH_START_OFFSET) % 2715648;
- sba->trx_no = trx;
+ sba->trx_no = selected_trx;
sba->ts_no = ts;
sba->fn = fn;
sba->ta = ta;
@@ -85,9 +89,11 @@ int SBAController::alloc(
llist_add(&sba->list, &m_sbas);
m_bts.sba_allocated();
- *_trx = trx;
+ *_trx = selected_trx;
*_ts = ts;
*_fn = fn;
+ LOGP(DRLCMAC, LOGL_DEBUG, " sba fn=%d ts = %d trx = %d\n", fn, ts, selected_trx);
+
return 0;
}
diff --git a/src/tbf.cpp b/src/tbf.cpp
index cbb7e30..fd39fe8 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -395,7 +395,7 @@ static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
for (ts = 0; ts < 8; ts++) {
if (!tbf->pdch[ts])
continue;
-
+ tbf->trx->current_load--;
tbf->pdch[ts]->detach_tbf(tbf);
tbf->pdch[ts] = NULL;
}