aboutsummaryrefslogtreecommitdiffstats
path: root/src/bts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bts.cpp')
-rw-r--r--src/bts.cpp158
1 files changed, 142 insertions, 16 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()