RSL: Add CCCH LOAD INDICATION for RACH

We now count the total number of RACH slots, the number with rx level
above the busy threshold, and the number of valid access bursts.

This data is used to generate RSL CCCH LOAD INDICATION for the RACH.
This commit is contained in:
Harald Welte 2012-06-15 11:07:03 +08:00
parent c882b85d8c
commit 821bf067e4
5 changed files with 69 additions and 23 deletions

View File

@ -36,6 +36,10 @@ struct gsm_bts_role_bts {
/* Input parameters from OML */
int16_t busy_thresh; /* in dBm */
uint16_t averaging_slots;
/* Internal data */
unsigned int total; /* total nr */
unsigned int busy; /* above busy_thresh */
unsigned int access; /* access bursts */
} rach;
} load;
uint8_t ny1;

View File

@ -16,6 +16,8 @@ int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx);
int rsl_tx_ipac_dlcx_ind(struct gsm_lchan *lchan, uint8_t cause);
int rsl_tx_ccch_load_ind_pch(struct gsm_bts *bts, uint16_t paging_avail);
int rsl_tx_ccch_load_ind_rach(struct gsm_bts *bts, uint16_t total,
uint16_t busy, uint16_t access);
struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr);

View File

@ -40,7 +40,7 @@ static void load_timer_cb(void *data)
{
struct gsm_bts *bts = data;
struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
unsigned int pch_percent;
unsigned int pch_percent, rach_percent;
/* compute percentages */
pch_percent = (btsb->load.ccch.pch_used * 100) / btsb->load.ccch.pch_total;
@ -51,6 +51,14 @@ static void load_timer_cb(void *data)
rsl_tx_ccch_load_ind_pch(bts, buffer_space);
}
rach_percent = (btsb->load.rach.busy * 100) / btsb->load.rach.total;
if (rach_percent >= btsb->load.ccch.load_ind_thresh) {
/* send RSL load indication message to BSC */
rsl_tx_ccch_load_ind_rach(bts, btsb->load.rach.total,
btsb->load.rach.busy,
btsb->load.rach.access);
}
reset_load_counters(bts);
/* re-schedule the timer */

View File

@ -342,13 +342,35 @@ int rsl_tx_ccch_load_ind_pch(struct gsm_bts *bts, uint16_t paging_avail)
msg = rsl_msgb_alloc(sizeof(struct abis_rsl_common_hdr));
if (!msg)
return -ENOMEM;
rsl_trx_push_hdr(msg, RSL_MT_CCCH_LOAD_IND);
rsl_cch_push_hdr(msg, RSL_MT_CCCH_LOAD_IND, RSL_CHAN_PCH_AGCH);
msgb_tv16_put(msg, RSL_IE_PAGING_LOAD, paging_avail);
msg->trx = bts->c0;
return abis_rsl_sendmsg(msg);
}
/* 8.5.2 CCCH Load Indication (RACH) */
int rsl_tx_ccch_load_ind_rach(struct gsm_bts *bts, uint16_t total,
uint16_t busy, uint16_t access)
{
struct msgb *msg;
msg = rsl_msgb_alloc(sizeof(struct abis_rsl_common_hdr));
if (!msg)
return -ENOMEM;
rsl_cch_push_hdr(msg, RSL_MT_CCCH_LOAD_IND, RSL_CHAN_RACH);
/* tag and length */
msgb_tv_put(msg, RSL_IE_RACH_LOAD, 6);
/* content of the IE */
msgb_put_u16(msg, total);
msgb_put_u16(msg, busy);
msgb_put_u16(msg, access);
msg->trx = bts->c0;
return abis_rsl_sendmsg(msg);
}
/* 8.5.5 PAGING COMMAND */
static int rsl_rx_paging_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
{
@ -379,27 +401,6 @@ static int rsl_rx_paging_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
return 0;
}
int rsl_tx_ccch_load_ind_rach(struct gsm_bts *bts, uint16_t rach_slots,
uint16_t rach_busy, uint16_t rach_access)
{
struct msgb *msg;
uint16_t payload[3];
payload[0] = htons(rach_slots);
payload[1] = htons(rach_busy);
payload[2] = htons(rach_access);
msg = rsl_msgb_alloc(sizeof(struct abis_rsl_common_hdr));
if (!msg)
return -ENOMEM;
msgb_tlv_put(msg, RSL_IE_RACH_LOAD, 6, (uint8_t *)payload);
rsl_trx_push_hdr(msg, RSL_MT_CCCH_LOAD_IND);
msg->trx = bts->c0;
return abis_rsl_sendmsg(msg);
}
/* 8.6.2 SACCH FILLING */
static int rsl_rx_sacch_fill(struct gsm_bts_trx *trx, struct msgb *msg)
{

View File

@ -539,6 +539,12 @@ empty_frame:
static int handle_mph_time_ind(struct femtol1_hdl *fl1,
GsmL1_MphTimeInd_t *time_ind)
{
struct gsm_bts_trx *trx = fl1->priv;
struct gsm_bts *bts = trx->bts;
struct gsm_bts_role_bts *btsb = bts->role;
int frames_expired = time_ind->u32Fn - fl1->gsm_time.fn;
/* Update our data structures with the current GSM time */
gsm_fn2gsmtime(&fl1->gsm_time, time_ind->u32Fn);
@ -549,6 +555,19 @@ static int handle_mph_time_ind(struct femtol1_hdl *fl1,
/* increment the primitive count for the alive timer */
fl1->alive_prim_cnt++;
/* increment number of RACH slots that have passed by since the
* last time indication */
if (trx == bts->c0) {
unsigned int num_rach_per_frame;
/* 27 / 51 taken from TS 05.01 Figure 3 */
if (bts->c0->ts[0].pchan == GSM_PCHAN_CCCH_SDCCH4)
num_rach_per_frame = 27;
else
num_rach_per_frame = 51;
btsb->load.rach.total += frames_expired * num_rach_per_frame;
}
return 0;
}
@ -681,12 +700,24 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind)
{
struct gsm_bts_trx *trx = fl1->priv;
struct gsm_bts *bts = trx->bts;
struct gsm_bts_role_bts *btsb = bts->role;
struct osmo_phsap_prim pp;
struct lapdm_channel *lc;
/* increment number of busy RACH slots, if required */
if (trx == bts->c0 &&
ra_ind->measParam.fRssi >= btsb->load.rach.busy_thresh)
btsb->load.rach.busy++;
if (ra_ind->measParam.fLinkQuality < MIN_QUAL_RACH)
return 0;
/* increment number of RACH slots with valid RACH burst */
if (trx == bts->c0)
btsb->load.rach.access++;
DEBUGP(DL1C, "Rx PH-RA.ind");
dump_meas_res(&ra_ind->measParam);