[VAMOS] Re-organize osmo-bts-trx specific structures
Together with the 'generic' structures which used to be shared between osmo-bsc and osmo-bts some time ago, we also have the following osmo-bts-trx specific structures (in hierarchical order): - struct l1sched_trx (struct gsm_bts_trx), - struct l1sched_ts (struct gsm_bts_trx_ts), - struct l1sched_chan_state (struct gsm_lchan). These structures are not integrated into the tree of the generic structures, but maintained in a _separate tree_ instead. Until recently, only the 'l1sched_trx' had a pointer to generic 'gsm_bts_trx', so in order to find the corresponding 'gsm_lchan' for 'l1sched_chan_state' one would need to traverse all the way up to 'l1sched_trx' and then tracerse another three backwards. + gsm_network | --+ gsm_bts (0..255) | --+ l1sched_trx --------------------> gsm_bts_trx (0..255) | | --+ l1sched_trx_ts --+ gsm_bts_trx_ts (8) | | --+ l1sched_chan_state --+ gsm_lchan (up to 8) I find this architecture a bit over-complicated, especially given that 'l1sched_trx' is kind of a dummy node containing nothing else than a pointer to 'gsm_bts_trx' and the list of 'l1sched_trx_ts'. In this path I slightly change the architecture as follows: + gsm_network | --+ gsm_bts (0..255) | --+ gsm_bts_trx (0..255) | --+ l1sched_trx_ts <----------------> gsm_bts_trx_ts (8) | | --+ l1sched_chan_state --+ gsm_lchan (up to 8) Note that unfortunately we cannot 1:1 map 'l1sched_chan_state' to 'gsm_lchan' (like we do for 'l1sched_trx_ts' and 'gsm_bts_trx_ts') because there is no direct mapping. The former is a higl-level representation of a logical channel, while the later represents one specific logical channel type like FCCH, SDCCH/0 or SACCH/0. osmo-bts-virtual re-uses the osmo-bts-trx hierarchy, so it's also affected by this change. Change-Id: I7c4379e43a25e9d858d582a99bf6c4b65c9af481
This commit is contained in:
parent
b4c0e43c60
commit
462bf0952a
|
@ -455,6 +455,9 @@ struct gsm_bts_trx_ts {
|
|||
/* Transceiver "cache" for frequency hopping */
|
||||
const struct gsm_bts_trx *fh_trx_list[64];
|
||||
|
||||
/* Implementation specific structure(s) */
|
||||
void *priv;
|
||||
|
||||
struct gsm_lchan lchan[TS_MAX_LCHAN];
|
||||
};
|
||||
|
||||
|
|
|
@ -114,9 +114,6 @@ struct phy_instance {
|
|||
struct trx_l1h *hdl;
|
||||
bool sw_act_reported;
|
||||
} osmotrx;
|
||||
struct {
|
||||
struct l1sched_trx sched;
|
||||
} virt;
|
||||
struct {
|
||||
/* logical transceiver number within one PHY */
|
||||
uint32_t trx_id;
|
||||
|
|
|
@ -136,6 +136,8 @@ struct l1sched_chan_state {
|
|||
};
|
||||
|
||||
struct l1sched_ts {
|
||||
struct gsm_bts_trx_ts *ts; /* timeslot we belong to */
|
||||
|
||||
uint8_t mf_index; /* selected multiframe index */
|
||||
uint8_t mf_period; /* period of multiframe */
|
||||
const struct trx_sched_frame *mf_frames; /* pointer to frame layout */
|
||||
|
@ -148,25 +150,18 @@ struct l1sched_ts {
|
|||
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 Initialize the scheduler data structures */
|
||||
int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx);
|
||||
void trx_sched_init(struct gsm_bts_trx *trx);
|
||||
|
||||
/*! \brief De-initialize the scheduler data structures */
|
||||
void trx_sched_exit(struct l1sched_trx *l1t);
|
||||
void trx_sched_clean(struct gsm_bts_trx *trx);
|
||||
|
||||
/*! \brief Handle a PH-DATA.req from L2 down to L1 */
|
||||
int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap);
|
||||
int trx_sched_ph_data_req(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap);
|
||||
|
||||
/*! \brief Handle a PH-TCH.req from L2 down to L1 */
|
||||
int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap);
|
||||
int trx_sched_tch_req(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap);
|
||||
|
||||
/*! \brief PHY informs us of new (current) GSM frame number */
|
||||
int trx_sched_clock(struct gsm_bts *bts, uint32_t fn);
|
||||
|
@ -178,21 +173,19 @@ int trx_sched_clock_started(struct gsm_bts *bts);
|
|||
int trx_sched_clock_stopped(struct gsm_bts *bts);
|
||||
|
||||
/*! \brief set multiframe scheduler to given physical channel config */
|
||||
int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn,
|
||||
enum gsm_phys_chan_config pchan);
|
||||
int trx_sched_set_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pchan);
|
||||
|
||||
/*! \brief set all matching logical channels active/inactive */
|
||||
int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id, bool active);
|
||||
int trx_sched_set_lchan(struct gsm_lchan *lchan, uint8_t chan_nr, uint8_t link_id, bool active);
|
||||
|
||||
/*! \brief set mode of all matching logical channels to given mode(s) */
|
||||
int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode,
|
||||
int trx_sched_set_mode(struct gsm_bts_trx_ts *ts, 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 l1sched_trx *l1t, uint8_t chan_nr, int downlink,
|
||||
int algo, uint8_t *key, int key_len);
|
||||
int trx_sched_set_cipher(struct gsm_lchan *lchan, uint8_t chan_nr, bool downlink);
|
||||
|
||||
/* frame structures */
|
||||
struct trx_sched_frame {
|
||||
|
@ -287,8 +280,8 @@ struct trx_dl_burst_req {
|
|||
};
|
||||
|
||||
/*! Handle an UL burst received by PHY */
|
||||
int trx_sched_route_burst_ind(struct trx_ul_burst_ind *bi, struct l1sched_trx *l1t);
|
||||
int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi);
|
||||
int trx_sched_route_burst_ind(const struct gsm_bts_trx *trx, struct trx_ul_burst_ind *bi);
|
||||
int trx_sched_ul_burst(struct l1sched_ts *l1ts, struct trx_ul_burst_ind *bi);
|
||||
|
||||
/* Averaging mode for trx_sched_meas_avg() */
|
||||
enum sched_meas_avg_mode {
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#define LOGL1S(subsys, level, l1t, tn, chan, fn, fmt, args ...) \
|
||||
#define LOGL1S(subsys, level, l1ts, chan, fn, fmt, args ...) \
|
||||
LOGP(subsys, level, "%s %s %s: " fmt, \
|
||||
gsm_fn_as_gsmtime_str(fn), \
|
||||
gsm_ts_name(&(l1t)->trx->ts[tn]), \
|
||||
gsm_ts_name((l1ts)->ts), \
|
||||
chan >=0 ? trx_chan_desc[chan].name : "", ## args)
|
||||
|
||||
/* Logging helper adding context from trx_{ul,dl}_burst_{ind,req} */
|
||||
#define LOGL1SB(subsys, level, l1t, b, fmt, args ...) \
|
||||
LOGL1S(subsys, level, l1t, (b)->tn, (b)->chan, (b)->fn, fmt, ## args)
|
||||
#define LOGL1SB(subsys, level, l1ts, b, fmt, args ...) \
|
||||
LOGL1S(subsys, level, l1ts, (b)->chan, (b)->fn, fmt, ## args)
|
||||
|
||||
typedef int trx_sched_rts_func(struct l1sched_trx *l1t, uint8_t tn,
|
||||
uint32_t fn, enum trx_chan_type chan);
|
||||
|
||||
typedef int trx_sched_dl_func(struct l1sched_trx *l1t, struct trx_dl_burst_req *br);
|
||||
|
||||
typedef int trx_sched_ul_func(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi);
|
||||
typedef int trx_sched_rts_func(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br);
|
||||
typedef int trx_sched_dl_func(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
|
||||
typedef int trx_sched_ul_func(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi);
|
||||
|
||||
struct trx_chan_desc {
|
||||
/*! \brief Human-readable name */
|
||||
|
@ -42,35 +39,34 @@ extern const ubit_t _sched_tsc[8][26];
|
|||
extern const ubit_t _sched_egprs_tsc[8][78];
|
||||
extern const ubit_t _sched_sch_train[64];
|
||||
|
||||
struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t,
|
||||
const struct trx_dl_burst_req *br);
|
||||
struct msgb *_sched_dequeue_prim(struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br);
|
||||
|
||||
int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||
int _sched_compose_ph_data_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t *l2,
|
||||
uint8_t l2_len, float rssi,
|
||||
int16_t ta_offs_256bits, int16_t link_qual_cb,
|
||||
uint16_t ber10k,
|
||||
enum osmo_ph_pres_info_type presence_info);
|
||||
|
||||
int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||
int _sched_compose_tch_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len,
|
||||
int16_t ta_offs_256bits, uint16_t ber10k, float rssi,
|
||||
uint8_t is_sub);
|
||||
|
||||
int tx_idle_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br);
|
||||
int tx_fcch_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br);
|
||||
int tx_sch_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br);
|
||||
int tx_data_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br);
|
||||
int tx_pdtch_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br);
|
||||
int tx_tchf_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br);
|
||||
int tx_tchh_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br);
|
||||
int tx_idle_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
|
||||
int tx_fcch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
|
||||
int tx_sch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
|
||||
int tx_data_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
|
||||
int tx_pdtch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
|
||||
int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
|
||||
int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
|
||||
|
||||
int rx_rach_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi);
|
||||
int rx_data_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi);
|
||||
int rx_pdtch_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi);
|
||||
int rx_tchf_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi);
|
||||
int rx_tchh_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi);
|
||||
int rx_rach_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi);
|
||||
int rx_data_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi);
|
||||
int rx_pdtch_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi);
|
||||
int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi);
|
||||
int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi);
|
||||
|
||||
void _sched_dl_burst(struct l1sched_trx *l1t, struct trx_dl_burst_req *br);
|
||||
int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn);
|
||||
void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate);
|
||||
void _sched_dl_burst(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br);
|
||||
int _sched_rts(const struct l1sched_ts *l1ts, uint32_t fn);
|
||||
void _sched_act_rach_det(struct gsm_bts_trx *trx, uint8_t tn, uint8_t ss, int activate);
|
||||
|
|
|
@ -3,6 +3,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>
|
||||
* Contributions by sysmocom - s.f.m.c. GmbH
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
|
@ -46,12 +47,9 @@
|
|||
|
||||
extern void *tall_bts_ctx;
|
||||
|
||||
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 l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan);
|
||||
static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan);
|
||||
static int rts_data_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br);
|
||||
static int rts_tchf_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br);
|
||||
static int rts_tchh_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br);
|
||||
|
||||
/*! \brief Dummy Burst (TS 05.02 Chapter 5.2.6) */
|
||||
const ubit_t _sched_dummy_burst[GSM_BURST_LEN] = {
|
||||
|
@ -576,20 +574,20 @@ static const struct rate_ctr_group_desc l1sched_ts_ctrg_desc = {
|
|||
* init / exit
|
||||
*/
|
||||
|
||||
int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx)
|
||||
void trx_sched_init(struct gsm_bts_trx *trx)
|
||||
{
|
||||
uint8_t tn;
|
||||
unsigned int i;
|
||||
unsigned int tn, i;
|
||||
|
||||
if (!trx)
|
||||
return -EINVAL;
|
||||
LOGPTRX(trx, DL1C, LOGL_DEBUG, "Init scheduler structures\n");
|
||||
|
||||
l1t->trx = trx;
|
||||
for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
|
||||
struct l1sched_ts *l1ts;
|
||||
|
||||
LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1t->trx->nr);
|
||||
l1ts = talloc_zero(trx, struct l1sched_ts);
|
||||
OSMO_ASSERT(l1ts != NULL);
|
||||
|
||||
for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
||||
trx->ts[tn].priv = l1ts;
|
||||
l1ts->ts = &trx->ts[tn];
|
||||
|
||||
l1ts->mf_index = 0;
|
||||
l1ts->ctrs = rate_ctr_group_alloc(trx, &l1sched_ts_ctrg_desc, (trx->nr + 1) * 10 + tn);
|
||||
|
@ -601,20 +599,18 @@ int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx)
|
|||
chan_state->active = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void trx_sched_exit(struct l1sched_trx *l1t)
|
||||
void trx_sched_clean(struct gsm_bts_trx *trx)
|
||||
{
|
||||
struct gsm_bts_trx_ts *ts;
|
||||
uint8_t tn;
|
||||
int i;
|
||||
unsigned int tn, i;
|
||||
|
||||
LOGP(DL1C, LOGL_NOTICE, "Exit scheduler for trx=%u\n", l1t->trx->nr);
|
||||
LOGPTRX(trx, DL1C, LOGL_DEBUG, "Clean scheduler structures\n");
|
||||
|
||||
for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
|
||||
struct gsm_bts_trx_ts *ts = &trx->ts[tn];
|
||||
struct l1sched_ts *l1ts = ts->priv;
|
||||
|
||||
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);
|
||||
rate_ctr_group_free(l1ts->ctrs);
|
||||
l1ts->ctrs = NULL;
|
||||
|
@ -631,19 +627,16 @@ void trx_sched_exit(struct l1sched_trx *l1t)
|
|||
}
|
||||
}
|
||||
/* clear lchan channel states */
|
||||
ts = &l1t->trx->ts[tn];
|
||||
for (i = 0; i < ARRAY_SIZE(ts->lchan); i++)
|
||||
lchan_set_state(&ts->lchan[i], LCHAN_S_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t,
|
||||
const struct trx_dl_burst_req *br)
|
||||
struct msgb *_sched_dequeue_prim(struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br)
|
||||
{
|
||||
struct msgb *msg, *msg2;
|
||||
uint32_t prim_fn, l1sap_fn;
|
||||
uint8_t chan_nr, link_id;
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||
|
||||
/* get prim of current fn from queue */
|
||||
llist_for_each_entry_safe(msg, msg2, &l1ts->dl_prims, list) {
|
||||
|
@ -660,17 +653,17 @@ struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t,
|
|||
l1sap_fn = l1sap->u.tch.fn;
|
||||
break;
|
||||
default:
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br, "Prim has wrong type.\n");
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Prim has wrong type.\n");
|
||||
goto free_msg;
|
||||
}
|
||||
prim_fn = GSM_TDMA_FN_SUB(l1sap_fn, br->fn);
|
||||
if (prim_fn > 100) { /* l1sap_fn < fn */
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, br,
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br,
|
||||
"Prim %u is out of range (%u vs exp %u), or channel %s with "
|
||||
"type %s is already disabled. If this happens in "
|
||||
"conjunction with PCU, increase 'rts-advance' by 5.\n",
|
||||
prim_fn, l1sap_fn, br->fn,
|
||||
get_lchan_by_chan_nr(l1t->trx, chan_nr)->name,
|
||||
get_lchan_by_chan_nr(l1ts->ts->trx, chan_nr)->name,
|
||||
trx_chan_desc[br->chan].name);
|
||||
rate_ctr_inc2(l1ts->ctrs, L1SCHED_TS_CTR_DL_LATE);
|
||||
/* unlink and free message */
|
||||
|
@ -684,7 +677,7 @@ struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t,
|
|||
/* l1sap_fn == fn */
|
||||
if ((chan_nr ^ (trx_chan_desc[br->chan].chan_nr | br->tn))
|
||||
|| ((link_id & 0xc0) ^ trx_chan_desc[br->chan].link_id)) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br, "Prim has wrong chan_nr=0x%02x link_id=%02x, "
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Prim has wrong chan_nr=0x%02x link_id=%02x, "
|
||||
"expecting chan_nr=0x%02x link_id=%02x.\n", chan_nr, link_id,
|
||||
trx_chan_desc[br->chan].chan_nr | br->tn, trx_chan_desc[br->chan].link_id);
|
||||
goto free_msg;
|
||||
|
@ -706,7 +699,7 @@ free_msg:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||
int _sched_compose_ph_data_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t *l2,
|
||||
uint8_t l2_len, float rssi,
|
||||
int16_t ta_offs_256bits, int16_t link_qual_cb,
|
||||
|
@ -715,8 +708,7 @@ int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
|||
{
|
||||
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);
|
||||
uint8_t chan_nr = trx_chan_desc[chan].chan_nr | l1ts->ts->nr;
|
||||
|
||||
/* compose primitive */
|
||||
msg = l1sap_msgb_alloc(l2_len);
|
||||
|
@ -739,22 +731,20 @@ int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
|||
l1ts->chan_state[chan].lost_frames = 0;
|
||||
|
||||
/* forward primitive */
|
||||
l1sap_up(l1t->trx, l1sap);
|
||||
l1sap_up(l1ts->ts->trx, l1sap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||
int _sched_compose_tch_ind(struct l1sched_ts *l1ts, uint32_t fn,
|
||||
enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len,
|
||||
int16_t ta_offs_256bits, uint16_t ber10k, float rssi,
|
||||
uint8_t is_sub)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct osmo_phsap_prim *l1sap;
|
||||
struct gsm_bts_trx *trx = l1t->trx;
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
||||
uint8_t chan_nr = trx_chan_desc[chan].chan_nr | tn;
|
||||
struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];
|
||||
uint8_t chan_nr = trx_chan_desc[chan].chan_nr | l1ts->ts->nr;
|
||||
struct gsm_lchan *lchan = &l1ts->ts->lchan[l1sap_chan2ss(chan_nr)];
|
||||
|
||||
/* compose primitive */
|
||||
msg = l1sap_msgb_alloc(tch_len);
|
||||
|
@ -775,11 +765,10 @@ int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
|||
if (l1ts->chan_state[chan].lost_frames)
|
||||
l1ts->chan_state[chan].lost_frames--;
|
||||
|
||||
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, -1, l1sap->u.data.fn,
|
||||
"%s Rx -> RTP: %s\n",
|
||||
LOGL1S(DL1P, LOGL_DEBUG, l1ts, chan, l1sap->u.data.fn, "%s Rx -> RTP: %s\n",
|
||||
gsm_lchan_name(lchan), osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
|
||||
/* forward primitive */
|
||||
l1sap_up(l1t->trx, l1sap);
|
||||
l1sap_up(l1ts->ts->trx, l1sap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -790,12 +779,12 @@ int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
|||
* data request (from upper layer)
|
||||
*/
|
||||
|
||||
int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap)
|
||||
int trx_sched_ph_data_req(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
||||
{
|
||||
uint8_t tn = l1sap->u.data.chan_nr & 7;
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
||||
uint8_t tn = L1SAP_CHAN2TS(l1sap->u.data.chan_nr);
|
||||
struct l1sched_ts *l1ts = trx->ts[tn].priv;
|
||||
|
||||
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, -1, l1sap->u.data.fn,
|
||||
LOGL1S(DL1P, LOGL_DEBUG, l1ts, -1, l1sap->u.data.fn,
|
||||
"PH-DATA.req: chan_nr=0x%02x link_id=0x%02x\n",
|
||||
l1sap->u.data.chan_nr, l1sap->u.data.link_id);
|
||||
|
||||
|
@ -813,13 +802,13 @@ int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap
|
|||
return 0;
|
||||
}
|
||||
|
||||
int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap)
|
||||
int trx_sched_tch_req(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
||||
{
|
||||
uint8_t tn = l1sap->u.tch.chan_nr & 7;
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
||||
uint8_t tn = L1SAP_CHAN2TS(l1sap->u.data.chan_nr);
|
||||
struct l1sched_ts *l1ts = trx->ts[tn].priv;
|
||||
|
||||
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, -1, l1sap->u.tch.fn, "TCH.req: chan_nr=0x%02x\n",
|
||||
l1sap->u.tch.chan_nr);
|
||||
LOGL1S(DL1P, LOGL_DEBUG, l1ts, -1, l1sap->u.tch.fn,
|
||||
"TCH.req: chan_nr=0x%02x\n", l1sap->u.tch.chan_nr);
|
||||
|
||||
OSMO_ASSERT(l1sap->oph.operation == PRIM_OP_REQUEST);
|
||||
OSMO_ASSERT(l1sap->oph.msg);
|
||||
|
@ -841,31 +830,28 @@ int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap)
|
|||
*/
|
||||
|
||||
/* RTS for data frame */
|
||||
static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan)
|
||||
static int rts_data_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br)
|
||||
{
|
||||
uint8_t chan_nr, link_id;
|
||||
struct msgb *msg;
|
||||
struct osmo_phsap_prim *l1sap;
|
||||
|
||||
/* get data for RTS indication */
|
||||
chan_nr = trx_chan_desc[chan].chan_nr | tn;
|
||||
link_id = trx_chan_desc[chan].link_id;
|
||||
chan_nr = trx_chan_desc[br->chan].chan_nr | br->tn;
|
||||
link_id = trx_chan_desc[br->chan].link_id;
|
||||
|
||||
if (!chan_nr) {
|
||||
LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,
|
||||
"RTS func with non-existing chan_nr %d\n", chan_nr);
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "RTS func with non-existing chan_nr 0x%02x\n", chan_nr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* For handover detection, there are cases where the SACCH should remain inactive until the first RACH
|
||||
* indicating the TA is received. */
|
||||
if (L1SAP_IS_LINK_SACCH(link_id)
|
||||
&& !l1t->ts[tn].chan_state[chan].lchan->want_dl_sacch_active)
|
||||
&& !l1ts->chan_state[br->chan].lchan->want_dl_sacch_active)
|
||||
return 0;
|
||||
|
||||
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn,
|
||||
"PH-RTS.ind: chan_nr=0x%02x link_id=0x%02x\n", chan_nr, link_id);
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "PH-RTS.ind: chan_nr=0x%02x link_id=0x%02x\n", chan_nr, link_id);
|
||||
|
||||
/* generate prim */
|
||||
msg = l1sap_msgb_alloc(200);
|
||||
|
@ -876,31 +862,30 @@ static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
|||
PRIM_OP_INDICATION, msg);
|
||||
l1sap->u.data.chan_nr = chan_nr;
|
||||
l1sap->u.data.link_id = link_id;
|
||||
l1sap->u.data.fn = fn;
|
||||
l1sap->u.data.fn = br->fn;
|
||||
|
||||
return l1sap_up(l1t->trx, l1sap);
|
||||
return l1sap_up(l1ts->ts->trx, l1sap);
|
||||
}
|
||||
|
||||
static int rts_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan, int facch)
|
||||
static int rts_tch_common(const struct l1sched_ts *l1ts,
|
||||
const struct trx_dl_burst_req *br,
|
||||
bool 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 */
|
||||
chan_nr = trx_chan_desc[chan].chan_nr | tn;
|
||||
link_id = trx_chan_desc[chan].link_id;
|
||||
chan_nr = trx_chan_desc[br->chan].chan_nr | br->tn;
|
||||
link_id = trx_chan_desc[br->chan].link_id;
|
||||
|
||||
if (!chan_nr) {
|
||||
LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn,
|
||||
"RTS func with non-existing chan_nr %d\n", chan_nr);
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "RTS func with non-existing chan_nr 0x%02x\n", chan_nr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "TCH RTS.ind: chan_nr=0x%02x\n", chan_nr);
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "TCH RTS.ind: chan_nr=0x%02x\n", chan_nr);
|
||||
|
||||
/* only send, if FACCH is selected */
|
||||
if (facch) {
|
||||
|
@ -913,13 +898,13 @@ static int rts_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
|||
PRIM_OP_INDICATION, msg);
|
||||
l1sap->u.data.chan_nr = chan_nr;
|
||||
l1sap->u.data.link_id = link_id;
|
||||
l1sap->u.data.fn = fn;
|
||||
l1sap->u.data.fn = br->fn;
|
||||
|
||||
rc = l1sap_up(l1t->trx, l1sap);
|
||||
rc = l1sap_up(l1ts->ts->trx, l1sap);
|
||||
}
|
||||
|
||||
/* don't send, if TCH is in signalling only mode */
|
||||
if (l1ts->chan_state[chan].rsl_cmode != RSL_CMOD_SPD_SIGN) {
|
||||
if (l1ts->chan_state[br->chan].rsl_cmode != RSL_CMOD_SPD_SIGN) {
|
||||
/* generate prim */
|
||||
msg = l1sap_msgb_alloc(200);
|
||||
if (!msg)
|
||||
|
@ -928,49 +913,44 @@ static int rts_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
|||
osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH_RTS,
|
||||
PRIM_OP_INDICATION, msg);
|
||||
l1sap->u.tch.chan_nr = chan_nr;
|
||||
l1sap->u.tch.fn = fn;
|
||||
l1sap->u.tch.fn = br->fn;
|
||||
|
||||
return l1sap_up(l1t->trx, l1sap);
|
||||
return l1sap_up(l1ts->ts->trx, l1sap);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* RTS for full rate traffic frame */
|
||||
static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan)
|
||||
static int rts_tchf_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br)
|
||||
{
|
||||
/* TCH/F may include FACCH on every 4th burst */
|
||||
return rts_tch_common(l1t, tn, fn, chan, 1);
|
||||
return rts_tch_common(l1ts, br, true);
|
||||
}
|
||||
|
||||
|
||||
/* RTS for half rate traffic frame */
|
||||
static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||
enum trx_chan_type chan)
|
||||
static int rts_tchh_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_req *br)
|
||||
{
|
||||
/* the FN 4/5, 13/14, 21/22 defines that FACCH may be included. */
|
||||
return rts_tch_common(l1t, tn, fn, chan, ((fn % 26) >> 2) & 1);
|
||||
return rts_tch_common(l1ts, br, ((br->fn % 26) >> 2) & 1);
|
||||
}
|
||||
|
||||
/* set multiframe scheduler to given pchan */
|
||||
int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn,
|
||||
enum gsm_phys_chan_config pchan)
|
||||
int trx_sched_set_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pchan)
|
||||
{
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
||||
int i;
|
||||
|
||||
i = find_sched_mframe_idx(pchan, tn);
|
||||
struct l1sched_ts *l1ts = ts->priv;
|
||||
int i = find_sched_mframe_idx(pchan, ts->nr);
|
||||
if (i < 0) {
|
||||
LOGP(DL1C, LOGL_NOTICE, "Failed to configure multiframe "
|
||||
"trx=%d ts=%d\n", l1t->trx->nr, tn);
|
||||
LOGP(DL1C, LOGL_NOTICE, "%s Failed to configure multiframe\n",
|
||||
gsm_ts_name(ts));
|
||||
return -ENOTSUP;
|
||||
}
|
||||
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, l1t->trx->nr, tn);
|
||||
LOGP(DL1C, LOGL_NOTICE, "%s Configured multiframe with '%s'\n",
|
||||
gsm_ts_name(ts), trx_sched_multiframes[i].name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1006,10 +986,10 @@ static void trx_sched_queue_filter(struct llist_head *q, uint8_t chan_nr, uint8_
|
|||
}
|
||||
|
||||
/* setting all logical channels given attributes to active/inactive */
|
||||
int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id, bool active)
|
||||
int trx_sched_set_lchan(struct gsm_lchan *lchan, uint8_t chan_nr, uint8_t link_id, bool active)
|
||||
{
|
||||
struct l1sched_ts *l1ts = lchan->ts->priv;
|
||||
uint8_t tn = L1SAP_CHAN2TS(chan_nr);
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
||||
uint8_t ss = l1sap_chan2ss(chan_nr);
|
||||
bool found = false;
|
||||
int i;
|
||||
|
@ -1026,9 +1006,9 @@ int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_i
|
|||
continue;
|
||||
found = true;
|
||||
|
||||
LOGP(DL1C, LOGL_NOTICE, "%s %s on trx=%d ts=%d\n",
|
||||
(active) ? "Activating" : "Deactivating",
|
||||
trx_chan_desc[i].name, l1t->trx->nr, tn);
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_NOTICE, "%s %s\n",
|
||||
(active) ? "Activating" : "Deactivating",
|
||||
trx_chan_desc[i].name);
|
||||
/* free burst memory, to cleanly start with burst 0 */
|
||||
if (chan_state->dl_bursts) {
|
||||
talloc_free(chan_state->dl_bursts);
|
||||
|
@ -1044,8 +1024,7 @@ int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_i
|
|||
memset(chan_state, 0, sizeof(*chan_state));
|
||||
|
||||
/* Bind to generic 'struct gsm_lchan' */
|
||||
chan_state->lchan = get_lchan_by_chan_nr(l1t->trx, chan_nr);
|
||||
OSMO_ASSERT(chan_state->lchan != NULL);
|
||||
chan_state->lchan = lchan;
|
||||
} else {
|
||||
chan_state->ho_rach_detect = 0;
|
||||
|
||||
|
@ -1058,36 +1037,37 @@ int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_i
|
|||
|
||||
/* disable handover detection (on deactivation) */
|
||||
if (!active)
|
||||
_sched_act_rach_det(l1t, tn, ss, 0);
|
||||
_sched_act_rach_det(lchan->ts->trx, tn, ss, 0);
|
||||
|
||||
return found ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
/* setting all logical channels given attributes to active/inactive */
|
||||
int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode,
|
||||
int trx_sched_set_mode(struct gsm_bts_trx_ts *ts, 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)
|
||||
{
|
||||
struct l1sched_ts *l1ts = ts->priv;
|
||||
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 l1sched_chan_state *chan_state;
|
||||
|
||||
/* no mode for PDCH */
|
||||
if (trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH)
|
||||
if (ts->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 = &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, l1t->trx->nr,
|
||||
tn);
|
||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[i];
|
||||
|
||||
LOGP(DL1C, LOGL_NOTICE,
|
||||
"%s Set mode for %s (rsl_cmode=%u, tch_mode=%u, handover=%u)\n",
|
||||
gsm_ts_name(ts), trx_chan_desc[i].name,
|
||||
rsl_cmode, tch_mode, handover);
|
||||
|
||||
chan_state->rsl_cmode = rsl_cmode;
|
||||
chan_state->tch_mode = tch_mode;
|
||||
chan_state->ho_rach_detect = handover;
|
||||
|
@ -1114,50 +1094,49 @@ int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmo
|
|||
* of transceiver link).
|
||||
* disable handover, if state is still set, since we might not know
|
||||
* the actual state of transceiver (due to loss of link) */
|
||||
_sched_act_rach_det(l1t, tn, ss, handover);
|
||||
_sched_act_rach_det(ts->trx, tn, ss, handover);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* setting cipher on logical channels */
|
||||
int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink,
|
||||
int algo, uint8_t *key, int key_len)
|
||||
int trx_sched_set_cipher(struct gsm_lchan *lchan, uint8_t chan_nr, bool downlink)
|
||||
{
|
||||
uint8_t tn = L1SAP_CHAN2TS(chan_nr);
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
||||
int i;
|
||||
int rc = -EINVAL;
|
||||
struct l1sched_chan_state *chan_state;
|
||||
int algo = lchan->encr.alg_id - 1;
|
||||
int i, rc = -EINVAL;
|
||||
|
||||
/* no cipher for PDCH */
|
||||
if (trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH)
|
||||
if (lchan->ts->pchan == GSM_PCHAN_PDCH)
|
||||
return 0;
|
||||
|
||||
/* no algorithm given means a5/0 */
|
||||
if (algo <= 0)
|
||||
algo = 0;
|
||||
else if (key_len != 8) {
|
||||
LOGP(DL1C, LOGL_ERROR, "Algo A5/%d not supported with given "
|
||||
"key len=%d\n", algo, key_len);
|
||||
else if (lchan->encr.key_len != 8) {
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_ERROR,
|
||||
"Algo A5/%d not supported with given key_len=%u\n",
|
||||
algo, lchan->encr.key_len);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* look for all matching chan_nr */
|
||||
for (i = 0; i < _TRX_CHAN_MAX; i++) {
|
||||
if (trx_chan_desc[i].chan_nr == (chan_nr & RSL_CHAN_NR_MASK)) {
|
||||
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, l1t->trx->nr, tn);
|
||||
struct l1sched_ts *l1ts = lchan->ts->priv;
|
||||
struct l1sched_chan_state *l1cs = &l1ts->chan_state[i];
|
||||
|
||||
LOGPLCHAN(lchan, DL1C, LOGL_NOTICE, "Set A5/%d %s for %s\n",
|
||||
algo, (downlink) ? "downlink" : "uplink",
|
||||
trx_chan_desc[i].name);
|
||||
|
||||
if (downlink) {
|
||||
chan_state->dl_encr_algo = algo;
|
||||
memcpy(chan_state->dl_encr_key, key, key_len);
|
||||
chan_state->dl_encr_key_len = key_len;
|
||||
l1cs->dl_encr_algo = algo;
|
||||
memcpy(l1cs->dl_encr_key, lchan->encr.key, lchan->encr.key_len);
|
||||
l1cs->dl_encr_key_len = lchan->encr.key_len;
|
||||
} else {
|
||||
chan_state->ul_encr_algo = algo;
|
||||
memcpy(chan_state->ul_encr_key, key, key_len);
|
||||
chan_state->ul_encr_key_len = key_len;
|
||||
l1cs->ul_encr_algo = algo;
|
||||
memcpy(l1cs->ul_encr_key, lchan->encr.key, lchan->encr.key_len);
|
||||
l1cs->ul_encr_key_len = lchan->encr.key_len;
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
|
@ -1167,9 +1146,8 @@ int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink,
|
|||
}
|
||||
|
||||
/* process ready-to-send */
|
||||
int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn)
|
||||
int _sched_rts(const struct l1sched_ts *l1ts, 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;
|
||||
|
@ -1200,14 +1178,21 @@ int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn)
|
|||
if (!TRX_CHAN_IS_ACTIVE(&l1ts->chan_state[chan], chan))
|
||||
return -EINVAL;
|
||||
|
||||
return func(l1t, tn, fn, frame->dl_chan);
|
||||
/* There is no burst, just for logging */
|
||||
struct trx_dl_burst_req dbr = {
|
||||
.fn = fn,
|
||||
.tn = l1ts->ts->nr,
|
||||
.bid = bid,
|
||||
.chan = chan,
|
||||
};
|
||||
|
||||
return func(l1ts, &dbr);
|
||||
}
|
||||
|
||||
/* process downlink burst */
|
||||
void _sched_dl_burst(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
void _sched_dl_burst(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||
struct l1sched_chan_state *l1cs;
|
||||
const struct l1sched_chan_state *l1cs;
|
||||
const struct trx_sched_frame *frame;
|
||||
uint8_t offset, period;
|
||||
trx_sched_dl_func *func;
|
||||
|
@ -1231,7 +1216,7 @@ void _sched_dl_burst(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
return;
|
||||
|
||||
/* get burst from function */
|
||||
if (func(l1t, br) != 0)
|
||||
if (func(l1ts, br) != 0)
|
||||
return;
|
||||
|
||||
/* BS Power reduction (in dB) per logical channel */
|
||||
|
@ -1251,12 +1236,11 @@ void _sched_dl_burst(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
}
|
||||
}
|
||||
|
||||
static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
|
||||
static int trx_sched_calc_frame_loss(struct l1sched_ts *l1ts,
|
||||
struct l1sched_chan_state *l1cs,
|
||||
const struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
const struct trx_sched_frame *frame;
|
||||
struct l1sched_ts *l1ts;
|
||||
uint32_t elapsed_fs;
|
||||
uint8_t offset, i;
|
||||
uint32_t fn_i;
|
||||
|
@ -1269,9 +1253,6 @@ static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
|
|||
if (l1cs->proc_tdma_fs == 0)
|
||||
return 0;
|
||||
|
||||
/* Get current TDMA frame info */
|
||||
l1ts = l1sched_trx_get_ts(l1t, bi->tn);
|
||||
|
||||
/* Not applicable for some logical channels */
|
||||
switch (bi->chan) {
|
||||
case TRXC_IDLE:
|
||||
|
@ -1288,7 +1269,7 @@ static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
|
|||
/* How many frames elapsed since the last one? */
|
||||
elapsed_fs = GSM_TDMA_FN_SUB(bi->fn, l1cs->last_tdma_fn);
|
||||
if (elapsed_fs > l1ts->mf_period) { /* Too many! */
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
|
||||
"Too many (>%u) contiguous TDMA frames=%u elapsed "
|
||||
"since the last processed fn=%u\n", l1ts->mf_period,
|
||||
elapsed_fs, l1cs->last_tdma_fn);
|
||||
|
@ -1314,7 +1295,7 @@ static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
|
|||
}
|
||||
|
||||
if (l1cs->lost_tdma_fs > 0) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi,
|
||||
"At least %u TDMA frames were lost since the last "
|
||||
"processed fn=%u\n", l1cs->lost_tdma_fs, l1cs->last_tdma_fn);
|
||||
|
||||
|
@ -1350,10 +1331,10 @@ static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
|
|||
dbi.bid = frame->ul_bid;
|
||||
dbi.fn = fn_i;
|
||||
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, &dbi,
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, &dbi,
|
||||
"Substituting lost burst with NOPE.ind\n");
|
||||
|
||||
func(l1t, &dbi);
|
||||
func(l1ts, &dbi);
|
||||
|
||||
l1cs->lost_tdma_fs--;
|
||||
}
|
||||
|
@ -1363,9 +1344,8 @@ static int trx_sched_calc_frame_loss(struct l1sched_trx *l1t,
|
|||
}
|
||||
|
||||
/* Process an Uplink burst indication */
|
||||
int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi)
|
||||
int trx_sched_ul_burst(struct l1sched_ts *l1ts, struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);
|
||||
struct l1sched_chan_state *l1cs;
|
||||
const struct trx_sched_frame *frame;
|
||||
uint8_t offset, period;
|
||||
|
@ -1386,7 +1366,7 @@ int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi)
|
|||
|
||||
/* TODO: handle noise measurements */
|
||||
if (bi->chan == TRXC_IDLE && bi->flags & TRX_BI_F_NOPE_IND) {
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi, "Rx noise measurement (%d)\n", bi->rssi);
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Rx noise measurement (%d)\n", bi->rssi);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
|
@ -1399,7 +1379,7 @@ int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi)
|
|||
return -EINVAL;
|
||||
|
||||
/* calculate how many TDMA frames were potentially lost */
|
||||
trx_sched_calc_frame_loss(l1t, l1cs, bi);
|
||||
trx_sched_calc_frame_loss(l1ts, l1cs, bi);
|
||||
|
||||
/* update TDMA frame counters */
|
||||
l1cs->last_tdma_fn = bi->fn;
|
||||
|
@ -1415,7 +1395,7 @@ int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi)
|
|||
default:
|
||||
/* NOTE: Uplink burst handler must check bi->burst_len before
|
||||
* accessing bi->burst to avoid uninitialized memory access. */
|
||||
return func(l1t, bi);
|
||||
return func(l1ts, bi);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1434,13 +1414,7 @@ int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi)
|
|||
}
|
||||
|
||||
/* Invoke the logical channel handler */
|
||||
func(l1t, bi);
|
||||
func(l1ts, bi);
|
||||
|
||||
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];
|
||||
}
|
||||
|
|
|
@ -109,9 +109,6 @@ static void check_transceiver_availability_trx(struct trx_l1h *l1h, int avail)
|
|||
|
||||
int bts_model_lchan_deactivate(struct gsm_lchan *lchan)
|
||||
{
|
||||
struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx);
|
||||
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
|
||||
|
||||
if (lchan->rel_act_kind == LCHAN_REL_ACT_REACT) {
|
||||
lchan->rel_act_kind = LCHAN_REL_ACT_RSL;
|
||||
/* FIXME: perform whatever is needed (if any) to set proper PCH/AGCH allocation according to
|
||||
|
@ -121,14 +118,12 @@ int bts_model_lchan_deactivate(struct gsm_lchan *lchan)
|
|||
/* set lchan inactive */
|
||||
lchan_set_state(lchan, LCHAN_S_NONE);
|
||||
|
||||
return trx_sched_set_lchan(&l1h->l1s, gsm_lchan2chan_nr(lchan), LID_DEDIC, false);
|
||||
return trx_sched_set_lchan(lchan, gsm_lchan2chan_nr(lchan), LID_DEDIC, false);
|
||||
}
|
||||
|
||||
int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan)
|
||||
{
|
||||
struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx);
|
||||
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
|
||||
return trx_sched_set_lchan(&l1h->l1s, gsm_lchan2chan_nr(lchan), LID_SACCH, false);
|
||||
return trx_sched_set_lchan(lchan, gsm_lchan2chan_nr(lchan), LID_SACCH, false);
|
||||
}
|
||||
|
||||
int l1if_trx_start_power_ramp(struct gsm_bts_trx *trx, ramp_compl_cb_t ramp_compl_cb)
|
||||
|
@ -293,7 +288,7 @@ static uint8_t trx_set_ts_as_pchan(struct gsm_bts_trx_ts *ts,
|
|||
* decided on a more specific PCHAN type already. */
|
||||
OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
|
||||
OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH);
|
||||
rc = trx_sched_set_pchan(&l1h->l1s, tn, pchan);
|
||||
rc = trx_sched_set_pchan(ts, pchan);
|
||||
if (rc)
|
||||
return NM_NACK_RES_NOTAVAIL;
|
||||
|
||||
|
@ -344,8 +339,7 @@ static uint8_t trx_set_ts(struct gsm_bts_trx_ts *ts)
|
|||
*/
|
||||
|
||||
/* enable ciphering */
|
||||
static int l1if_set_ciphering(struct trx_l1h *l1h, struct gsm_lchan *lchan,
|
||||
uint8_t chan_nr, int downlink)
|
||||
static int l1if_set_ciphering(struct gsm_lchan *lchan, uint8_t chan_nr, int downlink)
|
||||
{
|
||||
/* ciphering already enabled in both directions */
|
||||
if (lchan->ciph_state == LCHAN_CIPH_RXTX_CONF)
|
||||
|
@ -353,28 +347,22 @@ static int l1if_set_ciphering(struct trx_l1h *l1h, struct gsm_lchan *lchan,
|
|||
|
||||
if (!downlink) {
|
||||
/* set uplink */
|
||||
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(lchan, chan_nr, false);
|
||||
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->l1s, chan_nr, 0,
|
||||
lchan->encr.alg_id - 1, lchan->encr.key,
|
||||
lchan->encr.key_len);
|
||||
}
|
||||
trx_sched_set_cipher(&l1h->l1s, chan_nr, 1, lchan->encr.alg_id - 1,
|
||||
lchan->encr.key, lchan->encr.key_len);
|
||||
if (lchan->ciph_state != LCHAN_CIPH_RX_CONF)
|
||||
trx_sched_set_cipher(lchan, chan_nr, false);
|
||||
trx_sched_set_cipher(lchan, chan_nr, true);
|
||||
lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mph_info_chan_confirm(struct trx_l1h *l1h, uint8_t chan_nr,
|
||||
enum osmo_mph_info_type type, uint8_t cause)
|
||||
static int mph_info_chan_confirm(struct gsm_bts_trx *trx, uint8_t chan_nr,
|
||||
enum osmo_mph_info_type type, uint8_t cause)
|
||||
{
|
||||
struct phy_instance *pinst = l1h->phy_inst;
|
||||
struct osmo_phsap_prim l1sap;
|
||||
|
||||
memset(&l1sap, 0, sizeof(l1sap));
|
||||
|
@ -384,7 +372,7 @@ static int mph_info_chan_confirm(struct trx_l1h *l1h, uint8_t chan_nr,
|
|||
l1sap.u.info.u.act_cnf.chan_nr = chan_nr;
|
||||
l1sap.u.info.u.act_cnf.cause = cause;
|
||||
|
||||
return l1sap_up(pinst->trx, &l1sap);
|
||||
return l1sap_up(trx, &l1sap);
|
||||
}
|
||||
|
||||
int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn)
|
||||
|
@ -406,8 +394,6 @@ int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn)
|
|||
/* primitive from common part */
|
||||
int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
||||
{
|
||||
struct phy_instance *pinst = trx_phy_instance(trx);
|
||||
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
|
||||
struct msgb *msg = l1sap->oph.msg;
|
||||
uint8_t chan_nr;
|
||||
int rc = 0;
|
||||
|
@ -418,21 +404,21 @@ 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->l1s, l1sap);
|
||||
return trx_sched_ph_data_req(trx, l1sap);
|
||||
case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST):
|
||||
if (!msg)
|
||||
break;
|
||||
/* put data into scheduler's queue */
|
||||
return trx_sched_tch_req(&l1h->l1s, l1sap);
|
||||
return trx_sched_tch_req(trx, l1sap);
|
||||
case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_REQUEST):
|
||||
switch (l1sap->u.info.type) {
|
||||
case PRIM_INFO_ACT_CIPH:
|
||||
chan_nr = l1sap->u.info.u.ciph_req.chan_nr;
|
||||
lchan = get_lchan_by_chan_nr(trx, chan_nr);
|
||||
if (l1sap->u.info.u.ciph_req.uplink)
|
||||
l1if_set_ciphering(l1h, lchan, chan_nr, 0);
|
||||
l1if_set_ciphering(lchan, chan_nr, 0);
|
||||
if (l1sap->u.info.u.ciph_req.downlink)
|
||||
l1if_set_ciphering(l1h, lchan, chan_nr, 1);
|
||||
l1if_set_ciphering(lchan, chan_nr, 1);
|
||||
break;
|
||||
case PRIM_INFO_ACTIVATE:
|
||||
case PRIM_INFO_DEACTIVATE:
|
||||
|
@ -463,11 +449,11 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
|||
chan_nr = RSL_CHAN_OSMO_PDCH | (chan_nr & ~RSL_CHAN_NR_MASK);
|
||||
|
||||
/* activate dedicated channel */
|
||||
trx_sched_set_lchan(&l1h->l1s, chan_nr, LID_DEDIC, true);
|
||||
trx_sched_set_lchan(lchan, chan_nr, LID_DEDIC, true);
|
||||
/* activate associated channel */
|
||||
trx_sched_set_lchan(&l1h->l1s, chan_nr, LID_SACCH, true);
|
||||
trx_sched_set_lchan(lchan, chan_nr, LID_SACCH, true);
|
||||
/* set mode */
|
||||
trx_sched_set_mode(&l1h->l1s, chan_nr,
|
||||
trx_sched_set_mode(lchan->ts, chan_nr,
|
||||
lchan->rsl_cmode, lchan->tch_mode,
|
||||
lchan->tch.amr_mr.num_modes,
|
||||
lchan->tch.amr_mr.bts_mode[0].mode,
|
||||
|
@ -481,16 +467,15 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
|||
/* set lchan active */
|
||||
lchan_set_state(lchan, LCHAN_S_ACTIVE);
|
||||
/* set initial ciphering */
|
||||
l1if_set_ciphering(l1h, lchan, chan_nr, 0);
|
||||
l1if_set_ciphering(l1h, lchan, chan_nr, 1);
|
||||
l1if_set_ciphering(lchan, chan_nr, 0);
|
||||
l1if_set_ciphering(lchan, chan_nr, 1);
|
||||
if (lchan->encr.alg_id)
|
||||
lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
|
||||
else
|
||||
lchan->ciph_state = LCHAN_CIPH_NONE;
|
||||
|
||||
/* confirm */
|
||||
mph_info_chan_confirm(l1h, chan_nr,
|
||||
PRIM_INFO_ACTIVATE, 0);
|
||||
mph_info_chan_confirm(trx, chan_nr, PRIM_INFO_ACTIVATE, 0);
|
||||
break;
|
||||
}
|
||||
if (l1sap->u.info.type == PRIM_INFO_MODIFY) {
|
||||
|
@ -499,7 +484,7 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
|||
osmo_ecu_destroy(lchan->ecu_state);
|
||||
lchan->ecu_state = osmo_ecu_init(trx, lchan2ecu_codec(lchan));
|
||||
/* change mode */
|
||||
trx_sched_set_mode(&l1h->l1s, chan_nr,
|
||||
trx_sched_set_mode(lchan->ts, chan_nr,
|
||||
lchan->rsl_cmode, lchan->tch_mode,
|
||||
lchan->tch.amr_mr.num_modes,
|
||||
lchan->tch.amr_mr.bts_mode[0].mode,
|
||||
|
@ -527,8 +512,7 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
|||
/* deactivate dedicated channel */
|
||||
lchan_deactivate(lchan);
|
||||
/* confirm only on dedicated channel */
|
||||
mph_info_chan_confirm(l1h, chan_nr,
|
||||
PRIM_INFO_DEACTIVATE, 0);
|
||||
mph_info_chan_confirm(trx, chan_nr, PRIM_INFO_DEACTIVATE, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -125,8 +125,6 @@ struct trx_l1h {
|
|||
/* transceiver config */
|
||||
struct trx_config config;
|
||||
struct osmo_fsm_inst *provision_fi;
|
||||
|
||||
struct l1sched_trx l1s;
|
||||
};
|
||||
|
||||
struct trx_l1h *trx_l1h_alloc(void *tall_ctx, struct phy_instance *pinst);
|
||||
|
@ -136,10 +134,4 @@ void l1if_trx_set_nominal_power(struct gsm_bts_trx *trx, int nominal_power);
|
|||
int l1if_trx_start_power_ramp(struct gsm_bts_trx *trx, ramp_compl_cb_t ramp_compl_cb);
|
||||
enum gsm_phys_chan_config transceiver_chan_type_2_pchan(uint8_t type);
|
||||
|
||||
static inline struct l1sched_trx *trx_l1sched_hdl(struct gsm_bts_trx *trx)
|
||||
{
|
||||
struct trx_l1h *l1h = trx->pinst->u.osmotrx.hdl;
|
||||
return &l1h->l1s;
|
||||
}
|
||||
|
||||
#endif /* L1_IF_H_TRX */
|
||||
|
|
|
@ -35,13 +35,10 @@
|
|||
#include "l1_if.h"
|
||||
#include "loops.h"
|
||||
|
||||
void trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr,
|
||||
struct l1sched_chan_state *chan_state,
|
||||
int n_errors, int n_bits_total)
|
||||
void trx_loop_amr_input(struct l1sched_chan_state *chan_state,
|
||||
int n_errors, int n_bits_total)
|
||||
{
|
||||
struct gsm_bts_trx *trx = l1t->trx;
|
||||
struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)]
|
||||
.lchan[l1sap_chan2ss(chan_nr)];
|
||||
struct gsm_lchan *lchan = chan_state->lchan;
|
||||
float ber;
|
||||
|
||||
/* calculate BER (Bit Error Ratio) */
|
||||
|
@ -59,7 +56,7 @@ void trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr,
|
|||
return;
|
||||
|
||||
/* count bit errors */
|
||||
if (L1SAP_IS_CHAN_TCHH(chan_nr)) {
|
||||
if (lchan->type == GSM_LCHAN_TCH_H) {
|
||||
chan_state->ber_num += 2;
|
||||
chan_state->ber_sum += (ber + ber);
|
||||
} else {
|
||||
|
|
|
@ -11,9 +11,8 @@
|
|||
* loops api
|
||||
*/
|
||||
|
||||
void trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr,
|
||||
struct l1sched_chan_state *chan_state,
|
||||
int n_errors, int n_bits_total);
|
||||
void trx_loop_amr_input(struct l1sched_chan_state *chan_state,
|
||||
int n_errors, int n_bits_total);
|
||||
|
||||
void trx_loop_amr_set(struct l1sched_chan_state *chan_state, int loop);
|
||||
|
||||
|
|
|
@ -36,9 +36,9 @@
|
|||
#include <sched_utils.h>
|
||||
|
||||
/* obtain a to-be-transmitted FCCH (frequency correction channel) burst */
|
||||
int tx_fcch_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_fcch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, br, "Transmitting FCCH\n");
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting FCCH\n");
|
||||
|
||||
/* A frequency correction burst is basically a sequence of zeros.
|
||||
* Since br->burst is already zero-initialized, just set the length. */
|
||||
|
@ -48,21 +48,21 @@ int tx_fcch_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
}
|
||||
|
||||
/* obtain a to-be-transmitted SCH (synchronization channel) burst */
|
||||
int tx_sch_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_sch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
ubit_t burst[78];
|
||||
uint8_t sb_info[4];
|
||||
struct gsm_time t;
|
||||
uint8_t t3p, bsic;
|
||||
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, br, "Transmitting SCH\n");
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting SCH\n");
|
||||
|
||||
/* BURST BYPASS */
|
||||
|
||||
/* create SB info from GSM time and BSIC */
|
||||
gsm_fn2gsmtime(&t, br->fn);
|
||||
t3p = t.t3 / 10;
|
||||
bsic = l1t->trx->bts->bsic;
|
||||
bsic = l1ts->ts->trx->bts->bsic;
|
||||
sb_info[0] =
|
||||
((bsic & 0x3f) << 2) |
|
||||
((t.t1 & 0x600) >> 9);
|
||||
|
|
|
@ -39,9 +39,8 @@
|
|||
#define EGPRS_0503_MAX_BYTES 155
|
||||
|
||||
/*! \brief a single PDTCH burst was received by the PHY, process it */
|
||||
int rx_pdtch_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
||||
int rx_pdtch_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);
|
||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
|
||||
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
|
||||
uint32_t first_fn;
|
||||
|
@ -55,7 +54,7 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
int rc;
|
||||
enum osmo_ph_pres_info_type presence_info;
|
||||
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi, "Received PDTCH bid=%u\n", bi->bid);
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received PDTCH bid=%u\n", bi->bid);
|
||||
|
||||
/* allocate burst memory, if not already */
|
||||
if (!*bursts_p) {
|
||||
|
@ -107,7 +106,7 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
|
||||
/* check for complete set of bursts */
|
||||
if ((*mask & 0xf) != 0xf) {
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi, "Received incomplete frame (%u/%u)\n",
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received incomplete frame (%u/%u)\n",
|
||||
bi->fn % l1ts->mf_period, l1ts->mf_period);
|
||||
}
|
||||
*mask = 0x0;
|
||||
|
@ -129,7 +128,7 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
if (rc > 0) {
|
||||
presence_info = PRES_INFO_BOTH;
|
||||
} else {
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi, "Received bad PDTCH (%u/%u)\n",
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received bad PDTCH (%u/%u)\n",
|
||||
bi->fn % l1ts->mf_period, l1ts->mf_period);
|
||||
rc = 0;
|
||||
presence_info = PRES_INFO_INVALID;
|
||||
|
@ -138,7 +137,7 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
ber10k = compute_ber10k(n_bits_total, n_errors);
|
||||
|
||||
first_fn = GSM_TDMA_FN_SUB(bi->fn, 3);
|
||||
return _sched_compose_ph_data_ind(l1t, bi->tn,
|
||||
return _sched_compose_ph_data_ind(l1ts,
|
||||
first_fn, bi->chan, l2, rc,
|
||||
meas_avg.rssi, meas_avg.toa256,
|
||||
meas_avg.ci_cb, ber10k,
|
||||
|
@ -146,10 +145,8 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
}
|
||||
|
||||
/* obtain a to-be-transmitted PDTCH (packet data) burst */
|
||||
int tx_pdtch_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_pdtch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[br->tn];
|
||||
struct msgb *msg = NULL; /* make GCC happy */
|
||||
ubit_t *burst, **bursts_p = &l1ts->chan_state[br->chan].dl_bursts;
|
||||
enum trx_mod_type *mod = &l1ts->chan_state[br->chan].dl_mod_type;
|
||||
|
@ -163,11 +160,11 @@ int tx_pdtch_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
}
|
||||
|
||||
/* get mac block from queue */
|
||||
msg = _sched_dequeue_prim(l1t, br);
|
||||
msg = _sched_dequeue_prim(l1ts, br);
|
||||
if (msg)
|
||||
goto got_msg;
|
||||
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1t, br, "No prim for transmit.\n");
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "No prim for transmit.\n");
|
||||
|
||||
no_msg:
|
||||
/* free burst memory */
|
||||
|
@ -195,7 +192,7 @@ got_msg:
|
|||
|
||||
/* check validity of message */
|
||||
if (rc < 0) {
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1t, br, "Prim invalid length, please FIX! "
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim invalid length, please FIX! "
|
||||
"(len=%ld)\n", (long)(msg->tail - msg->l2h));
|
||||
/* free message */
|
||||
msgb_free(msg);
|
||||
|
@ -215,7 +212,7 @@ send_burst:
|
|||
burst = *bursts_p + br->bid * 348;
|
||||
memset(br->burst, 1, 9);
|
||||
memcpy(br->burst + 9, burst, 174);
|
||||
memcpy(br->burst + 183, _sched_egprs_tsc[gsm_ts_tsc(ts)], 78);
|
||||
memcpy(br->burst + 183, _sched_egprs_tsc[gsm_ts_tsc(l1ts->ts)], 78);
|
||||
memcpy(br->burst + 261, burst + 174, 174);
|
||||
memset(br->burst + 435, 1, 9);
|
||||
|
||||
|
@ -223,13 +220,13 @@ send_burst:
|
|||
} else {
|
||||
burst = *bursts_p + br->bid * 116;
|
||||
memcpy(br->burst + 3, burst, 58);
|
||||
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
||||
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(l1ts->ts)], 26);
|
||||
memcpy(br->burst + 87, burst + 58, 58);
|
||||
|
||||
br->burst_len = GSM_BURST_LEN;
|
||||
}
|
||||
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, br, "Transmitting burst=%u.\n", br->bid);
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting burst=%u.\n", br->bid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -102,8 +102,9 @@ static enum rach_synch_seq_t rach_get_synch_seq(sbit_t *bits, int *best_score)
|
|||
return seq;
|
||||
}
|
||||
|
||||
int rx_rach_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
||||
int rx_rach_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
struct gsm_bts_trx *trx = l1ts->ts->trx;
|
||||
struct osmo_phsap_prim l1sap;
|
||||
int n_errors = 0;
|
||||
int n_bits_total = 0;
|
||||
|
@ -130,7 +131,7 @@ int rx_rach_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
synch_seq = rach_get_synch_seq((sbit_t *) bi->burst, &best_score);
|
||||
}
|
||||
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi,
|
||||
"Received%s RACH (%s): rssi=%d toa256=%d",
|
||||
(bi->chan != TRXC_RACH) ? " handover" : "",
|
||||
get_value_string(rach_synch_seq_names, synch_seq),
|
||||
|
@ -157,16 +158,16 @@ int rx_rach_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
if (bi->flags & TRX_BI_F_CI_CB)
|
||||
l1sap.u.rach_ind.lqual_cb = bi->ci_cb;
|
||||
else
|
||||
l1sap.u.rach_ind.lqual_cb = l1t->trx->bts->min_qual_rach;
|
||||
l1sap.u.rach_ind.lqual_cb = trx->bts->min_qual_rach;
|
||||
|
||||
/* Decode RACH depending on its synch. sequence */
|
||||
switch (synch_seq) {
|
||||
case RACH_SYNCH_SEQ_TS1:
|
||||
case RACH_SYNCH_SEQ_TS2:
|
||||
rc = gsm0503_rach_ext_decode_ber(&ra11, bi->burst + RACH_EXT_TAIL_LEN + RACH_SYNCH_SEQ_LEN,
|
||||
l1t->trx->bts->bsic, &n_errors, &n_bits_total);
|
||||
trx->bts->bsic, &n_errors, &n_bits_total);
|
||||
if (rc) {
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi, "Received bad Access Burst\n");
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received bad Access Burst\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -183,14 +184,14 @@ int rx_rach_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
default:
|
||||
/* Fall-back to the default TS0 if needed */
|
||||
if (synch_seq != RACH_SYNCH_SEQ_TS0) {
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi, "Falling-back to the default TS0\n");
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Falling-back to the default TS0\n");
|
||||
synch_seq = RACH_SYNCH_SEQ_TS0;
|
||||
}
|
||||
|
||||
rc = gsm0503_rach_decode_ber(&ra, bi->burst + RACH_EXT_TAIL_LEN + RACH_SYNCH_SEQ_LEN,
|
||||
l1t->trx->bts->bsic, &n_errors, &n_bits_total);
|
||||
trx->bts->bsic, &n_errors, &n_bits_total);
|
||||
if (rc) {
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi, "Received bad Access Burst\n");
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received bad Access Burst\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -203,7 +204,7 @@ int rx_rach_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
l1sap.u.rach_ind.ber10k = compute_ber10k(n_bits_total, n_errors);
|
||||
|
||||
/* forward primitive */
|
||||
l1sap_up(l1t->trx, &l1sap);
|
||||
l1sap_up(trx, &l1sap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -46,9 +46,8 @@
|
|||
#include <loops.h>
|
||||
|
||||
/*! \brief a single TCH/F burst was received by the PHY, process it */
|
||||
int rx_tchf_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
||||
int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);
|
||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
|
||||
struct gsm_lchan *lchan = chan_state->lchan;
|
||||
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
|
||||
|
@ -70,9 +69,9 @@ int rx_tchf_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
/* If handover RACH detection is turned on, treat this burst as an Access Burst.
|
||||
* Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */
|
||||
if (chan_state->ho_rach_detect == 1 && ~bi->flags & TRX_BI_F_NOPE_IND)
|
||||
return rx_rach_fn(l1t, bi);
|
||||
return rx_rach_fn(l1ts, bi);
|
||||
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi, "Received TCH/F, bid=%u\n", bi->bid);
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received TCH/F, bid=%u\n", bi->bid);
|
||||
|
||||
/* allocate burst memory, if not already */
|
||||
if (!*bursts_p) {
|
||||
|
@ -107,7 +106,7 @@ int rx_tchf_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
|
||||
/* check for complete set of bursts */
|
||||
if ((*mask & 0xf) != 0xf) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi,
|
||||
"Received incomplete frame (%u/%u)\n",
|
||||
bi->fn % l1ts->mf_period, l1ts->mf_period);
|
||||
}
|
||||
|
@ -152,7 +151,7 @@ int rx_tchf_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
/* Tag all frames that are not regular AMR voice frames as
|
||||
* SUB-Frames */
|
||||
if (chan_state->amr_last_dtx != AMR_OTHER) {
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi, "Received AMR SID frame: %s\n",
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received AMR SID frame: %s\n",
|
||||
gsm0503_amr_dtx_frame_name(chan_state->amr_last_dtx));
|
||||
is_sub = 1;
|
||||
}
|
||||
|
@ -183,9 +182,7 @@ int rx_tchf_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
}
|
||||
|
||||
if (rc)
|
||||
trx_loop_amr_input(l1t,
|
||||
trx_chan_desc[bi->chan].chan_nr | bi->tn, chan_state,
|
||||
n_errors, n_bits_total);
|
||||
trx_loop_amr_input(chan_state, n_errors, n_bits_total);
|
||||
/* only good speech frames get rtp header */
|
||||
if (rc != GSM_MACBLOCK_LEN && rc >= 4) {
|
||||
if (chan_state->amr_last_dtx == AMR_OTHER) {
|
||||
|
@ -201,7 +198,7 @@ int rx_tchf_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
|
||||
break;
|
||||
default:
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
|
||||
"TCH mode %u invalid, please fix!\n",
|
||||
tch_mode);
|
||||
return -EINVAL;
|
||||
|
@ -213,11 +210,11 @@ int rx_tchf_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
|
||||
/* Check if the frame is bad */
|
||||
if (rc < 0) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, bi, "Received bad data (%u/%u)\n",
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi, "Received bad data (%u/%u)\n",
|
||||
bi->fn % l1ts->mf_period, l1ts->mf_period);
|
||||
bfi_flag = true;
|
||||
} else if (rc < 4) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi,
|
||||
"Received bad data (%u/%u) with invalid codec mode %d\n",
|
||||
bi->fn % l1ts->mf_period, l1ts->mf_period, rc);
|
||||
bfi_flag = true;
|
||||
|
@ -233,7 +230,7 @@ int rx_tchf_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
/* FACCH */
|
||||
if (rc == GSM_MACBLOCK_LEN) {
|
||||
fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_F);
|
||||
_sched_compose_ph_data_ind(l1t, bi->tn, fn_begin, bi->chan,
|
||||
_sched_compose_ph_data_ind(l1ts, fn_begin, bi->chan,
|
||||
tch_data + amr, GSM_MACBLOCK_LEN,
|
||||
meas_avg.rssi, meas_avg.toa256,
|
||||
meas_avg.ci_cb, ber10k,
|
||||
|
@ -281,7 +278,7 @@ bfi:
|
|||
chan_state->codec[chan_state->dl_ft],
|
||||
AMR_BAD);
|
||||
if (rc < 2) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
|
||||
"Failed to encode AMR_BAD frame (rc=%d), "
|
||||
"not sending BFI\n", rc);
|
||||
return -EINVAL;
|
||||
|
@ -289,7 +286,7 @@ bfi:
|
|||
memset(tch_data + 2, 0, rc - 2);
|
||||
break;
|
||||
default:
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
|
||||
"TCH mode %u invalid, please fix!\n", tch_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -302,7 +299,7 @@ bfi:
|
|||
/* TCH or BFI */
|
||||
compose_l1sap:
|
||||
fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_TCH_F);
|
||||
return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, bi->chan, tch_data, rc,
|
||||
return _sched_compose_tch_ind(l1ts, fn_begin, bi->chan, tch_data, rc,
|
||||
/* FIXME: what should we use for BFI here? */
|
||||
bfi_flag ? bi->toa256 : meas_avg.toa256, ber10k,
|
||||
bfi_flag ? bi->rssi : meas_avg.rssi, is_sub);
|
||||
|
@ -310,10 +307,9 @@ compose_l1sap:
|
|||
|
||||
/* common section for generation of TCH bursts (TCH/H and TCH/F).
|
||||
* FIXME: this function is over-complicated, refactor / get rid of it. */
|
||||
void tx_tch_common(struct l1sched_trx *l1t, struct trx_dl_burst_req *br,
|
||||
void tx_tch_common(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br,
|
||||
struct msgb **_msg_tch, struct msgb **_msg_facch)
|
||||
{
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||
struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL;
|
||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan];
|
||||
uint8_t rsl_cmode = chan_state->rsl_cmode;
|
||||
|
@ -326,7 +322,7 @@ void tx_tch_common(struct l1sched_trx *l1t, struct trx_dl_burst_req *br,
|
|||
uint8_t tch_data[GSM_FR_BYTES];
|
||||
int len;
|
||||
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, br, "Missing TCH bursts detected, sending BFI\n");
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Missing TCH bursts detected, sending BFI\n");
|
||||
|
||||
/* indicate bad frame */
|
||||
switch (tch_mode) {
|
||||
|
@ -351,7 +347,7 @@ void tx_tch_common(struct l1sched_trx *l1t, struct trx_dl_burst_req *br,
|
|||
chan_state->codec[chan_state->dl_cmr],
|
||||
chan_state->codec[chan_state->dl_ft], AMR_BAD);
|
||||
if (len < 2) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br,
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br,
|
||||
"Failed to encode AMR_BAD frame (rc=%d), "
|
||||
"not sending BFI\n", len);
|
||||
return;
|
||||
|
@ -360,21 +356,21 @@ void tx_tch_common(struct l1sched_trx *l1t, struct trx_dl_burst_req *br,
|
|||
break;
|
||||
default:
|
||||
inval_mode1:
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br, "TCH mode invalid, please fix!\n");
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "TCH mode invalid, please fix!\n");
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
/* Note: RSSI/ToA256 is set to 0 to indicate to the higher
|
||||
* layers that this is a faked tch_ind */
|
||||
_sched_compose_tch_ind(l1t, br->tn, br->fn, br->chan,
|
||||
_sched_compose_tch_ind(l1ts, br->fn, br->chan,
|
||||
tch_data, len, 0, 10000, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* get frame and unlink from queue */
|
||||
msg1 = _sched_dequeue_prim(l1t, br);
|
||||
msg2 = _sched_dequeue_prim(l1t, br);
|
||||
msg1 = _sched_dequeue_prim(l1ts, br);
|
||||
msg2 = _sched_dequeue_prim(l1ts, br);
|
||||
if (msg1) {
|
||||
l1sap = msgb_l1sap_prim(msg1);
|
||||
if (l1sap->oph.primitive == PRIM_TCH) {
|
||||
|
@ -382,7 +378,7 @@ inval_mode1:
|
|||
if (msg2) {
|
||||
l1sap = msgb_l1sap_prim(msg2);
|
||||
if (l1sap->oph.primitive == PRIM_TCH) {
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1t, br, "TCH twice, please FIX!\n");
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "TCH twice, please FIX!\n");
|
||||
msgb_free(msg2);
|
||||
} else
|
||||
msg_facch = msg2;
|
||||
|
@ -392,7 +388,7 @@ inval_mode1:
|
|||
if (msg2) {
|
||||
l1sap = msgb_l1sap_prim(msg2);
|
||||
if (l1sap->oph.primitive != PRIM_TCH) {
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1t, br, "FACCH twice, please FIX!\n");
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "FACCH twice, please FIX!\n");
|
||||
msgb_free(msg2);
|
||||
} else
|
||||
msg_tch = msg2;
|
||||
|
@ -408,7 +404,7 @@ inval_mode1:
|
|||
|
||||
/* check validity of message */
|
||||
if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) {
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1t, br, "Prim has odd len=%u != %u\n",
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim has odd len=%u != %u\n",
|
||||
msgb_l2len(msg_facch), GSM_MACBLOCK_LEN);
|
||||
/* free message */
|
||||
msgb_free(msg_facch);
|
||||
|
@ -425,7 +421,7 @@ inval_mode1:
|
|||
int8_t sti, cmi;
|
||||
|
||||
if (rsl_cmode != RSL_CMOD_SPD_SPEECH) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, br, "Dropping speech frame, "
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Dropping speech frame, "
|
||||
"because we are not in speech mode\n");
|
||||
goto free_bad_msg;
|
||||
}
|
||||
|
@ -463,32 +459,32 @@ inval_mode1:
|
|||
trx_loop_amr_set(chan_state, 1);
|
||||
}
|
||||
if (ft < 0) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br,
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br,
|
||||
"Codec (FT = %d) of RTP frame not in list\n", ft_codec);
|
||||
goto free_bad_msg;
|
||||
}
|
||||
if (fn_is_codec_mode_request(br->fn) && chan_state->dl_ft != ft) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, br, "Codec (FT = %d) "
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Codec (FT = %d) "
|
||||
" of RTP cannot be changed now, but in next frame\n", ft_codec);
|
||||
goto free_bad_msg;
|
||||
}
|
||||
chan_state->dl_ft = ft;
|
||||
if (bfi == AMR_BAD) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, br, "Transmitting 'bad AMR frame'\n");
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Transmitting 'bad AMR frame'\n");
|
||||
goto free_bad_msg;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
inval_mode2:
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br, "TCH mode invalid, please fix!\n");
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "TCH mode invalid, please fix!\n");
|
||||
goto free_bad_msg;
|
||||
}
|
||||
if (len < 0) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br, "Cannot send invalid AMR payload\n");
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot send invalid AMR payload\n");
|
||||
goto free_bad_msg;
|
||||
}
|
||||
if (msgb_l2len(msg_tch) != len) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br, "Cannot send payload with "
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot send payload with "
|
||||
"invalid length! (expecting %d, received %d)\n",
|
||||
len, msgb_l2len(msg_tch));
|
||||
free_bad_msg:
|
||||
|
@ -505,11 +501,9 @@ send_frame:
|
|||
}
|
||||
|
||||
/* obtain a to-be-transmitted TCH/F (Full Traffic Channel) burst */
|
||||
int tx_tchf_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[br->tn];
|
||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan];
|
||||
uint8_t tch_mode = chan_state->tch_mode;
|
||||
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
|
||||
|
@ -521,7 +515,7 @@ int tx_tchf_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
goto send_burst;
|
||||
}
|
||||
|
||||
tx_tch_common(l1t, br, &msg_tch, &msg_facch);
|
||||
tx_tch_common(l1ts, br, &msg_tch, &msg_facch);
|
||||
|
||||
/* BURST BYPASS */
|
||||
|
||||
|
@ -538,7 +532,7 @@ int tx_tchf_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
|
||||
/* no message at all */
|
||||
if (!msg_tch && !msg_facch) {
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1t, br, "No TCH or FACCH prim for transmit.\n");
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "No TCH or FACCH prim for transmit.\n");
|
||||
goto send_burst;
|
||||
}
|
||||
|
||||
|
@ -568,12 +562,12 @@ send_burst:
|
|||
/* compose burst */
|
||||
burst = *bursts_p + br->bid * 116;
|
||||
memcpy(br->burst + 3, burst, 58);
|
||||
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
||||
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(l1ts->ts)], 26);
|
||||
memcpy(br->burst + 87, burst + 58, 58);
|
||||
|
||||
br->burst_len = GSM_BURST_LEN;
|
||||
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, br, "Transmitting burst=%u.\n", br->bid);
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting burst=%u.\n", br->bid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -46,9 +46,8 @@
|
|||
#include <loops.h>
|
||||
|
||||
/*! \brief a single TCH/H burst was received by the PHY, process it */
|
||||
int rx_tchh_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
||||
int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);
|
||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
|
||||
struct gsm_lchan *lchan = chan_state->lchan;
|
||||
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
|
||||
|
@ -77,9 +76,9 @@ int rx_tchh_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
/* If handover RACH detection is turned on, treat this burst as an Access Burst.
|
||||
* Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */
|
||||
if (chan_state->ho_rach_detect == 1 && ~bi->flags & TRX_BI_F_NOPE_IND)
|
||||
return rx_rach_fn(l1t, bi);
|
||||
return rx_rach_fn(l1ts, bi);
|
||||
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi, "Received TCH/H, bid=%u\n", bi->bid);
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received TCH/H, bid=%u\n", bi->bid);
|
||||
|
||||
/* allocate burst memory, if not already */
|
||||
if (!*bursts_p) {
|
||||
|
@ -114,7 +113,7 @@ int rx_tchh_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
|
||||
/* check for complete set of bursts */
|
||||
if ((*mask & 0x3) != 0x3) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi,
|
||||
"Received incomplete frame (%u/%u)\n",
|
||||
bi->fn % l1ts->mf_period, l1ts->mf_period);
|
||||
}
|
||||
|
@ -175,7 +174,7 @@ int rx_tchh_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
/* Tag all frames that are not regular AMR voice frames
|
||||
as SUB-Frames */
|
||||
if (chan_state->amr_last_dtx != AMR_OTHER) {
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi, "Received AMR SID frame: %s\n",
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received AMR SID frame: %s\n",
|
||||
gsm0503_amr_dtx_frame_name(chan_state->amr_last_dtx));
|
||||
is_sub = 1;
|
||||
}
|
||||
|
@ -206,9 +205,7 @@ int rx_tchh_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
}
|
||||
|
||||
if (rc)
|
||||
trx_loop_amr_input(l1t,
|
||||
trx_chan_desc[bi->chan].chan_nr | bi->tn, chan_state,
|
||||
n_errors, n_bits_total);
|
||||
trx_loop_amr_input(chan_state, n_errors, n_bits_total);
|
||||
|
||||
/* only good speech frames get rtp header */
|
||||
if (rc != GSM_MACBLOCK_LEN && rc >= 4) {
|
||||
|
@ -225,7 +222,7 @@ int rx_tchh_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
|
||||
break;
|
||||
default:
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
|
||||
"TCH mode %u invalid, please fix!\n",
|
||||
tch_mode);
|
||||
return -EINVAL;
|
||||
|
@ -241,11 +238,11 @@ int rx_tchh_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
|
||||
/* Check if the frame is bad */
|
||||
if (rc < 0) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, bi, "Received bad data (%u/%u)\n",
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi, "Received bad data (%u/%u)\n",
|
||||
bi->fn % l1ts->mf_period, l1ts->mf_period);
|
||||
bfi_flag = true;
|
||||
} else if (rc < 4) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi,
|
||||
"Received bad data (%u/%u) with invalid codec mode %d\n",
|
||||
bi->fn % l1ts->mf_period, l1ts->mf_period, rc);
|
||||
bfi_flag = true;
|
||||
|
@ -265,7 +262,7 @@ int rx_tchh_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_H0);
|
||||
else
|
||||
fn_begin = gsm0502_fn_remap(bi->fn, FN_REMAP_FACCH_H1);
|
||||
_sched_compose_ph_data_ind(l1t, bi->tn, fn_begin, bi->chan,
|
||||
_sched_compose_ph_data_ind(l1ts, fn_begin, bi->chan,
|
||||
tch_data + amr, GSM_MACBLOCK_LEN,
|
||||
meas_avg.rssi, meas_avg.toa256,
|
||||
meas_avg.ci_cb, ber10k,
|
||||
|
@ -312,7 +309,7 @@ bfi:
|
|||
chan_state->codec[chan_state->dl_ft],
|
||||
AMR_BAD);
|
||||
if (rc < 2) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
|
||||
"Failed to encode AMR_BAD frame (rc=%d), "
|
||||
"not sending BFI\n", rc);
|
||||
return -EINVAL;
|
||||
|
@ -320,7 +317,7 @@ bfi:
|
|||
memset(tch_data + 2, 0, rc - 2);
|
||||
break;
|
||||
default:
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, bi,
|
||||
"TCH mode %u invalid, please fix!\n", tch_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -364,7 +361,7 @@ compose_l1sap:
|
|||
chan_state->ber10k_facch = 0;
|
||||
}
|
||||
|
||||
return _sched_compose_tch_ind(l1t, bi->tn, fn_begin, bi->chan, tch_data, rc,
|
||||
return _sched_compose_tch_ind(l1ts, fn_begin, bi->chan, tch_data, rc,
|
||||
/* FIXME: what should we use for BFI here? */
|
||||
bfi_flag ? bi->toa256 : meas_avg.toa256, ber10k,
|
||||
bfi_flag ? bi->rssi : meas_avg.rssi, is_sub);
|
||||
|
@ -372,16 +369,14 @@ compose_l1sap:
|
|||
|
||||
/* common section for generation of TCH bursts (TCH/H and TCH/F).
|
||||
* FIXME: this function is over-complicated, refactor / get rid of it. */
|
||||
extern void tx_tch_common(struct l1sched_trx *l1t,
|
||||
extern void tx_tch_common(struct l1sched_ts *l1ts,
|
||||
const struct trx_dl_burst_req *br,
|
||||
struct msgb **_msg_tch, struct msgb **_msg_facch);
|
||||
|
||||
/* obtain a to-be-transmitted TCH/H (Half Traffic Channel) burst */
|
||||
int tx_tchh_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[br->tn];
|
||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan];
|
||||
uint8_t tch_mode = chan_state->tch_mode;
|
||||
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
|
||||
|
@ -394,11 +389,11 @@ int tx_tchh_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
}
|
||||
|
||||
/* get TCH and/or FACCH */
|
||||
tx_tch_common(l1t, br, &msg_tch, &msg_facch);
|
||||
tx_tch_common(l1ts, br, &msg_tch, &msg_facch);
|
||||
|
||||
/* check for FACCH alignment */
|
||||
if (msg_facch && ((((br->fn + 4) % 26) >> 2) & 1)) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br,
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br,
|
||||
"Cannot transmit FACCH starting on even frames, please fix RTS!\n");
|
||||
msgb_free(msg_facch);
|
||||
msg_facch = NULL;
|
||||
|
@ -424,7 +419,7 @@ int tx_tchh_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
|
||||
/* no message at all */
|
||||
if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1t, br, "No TCH or FACCH prim for transmit.\n");
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "No TCH or FACCH prim for transmit.\n");
|
||||
goto send_burst;
|
||||
}
|
||||
|
||||
|
@ -456,12 +451,12 @@ send_burst:
|
|||
/* compose burst */
|
||||
burst = *bursts_p + br->bid * 116;
|
||||
memcpy(br->burst + 3, burst, 58);
|
||||
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
||||
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(l1ts->ts)], 26);
|
||||
memcpy(br->burst + 87, burst + 58, 58);
|
||||
|
||||
br->burst_len = GSM_BURST_LEN;
|
||||
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, br, "Transmitting burst=%u.\n", br->bid);
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting burst=%u.\n", br->bid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -47,9 +47,8 @@ static void add_sbits(sbit_t * current, const sbit_t * previous)
|
|||
}
|
||||
|
||||
/*! \brief a single (SDCCH/SACCH) burst was received by the PHY, process it */
|
||||
int rx_data_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
||||
int rx_data_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, bi->tn);
|
||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[bi->chan];
|
||||
sbit_t *burst, **bursts_p = &chan_state->ul_bursts;
|
||||
uint32_t *first_fn = &chan_state->ul_first_fn;
|
||||
|
@ -66,9 +65,9 @@ int rx_data_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
/* If handover RACH detection is turned on, treat this burst as an Access Burst.
|
||||
* Handle NOPE.ind as usually to ensure proper Uplink measurement reporting. */
|
||||
if (chan_state->ho_rach_detect == 1 && ~bi->flags & TRX_BI_F_NOPE_IND)
|
||||
return rx_rach_fn(l1t, bi);
|
||||
return rx_rach_fn(l1ts, bi);
|
||||
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi, "Received Data, bid=%u\n", bi->bid);
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi, "Received Data, bid=%u\n", bi->bid);
|
||||
|
||||
/* allocate burst memory, if not already */
|
||||
if (!*bursts_p) {
|
||||
|
@ -116,7 +115,7 @@ int rx_data_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
|
||||
/* check for complete set of bursts */
|
||||
if ((*mask & 0xf) != 0xf) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, bi, "Received incomplete data (%u/%u)\n",
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi, "Received incomplete data (%u/%u)\n",
|
||||
bi->fn % l1ts->mf_period, l1ts->mf_period);
|
||||
|
||||
/* we require first burst to have correct FN */
|
||||
|
@ -130,7 +129,7 @@ int rx_data_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
/* decode */
|
||||
rc = gsm0503_xcch_decode(l2, *bursts_p, &n_errors, &n_bits_total);
|
||||
if (rc) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, bi, "Received bad data (%u/%u)\n",
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi, "Received bad data (%u/%u)\n",
|
||||
bi->fn % l1ts->mf_period, l1ts->mf_period);
|
||||
l2_len = 0;
|
||||
|
||||
|
@ -142,11 +141,11 @@ int rx_data_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
add_sbits(*bursts_p, chan_state->ul_bursts_prev);
|
||||
rc = gsm0503_xcch_decode(l2, *bursts_p, &n_errors, &n_bits_total);
|
||||
if (rc) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, bi,
|
||||
"Combining current SACCH block with previous SACCH block also yields bad data (%u/%u)\n",
|
||||
bi->fn % l1ts->mf_period, l1ts->mf_period);
|
||||
} else {
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, bi,
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, bi,
|
||||
"Combining current SACCH block with previous SACCH block yields good data (%u/%u)\n",
|
||||
bi->fn % l1ts->mf_period, l1ts->mf_period);
|
||||
l2_len = GSM_MACBLOCK_LEN;
|
||||
|
@ -161,7 +160,7 @@ int rx_data_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
if (rep_sacch)
|
||||
memcpy(chan_state->ul_bursts_prev, *bursts_p, 464);
|
||||
|
||||
return _sched_compose_ph_data_ind(l1t, bi->tn, *first_fn,
|
||||
return _sched_compose_ph_data_ind(l1ts, *first_fn,
|
||||
bi->chan, l2, l2_len,
|
||||
meas_avg.rssi, meas_avg.toa256,
|
||||
meas_avg.ci_cb, ber10k,
|
||||
|
@ -169,10 +168,8 @@ int rx_data_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
|||
}
|
||||
|
||||
/* obtain a to-be-transmitted xCCH (e.g SACCH or SDCCH) burst */
|
||||
int tx_data_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_data_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[br->tn];
|
||||
struct msgb *msg = NULL; /* make GCC happy */
|
||||
ubit_t *burst, **bursts_p = &l1ts->chan_state[br->chan].dl_bursts;
|
||||
|
||||
|
@ -184,11 +181,11 @@ int tx_data_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
}
|
||||
|
||||
/* get mac block from queue */
|
||||
msg = _sched_dequeue_prim(l1t, br);
|
||||
msg = _sched_dequeue_prim(l1ts, br);
|
||||
if (msg)
|
||||
goto got_msg;
|
||||
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1t, br, "No prim for transmit.\n");
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "No prim for transmit.\n");
|
||||
|
||||
no_msg:
|
||||
/* free burst memory */
|
||||
|
@ -201,7 +198,7 @@ no_msg:
|
|||
got_msg:
|
||||
/* check validity of message */
|
||||
if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1t, br, "Prim has odd len=%u != %u\n",
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim has odd len=%u != %u\n",
|
||||
msgb_l2len(msg), GSM_MACBLOCK_LEN);
|
||||
/* free message */
|
||||
msgb_free(msg);
|
||||
|
@ -219,7 +216,7 @@ got_msg:
|
|||
|
||||
/* Note: RSSI is set to 0 to indicate to the higher
|
||||
* layers that this is a faked ph_data_ind */
|
||||
_sched_compose_ph_data_ind(l1t, br->tn, 0, br->chan, NULL, 0,
|
||||
_sched_compose_ph_data_ind(l1ts, 0, br->chan, NULL, 0,
|
||||
0, 0, 0, 10000,
|
||||
PRES_INFO_INVALID);
|
||||
}
|
||||
|
@ -242,12 +239,12 @@ send_burst:
|
|||
/* compose burst */
|
||||
burst = *bursts_p + br->bid * 116;
|
||||
memcpy(br->burst + 3, burst, 58);
|
||||
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
||||
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(l1ts->ts)], 26);
|
||||
memcpy(br->burst + 87, burst + 58, 58);
|
||||
|
||||
br->burst_len = GSM_BURST_LEN;
|
||||
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, br, "Transmitting burst=%u.\n", br->bid);
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting burst=%u.\n", br->bid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -53,9 +53,9 @@
|
|||
(ts)->hopping.hsn, (ts)->hopping.maio, (ts)->hopping.arfcn_num
|
||||
|
||||
/* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */
|
||||
int tx_idle_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_idle_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, br, "Transmitting IDLE\n");
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "Transmitting IDLE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,6 @@ static void bts_sched_fn(struct gsm_bts *bts, const uint32_t fn)
|
|||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
const struct phy_link *plink = trx->pinst->phy_link;
|
||||
struct trx_l1h *l1h = trx->pinst->u.osmotrx.hdl;
|
||||
struct l1sched_trx *l1t = &l1h->l1s;
|
||||
|
||||
/* we don't schedule, if power is off */
|
||||
if (!trx_if_powered(l1h))
|
||||
|
@ -119,11 +118,12 @@ static void bts_sched_fn(struct gsm_bts *bts, const uint32_t fn)
|
|||
sched_fn = GSM_TDMA_FN_SUM(fn, plink->u.osmotrx.clock_advance);
|
||||
|
||||
/* process every TS of TRX */
|
||||
for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
|
||||
for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
|
||||
const struct phy_instance *pinst = trx->pinst;
|
||||
struct l1sched_ts *l1ts = trx->ts[tn].priv;
|
||||
|
||||
/* ready-to-send */
|
||||
_sched_rts(l1t, tn, GSM_TDMA_FN_SUM(sched_fn, plink->u.osmotrx.rts_advance));
|
||||
_sched_rts(l1ts, GSM_TDMA_FN_SUM(sched_fn, plink->u.osmotrx.rts_advance));
|
||||
|
||||
/* All other parameters to be set by _sched_dl_burst() */
|
||||
br = (struct trx_dl_burst_req) {
|
||||
|
@ -132,7 +132,7 @@ static void bts_sched_fn(struct gsm_bts *bts, const uint32_t fn)
|
|||
};
|
||||
|
||||
/* get burst for FN */
|
||||
_sched_dl_burst(l1t, &br);
|
||||
_sched_dl_burst(l1ts, &br);
|
||||
if (br.burst_len == 0) {
|
||||
/* if no bits, send no burst */
|
||||
continue;
|
||||
|
@ -206,24 +206,17 @@ static struct gsm_bts_trx *ulfh_route_bi(const struct trx_ul_burst_ind *bi,
|
|||
}
|
||||
|
||||
/* Route a given Uplink burst indication to the scheduler depending on freq. hopping state */
|
||||
int trx_sched_route_burst_ind(struct trx_ul_burst_ind *bi, struct l1sched_trx *l1t)
|
||||
int trx_sched_route_burst_ind(const struct gsm_bts_trx *trx, struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
const struct phy_instance *pinst;
|
||||
const struct gsm_bts_trx *trx;
|
||||
struct trx_l1h *l1h;
|
||||
|
||||
/* no frequency hopping => nothing to do */
|
||||
if (!l1t->trx->ts[bi->tn].hopping.enabled)
|
||||
return trx_sched_ul_burst(l1t, bi);
|
||||
if (!trx->ts[bi->tn].hopping.enabled)
|
||||
return trx_sched_ul_burst(trx->ts[bi->tn].priv, bi);
|
||||
|
||||
trx = ulfh_route_bi(bi, l1t->trx);
|
||||
trx = ulfh_route_bi(bi, trx);
|
||||
if (trx == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
pinst = trx_phy_instance(trx);
|
||||
l1h = pinst->u.osmotrx.hdl;
|
||||
|
||||
return trx_sched_ul_burst(&l1h->l1s, bi);
|
||||
return trx_sched_ul_burst(trx->ts[bi->tn].priv, bi);
|
||||
}
|
||||
|
||||
/*! maximum number of 'missed' frame periods we can tolerate of OS doesn't schedule us*/
|
||||
|
@ -462,9 +455,9 @@ int trx_sched_clock(struct gsm_bts *bts, uint32_t fn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate)
|
||||
void _sched_act_rach_det(struct gsm_bts_trx *trx, uint8_t tn, uint8_t ss, int activate)
|
||||
{
|
||||
struct phy_instance *pinst = trx_phy_instance(l1t->trx);
|
||||
struct phy_instance *pinst = trx_phy_instance(trx);
|
||||
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
|
||||
|
||||
if (activate)
|
||||
|
|
|
@ -1057,7 +1057,7 @@ static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what)
|
|||
bi._num_pdus++;
|
||||
|
||||
/* feed received burst into scheduler code */
|
||||
trx_sched_route_burst_ind(&bi, &l1h->l1s);
|
||||
trx_sched_route_burst_ind(l1h->phy_inst->trx, &bi);
|
||||
} while (bi.flags & TRX_BI_F_BATCH_IND);
|
||||
|
||||
return 0;
|
||||
|
@ -1222,7 +1222,7 @@ static void trx_phy_inst_close(struct phy_instance *pinst)
|
|||
struct trx_l1h *l1h = pinst->u.osmotrx.hdl;
|
||||
|
||||
trx_if_close(l1h);
|
||||
trx_sched_exit(&l1h->l1s);
|
||||
trx_sched_clean(pinst->trx);
|
||||
}
|
||||
|
||||
/*! open the control + burst data sockets for one phy_instance */
|
||||
|
@ -1235,11 +1235,7 @@ static int trx_phy_inst_open(struct phy_instance *pinst)
|
|||
if (!l1h)
|
||||
return -EINVAL;
|
||||
|
||||
rc = trx_sched_init(&l1h->l1s, pinst->trx);
|
||||
if (rc < 0) {
|
||||
LOGPPHI(l1h->phy_inst, DL1C, LOGL_FATAL, "Cannot initialize scheduler\n");
|
||||
return -EIO;
|
||||
}
|
||||
trx_sched_init(pinst->trx);
|
||||
|
||||
rc = trx_if_open(l1h);
|
||||
if (rc < 0) {
|
||||
|
|
|
@ -100,11 +100,7 @@ static uint8_t vbts_set_trx(struct gsm_bts_trx *trx)
|
|||
|
||||
static uint8_t vbts_set_ts(struct gsm_bts_trx_ts *ts)
|
||||
{
|
||||
struct phy_instance *pinst = trx_phy_instance(ts->trx);
|
||||
int rc;
|
||||
|
||||
rc = trx_sched_set_pchan(&pinst->u.virt.sched, ts->nr, ts->pchan);
|
||||
if (rc)
|
||||
if (trx_sched_set_pchan(ts, ts->pchan) != 0)
|
||||
return NM_NACK_RES_NOTAVAIL;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -214,7 +214,7 @@ int bts_model_phy_link_open(struct phy_link *plink)
|
|||
|
||||
/* iterate over list of PHY instances and initialize the scheduler */
|
||||
llist_for_each_entry(pinst, &plink->instances, list) {
|
||||
trx_sched_init(&pinst->u.virt.sched, pinst->trx);
|
||||
trx_sched_init(pinst->trx);
|
||||
/* Only start the scheduler for the transceiver on C0.
|
||||
* If we have multiple transceivers, CCCH is always on C0
|
||||
* and has to be auto active */
|
||||
|
@ -244,28 +244,19 @@ int bts_model_phy_link_open(struct phy_link *plink)
|
|||
/* enable ciphering */
|
||||
static int l1if_set_ciphering(struct gsm_lchan *lchan, uint8_t chan_nr, int downlink)
|
||||
{
|
||||
struct gsm_bts_trx *trx = lchan->ts->trx;
|
||||
struct phy_instance *pinst = trx_phy_instance(trx);
|
||||
struct l1sched_trx *sched = &pinst->u.virt.sched;
|
||||
|
||||
/* ciphering already enabled in both directions */
|
||||
if (lchan->ciph_state == LCHAN_CIPH_RXTX_CONF)
|
||||
return -EINVAL;
|
||||
|
||||
if (!downlink) {
|
||||
/* set uplink */
|
||||
trx_sched_set_cipher(sched, chan_nr, 0, lchan->encr.alg_id - 1,
|
||||
lchan->encr.key, lchan->encr.key_len);
|
||||
trx_sched_set_cipher(lchan, chan_nr, false);
|
||||
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(sched, chan_nr, 0,
|
||||
lchan->encr.alg_id - 1, lchan->encr.key,
|
||||
lchan->encr.key_len);
|
||||
}
|
||||
trx_sched_set_cipher(sched, chan_nr, 1, lchan->encr.alg_id - 1,
|
||||
lchan->encr.key, lchan->encr.key_len);
|
||||
if (lchan->ciph_state != LCHAN_CIPH_RX_CONF)
|
||||
trx_sched_set_cipher(lchan, chan_nr, false);
|
||||
trx_sched_set_cipher(lchan, chan_nr, true);
|
||||
lchan->ciph_state = LCHAN_CIPH_RXTX_CONF;
|
||||
}
|
||||
|
||||
|
@ -341,8 +332,6 @@ static int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t f
|
|||
/* primitive from common part */
|
||||
int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
||||
{
|
||||
struct phy_instance *pinst = trx_phy_instance(trx);
|
||||
struct l1sched_trx *sched = &pinst->u.virt.sched;
|
||||
struct msgb *msg = l1sap->oph.msg;
|
||||
uint8_t chan_nr;
|
||||
uint8_t tn, ss;
|
||||
|
@ -354,12 +343,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(sched, l1sap);
|
||||
return trx_sched_ph_data_req(trx, l1sap);
|
||||
case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST):
|
||||
if (!msg)
|
||||
break;
|
||||
/* put data into scheduler's queue */
|
||||
return trx_sched_tch_req(sched, l1sap);
|
||||
return trx_sched_tch_req(trx, l1sap);
|
||||
case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_REQUEST):
|
||||
switch (l1sap->u.info.type) {
|
||||
case PRIM_INFO_ACT_CIPH:
|
||||
|
@ -388,11 +377,11 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
|||
break;
|
||||
}
|
||||
/* activate dedicated channel */
|
||||
trx_sched_set_lchan(sched, chan_nr, LID_DEDIC, true);
|
||||
trx_sched_set_lchan(lchan, chan_nr, LID_DEDIC, true);
|
||||
/* activate associated channel */
|
||||
trx_sched_set_lchan(sched, chan_nr, LID_SACCH, true);
|
||||
trx_sched_set_lchan(lchan, chan_nr, LID_SACCH, true);
|
||||
/* set mode */
|
||||
trx_sched_set_mode(sched, chan_nr,
|
||||
trx_sched_set_mode(lchan->ts, chan_nr,
|
||||
lchan->rsl_cmode, lchan->tch_mode,
|
||||
lchan->tch.amr_mr.num_modes,
|
||||
lchan->tch.amr_mr.bts_mode[0].mode,
|
||||
|
@ -420,7 +409,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(sched, chan_nr,
|
||||
trx_sched_set_mode(lchan->ts, chan_nr,
|
||||
lchan->rsl_cmode, lchan->tch_mode,
|
||||
lchan->tch.amr_mr.num_modes,
|
||||
lchan->tch.amr_mr.bts_mode[0].mode,
|
||||
|
@ -437,12 +426,12 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
|
|||
break;
|
||||
}
|
||||
/* deactivate associated channel */
|
||||
trx_sched_set_lchan(sched, chan_nr, LID_SACCH, false);
|
||||
trx_sched_set_lchan(lchan, chan_nr, LID_SACCH, false);
|
||||
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(sched, chan_nr, LID_DEDIC, false);
|
||||
trx_sched_set_lchan(lchan, chan_nr, LID_DEDIC, false);
|
||||
/* confirm only on dedicated channel */
|
||||
mph_info_chan_confirm(trx, chan_nr,
|
||||
PRIM_INFO_DEACTIVATE, 0);
|
||||
|
|
|
@ -14,7 +14,6 @@ struct bts_virt_priv {
|
|||
|
||||
struct vbts_l1h {
|
||||
struct gsm_bts_trx *trx;
|
||||
struct l1sched_trx l1s;
|
||||
struct virt_um_inst *virt_um;
|
||||
};
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
/* (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2017 Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
|
||||
* Contributions by sysmocom - s.f.m.c. GmbH
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
|
@ -51,13 +52,14 @@
|
|||
* Send a message over the virtual um interface.
|
||||
* This will at first wrap the msg with a GSMTAP header and then write it to the declared multicast socket.
|
||||
*/
|
||||
static void _tx_to_virt_um(struct l1sched_trx *l1t,
|
||||
static void _tx_to_virt_um(struct l1sched_ts *l1ts,
|
||||
struct trx_dl_burst_req *br,
|
||||
struct msgb *msg, bool is_voice_frame)
|
||||
{
|
||||
const struct trx_chan_desc *chdesc = &trx_chan_desc[br->chan];
|
||||
const struct gsm_bts_trx *trx = l1ts->ts->trx;
|
||||
struct msgb *outmsg; /* msg to send with gsmtap header prepended */
|
||||
uint16_t arfcn = l1t->trx->arfcn; /* ARFCN of the transceiver the message is send with */
|
||||
uint16_t arfcn = trx->arfcn; /* ARFCN of the transceiver the message is send with */
|
||||
uint8_t signal_dbm = 63; /* signal strength, 63 is best */
|
||||
uint8_t snr = 63; /* signal noise ratio, 63 is best */
|
||||
uint8_t *data = msgb_l2(msg); /* data to transmit (whole message without l1 header) */
|
||||
|
@ -73,13 +75,13 @@ static void _tx_to_virt_um(struct l1sched_trx *l1t,
|
|||
/* in Osmocom, AGCH is only sent on ccch block 0. no idea why. this seems to cause false GSMTAP channel
|
||||
* types for agch and pch. */
|
||||
if (rsl_chantype == RSL_CHAN_PCH_AGCH &&
|
||||
l1sap_fn2ccch_block(br->fn) >= num_agch(l1t->trx, "PH-DATA-REQ"))
|
||||
l1sap_fn2ccch_block(br->fn) >= num_agch(trx, "PH-DATA-REQ"))
|
||||
gsmtap_chantype = GSMTAP_CHANNEL_PCH;
|
||||
else
|
||||
gsmtap_chantype = chantype_rsl2gsmtap2(rsl_chantype, chdesc->link_id, is_voice_frame); /* the logical channel type */
|
||||
|
||||
if (gsmtap_chantype == GSMTAP_CHANNEL_UNKNOWN) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br, "Tx GSMTAP for RSL channel type 0x%02x: cannot send, this"
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Tx GSMTAP for RSL channel type 0x%02x: cannot send, this"
|
||||
" channel type is unknown in GSMTAP\n", rsl_chantype);
|
||||
msgb_free(msg);
|
||||
return;
|
||||
|
@ -93,44 +95,42 @@ static void _tx_to_virt_um(struct l1sched_trx *l1t,
|
|||
outmsg = gsmtap_makemsg(arfcn, timeslot, gsmtap_chantype, subslot, br->fn, signal_dbm, snr, data, data_len);
|
||||
|
||||
if (outmsg) {
|
||||
struct phy_instance *pinst = trx_phy_instance(l1t->trx);
|
||||
struct phy_instance *pinst = trx_phy_instance(trx);
|
||||
int rc;
|
||||
|
||||
rc = virt_um_write_msg(pinst->phy_link->u.virt.virt_um, outmsg);
|
||||
if (rc < 0)
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br,
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br,
|
||||
"GSMTAP msg could not send to virtual Um: %s\n", strerror(-rc));
|
||||
else if (rc == 0)
|
||||
bts_shutdown(l1t->trx->bts, "VirtPHY write socket died\n");
|
||||
bts_shutdown(trx->bts, "VirtPHY write socket died\n");
|
||||
else
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1t, br,
|
||||
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br,
|
||||
"Sending GSMTAP message to virtual Um\n");
|
||||
} else
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br, "GSMTAP msg could not be created!\n");
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "GSMTAP msg could not be created!\n");
|
||||
|
||||
/* free incoming message */
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
static void tx_to_virt_um(struct l1sched_trx *l1t,
|
||||
static void tx_to_virt_um(struct l1sched_ts *l1ts,
|
||||
struct trx_dl_burst_req *br,
|
||||
struct msgb *msg)
|
||||
{
|
||||
_tx_to_virt_um(l1t, br, msg, false);
|
||||
_tx_to_virt_um(l1ts, br, msg, false);
|
||||
}
|
||||
|
||||
|
||||
static struct gsm_lchan *lchan_from_l1t(struct l1sched_trx *l1t, uint8_t tn, enum trx_chan_type chan)
|
||||
static struct gsm_lchan *lchan_from_l1t(const struct l1sched_ts *l1ts,
|
||||
const enum trx_chan_type chan)
|
||||
{
|
||||
struct gsm_bts_trx_ts *ts;
|
||||
struct gsm_bts_trx_ts *ts = l1ts->ts;
|
||||
uint8_t subslot = 0;
|
||||
|
||||
OSMO_ASSERT(l1t && l1t->trx);
|
||||
|
||||
if (chan == TRXC_TCHH_1)
|
||||
subslot = 1;
|
||||
|
||||
ts = &l1t->trx->ts[tn];
|
||||
return &ts->lchan[subslot];
|
||||
}
|
||||
|
||||
|
@ -152,11 +152,11 @@ static int get_um_voice_type(const struct gsm_lchan *lchan)
|
|||
}
|
||||
}
|
||||
|
||||
static void tx_to_virt_um_voice_frame(struct l1sched_trx *l1t,
|
||||
static void tx_to_virt_um_voice_frame(struct l1sched_ts *l1ts,
|
||||
struct trx_dl_burst_req *br,
|
||||
struct msgb *msg)
|
||||
{
|
||||
struct gsm_lchan *lchan = lchan_from_l1t(l1t, br->tn, br->chan);
|
||||
struct gsm_lchan *lchan = lchan_from_l1t(l1ts, br->chan);
|
||||
int um_voice_type;
|
||||
|
||||
OSMO_ASSERT(lchan);
|
||||
|
@ -170,7 +170,7 @@ static void tx_to_virt_um_voice_frame(struct l1sched_trx *l1t,
|
|||
msgb_pull_to_l2(msg);
|
||||
msgb_push_u8(msg, um_voice_type);
|
||||
msg->l2h = msg->data;
|
||||
_tx_to_virt_um(l1t, br, msg, true);
|
||||
_tx_to_virt_um(l1ts, br, msg, true);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -178,22 +178,22 @@ static void tx_to_virt_um_voice_frame(struct l1sched_trx *l1t,
|
|||
*/
|
||||
|
||||
/* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */
|
||||
int tx_idle_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_idle_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tx_fcch_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_fcch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tx_sch_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_sch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tx_data_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_data_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
struct msgb *msg;
|
||||
|
||||
|
@ -201,15 +201,15 @@ int tx_data_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
return 0;
|
||||
|
||||
/* get mac block from queue */
|
||||
msg = _sched_dequeue_prim(l1t, br);
|
||||
msg = _sched_dequeue_prim(l1ts, br);
|
||||
if (!msg) {
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1t, br, "has not been served !! No prim\n");
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "has not been served !! No prim\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* check validity of message */
|
||||
if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1t, br, "Prim not 23 bytes, please FIX! (len=%d)\n",
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim not 23 bytes, please FIX! (len=%d)\n",
|
||||
msgb_l2len(msg));
|
||||
/* free message */
|
||||
msgb_free(msg);
|
||||
|
@ -217,12 +217,12 @@ int tx_data_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
}
|
||||
|
||||
/* transmit the msg received on dl from bsc to layer1 (virt Um) */
|
||||
tx_to_virt_um(l1t, br, msg);
|
||||
tx_to_virt_um(l1ts, br, msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tx_pdtch_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_pdtch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
struct msgb *msg = NULL; /* make GCC happy */
|
||||
|
||||
|
@ -230,23 +230,22 @@ int tx_pdtch_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
return 0;
|
||||
|
||||
/* get mac block from queue */
|
||||
msg = _sched_dequeue_prim(l1t, br);
|
||||
msg = _sched_dequeue_prim(l1ts, br);
|
||||
if (!msg) {
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1t, br, "has not been served !! No prim\n");
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "has not been served !! No prim\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
tx_to_virt_um(l1t, br, msg);
|
||||
tx_to_virt_um(l1ts, br, msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tx_tch_common(struct l1sched_trx *l1t,
|
||||
static void tx_tch_common(struct l1sched_ts *l1ts,
|
||||
const struct trx_dl_burst_req *br,
|
||||
struct msgb **_msg_tch, struct msgb **_msg_facch,
|
||||
int codec_mode_request)
|
||||
{
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||
struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL;
|
||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan];
|
||||
uint8_t rsl_cmode = chan_state->rsl_cmode;
|
||||
|
@ -259,7 +258,7 @@ static void tx_tch_common(struct l1sched_trx *l1t,
|
|||
uint8_t tch_data[GSM_FR_BYTES];
|
||||
int len;
|
||||
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, br, "Missing TCH bursts detected, sending "
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Missing TCH bursts detected, sending "
|
||||
"BFI for %s\n", trx_chan_desc[br->chan].name);
|
||||
|
||||
/* indicate bad frame */
|
||||
|
@ -287,7 +286,7 @@ static void tx_tch_common(struct l1sched_trx *l1t,
|
|||
if (len < 2)
|
||||
break;
|
||||
memset(tch_data + 2, 0, len - 2);
|
||||
_sched_compose_tch_ind(l1t, br->tn, 0, br->chan, tch_data, len);
|
||||
_sched_compose_tch_ind(l1ts, 0, br->chan, tch_data, len);
|
||||
break;
|
||||
default:
|
||||
inval_mode1:
|
||||
|
@ -296,13 +295,13 @@ inval_mode1:
|
|||
len = 0;
|
||||
}
|
||||
if (len)
|
||||
_sched_compose_tch_ind(l1t, br->tn, 0, br->chan, tch_data, len);
|
||||
_sched_compose_tch_ind(l1ts, 0, br->chan, tch_data, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* get frame and unlink from queue */
|
||||
msg1 = _sched_dequeue_prim(l1t, br);
|
||||
msg2 = _sched_dequeue_prim(l1t, br);
|
||||
msg1 = _sched_dequeue_prim(l1ts, br);
|
||||
msg2 = _sched_dequeue_prim(l1ts, br);
|
||||
if (msg1) {
|
||||
l1sap = msgb_l1sap_prim(msg1);
|
||||
if (l1sap->oph.primitive == PRIM_TCH) {
|
||||
|
@ -310,7 +309,7 @@ inval_mode1:
|
|||
if (msg2) {
|
||||
l1sap = msgb_l1sap_prim(msg2);
|
||||
if (l1sap->oph.primitive == PRIM_TCH) {
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1t, br,
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1ts, br,
|
||||
"TCH twice, please FIX!\n");
|
||||
msgb_free(msg2);
|
||||
} else
|
||||
|
@ -321,7 +320,7 @@ inval_mode1:
|
|||
if (msg2) {
|
||||
l1sap = msgb_l1sap_prim(msg2);
|
||||
if (l1sap->oph.primitive != PRIM_TCH) {
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1t, br,
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1ts, br,
|
||||
"FACCH twice, please FIX!\n");
|
||||
msgb_free(msg2);
|
||||
} else
|
||||
|
@ -338,7 +337,7 @@ inval_mode1:
|
|||
|
||||
/* check validity of message */
|
||||
if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) {
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1t, br, "Prim has odd len=%u != %u\n",
|
||||
LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, "Prim has odd len=%u != %u\n",
|
||||
msgb_l2len(msg_facch), GSM_MACBLOCK_LEN);
|
||||
/* free message */
|
||||
msgb_free(msg_facch);
|
||||
|
@ -354,7 +353,7 @@ inval_mode1:
|
|||
#endif
|
||||
|
||||
if (rsl_cmode != RSL_CMOD_SPD_SPEECH) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, br, "Dropping speech frame, "
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Dropping speech frame, "
|
||||
"because we are not in speech mode\n");
|
||||
goto free_bad_msg;
|
||||
}
|
||||
|
@ -365,7 +364,7 @@ inval_mode1:
|
|||
len = 15;
|
||||
if (msgb_l2len(msg_tch) >= 1
|
||||
&& (msg_tch->l2h[0] & 0xf0) != 0x00) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, br,
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br,
|
||||
"Transmitting 'bad HR frame'\n");
|
||||
goto free_bad_msg;
|
||||
}
|
||||
|
@ -374,7 +373,7 @@ inval_mode1:
|
|||
len = GSM_FR_BYTES;
|
||||
if (msgb_l2len(msg_tch) >= 1
|
||||
&& (msg_tch->l2h[0] >> 4) != 0xd) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, br,
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br,
|
||||
"Transmitting 'bad FR frame'\n");
|
||||
goto free_bad_msg;
|
||||
}
|
||||
|
@ -385,7 +384,7 @@ inval_mode1:
|
|||
len = GSM_EFR_BYTES;
|
||||
if (msgb_l2len(msg_tch) >= 1
|
||||
&& (msg_tch->l2h[0] >> 4) != 0xc) {
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1t, br,
|
||||
LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br,
|
||||
"Transmitting 'bad EFR frame'\n");
|
||||
goto free_bad_msg;
|
||||
}
|
||||
|
@ -396,15 +395,15 @@ inval_mode1:
|
|||
break;
|
||||
default:
|
||||
inval_mode2:
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br, "TCH mode invalid, please fix!\n");
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "TCH mode invalid, please fix!\n");
|
||||
goto free_bad_msg;
|
||||
}
|
||||
if (len < 0) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br, "Cannot send invalid AMR payload\n");
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot send invalid AMR payload\n");
|
||||
goto free_bad_msg;
|
||||
}
|
||||
if (msgb_l2len(msg_tch) != len) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br, "Cannot send payload with "
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot send payload with "
|
||||
"invalid length! (expecing %d, received %d)\n", len, msgb_l2len(msg_tch));
|
||||
free_bad_msg:
|
||||
/* free message */
|
||||
|
@ -419,34 +418,33 @@ send_frame:
|
|||
*_msg_facch = msg_facch;
|
||||
}
|
||||
|
||||
int tx_tchf_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_tchf_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
||||
|
||||
if (br->bid > 0)
|
||||
return 0;
|
||||
|
||||
tx_tch_common(l1t, br, &msg_tch, &msg_facch, (((br->fn + 4) % 26) >> 2) & 1);
|
||||
tx_tch_common(l1ts, br, &msg_tch, &msg_facch, (((br->fn + 4) % 26) >> 2) & 1);
|
||||
|
||||
/* no message at all */
|
||||
if (!msg_tch && !msg_facch) {
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1t, br, "has not been served !! No prim\n");
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "has not been served !! No prim\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (msg_facch) {
|
||||
tx_to_virt_um(l1t, br, msg_facch);
|
||||
tx_to_virt_um(l1ts, br, msg_facch);
|
||||
msgb_free(msg_tch);
|
||||
} else if (msg_tch)
|
||||
tx_to_virt_um_voice_frame(l1t, br, msg_tch);
|
||||
tx_to_virt_um_voice_frame(l1ts, br, msg_tch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tx_tchh_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||
int tx_tchh_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br)
|
||||
{
|
||||
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan];
|
||||
//uint8_t tch_mode = chan_state->tch_mode;
|
||||
|
||||
|
@ -455,11 +453,11 @@ int tx_tchh_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
return 0;
|
||||
|
||||
/* get TCH and/or FACCH */
|
||||
tx_tch_common(l1t, br, &msg_tch, &msg_facch, (((br->fn + 4) % 26) >> 2) & 1);
|
||||
tx_tch_common(l1ts, br, &msg_tch, &msg_facch, (((br->fn + 4) % 26) >> 2) & 1);
|
||||
|
||||
/* check for FACCH alignment */
|
||||
if (msg_facch && ((((br->fn + 4) % 26) >> 2) & 1)) {
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1t, br, "Cannot transmit FACCH starting on "
|
||||
LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, "Cannot transmit FACCH starting on "
|
||||
"even frames, please fix RTS!\n");
|
||||
msgb_free(msg_facch);
|
||||
msg_facch = NULL;
|
||||
|
@ -467,15 +465,15 @@ int tx_tchh_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
|
||||
/* no message at all */
|
||||
if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1t, br, "has not been served !! No prim\n");
|
||||
LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "has not been served !! No prim\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (msg_facch) {
|
||||
tx_to_virt_um(l1t, br, msg_facch);
|
||||
tx_to_virt_um(l1ts, br, msg_facch);
|
||||
msgb_free(msg_tch);
|
||||
} else if (msg_tch)
|
||||
tx_to_virt_um_voice_frame(l1t, br, msg_tch);
|
||||
tx_to_virt_um_voice_frame(l1ts, br, msg_tch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -489,33 +487,33 @@ int tx_tchh_fn(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
|||
* directly into the L1SAP, bypassing the TDMA multiplex logic oriented
|
||||
* towards receiving bursts */
|
||||
|
||||
int rx_rach_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
||||
int rx_rach_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief a single burst was received by the PHY, process it */
|
||||
int rx_data_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
||||
int rx_data_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rx_pdtch_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
||||
int rx_pdtch_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rx_tchf_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
||||
int rx_tchf_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rx_tchh_fn(struct l1sched_trx *l1t, const struct trx_ul_burst_ind *bi)
|
||||
int rx_tchh_fn(struct l1sched_ts *l1ts, const struct trx_ul_burst_ind *bi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate)
|
||||
void _sched_act_rach_det(struct gsm_bts_trx *trx, uint8_t tn, uint8_t ss, int activate)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -536,12 +534,11 @@ static int vbts_sched_fn(struct gsm_bts *bts, uint32_t fn)
|
|||
|
||||
/* advance the frame number? */
|
||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
struct phy_instance *pinst = trx_phy_instance(trx);
|
||||
struct l1sched_trx *l1t = &pinst->u.virt.sched;
|
||||
struct trx_dl_burst_req br = { .fn = fn };
|
||||
|
||||
/* do for each of the 8 timeslots */
|
||||
for (br.tn = 0; br.tn < ARRAY_SIZE(l1t->ts); br.tn++) {
|
||||
for (br.tn = 0; br.tn < ARRAY_SIZE(trx->ts); br.tn++) {
|
||||
struct l1sched_ts *l1ts = trx->ts[br.tn].priv;
|
||||
/* Generate RTS indication to higher layers */
|
||||
/* This will basically do 2 things (check l1_if:bts_model_l1sap_down):
|
||||
* 1) Get pending messages from layer 2 (from the lapdm queue)
|
||||
|
@ -549,13 +546,13 @@ static int vbts_sched_fn(struct gsm_bts *bts, uint32_t fn)
|
|||
* --> Handle and process non-transparent RSL-Messages (activate channel, )
|
||||
* --> Forward transparent RSL-DATA-Messages to the ms by appending them to
|
||||
* the l1-dl-queue */
|
||||
_sched_rts(l1t, br.tn, GSM_TDMA_FN_SUM(fn, RTS_ADVANCE));
|
||||
_sched_rts(l1ts, GSM_TDMA_FN_SUM(fn, RTS_ADVANCE));
|
||||
/* schedule transmit backend functions */
|
||||
/* Process data in the l1-dlqueue and forward it
|
||||
* to MS */
|
||||
/* the returned bits are not used here, the routines called will directly forward their
|
||||
* bits to the virt Um */
|
||||
_sched_dl_burst(l1t, &br);
|
||||
_sched_dl_burst(l1ts, &br);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue