@@ -68,9 +68,10 @@ struct trx_l1h *l1if_open(struct gsm_bts_trx *trx)
if (!l1h)
return NULL;
l1h->trx = trx;
+ l1h->l1s.trx = trx;
trx->role_bts.l1h = l1h;
- trx_sched_init(l1h);
+ trx_sched_init(&l1h->l1s);
rc = trx_if_open(l1h);
if (rc < 0) {
@@ -89,7 +90,7 @@ err:
void l1if_close(struct trx_l1h *l1h)
{
trx_if_close(l1h);
- trx_sched_exit(l1h);
+ trx_sched_exit(&l1h->l1s);
talloc_free(l1h);
}
@@ -267,7 +268,7 @@ int bts_model_trx_close(struct gsm_bts_trx *trx)
enum gsm_phys_chan_config pchan = trx->ts[0].pchan;
/* close all logical channels and reset timeslots */
- trx_sched_reset(l1h);
+ trx_sched_reset(&l1h->l1s);
/* deactivate lchan for CCCH */
if (pchan == GSM_PCHAN_CCCH || pchan == GSM_PCHAN_CCCH_SDCCH4) {
@@ -374,8 +375,12 @@ static uint8_t trx_set_ts(struct gsm_bts_trx_ts *ts)
l1if_provision_transceiver_trx(l1h);
}
+ /* ignore disabled slots */
+ if (!(l1h->config.slotmask & (1 << tn)))
+ return NM_NACK_RES_NOTAVAIL;
+
/* set physical channel */
- rc = trx_sched_set_pchan(l1h, tn, pchan);
+ rc = trx_sched_set_pchan(&l1h->l1s, tn, pchan);
if (rc)
return NM_NACK_RES_NOTAVAIL;
@@ -413,17 +418,17 @@ static int l1if_set_ciphering(struct trx_l1h *l1h, struct gsm_lchan *lchan,
if (!downlink) {
/* set uplink */
- trx_sched_set_cipher(l1h, chan_nr, 0, lchan->encr.alg_id - 1,
+ trx_sched_set_cipher(&l1h->l1s, chan_nr, 0, lchan->encr.alg_id - 1,
lchan->encr.key, lchan->encr.key_len);
lchan->ciph_state = LCHAN_CIPH_RX_CONF;
} else {
/* set downlink and also set uplink, if not already */
if (lchan->ciph_state != LCHAN_CIPH_RX_CONF) {
- trx_sched_set_cipher(l1h, chan_nr, 0,
+ trx_sched_set_cipher(&l1h->l1s, chan_nr, 0,
lchan->encr.alg_id - 1, lchan->encr.key,
lchan->encr.key_len);
}
- trx_sched_set_cipher(l1h, chan_nr, 1, lchan->encr.alg_id - 1,
+ trx_sched_set_cipher(&l1h->l1s, chan_nr, 1, lchan->encr.alg_id - 1,
lchan->encr.key, lchan->encr.key_len);
lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
}
@@ -510,12 +515,12 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
if (!msg)
break;
/* put data into scheduler's queue */
- return trx_sched_ph_data_req(l1h, l1sap);
+ return trx_sched_ph_data_req(&l1h->l1s, l1sap);
case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST):
if (!msg)
break;
/* put data into scheduler's queue */
- return trx_sched_tch_req(l1h, l1sap);
+ return trx_sched_tch_req(&l1h->l1s, l1sap);
case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_REQUEST):
switch (l1sap->u.info.type) {
case PRIM_INFO_ACT_CIPH:
@@ -542,11 +547,11 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
break;
}
/* activate dedicated channel */
- trx_sched_set_lchan(l1h, chan_nr, 0x00, 1);
+ trx_sched_set_lchan(&l1h->l1s, chan_nr, 0x00, 1);
/* activate associated channel */
- trx_sched_set_lchan(l1h, chan_nr, 0x40, 1);
+ trx_sched_set_lchan(&l1h->l1s, chan_nr, 0x40, 1);
/* set mode */
- trx_sched_set_mode(l1h, chan_nr,
+ trx_sched_set_mode(&l1h->l1s, chan_nr,
lchan->rsl_cmode, lchan->tch_mode,
lchan->tch.amr_mr.num_modes,
lchan->tch.amr_mr.bts_mode[0].mode,
@@ -574,7 +579,7 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
}
if (l1sap->u.info.type == PRIM_INFO_MODIFY) {
/* change mode */
- trx_sched_set_mode(l1h, chan_nr,
+ trx_sched_set_mode(&l1h->l1s, chan_nr,
lchan->rsl_cmode, lchan->tch_mode,
lchan->tch.amr_mr.num_modes,
lchan->tch.amr_mr.bts_mode[0].mode,
@@ -591,12 +596,12 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
break;
}
/* deactivate associated channel */
- trx_sched_set_lchan(l1h, chan_nr, 0x40, 0);
+ trx_sched_set_lchan(&l1h->l1s, chan_nr, 0x40, 0);
if (!l1sap->u.info.u.act_req.sacch_only) {
/* set lchan inactive */
lchan_set_state(lchan, LCHAN_S_NONE);
/* deactivate dedicated channel */
- trx_sched_set_lchan(l1h, chan_nr, 0x00, 0);
+ trx_sched_set_lchan(&l1h->l1s, chan_nr, 0x00, 0);
/* confirm only on dedicated channel */
mph_info_chan_confirm(l1h, chan_nr,
PRIM_INFO_DEACTIVATE, 0);
@@ -1,109 +1,7 @@
#ifndef L1_IF_H_TRX
#define L1_IF_H_TRX
-/* These types define the different channels on a multiframe.
- * Each channel has queues and can be activated individually.
- */
-enum trx_chan_type {
- TRXC_IDLE = 0,
- TRXC_FCCH,
- TRXC_SCH,
- TRXC_BCCH,
- TRXC_RACH,
- TRXC_CCCH,
- TRXC_TCHF,
- TRXC_TCHH_0,
- TRXC_TCHH_1,
- TRXC_SDCCH4_0,
- TRXC_SDCCH4_1,
- TRXC_SDCCH4_2,
- TRXC_SDCCH4_3,
- TRXC_SDCCH8_0,
- TRXC_SDCCH8_1,
- TRXC_SDCCH8_2,
- TRXC_SDCCH8_3,
- TRXC_SDCCH8_4,
- TRXC_SDCCH8_5,
- TRXC_SDCCH8_6,
- TRXC_SDCCH8_7,
- TRXC_SACCHTF,
- TRXC_SACCHTH_0,
- TRXC_SACCHTH_1,
- TRXC_SACCH4_0,
- TRXC_SACCH4_1,
- TRXC_SACCH4_2,
- TRXC_SACCH4_3,
- TRXC_SACCH8_0,
- TRXC_SACCH8_1,
- TRXC_SACCH8_2,
- TRXC_SACCH8_3,
- TRXC_SACCH8_4,
- TRXC_SACCH8_5,
- TRXC_SACCH8_6,
- TRXC_SACCH8_7,
- TRXC_PDTCH,
- TRXC_PTCCH,
- _TRX_CHAN_MAX
-};
-
-/* States each channel on a multiframe */
-struct trx_chan_state {
- /* scheduler */
- uint8_t active; /* Channel is active */
- ubit_t *dl_bursts; /* burst buffer for TX */
- sbit_t *ul_bursts; /* burst buffer for RX */
- uint32_t ul_first_fn; /* fn of first burst */
- uint8_t ul_mask; /* mask of received bursts */
-
- /* RSSI / TOA */
- uint8_t rssi_num; /* number of RSSI values */
- float rssi_sum; /* sum of RSSI values */
- uint8_t toa_num; /* number of TOA values */
- float toa_sum; /* sum of TOA values */
-
- /* loss detection */
- uint8_t lost; /* (SACCH) loss detection */
-
- /* mode */
- uint8_t rsl_cmode, tch_mode; /* mode for TCH channels */
-
- /* AMR */
- uint8_t codec[4]; /* 4 possible codecs for amr */
- int codecs; /* number of possible codecs */
- float ber_sum; /* sum of bit error rates */
- int ber_num; /* number of bit error rates */
- uint8_t ul_ft; /* current uplink FT index */
- uint8_t dl_ft; /* current downlink FT index */
- uint8_t ul_cmr; /* current uplink CMR index */
- uint8_t dl_cmr; /* current downlink CMR index */
- uint8_t amr_loop; /* if AMR loop is enabled */
-
- /* TCH/H */
- uint8_t dl_ongoing_facch; /* FACCH/H on downlink */
- uint8_t ul_ongoing_facch; /* FACCH/H on uplink */
-
- /* encryption */
- int ul_encr_algo; /* A5/x encry algo downlink */
- int dl_encr_algo; /* A5/x encry algo uplink */
- int ul_encr_key_len;
- int dl_encr_key_len;
- uint8_t ul_encr_key[MAX_A5_KEY_LEN];
- uint8_t dl_encr_key[MAX_A5_KEY_LEN];
-
- /* measurements */
- struct {
- uint8_t clock; /* cyclic clock counter */
- int8_t rssi[32]; /* last RSSI values */
- int rssi_count; /* received RSSI values */
- int rssi_valid_count; /* number of stored value */
- int rssi_got_burst; /* any burst received so far */
- float toa_sum; /* sum of TOA values */
- int toa_num; /* number of TOA value */
- } meas;
-
- /* handover */
- uint8_t ho_rach_detect; /* if rach detection is on */
-};
+#include "scheduler.h"
struct trx_config {
uint8_t poweron; /* poweron(1) or poweroff(0) */
@@ -152,16 +50,9 @@ struct trx_l1h {
/* transceiver config */
struct trx_config config;
-
- uint8_t mf_index[TRX_NR_TS]; /* selected multiframe index */
- uint32_t mf_last_fn[TRX_NR_TS]; /* last received frame */
- uint8_t mf_period[TRX_NR_TS]; /* period of multiframe */
- const struct trx_sched_frame *mf_frames[TRX_NR_TS]; /* pointer to frame layout */
-
- /* Channel states for all channels on all timeslots */
- struct trx_chan_state chan_states[TRX_NR_TS][_TRX_CHAN_MAX];
- struct llist_head dl_prims[TRX_NR_TS]; /* Queue primitves for TX */
uint8_t ho_rach_detect[TRX_NR_TS][TS_MAX_LCHAN];
+
+ struct l1sched_trx l1s;
};
struct trx_l1h *l1if_open(struct gsm_bts_trx *trx);
@@ -176,4 +67,10 @@ void l1if_fill_meas_res(struct osmo_phsap_prim *l1sap, uint8_t chan_nr, float ta
int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint8_t chan_nr,
int n_errors, int n_bits_total, float rssi, float toa);
+static inline struct l1sched_trx *trx_l1sched_hdl(struct gsm_bts_trx *trx)
+{
+ struct trx_l1h *l1h = trx_l1h_hdl(trx);
+ return &l1h->l1s;
+}
+
#endif /* L1_IF_H_TRX */
@@ -33,7 +33,7 @@
#include "l1_if.h"
#include "loops.h"
-#define MS_PWR_DBM(lvl) ms_pwr_dbm(gsm_arfcn2band(l1h->config.arfcn), lvl)
+#define MS_PWR_DBM(arfcn, lvl) ms_pwr_dbm(gsm_arfcn2band(arfcn), lvl)
/*
* MS Power loop
@@ -42,11 +42,12 @@
int trx_ms_power_loop = 0;
int8_t trx_target_rssi = -10;
-static int ms_power_diff(struct trx_l1h *l1h, struct gsm_lchan *lchan,
- uint8_t chan_nr, struct trx_chan_state *chan_state, int8_t diff)
+static int ms_power_diff(struct gsm_lchan *lchan, uint8_t chan_nr, int8_t diff)
{
+ struct gsm_bts_trx *trx = lchan->ts->trx;
+ uint16_t arfcn = trx->arfcn;
int8_t new_power;
-
+
new_power = lchan->ms_power - (diff >> 1);
if (diff == 0)
@@ -56,7 +57,7 @@ static int ms_power_diff(struct trx_l1h *l1h, struct gsm_lchan *lchan,
new_power = 0;
// FIXME: to go above 1W, we need to know classmark of MS
- if (l1h->config.arfcn >= 512 && l1h->config.arfcn <= 885) {
+ if (arfcn >= 512 && arfcn <= 885) {
if (new_power > 15)
new_power = 15;
} else {
@@ -73,8 +74,8 @@ static int ms_power_diff(struct trx_l1h *l1h, struct gsm_lchan *lchan,
if (lchan->ms_power == new_power) {
LOGP(DLOOP, LOGL_INFO, "Keeping MS new_power of trx=%u "
"chan_nr=0x%02x at control level %d (%d dBm)\n",
- l1h->trx->nr, chan_nr, new_power,
- MS_PWR_DBM(new_power));
+ trx->nr, chan_nr, new_power,
+ MS_PWR_DBM(arfcn, new_power));
return 0;
}
@@ -82,15 +83,16 @@ static int ms_power_diff(struct trx_l1h *l1h, struct gsm_lchan *lchan,
LOGP(DLOOP, LOGL_INFO, "%s MS new_power of trx=%u chan_nr=0x%02x from "
"control level %d (%d dBm) to %d (%d dBm)\n",
(diff > 0) ? "Raising" : "Lowering",
- l1h->trx->nr, chan_nr, lchan->ms_power,
- MS_PWR_DBM(lchan->ms_power), new_power, MS_PWR_DBM(new_power));
+ trx->nr, chan_nr, lchan->ms_power,
+ MS_PWR_DBM(arfcn, lchan->ms_power), new_power,
+ MS_PWR_DBM(arfcn, new_power));
lchan->ms_power = new_power;
return 0;
}
-static int ms_power_val(struct trx_chan_state *chan_state, int8_t rssi)
+static int ms_power_val(struct l1sched_chan_state *chan_state, int8_t rssi)
{
/* ignore inserted dummy frames, treat as lost frames */
if (rssi < -127)
@@ -112,9 +114,10 @@ static int ms_power_val(struct trx_chan_state *chan_state, int8_t rssi)
return 0;
}
-static int ms_power_clock(struct trx_l1h *l1h, struct gsm_lchan *lchan,
- uint8_t chan_nr, struct trx_chan_state *chan_state)
+static int ms_power_clock(struct gsm_lchan *lchan,
+ uint8_t chan_nr, struct l1sched_chan_state *chan_state)
{
+ struct gsm_bts_trx *trx = lchan->ts->trx;
int rssi;
int i;
@@ -134,9 +137,8 @@ static int ms_power_clock(struct trx_l1h *l1h, struct gsm_lchan *lchan,
if (chan_state->meas.rssi_count == 0) {
LOGP(DLOOP, LOGL_NOTICE, "LOST SACCH frame of trx=%u "
"chan_nr=0x%02x, so we raise MS power\n",
- l1h->trx->nr, chan_nr);
- return ms_power_diff(l1h, lchan, chan_nr, chan_state,
- MS_RAISE_MAX);
+ trx->nr, chan_nr);
+ return ms_power_diff(lchan, chan_nr, MS_RAISE_MAX);
}
/* reset total counter */
@@ -157,9 +159,10 @@ static int ms_power_clock(struct trx_l1h *l1h, struct gsm_lchan *lchan,
/* change RSSI */
LOGP(DLOOP, LOGL_DEBUG, "Lowest RSSI: %d Target RSSI: %d Current "
"MS power: %d (%d dBm) of trx=%u chan_nr=0x%02x\n", rssi,
- trx_target_rssi, lchan->ms_power, MS_PWR_DBM(lchan->ms_power),
- l1h->trx->nr, chan_nr);
- ms_power_diff(l1h, lchan, chan_nr, chan_state, trx_target_rssi - rssi);
+ trx_target_rssi, lchan->ms_power,
+ MS_PWR_DBM(trx->arfcn, lchan->ms_power),
+ trx->nr, chan_nr);
+ ms_power_diff(lchan, chan_nr, trx_target_rssi - rssi);
return 0;
}
@@ -171,9 +174,11 @@ static int ms_power_clock(struct trx_l1h *l1h, struct gsm_lchan *lchan,
int trx_ta_loop = 1;
-int ta_val(struct trx_l1h *l1h, struct gsm_lchan *lchan, uint8_t chan_nr,
- struct trx_chan_state *chan_state, float toa)
+int ta_val(struct gsm_lchan *lchan, uint8_t chan_nr,
+ struct l1sched_chan_state *chan_state, float toa)
{
+ struct gsm_bts_trx *trx = lchan->ts->trx;
+
/* check if the current L1 header acks to the current ordered TA */
if (lchan->meas.l1_info[1] != lchan->rqd_ta)
return 0;
@@ -190,19 +195,19 @@ int ta_val(struct trx_l1h *l1h, struct gsm_lchan *lchan, uint8_t chan_nr,
if (toa < -0.9F && lchan->rqd_ta > 0) {
LOGP(DLOOP, LOGL_INFO, "TOA of trx=%u chan_nr=0x%02x is too "
"early (%.2f), now lowering TA from %d to %d\n",
- l1h->trx->nr, chan_nr, toa, lchan->rqd_ta,
+ trx->nr, chan_nr, toa, lchan->rqd_ta,
lchan->rqd_ta - 1);
lchan->rqd_ta--;
} else if (toa > 0.9F && lchan->rqd_ta < 63) {
LOGP(DLOOP, LOGL_INFO, "TOA of trx=%u chan_nr=0x%02x is too "
"late (%.2f), now raising TA from %d to %d\n",
- l1h->trx->nr, chan_nr, toa, lchan->rqd_ta,
+ trx->nr, chan_nr, toa, lchan->rqd_ta,
lchan->rqd_ta + 1);
lchan->rqd_ta++;
} else
LOGP(DLOOP, LOGL_INFO, "TOA of trx=%u chan_nr=0x%02x is "
"correct (%.2f), keeping current TA of %d\n",
- l1h->trx->nr, chan_nr, toa, lchan->rqd_ta);
+ trx->nr, chan_nr, toa, lchan->rqd_ta);
chan_state->meas.toa_num = 0;
chan_state->meas.toa_sum = 0;
@@ -210,29 +215,29 @@ int ta_val(struct trx_l1h *l1h, struct gsm_lchan *lchan, uint8_t chan_nr,
return 0;
}
-int trx_loop_sacch_input(struct trx_l1h *l1h, uint8_t chan_nr,
- struct trx_chan_state *chan_state, int8_t rssi, float toa)
+int trx_loop_sacch_input(struct l1sched_trx *l1t, uint8_t chan_nr,
+ struct l1sched_chan_state *chan_state, int8_t rssi, float toa)
{
- struct gsm_lchan *lchan = &l1h->trx->ts[L1SAP_CHAN2TS(chan_nr)]
+ struct gsm_lchan *lchan = &l1t->trx->ts[L1SAP_CHAN2TS(chan_nr)]
.lchan[l1sap_chan2ss(chan_nr)];
if (trx_ms_power_loop)
ms_power_val(chan_state, rssi);
if (trx_ta_loop)
- ta_val(l1h, lchan, chan_nr, chan_state, toa);
+ ta_val(lchan, chan_nr, chan_state, toa);
return 0;
}
-int trx_loop_sacch_clock(struct trx_l1h *l1h, uint8_t chan_nr,
- struct trx_chan_state *chan_state)
+int trx_loop_sacch_clock(struct l1sched_trx *l1t, uint8_t chan_nr,
+ struct l1sched_chan_state *chan_state)
{
- struct gsm_lchan *lchan = &l1h->trx->ts[L1SAP_CHAN2TS(chan_nr)]
+ struct gsm_lchan *lchan = &l1t->trx->ts[L1SAP_CHAN2TS(chan_nr)]
.lchan[l1sap_chan2ss(chan_nr)];
if (trx_ms_power_loop)
- ms_power_clock(l1h, lchan, chan_nr, chan_state);
+ ms_power_clock(lchan, chan_nr, chan_state);
/* count the number of SACCH clocks */
chan_state->meas.clock++;
@@ -240,10 +245,11 @@ int trx_loop_sacch_clock(struct trx_l1h *l1h, uint8_t chan_nr,
return 0;
}
-int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr,
- struct trx_chan_state *chan_state, float ber)
+int trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr,
+ struct l1sched_chan_state *chan_state, float ber)
{
- struct gsm_lchan *lchan = &l1h->trx->ts[L1SAP_CHAN2TS(chan_nr)]
+ struct gsm_bts_trx *trx = l1t->trx;
+ struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)]
.lchan[l1sap_chan2ss(chan_nr)];
int c_i;
@@ -280,7 +286,7 @@ int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr,
LOGP(DLOOP, LOGL_DEBUG, "Current bit error rate (BER) %.6f "
"codec id %d of trx=%u chan_nr=0x%02x\n", ber,
- chan_state->ul_ft, l1h->trx->nr, chan_nr);
+ chan_state->ul_ft, trx->nr, chan_nr);
/* degrade */
if (chan_state->dl_cmr > 0) {
@@ -290,7 +296,7 @@ int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr,
LOGP(DLOOP, LOGL_DEBUG, "Degrading due to BER %.6f "
"from codec id %d to %d of trx=%u "
"chan_nr=0x%02x\n", ber, chan_state->dl_cmr,
- chan_state->dl_cmr - 1, l1h->trx->nr, chan_nr);
+ chan_state->dl_cmr - 1, trx->nr, chan_nr);
chan_state->dl_cmr--;
}
@@ -306,7 +312,7 @@ int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr,
LOGP(DLOOP, LOGL_DEBUG, "Upgrading due to BER %.6f "
"from codec id %d to %d of trx=%u "
"chan_nr=0x%02x\n", ber, chan_state->dl_cmr,
- chan_state->dl_cmr + 1, l1h->trx->nr, chan_nr);
+ chan_state->dl_cmr + 1, trx->nr, chan_nr);
chan_state->dl_cmr++;
}
@@ -316,7 +322,7 @@ int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr,
return 0;
}
-int trx_loop_amr_set(struct trx_chan_state *chan_state, int loop)
+int trx_loop_amr_set(struct l1sched_chan_state *chan_state, int loop)
{
if (chan_state->amr_loop && !loop) {
chan_state->amr_loop = 0;
@@ -336,4 +342,3 @@ int trx_loop_amr_set(struct trx_chan_state *chan_state, int loop)
return 0;
}
-
@@ -17,15 +17,15 @@ extern int trx_ms_power_loop;
extern int8_t trx_target_rssi;
extern int trx_ta_loop;
-int trx_loop_sacch_input(struct trx_l1h *l1h, uint8_t chan_nr,
- struct trx_chan_state *chan_state, int8_t rssi, float toa);
+int trx_loop_sacch_input(struct l1sched_trx *l1t, uint8_t chan_nr,
+ struct l1sched_chan_state *chan_state, int8_t rssi, float toa);
-int trx_loop_sacch_clock(struct trx_l1h *l1h, uint8_t chan_nr,
- struct trx_chan_state *chan_state);
+int trx_loop_sacch_clock(struct l1sched_trx *l1t, uint8_t chan_nr,
+ struct l1sched_chan_state *chan_state);
-int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr,
- struct trx_chan_state *chan_state, float ber);
+int trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr,
+ struct l1sched_chan_state *chan_state, float ber);
-int trx_loop_amr_set(struct trx_chan_state *chan_state, int loop);
+int trx_loop_amr_set(struct l1sched_chan_state *chan_state, int loop);
#endif /* _TRX_LOOPS_H */
@@ -2,6 +2,7 @@
/* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
* (C) 2015 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
+ * (C) 2015 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -67,47 +68,47 @@ uint32_t trx_clock_advance = 20;
/* advance RTS to give some time for data processing. (especially PCU) */
uint32_t trx_rts_advance = 5; /* about 20ms */
-typedef int trx_sched_rts_func(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+typedef int trx_sched_rts_func(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan);
-typedef ubit_t *trx_sched_dl_func(struct trx_l1h *l1h, uint8_t tn,
+typedef ubit_t *trx_sched_dl_func(struct l1sched_trx *l1t, uint8_t tn,
uint32_t fn, enum trx_chan_type chan, uint8_t bid);
-typedef int trx_sched_ul_func(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+typedef int trx_sched_ul_func(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
float toa);
-static int rts_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan);
-static int rts_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan);
-static int rts_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan);
-static ubit_t *tx_idle_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid);
-static ubit_t *tx_fcch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid);
-static ubit_t *tx_sch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid);
-static ubit_t *tx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid);
-static ubit_t *tx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid);
-static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid);
-static ubit_t *tx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid);
-static int rx_rach_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
float toa);
-static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
float toa);
-static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
float toa);
-static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
float toa);
-static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
float toa);
@@ -219,23 +220,22 @@ static const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
* init / exit
*/
-int trx_sched_init(struct trx_l1h *l1h)
+int trx_sched_init(struct l1sched_trx *l1t)
{
uint8_t tn;
int i;
- struct trx_chan_state *chan_state;
- LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1h->trx->nr);
+ LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1t->trx->nr);
- /* hack to get bts */
- bts = l1h->trx->bts;
+ for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
- for (tn = 0; tn < TRX_NR_TS; tn++) {
- l1h->mf_index[tn] = 0;
- l1h->mf_last_fn[tn] = 0;
- INIT_LLIST_HEAD(&l1h->dl_prims[tn]);
- for (i = 0; i < _TRX_CHAN_MAX; i++) {
- chan_state = &l1h->chan_states[tn][i];
+ l1ts->mf_index = 0;
+ l1ts->mf_last_fn = 0;
+ INIT_LLIST_HEAD(&l1ts->dl_prims);
+ for (i = 0; i < ARRAY_SIZE(&l1ts->chan_state); i++) {
+ struct l1sched_chan_state *chan_state;
+ chan_state = &l1ts->chan_state[i];
chan_state->active = 0;
}
}
@@ -243,18 +243,20 @@ int trx_sched_init(struct trx_l1h *l1h)
return 0;
}
-void trx_sched_exit(struct trx_l1h *l1h)
+void trx_sched_exit(struct l1sched_trx *l1t)
{
+ struct gsm_bts_trx_ts *ts;
uint8_t tn;
int i;
- struct trx_chan_state *chan_state;
- LOGP(DL1C, LOGL_NOTICE, "Exit scheduler for trx=%u\n", l1h->trx->nr);
+ LOGP(DL1C, LOGL_NOTICE, "Exit scheduler for trx=%u\n", l1t->trx->nr);
- for (tn = 0; tn < TRX_NR_TS; tn++) {
- msgb_queue_flush(&l1h->dl_prims[tn]);
+ for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ msgb_queue_flush(&l1ts->dl_prims);
for (i = 0; i < _TRX_CHAN_MAX; i++) {
- chan_state = &l1h->chan_states[tn][i];
+ struct l1sched_chan_state *chan_state;
+ chan_state = &l1ts->chan_state[i];
if (chan_state->dl_bursts) {
talloc_free(chan_state->dl_bursts);
chan_state->dl_bursts = NULL;
@@ -265,16 +267,17 @@ void trx_sched_exit(struct trx_l1h *l1h)
}
}
/* clear lchan channel states */
- for (i = 0; i < TRX_NR_TS; i++)
- l1h->trx->ts[tn].lchan[i].state = LCHAN_S_NONE;
+ ts = &l1t->trx->ts[tn];
+ for (i = 0; i < ARRAY_SIZE(ts->lchan); i++)
+ lchan_set_state(&ts->lchan[i], LCHAN_S_NONE);
}
}
/* close all logical channels and reset timeslots */
-void trx_sched_reset(struct trx_l1h *l1h)
+void trx_sched_reset(struct l1sched_trx *l1t)
{
- trx_sched_exit(l1h);
- trx_sched_init(l1h);
+ trx_sched_exit(l1t);
+ trx_sched_init(l1t);
}
@@ -282,13 +285,14 @@ void trx_sched_reset(struct trx_l1h *l1h)
* data request (from upper layer)
*/
-int trx_sched_ph_data_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap)
+int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap)
{
uint8_t tn = l1sap->u.data.chan_nr & 7;
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
LOGP(DL1C, LOGL_INFO, "PH-DATA.req: chan_nr=0x%02x link_id=0x%02x "
"fn=%u ts=%u trx=%u\n", l1sap->u.data.chan_nr,
- l1sap->u.data.link_id, l1sap->u.data.fn, tn, l1h->trx->nr);
+ l1sap->u.data.link_id, l1sap->u.data.fn, tn, l1t->trx->nr);
if (!l1sap->oph.msg)
abort();
@@ -299,18 +303,19 @@ int trx_sched_ph_data_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap)
return 0;
}
- msgb_enqueue(&l1h->dl_prims[tn], l1sap->oph.msg);
+ msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg);
return 0;
}
-int trx_sched_tch_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap)
+int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap)
{
uint8_t tn = l1sap->u.tch.chan_nr & 7;
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
LOGP(DL1C, LOGL_INFO, "TCH.req: chan_nr=0x%02x "
"fn=%u ts=%u trx=%u\n", l1sap->u.tch.chan_nr,
- l1sap->u.tch.fn, tn, l1h->trx->nr);
+ l1sap->u.tch.fn, tn, l1t->trx->nr);
if (!l1sap->oph.msg)
abort();
@@ -321,7 +326,7 @@ int trx_sched_tch_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap)
return 0;
}
- msgb_enqueue(&l1h->dl_prims[tn], l1sap->oph.msg);
+ msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg);
return 0;
}
@@ -332,12 +337,13 @@ int trx_sched_tch_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap)
*/
/* RTS for data frame */
-static int rts_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan)
{
uint8_t chan_nr, link_id;
struct msgb *msg;
struct osmo_phsap_prim *l1sap;
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
/* get data for RTS indication */
chan_nr = trx_chan_desc[chan].chan_nr | tn;
@@ -351,11 +357,11 @@ static int rts_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
LOGP(DL1C, LOGL_INFO, "PH-RTS.ind: chan=%s chan_nr=0x%02x "
"link_id=0x%02x fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name,
- chan_nr, link_id, fn, tn, l1h->trx->nr);
+ chan_nr, link_id, fn, tn, l1t->trx->nr);
/* send clock information to loops process */
if (L1SAP_IS_LINK_SACCH(link_id))
- trx_loop_sacch_clock(l1h, chan_nr, &l1h->chan_states[tn][chan]);
+ trx_loop_sacch_clock(l1t, chan_nr, &l1ts->chan_state[chan]);
/* generate prim */
msg = l1sap_msgb_alloc(200);
@@ -368,15 +374,16 @@ static int rts_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
l1sap->u.data.link_id = link_id;
l1sap->u.data.fn = fn;
- return l1sap_up(l1h->trx, l1sap);
+ return l1sap_up(l1t->trx, l1sap);
}
-static int rts_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rts_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, int facch)
{
uint8_t chan_nr, link_id;
struct msgb *msg;
struct osmo_phsap_prim *l1sap;
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
int rc = 0;
/* get data for RTS indication */
@@ -391,7 +398,7 @@ static int rts_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
LOGP(DL1C, LOGL_INFO, "TCH RTS.ind: chan=%s chan_nr=0x%02x "
"fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name,
- chan_nr, fn, tn, l1h->trx->nr);
+ chan_nr, fn, tn, l1t->trx->nr);
/* only send, if FACCH is selected */
if (facch) {
@@ -406,11 +413,11 @@ static int rts_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
l1sap->u.data.link_id = link_id;
l1sap->u.data.fn = fn;
- rc = l1sap_up(l1h->trx, l1sap);
+ rc = l1sap_up(l1t->trx, l1sap);
}
/* dont send, if TCH is in signalling only mode */
- if (l1h->chan_states[tn][chan].rsl_cmode != RSL_CMOD_SPD_SIGN) {
+ if (l1ts->chan_state[chan].rsl_cmode != RSL_CMOD_SPD_SIGN) {
/* generate prim */
msg = l1sap_msgb_alloc(200);
if (!msg)
@@ -421,27 +428,27 @@ static int rts_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
l1sap->u.tch.chan_nr = chan_nr;
l1sap->u.tch.fn = fn;
- return l1sap_up(l1h->trx, l1sap);
+ return l1sap_up(l1t->trx, l1sap);
}
return rc;
}
/* RTS for full rate traffic frame */
-static int rts_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan)
{
/* TCH/F may include FACCH on every 4th burst */
- return rts_tch_common(l1h, tn, fn, chan, 1);
+ return rts_tch_common(l1t, tn, fn, chan, 1);
}
/* RTS for half rate traffic frame */
-static int rts_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan)
{
/* the FN 4/5, 13/14, 21/22 defines that FACCH may be included. */
- return rts_tch_common(l1h, tn, fn, chan, ((fn % 26) >> 2) & 1);
+ return rts_tch_common(l1t, tn, fn, chan, ((fn % 26) >> 2) & 1);
}
@@ -450,25 +457,25 @@ static int rts_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
*/
/* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */
-static ubit_t *tx_idle_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid)
{
LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u\n",
- trx_chan_desc[chan].name, fn, tn, l1h->trx->nr);
+ trx_chan_desc[chan].name, fn, tn, l1t->trx->nr);
return NULL;
}
-static ubit_t *tx_fcch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid)
{
LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u\n",
- trx_chan_desc[chan].name, fn, tn, l1h->trx->nr);
+ trx_chan_desc[chan].name, fn, tn, l1t->trx->nr);
return (ubit_t *) fcch_burst;
}
-static ubit_t *tx_sch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid)
{
static ubit_t bits[148], burst[78];
@@ -477,12 +484,12 @@ static ubit_t *tx_sch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
uint8_t t3p, bsic;
LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u\n",
- trx_chan_desc[chan].name, fn, tn, l1h->trx->nr);
+ trx_chan_desc[chan].name, fn, tn, l1t->trx->nr);
/* create SB info from GSM time and BSIC */
gsm_fn2gsmtime(&t, fn);
t3p = t.t3 / 10;
- bsic = l1h->trx->bts->bsic;
+ bsic = l1t->trx->bts->bsic;
sb_info[0] =
((bsic & 0x3f) << 2) |
((t.t1 & 0x600) >> 9);
@@ -508,16 +515,17 @@ static ubit_t *tx_sch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
return bits;
}
-static struct msgb *dequeue_prim(struct trx_l1h *l1h, int8_t tn,uint32_t fn,
+static struct msgb *dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn,
enum trx_chan_type chan)
{
struct msgb *msg, *msg2;
struct osmo_phsap_prim *l1sap;
uint32_t prim_fn;
uint8_t chan_nr, link_id;
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
/* get prim of current fn from queue */
- llist_for_each_entry_safe(msg, msg2, &l1h->dl_prims[tn], list) {
+ llist_for_each_entry_safe(msg, msg2, &l1ts->dl_prims, list) {
l1sap = msgb_l1sap_prim(msg);
if (l1sap->oph.operation != PRIM_OP_REQUEST) {
wrong_type:
@@ -548,7 +556,7 @@ free_msg:
"is out of range, or channel already disabled. "
"If this happens in conjunction with PCU, "
"increase 'rts-advance' by 5. (current fn=%u)\n",
- l1h->trx->nr, tn, l1sap->u.data.fn, fn);
+ l1t->trx->nr, tn, l1sap->u.data.fn, fn);
/* unlink and free message */
llist_del(&msg->list);
msgb_free(msg);
@@ -578,12 +586,13 @@ found_msg:
return msg;
}
-static int compose_ph_data_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi)
{
struct msgb *msg;
struct osmo_phsap_prim *l1sap;
uint8_t chan_nr = trx_chan_desc[chan].chan_nr | tn;
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
/* compose primitive */
msg = l1sap_msgb_alloc(l2_len);
@@ -599,19 +608,20 @@ static int compose_ph_data_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
memcpy(msg->l2h, l2, l2_len);
if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id))
- l1h->chan_states[tn][chan].lost = 0;
+ l1ts->chan_state[chan].lost = 0;
/* forward primitive */
- l1sap_up(l1h->trx, l1sap);
+ l1sap_up(l1t->trx, l1sap);
return 0;
}
-static int compose_tch_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len)
{
struct msgb *msg;
struct osmo_phsap_prim *l1sap;
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
/* compose primitive */
msg = l1sap_msgb_alloc(tch_len);
@@ -624,20 +634,22 @@ static int compose_tch_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
if (tch_len)
memcpy(msg->l2h, tch, tch_len);
- if (l1h->chan_states[tn][chan].lost)
- l1h->chan_states[tn][chan].lost--;
+ if (l1ts->chan_state[chan].lost)
+ l1ts->chan_state[chan].lost--;
/* forward primitive */
- l1sap_up(l1h->trx, l1sap);
+ l1sap_up(l1t->trx, l1sap);
return 0;
}
-static ubit_t *tx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid)
{
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
struct msgb *msg = NULL; /* make GCC happy */
- ubit_t *burst, **bursts_p = &l1h->chan_states[tn][chan].dl_bursts;
+ ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;
static ubit_t bits[148];
/* send burst, if we already got a frame */
@@ -648,13 +660,13 @@ static ubit_t *tx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
}
/* get mac block from queue */
- msg = dequeue_prim(l1h, tn, fn, chan);
+ msg = dequeue_prim(l1t, tn, fn, chan);
if (msg)
goto got_msg;
LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for "
"trx=%u ts=%u at fn=%u to transmit.\n",
- trx_chan_desc[chan].name, l1h->trx->nr, tn, fn);
+ trx_chan_desc[chan].name, l1t->trx->nr, tn, fn);
no_msg:
/* free burst memory */
@@ -677,15 +689,15 @@ got_msg:
/* handle loss detection of sacch */
if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) {
/* count and send BFI */
- if (++(l1h->chan_states[tn][chan].lost) > 1) {
+ if (++(l1ts->chan_state[chan].lost) > 1) {
/* TODO: Should we pass old TOA here? Otherwise we risk
* unnecessary decreasing TA */
/* Send uplnk measurement information to L2 */
- l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn,
+ l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn,
456, 456, -110, 0);
- compose_ph_data_ind(l1h, tn, 0, chan, NULL, 0, -110);
+ compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0, -110);
}
}
@@ -707,21 +719,23 @@ send_burst:
burst = *bursts_p + bid * 116;
memset(bits, 0, 3);
memcpy(bits + 3, burst, 58);
- memcpy(bits + 61, tsc[l1h->config.tsc], 26);
+ memcpy(bits + 61, tsc[gsm_ts_tsc(ts)], 26);
memcpy(bits + 87, burst + 58, 58);
memset(bits + 145, 0, 3);
LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n",
- trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid);
+ trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid);
return bits;
}
-static ubit_t *tx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid)
{
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
struct msgb *msg = NULL; /* make GCC happy */
- ubit_t *burst, **bursts_p = &l1h->chan_states[tn][chan].dl_bursts;
+ ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;
static ubit_t bits[148];
int rc;
@@ -733,13 +747,13 @@ static ubit_t *tx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
}
/* get mac block from queue */
- msg = dequeue_prim(l1h, tn, fn, chan);
+ msg = dequeue_prim(l1t, tn, fn, chan);
if (msg)
goto got_msg;
LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for "
"trx=%u ts=%u at fn=%u to transmit.\n",
- trx_chan_desc[chan].name, l1h->trx->nr, tn, fn);
+ trx_chan_desc[chan].name, l1t->trx->nr, tn, fn);
no_msg:
/* free burst memory */
@@ -777,29 +791,30 @@ send_burst:
burst = *bursts_p + bid * 116;
memset(bits, 0, 3);
memcpy(bits + 3, burst, 58);
- memcpy(bits + 61, tsc[l1h->config.tsc], 26);
+ memcpy(bits + 61, tsc[gsm_ts_tsc(ts)], 26);
memcpy(bits + 87, burst + 58, 58);
memset(bits + 145, 0, 3);
LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n",
- trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid);
+ trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid);
return bits;
}
-static void tx_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, struct msgb **_msg_tch,
struct msgb **_msg_facch, int codec_mode_request)
{
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL;
- struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
uint8_t rsl_cmode = chan_state->rsl_cmode;
uint8_t tch_mode = chan_state->tch_mode;
struct osmo_phsap_prim *l1sap;
/* handle loss detection of received TCH frames */
if (rsl_cmode == RSL_CMOD_SPD_SPEECH
- && ++(l1h->chan_states[tn][chan].lost) > 5) {
+ && ++(chan_state->lost) > 5) {
uint8_t tch_data[GSM_FR_BYTES];
int len;
@@ -831,7 +846,7 @@ static void tx_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
if (len < 2)
break;
memset(tch_data + 2, 0, len - 2);
- compose_tch_ind(l1h, tn, 0, chan, tch_data, len);
+ compose_tch_ind(l1t, tn, 0, chan, tch_data, len);
break;
default:
inval_mode1:
@@ -840,12 +855,12 @@ inval_mode1:
len = 0;
}
if (len)
- compose_tch_ind(l1h, tn, 0, chan, tch_data, len);
+ compose_tch_ind(l1t, tn, 0, chan, tch_data, len);
}
/* get frame and unlink from queue */
- msg1 = dequeue_prim(l1h, tn, fn, chan);
- msg2 = dequeue_prim(l1h, tn, fn, chan);
+ msg1 = dequeue_prim(l1t, tn, fn, chan);
+ msg2 = dequeue_prim(l1t, tn, fn, chan);
if (msg1) {
l1sap = msgb_l1sap_prim(msg1);
if (l1sap->oph.primitive == PRIM_TCH) {
@@ -898,7 +913,7 @@ inval_mode1:
LOGP(DL1C, LOGL_NOTICE, "%s Dropping speech frame, "
"because we are not in speech mode trx=%u "
"ts=%u at fn=%u.\n", trx_chan_desc[chan].name,
- l1h->trx->nr, tn, fn);
+ l1t->trx->nr, tn, fn);
goto free_bad_msg;
}
@@ -913,7 +928,7 @@ inval_mode1:
"HR frame' trx=%u ts=%u at "
"fn=%u.\n",
trx_chan_desc[chan].name,
- l1h->trx->nr, tn, fn);
+ l1t->trx->nr, tn, fn);
goto free_bad_msg;
}
break;
@@ -924,7 +939,7 @@ inval_mode1:
LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad "
"FR frame' trx=%u ts=%u at fn=%u.\n",
trx_chan_desc[chan].name,
- l1h->trx->nr, tn, fn);
+ l1t->trx->nr, tn, fn);
goto free_bad_msg;
}
break;
@@ -937,7 +952,7 @@ inval_mode1:
LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad "
"EFR frame' trx=%u ts=%u at fn=%u.\n",
trx_chan_desc[chan].name,
- l1h->trx->nr, tn, fn);
+ l1t->trx->nr, tn, fn);
goto free_bad_msg;
}
break;
@@ -966,7 +981,7 @@ inval_mode1:
" of RTP frame not in list. "
"trx=%u ts=%u\n",
trx_chan_desc[chan].name, ft_codec,
- l1h->trx->nr, tn);
+ l1t->trx->nr, tn);
goto free_bad_msg;
}
if (codec_mode_request && chan_state->dl_ft != ft) {
@@ -974,7 +989,7 @@ inval_mode1:
" of RTP cannot be changed now, but in "
"next frame. trx=%u ts=%u\n",
trx_chan_desc[chan].name, ft_codec,
- l1h->trx->nr, tn);
+ l1t->trx->nr, tn);
goto free_bad_msg;
}
chan_state->dl_ft = ft;
@@ -982,7 +997,7 @@ inval_mode1:
LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad "
"AMR frame' trx=%u ts=%u at fn=%u.\n",
trx_chan_desc[chan].name,
- l1h->trx->nr, tn, fn);
+ l1t->trx->nr, tn, fn);
goto free_bad_msg;
}
break;
@@ -1014,11 +1029,13 @@ send_frame:
*_msg_facch = msg_facch;
}
-static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid)
{
struct msgb *msg_tch = NULL, *msg_facch = NULL;
- struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
uint8_t tch_mode = chan_state->tch_mode;
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
static ubit_t bits[148];
@@ -1030,7 +1047,7 @@ static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
goto send_burst;
}
- tx_tch_common(l1h, tn, fn, chan, bid, &msg_tch, &msg_facch,
+ tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch,
(((fn + 4) % 26) >> 2) & 1);
/* alloc burst memory, if not already,
@@ -1048,7 +1065,7 @@ static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
if (!msg_tch && !msg_facch) {
LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for "
"trx=%u ts=%u at fn=%u to transmit.\n",
- trx_chan_desc[chan].name, l1h->trx->nr, tn, fn);
+ trx_chan_desc[chan].name, l1t->trx->nr, tn, fn);
goto send_burst;
}
@@ -1079,21 +1096,23 @@ send_burst:
burst = *bursts_p + bid * 116;
memset(bits, 0, 3);
memcpy(bits + 3, burst, 58);
- memcpy(bits + 61, tsc[l1h->config.tsc], 26);
+ memcpy(bits + 61, tsc[gsm_ts_tsc(ts)], 26);
memcpy(bits + 87, burst + 58, 58);
memset(bits + 145, 0, 3);
LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n",
- trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid);
+ trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid);
return bits;
}
-static ubit_t *tx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid)
{
struct msgb *msg_tch = NULL, *msg_facch = NULL;
- struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
uint8_t tch_mode = chan_state->tch_mode;
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
static ubit_t bits[148];
@@ -1106,7 +1125,7 @@ static ubit_t *tx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
}
/* get TCH and/or FACCH */
- tx_tch_common(l1h, tn, fn, chan, bid, &msg_tch, &msg_facch,
+ tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch,
(((fn + 4) % 26) >> 2) & 1);
/* check for FACCH alignment */
@@ -1138,7 +1157,7 @@ static ubit_t *tx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {
LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for "
"trx=%u ts=%u at fn=%u to transmit.\n",
- trx_chan_desc[chan].name, l1h->trx->nr, tn, fn);
+ trx_chan_desc[chan].name, l1t->trx->nr, tn, fn);
goto send_burst;
}
@@ -1171,12 +1190,12 @@ send_burst:
burst = *bursts_p + bid * 116;
memset(bits, 0, 3);
memcpy(bits + 3, burst, 58);
- memcpy(bits + 61, tsc[l1h->config.tsc], 26);
+ memcpy(bits + 61, tsc[gsm_ts_tsc(ts)], 26);
memcpy(bits + 87, burst + 58, 58);
memset(bits + 145, 0, 3);
LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n",
- trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid);
+ trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid);
return bits;
}
@@ -1186,7 +1205,7 @@ send_burst:
* RX on uplink (indication to upper layer)
*/
-static int rx_rach_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
float toa)
{
@@ -1201,7 +1220,7 @@ static int rx_rach_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
trx_chan_desc[chan].name, fn, toa);
/* decode */
- rc = rach_decode(&ra, bits + 8 + 41, l1h->trx->bts->bsic);
+ rc = rach_decode(&ra, bits + 8 + 41, l1t->trx->bts->bsic);
if (rc) {
LOGP(DL1C, LOGL_NOTICE, "Received bad AB frame at fn=%u "
"(%u/51)\n", fn, fn % 51);
@@ -1223,17 +1242,18 @@ static int rx_rach_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
l1sap.u.rach_ind.fn = fn;
/* forward primitive */
- l1sap_up(l1h->trx, &l1sap);
+ l1sap_up(l1t->trx, &l1sap);
return 0;
}
/*! \brief a single burst was received by the PHY, process it */
-static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
float toa)
{
- struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
uint32_t *first_fn = &chan_state->ul_first_fn;
uint8_t *mask = &chan_state->ul_mask;
@@ -1247,10 +1267,10 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
/* handle rach, if handover rach detection is turned on */
if (chan_state->ho_rach_detect == 1)
- return rx_rach_fn(l1h, tn, fn, chan, bid, bits, rssi, toa);
+ return rx_rach_fn(l1t, tn, fn, chan, bid, bits, rssi, toa);
LOGP(DL1C, LOGL_DEBUG, "Data received %s fn=%u ts=%u trx=%u bid=%u\n",
- trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid);
+ trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid);
/* alloc burst memory, if not already */
if (!*bursts_p) {
@@ -1284,7 +1304,7 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
/* send burst information to loops process */
if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) {
- trx_loop_sacch_input(l1h, trx_chan_desc[chan].chan_nr | tn,
+ trx_loop_sacch_input(l1t, trx_chan_desc[chan].chan_nr | tn,
chan_state, rssi, toa);
}
@@ -1296,7 +1316,7 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
if ((*mask & 0xf) != 0xf) {
LOGP(DL1C, LOGL_NOTICE, "Received incomplete data frame at "
"fn=%u (%u/%u) for %s\n", *first_fn,
- (*first_fn) % l1h->mf_period[tn], l1h->mf_period[tn],
+ (*first_fn) % l1ts->mf_period, l1ts->mf_period,
trx_chan_desc[chan].name);
/* we require first burst to have correct FN */
@@ -1312,24 +1332,25 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
if (rc) {
LOGP(DL1C, LOGL_NOTICE, "Received bad data frame at fn=%u "
"(%u/%u) for %s\n", *first_fn,
- (*first_fn) % l1h->mf_period[tn], l1h->mf_period[tn],
+ (*first_fn) % l1ts->mf_period, l1ts->mf_period,
trx_chan_desc[chan].name);
l2_len = 0;
} else
l2_len = GSM_MACBLOCK_LEN;
/* Send uplnk measurement information to L2 */
- l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn,
+ l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn,
n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num);
- return compose_ph_data_ind(l1h, tn, *first_fn, chan, l2, l2_len, *rssi_sum / *rssi_num);
+ return compose_ph_data_ind(l1t, tn, *first_fn, chan, l2, l2_len, *rssi_sum / *rssi_num);
}
-static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
float toa)
{
- struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
uint8_t *mask = &chan_state->ul_mask;
float *rssi_sum = &chan_state->rssi_sum;
@@ -1341,7 +1362,7 @@ static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
int rc;
LOGP(DL1C, LOGL_DEBUG, "PDTCH received %s fn=%u ts=%u trx=%u bid=%u\n",
- trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid);
+ trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid);
/* alloc burst memory, if not already */
if (!*bursts_p) {
@@ -1380,7 +1401,7 @@ static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
if ((*mask & 0xf) != 0xf) {
LOGP(DL1C, LOGL_NOTICE, "Received incomplete PDTCH block "
"ending at fn=%u (%u/%u) for %s\n", fn,
- fn % l1h->mf_period[tn], l1h->mf_period[tn],
+ fn % l1ts->mf_period, l1ts->mf_period,
trx_chan_desc[chan].name);
}
*mask = 0x0;
@@ -1389,27 +1410,28 @@ static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
rc = pdtch_decode(l2 + 1, *bursts_p, NULL, &n_errors, &n_bits_total);
/* Send uplnk measurement information to L2 */
- l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn,
+ l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn,
n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num);
if (rc <= 0) {
LOGP(DL1C, LOGL_NOTICE, "Received bad PDTCH block ending at "
- "fn=%u (%u/%u) for %s\n", fn, fn % l1h->mf_period[tn],
- l1h->mf_period[tn], trx_chan_desc[chan].name);
+ "fn=%u (%u/%u) for %s\n", fn, fn % l1ts->mf_period,
+ l1ts->mf_period, trx_chan_desc[chan].name);
return 0;
}
l2[0] = 7; /* valid frame */
- return compose_ph_data_ind(l1h, tn, (fn + GSM_HYPERFRAME - 3) % GSM_HYPERFRAME, chan,
+ return compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 3) % GSM_HYPERFRAME, chan,
l2, rc + 1, *rssi_sum / *rssi_num);
}
-static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
float toa)
{
- struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
uint8_t *mask = &chan_state->ul_mask;
uint8_t rsl_cmode = chan_state->rsl_cmode;
@@ -1420,10 +1442,10 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
/* handle rach, if handover rach detection is turned on */
if (chan_state->ho_rach_detect == 1)
- return rx_rach_fn(l1h, tn, fn, chan, bid, bits, rssi, toa);
+ return rx_rach_fn(l1t, tn, fn, chan, bid, bits, rssi, toa);
LOGP(DL1C, LOGL_DEBUG, "TCH/F received %s fn=%u ts=%u trx=%u bid=%u\n",
- trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid);
+ trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid);
/* alloc burst memory, if not already */
if (!*bursts_p) {
@@ -1454,7 +1476,7 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
if ((*mask & 0xf) != 0xf) {
LOGP(DL1C, LOGL_NOTICE, "Received incomplete TCH frame ending "
"at fn=%u (%u/%u) for %s\n", fn,
- fn % l1h->mf_period[tn], l1h->mf_period[tn],
+ fn % l1ts->mf_period, l1ts->mf_period,
trx_chan_desc[chan].name);
}
*mask = 0x0;
@@ -1479,7 +1501,7 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
chan_state->codecs, &chan_state->ul_ft,
&chan_state->ul_cmr, &n_errors, &n_bits_total);
if (rc)
- trx_loop_amr_input(l1h,
+ trx_loop_amr_input(l1t,
trx_chan_desc[chan].chan_nr | tn, chan_state,
(float)n_errors/(float)n_bits_total);
amr = 2; /* we store tch_data + 2 header bytes */
@@ -1498,7 +1520,7 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
memcpy(*bursts_p, *bursts_p + 464, 464);
/* Send uplnk measurement information to L2 */
- l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn,
+ l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn,
n_errors, n_bits_total, rssi, toa);
/* Check if the frame is bad */
@@ -1516,7 +1538,7 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
/* FACCH */
if (rc == GSM_MACBLOCK_LEN) {
- compose_ph_data_ind(l1h, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan,
+ compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan,
tch_data + amr, GSM_MACBLOCK_LEN, rssi);
bfi:
if (rsl_cmode == RSL_CMOD_SPD_SPEECH) {
@@ -1551,15 +1573,16 @@ bfi:
return 0;
/* TCH or BFI */
- return compose_tch_ind(l1h, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan,
+ return compose_tch_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan,
tch_data, rc);
}
-static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+static int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi,
float toa)
{
- struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan];
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
uint8_t *mask = &chan_state->ul_mask;
uint8_t rsl_cmode = chan_state->rsl_cmode;
@@ -1570,10 +1593,10 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
/* handle rach, if handover rach detection is turned on */
if (chan_state->ho_rach_detect == 1)
- return rx_rach_fn(l1h, tn, fn, chan, bid, bits, rssi, toa);
+ return rx_rach_fn(l1t, tn, fn, chan, bid, bits, rssi, toa);
LOGP(DL1C, LOGL_DEBUG, "TCH/H received %s fn=%u ts=%u trx=%u bid=%u\n",
- trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid);
+ trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid);
/* alloc burst memory, if not already */
if (!*bursts_p) {
@@ -1604,7 +1627,7 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
if ((*mask & 0x3) != 0x3) {
LOGP(DL1C, LOGL_NOTICE, "Received incomplete TCH frame ending "
"at fn=%u (%u/%u) for %s\n", fn,
- fn % l1h->mf_period[tn], l1h->mf_period[tn],
+ fn % l1ts->mf_period, l1ts->mf_period,
trx_chan_desc[chan].name);
}
*mask = 0x0;
@@ -1641,7 +1664,7 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
chan_state->codecs, &chan_state->ul_ft,
&chan_state->ul_cmr, &n_errors, &n_bits_total);
if (rc)
- trx_loop_amr_input(l1h,
+ trx_loop_amr_input(l1t,
trx_chan_desc[chan].chan_nr | tn, chan_state,
(float)n_errors/(float)n_bits_total);
amr = 2; /* we store tch_data + 2 two */
@@ -1661,7 +1684,7 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
memcpy(*bursts_p + 232, *bursts_p + 464, 232);
/* Send uplnk measurement information to L2 */
- l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn,
+ l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn,
n_errors, n_bits_total, rssi, toa);
/* Check if the frame is bad */
@@ -1680,7 +1703,7 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
/* FACCH */
if (rc == GSM_MACBLOCK_LEN) {
chan_state->ul_ongoing_facch = 1;
- compose_ph_data_ind(l1h, tn,
+ compose_ph_data_ind(l1t, tn,
(fn + GSM_HYPERFRAME - 10 - ((fn % 26) >= 19)) % GSM_HYPERFRAME, chan,
tch_data + amr, GSM_MACBLOCK_LEN, rssi);
bfi:
@@ -1718,7 +1741,7 @@ bfi:
* with the slot 12, so an extra FN must be substracted to get correct
* start of frame.
*/
- return compose_tch_ind(l1h, tn,
+ return compose_tch_ind(l1t, tn,
(fn + GSM_HYPERFRAME - 10 - ((fn%26)==19) - ((fn%26)==20)) % GSM_HYPERFRAME,
chan, tch_data, rc);
}
@@ -2487,61 +2510,59 @@ static const struct trx_sched_multiframe trx_sched_multiframes[] = {
*/
/* set multiframe scheduler to given pchan */
-int trx_sched_set_pchan(struct trx_l1h *l1h, uint8_t tn,
+int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn,
enum gsm_phys_chan_config pchan)
{
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
int i;
- /* ignore disabled slots */
- if (!(l1h->config.slotmask & (1 << tn)))
- return -ENOTSUP;
-
for (i = 0; i < ARRAY_SIZE(trx_sched_multiframes); i++) {
if (trx_sched_multiframes[i].pchan == pchan
&& (trx_sched_multiframes[i].slotmask & (1 << tn))) {
- l1h->mf_index[tn] = i;
- l1h->mf_period[tn] = trx_sched_multiframes[i].period;
- l1h->mf_frames[tn] = trx_sched_multiframes[i].frames;
+ l1ts->mf_index = i;
+ l1ts->mf_period = trx_sched_multiframes[i].period;
+ l1ts->mf_frames = trx_sched_multiframes[i].frames;
LOGP(DL1C, LOGL_NOTICE, "Configuring multiframe with "
"%s trx=%d ts=%d\n",
trx_sched_multiframes[i].name,
- l1h->trx->nr, tn);
+ l1t->trx->nr, tn);
return 0;
}
}
LOGP(DL1C, LOGL_NOTICE, "Failed to configuring multiframe "
- "trx=%d ts=%d\n", l1h->trx->nr, tn);
+ "trx=%d ts=%d\n", l1t->trx->nr, tn);
return -ENOTSUP;
}
/* setting all logical channels given attributes to active/inactive */
-int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id,
+int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id,
int active)
{
uint8_t tn = L1SAP_CHAN2TS(chan_nr);
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
uint8_t ss = l1sap_chan2ss(chan_nr);
int i;
int rc = -EINVAL;
- struct trx_chan_state *chan_state;
/* look for all matching chan_nr/link_id */
for (i = 0; i < _TRX_CHAN_MAX; i++) {
+ struct l1sched_chan_state *chan_state;
+ chan_state = &l1ts->chan_state[i];
/* skip if pchan type does not match pdch flag */
- if ((trx_sched_multiframes[l1h->mf_index[tn]].pchan
+ if ((trx_sched_multiframes[l1ts->mf_index].pchan
== GSM_PCHAN_PDCH)
!= trx_chan_desc[i].pdch)
continue;
if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8)
&& trx_chan_desc[i].link_id == link_id) {
- chan_state = &l1h->chan_states[tn][i];
rc = 0;
if (chan_state->active == active)
continue;
LOGP(DL1C, LOGL_NOTICE, "%s %s on trx=%d ts=%d\n",
(active) ? "Activating" : "Deactivating",
- trx_chan_desc[i].name, l1h->trx->nr, tn);
+ trx_chan_desc[i].name, l1t->trx->nr, tn);
if (active)
memset(chan_state, 0, sizeof(*chan_state));
chan_state->active = active;
@@ -2554,12 +2575,14 @@ int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id,
talloc_free(chan_state->ul_bursts);
chan_state->ul_bursts = NULL;
}
+ if (!active)
+ chan_state->ho_rach_detect = 0;
}
}
/* disable handover detection (on deactivation) */
- if (l1h->ho_rach_detect[tn][ss]) {
- l1h->ho_rach_detect[tn][ss] = 0;
+ if (!active) {
+ struct trx_l1h *l1h = trx_l1h_hdl(l1t->trx);
trx_if_cmd_nohandover(l1h, tn, ss);
}
@@ -2567,28 +2590,30 @@ int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id,
}
/* setting all logical channels given attributes to active/inactive */
-int trx_sched_set_mode(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t rsl_cmode,
+int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode,
uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1,
uint8_t codec2, uint8_t codec3, uint8_t initial_id, uint8_t handover)
{
uint8_t tn = L1SAP_CHAN2TS(chan_nr);
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ struct trx_l1h *l1h = trx_l1h_hdl(l1t->trx);
uint8_t ss = l1sap_chan2ss(chan_nr);
int i;
int rc = -EINVAL;
- struct trx_chan_state *chan_state;
+ struct l1sched_chan_state *chan_state;
/* no mode for PDCH */
- if (trx_sched_multiframes[l1h->mf_index[tn]].pchan == GSM_PCHAN_PDCH)
+ if (trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH)
return 0;
/* look for all matching chan_nr/link_id */
for (i = 0; i < _TRX_CHAN_MAX; i++) {
if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8)
&& trx_chan_desc[i].link_id == 0x00) {
- chan_state = &l1h->chan_states[tn][i];
+ chan_state = &l1ts->chan_state[i];
LOGP(DL1C, LOGL_NOTICE, "Set mode %u, %u, handover %u "
"on %s of trx=%d ts=%d\n", rsl_cmode, tch_mode,
- handover, trx_chan_desc[i].name, l1h->trx->nr,
+ handover, trx_chan_desc[i].name, l1t->trx->nr,
tn);
chan_state->rsl_cmode = rsl_cmode;
chan_state->tch_mode = tch_mode;
@@ -2617,10 +2642,8 @@ int trx_sched_set_mode(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t rsl_cmode,
* disable handover, if state is still set, since we might not know
* the actual state of transceiver (due to loss of link) */
if (handover) {
- l1h->ho_rach_detect[tn][ss] = 1;
trx_if_cmd_handover(l1h, tn, ss);
- } else if (l1h->ho_rach_detect[tn][ss]) {
- l1h->ho_rach_detect[tn][ss] = 0;
+ } else {
trx_if_cmd_nohandover(l1h, tn, ss);
}
@@ -2628,16 +2651,17 @@ int trx_sched_set_mode(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t rsl_cmode,
}
/* setting cipher on logical channels */
-int trx_sched_set_cipher(struct trx_l1h *l1h, uint8_t chan_nr, int downlink,
+int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink,
int algo, uint8_t *key, int key_len)
{
uint8_t tn = L1SAP_CHAN2TS(chan_nr);
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
int i;
int rc = -EINVAL;
- struct trx_chan_state *chan_state;
+ struct l1sched_chan_state *chan_state;
/* no cipher for PDCH */
- if (trx_sched_multiframes[l1h->mf_index[tn]].pchan == GSM_PCHAN_PDCH)
+ if (trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH)
return 0;
/* no algorithm given means a5/0 */
@@ -2655,11 +2679,11 @@ int trx_sched_set_cipher(struct trx_l1h *l1h, uint8_t chan_nr, int downlink,
if (trx_chan_desc[i].pdch)
continue;
if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8)) {
- chan_state = &l1h->chan_states[tn][i];
+ chan_state = &l1ts->chan_state[i];
LOGP(DL1C, LOGL_NOTICE, "Set a5/%d %s for %s on trx=%d "
"ts=%d\n", algo,
(downlink) ? "downlink" : "uplink",
- trx_chan_desc[i].name, l1h->trx->nr, tn);
+ trx_chan_desc[i].name, l1t->trx->nr, tn);
if (downlink) {
chan_state->dl_encr_algo = algo;
memcpy(chan_state->dl_encr_key, key, key_len);
@@ -2677,21 +2701,22 @@ int trx_sched_set_cipher(struct trx_l1h *l1h, uint8_t chan_nr, int downlink,
}
/* process ready-to-send */
-static int trx_sched_rts(struct trx_l1h *l1h, uint8_t tn, uint32_t fn)
+static int trx_sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn)
{
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
const struct trx_sched_frame *frame;
uint8_t offset, period, bid;
trx_sched_rts_func *func;
enum trx_chan_type chan;
/* no multiframe set */
- if (!l1h->mf_index[tn])
+ if (!l1ts->mf_index)
return 0;
/* get frame from multiframe */
- period = l1h->mf_period[tn];
+ period = l1ts->mf_period;
offset = fn % period;
- frame = l1h->mf_frames[tn] + offset;
+ frame = l1ts->mf_frames + offset;
chan = frame->dl_chan;
bid = frame->dl_bid;
@@ -2707,49 +2732,51 @@ static int trx_sched_rts(struct trx_l1h *l1h, uint8_t tn, uint32_t fn)
/* check if channel is active */
if (!trx_chan_desc[chan].auto_active
- && !l1h->chan_states[tn][chan].active)
+ && !l1ts->chan_state[chan].active)
return -EINVAL;
- return func(l1h, tn, fn, frame->dl_chan);
+ return func(l1t, tn, fn, frame->dl_chan);
}
/* process downlink burst */
-static const ubit_t *trx_sched_dl_burst(struct trx_l1h *l1h, uint8_t tn,
+static const ubit_t *trx_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn,
uint32_t fn)
{
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ struct l1sched_chan_state *l1cs;
const struct trx_sched_frame *frame;
uint8_t offset, period, bid;
trx_sched_dl_func *func;
enum trx_chan_type chan;
ubit_t *bits = NULL;
- if (!l1h->mf_index[tn])
+ if (!l1ts->mf_index)
goto no_data;
/* get frame from multiframe */
- period = l1h->mf_period[tn];
+ period = l1ts->mf_period;
offset = fn % period;
- frame = l1h->mf_frames[tn] + offset;
+ frame = l1ts->mf_frames + offset;
chan = frame->dl_chan;
bid = frame->dl_bid;
func = trx_chan_desc[chan].dl_fn;
+ l1cs = &l1ts->chan_state[chan];
+
/* check if channel is active */
- if (!trx_chan_desc[chan].auto_active
- && !l1h->chan_states[tn][chan].active)
+ if (!trx_chan_desc[chan].auto_active && !l1cs->active)
goto no_data;
/* get burst from function */
- bits = func(l1h, tn, fn, chan, bid);
+ bits = func(l1t, tn, fn, chan, bid);
/* encrypt */
- if (bits && l1h->chan_states[tn][chan].dl_encr_algo) {
+ if (bits && l1cs->dl_encr_algo) {
ubit_t ks[114];
int i;
- osmo_a5(l1h->chan_states[tn][chan].dl_encr_algo,
- l1h->chan_states[tn][chan].dl_encr_key, fn, ks, NULL);
+ osmo_a5(l1cs->dl_encr_algo, l1cs->dl_encr_key, fn, ks, NULL);
for (i = 0; i < 57; i++) {
bits[i + 3] ^= ks[i];
bits[i + 88] ^= ks[i + 57];
@@ -2758,7 +2785,7 @@ static const ubit_t *trx_sched_dl_burst(struct trx_l1h *l1h, uint8_t tn,
no_data:
/* in case of C0, we need a dummy burst to maintain RF power */
- if (bits == NULL && l1h->trx == l1h->trx->bts->c0) {
+ if (bits == NULL && l1t->trx == l1t->trx->bts->c0) {
if (0) if (chan != TRXC_IDLE) // hack
LOGP(DL1C, LOGL_DEBUG, "No burst data for %s fn=%u ts=%u "
"burst=%d on C0, so filling with dummy burst\n",
@@ -2770,41 +2797,44 @@ if (0) if (chan != TRXC_IDLE) // hack
}
/* process uplink burst */
-int trx_sched_ul_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t current_fn,
+int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t current_fn,
sbit_t *bits, int8_t rssi, float toa)
{
+ struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
+ struct l1sched_chan_state *l1cs;
const struct trx_sched_frame *frame;
uint8_t offset, period, bid;
trx_sched_ul_func *func;
enum trx_chan_type chan;
uint32_t fn, elapsed;
- if (!l1h->mf_index[tn])
+ if (!l1ts->mf_index)
return -EINVAL;
/* calculate how many frames have been elapsed */
- elapsed = (current_fn + GSM_HYPERFRAME - l1h->mf_last_fn[tn]) % GSM_HYPERFRAME;
+ elapsed = (current_fn + GSM_HYPERFRAME - l1ts->mf_last_fn) % GSM_HYPERFRAME;
/* start counting from last fn + 1, but only if not too many fn have
* been elapsed */
if (elapsed < 10)
- fn = (l1h->mf_last_fn[tn] + 1) % GSM_HYPERFRAME;
+ fn = (l1ts->mf_last_fn + 1) % GSM_HYPERFRAME;
else
fn = current_fn;
while (42) {
/* get frame from multiframe */
- period = l1h->mf_period[tn];
+ period = l1ts->mf_period;
offset = fn % period;
- frame = l1h->mf_frames[tn] + offset;
+ frame = l1ts->mf_frames + offset;
chan = frame->ul_chan;
bid = frame->ul_bid;
func = trx_chan_desc[chan].ul_fn;
+ l1cs = &l1ts->chan_state[chan];
+
/* check if channel is active */
- if (!trx_chan_desc[chan].auto_active
- && !l1h->chan_states[tn][chan].active)
+ if (!trx_chan_desc[chan].auto_active && !l1cs->active)
goto next_frame;
/* omit bursts which have no handler, like IDLE bursts */
@@ -2814,12 +2844,12 @@ int trx_sched_ul_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t current_fn,
/* put burst to function */
if (fn == current_fn) {
/* decrypt */
- if (bits && l1h->chan_states[tn][chan].ul_encr_algo) {
+ if (bits && l1cs->ul_encr_algo) {
ubit_t ks[114];
int i;
- osmo_a5(l1h->chan_states[tn][chan].ul_encr_algo,
- l1h->chan_states[tn][chan].ul_encr_key,
+ osmo_a5(l1cs->ul_encr_algo,
+ l1cs->ul_encr_key,
fn, NULL, ks);
for (i = 0; i < 57; i++) {
if (ks[i])
@@ -2829,13 +2859,12 @@ int trx_sched_ul_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t current_fn,
}
}
- func(l1h, tn, fn, chan, bid, bits, rssi, toa);
- } else if (chan != TRXC_RACH
- && !l1h->chan_states[tn][chan].ho_rach_detect) {
+ func(l1t, tn, fn, chan, bid, bits, rssi, toa);
+ } else if (chan != TRXC_RACH && !l1cs->ho_rach_detect) {
sbit_t spare[148];
memset(spare, 0, 148);
- func(l1h, tn, fn, chan, bid, spare, -128, 0);
+ func(l1t, tn, fn, chan, bid, spare, -128, 0);
}
next_frame:
@@ -2846,7 +2875,7 @@ next_frame:
fn = (fn + 1) % GSM_HYPERFRAME;
}
- l1h->mf_last_fn[tn] = fn;
+ l1ts->mf_last_fn = fn;
return 0;
}
@@ -2855,7 +2884,6 @@ next_frame:
static int trx_sched_fn(uint32_t fn)
{
struct gsm_bts_trx *trx;
- struct trx_l1h *l1h;
uint8_t tn;
const ubit_t *bits;
uint8_t gain;
@@ -2869,22 +2897,20 @@ static int trx_sched_fn(uint32_t fn)
/* process every TRX */
llist_for_each_entry(trx, &bts->trx_list, list) {
- l1h = trx_l1h_hdl(trx);
+ struct trx_l1h *l1h = trx_l1h_hdl(trx);
+ struct l1sched_trx *l1t = trx_l1sched_hdl(trx);
/* we don't schedule, if power is off */
if (!l1h->config.poweron)
continue;
/* process every TS of TRX */
- for (tn = 0; tn < TRX_NR_TS; tn++) {
- /* ignore disabled slots */
- if (!(l1h->config.slotmask & (1 << tn)))
- continue;
+ for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
/* ready-to-send */
- trx_sched_rts(l1h, tn,
+ trx_sched_rts(l1t, tn,
(fn + trx_rts_advance) % GSM_HYPERFRAME);
/* get burst for FN */
- bits = trx_sched_dl_burst(l1h, tn, fn);
+ bits = trx_sched_dl_burst(l1t, tn, fn);
if (!bits) {
/* if no bits, send no burst */
continue;
@@ -2910,6 +2936,7 @@ extern int quit;
/* this timer fires for every FN to be processed */
static void trx_ctrl_timer_cb(void *data)
{
+ struct gsm_bts *bts = data;
struct timeval tv_now, *tv_clock = &transceiver_clock_tv;
int32_t elapsed;
@@ -2926,7 +2953,7 @@ no_clock:
/* close all logical channels and reset timeslots */
llist_for_each_entry(trx, &bts->trx_list, list) {
trx_if_flush(trx_l1h_hdl(trx));
- trx_sched_reset(trx_l1h_hdl(trx));
+ trx_sched_reset(trx_l1sched_hdl(trx));
if (trx->nr == 0)
trx_if_cmd_poweroff(trx_l1h_hdl(trx));
}
@@ -3061,3 +3088,8 @@ new_clock:
return 0;
}
+struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn)
+{
+ OSMO_ASSERT(tn < ARRAY_SIZE(l1t->ts));
+ return &l1t->ts[tn];
+}
@@ -1,6 +1,129 @@
#ifndef TRX_SCHEDULER_H
#define TRX_SCHEDULER_H
+/* These types define the different channels on a multiframe.
+ * Each channel has queues and can be activated individually.
+ */
+enum trx_chan_type {
+ TRXC_IDLE = 0,
+ TRXC_FCCH,
+ TRXC_SCH,
+ TRXC_BCCH,
+ TRXC_RACH,
+ TRXC_CCCH,
+ TRXC_TCHF,
+ TRXC_TCHH_0,
+ TRXC_TCHH_1,
+ TRXC_SDCCH4_0,
+ TRXC_SDCCH4_1,
+ TRXC_SDCCH4_2,
+ TRXC_SDCCH4_3,
+ TRXC_SDCCH8_0,
+ TRXC_SDCCH8_1,
+ TRXC_SDCCH8_2,
+ TRXC_SDCCH8_3,
+ TRXC_SDCCH8_4,
+ TRXC_SDCCH8_5,
+ TRXC_SDCCH8_6,
+ TRXC_SDCCH8_7,
+ TRXC_SACCHTF,
+ TRXC_SACCHTH_0,
+ TRXC_SACCHTH_1,
+ TRXC_SACCH4_0,
+ TRXC_SACCH4_1,
+ TRXC_SACCH4_2,
+ TRXC_SACCH4_3,
+ TRXC_SACCH8_0,
+ TRXC_SACCH8_1,
+ TRXC_SACCH8_2,
+ TRXC_SACCH8_3,
+ TRXC_SACCH8_4,
+ TRXC_SACCH8_5,
+ TRXC_SACCH8_6,
+ TRXC_SACCH8_7,
+ TRXC_PDTCH,
+ TRXC_PTCCH,
+ _TRX_CHAN_MAX
+};
+
+/* States each channel on a multiframe */
+struct l1sched_chan_state {
+ /* scheduler */
+ uint8_t active; /* Channel is active */
+ ubit_t *dl_bursts; /* burst buffer for TX */
+ sbit_t *ul_bursts; /* burst buffer for RX */
+ uint32_t ul_first_fn; /* fn of first burst */
+ uint8_t ul_mask; /* mask of received bursts */
+
+ /* RSSI / TOA */
+ uint8_t rssi_num; /* number of RSSI values */
+ float rssi_sum; /* sum of RSSI values */
+ uint8_t toa_num; /* number of TOA values */
+ float toa_sum; /* sum of TOA values */
+
+ /* loss detection */
+ uint8_t lost; /* (SACCH) loss detection */
+
+ /* mode */
+ uint8_t rsl_cmode, tch_mode; /* mode for TCH channels */
+
+ /* AMR */
+ uint8_t codec[4]; /* 4 possible codecs for amr */
+ int codecs; /* number of possible codecs */
+ float ber_sum; /* sum of bit error rates */
+ int ber_num; /* number of bit error rates */
+ uint8_t ul_ft; /* current uplink FT index */
+ uint8_t dl_ft; /* current downlink FT index */
+ uint8_t ul_cmr; /* current uplink CMR index */
+ uint8_t dl_cmr; /* current downlink CMR index */
+ uint8_t amr_loop; /* if AMR loop is enabled */
+
+ /* TCH/H */
+ uint8_t dl_ongoing_facch; /* FACCH/H on downlink */
+ uint8_t ul_ongoing_facch; /* FACCH/H on uplink */
+
+ /* encryption */
+ int ul_encr_algo; /* A5/x encry algo downlink */
+ int dl_encr_algo; /* A5/x encry algo uplink */
+ int ul_encr_key_len;
+ int dl_encr_key_len;
+ uint8_t ul_encr_key[MAX_A5_KEY_LEN];
+ uint8_t dl_encr_key[MAX_A5_KEY_LEN];
+
+ /* measurements */
+ struct {
+ uint8_t clock; /* cyclic clock counter */
+ int8_t rssi[32]; /* last RSSI values */
+ int rssi_count; /* received RSSI values */
+ int rssi_valid_count; /* number of stored value */
+ int rssi_got_burst; /* any burst received so far */
+ float toa_sum; /* sum of TOA values */
+ int toa_num; /* number of TOA value */
+ } meas;
+
+ /* handover */
+ uint8_t ho_rach_detect; /* if rach detection is on */
+};
+
+struct l1sched_ts {
+ uint8_t mf_index; /* selected multiframe index */
+ uint32_t mf_last_fn; /* last received frame number */
+ uint8_t mf_period; /* period of multiframe */
+ const struct trx_sched_frame *mf_frames; /* pointer to frame layout */
+
+ struct llist_head dl_prims; /* Queue primitves for TX */
+
+ /* Channel states for all logical channels */
+ struct l1sched_chan_state chan_state[_TRX_CHAN_MAX];
+};
+
+struct l1sched_trx {
+ struct gsm_bts_trx *trx;
+ struct l1sched_ts ts[TRX_NR_TS];
+};
+
+struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn);
+
/*! \brief how many frame numbers in advance we should send bursts to PHY */
extern uint32_t trx_clock_advance;
/*! \brief advance RTS.ind to L2 by that many clocks */
@@ -10,43 +133,43 @@ extern uint32_t transceiver_last_fn;
/*! \brief Initialize the scheudler data structures */
-int trx_sched_init(struct trx_l1h *l1h);
+int trx_sched_init(struct l1sched_trx *l1t);
/*! \brief De-initialize the scheudler data structures */
-void trx_sched_exit(struct trx_l1h *l1h);
+void trx_sched_exit(struct l1sched_trx *l1t);
/*! \brief Handle a PH-DATA.req from L2 down to L1 */
-int trx_sched_ph_data_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap);
+int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap);
/*! \brief Handle a PH-TCH.req from L2 down to L1 */
-int trx_sched_tch_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap);
+int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap);
/*! \brief PHY informs us of new (current) GSM freme nunmber */
int trx_sched_clock(uint32_t fn);
/*! \brief handle an UL burst received by PHY */
-int trx_sched_ul_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t fn,
+int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
sbit_t *bits, int8_t rssi, float toa);
/*! \brief set multiframe scheduler to given physical channel config */
-int trx_sched_set_pchan(struct trx_l1h *l1h, uint8_t tn,
+int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn,
enum gsm_phys_chan_config pchan);
/*! \brief set all matching logical channels active/inactive */
-int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id,
+int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id,
int active);
/*! \brief set mode of all matching logical channels to given mode(s) */
-int trx_sched_set_mode(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t rsl_cmode,
+int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode,
uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1,
uint8_t codec2, uint8_t codec3, uint8_t initial_codec,
uint8_t handover);
/*! \brief set ciphering on given logical channels */
-int trx_sched_set_cipher(struct trx_l1h *l1h, uint8_t chan_nr, int downlink,
+int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink,
int algo, uint8_t *key, int key_len);
/* \brief close all logical channels and reset timeslots */
-void trx_sched_reset(struct trx_l1h *l1h);
+void trx_sched_reset(struct l1sched_trx *l1t);
#endif /* TRX_SCHEDULER_H */
@@ -454,7 +454,7 @@ static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what)
fprintf(stderr, "%s\n", deb);
#endif
- trx_sched_ul_burst(l1h, tn, fn, bits, rssi, toa);
+ trx_sched_ul_burst(&l1h->l1s, tn, fn, bits, rssi, toa);
return 0;
}
From: Harald Welte <laforge@gnumonks.org> The L1 scheduler is a generally useful component that is unfortunately tied quite a bit into the OsmoTRX support. Let's try to separate it out by having separate per-trx/per-ts/per-chan data structures pre-fixed with l1sched_ Using this patch it should be one step easier to use the scheduler for other BTS models, such as the intended upcoming virtual BTS. --- src/osmo-bts-trx/l1_if.c | 35 ++-- src/osmo-bts-trx/l1_if.h | 121 +---------- src/osmo-bts-trx/loops.c | 83 ++++---- src/osmo-bts-trx/loops.h | 14 +- src/osmo-bts-trx/scheduler.c | 486 +++++++++++++++++++++++-------------------- src/osmo-bts-trx/scheduler.h | 143 ++++++++++++- src/osmo-bts-trx/trx_if.c | 2 +- 7 files changed, 473 insertions(+), 411 deletions(-)