osmo-bts-trx: introduce and use struct trx_dl_burst_req
This change is similar to what we did for Uplink bursts: - group all Downlink burst parameters into a single structure, - allocate it once and pass a pointer to lchan handlers, - pass a pointer to trx_if_send_burst(). Given that the structure is allocated and (zero-)initialized in trx_sched_fn(), we can get rid of some memset() calls in lchan handlers and thus improve the overall performance a bit. Change-Id: If3014e69746559963569b77561dbf7b163c68ffa
This commit is contained in:
parent
36c5ec4881
commit
ae781bc5cd
|
@ -250,6 +250,17 @@ struct trx_ul_burst_ind {
|
||||||
size_t burst_len;
|
size_t burst_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*! DL burst request with the corresponding meta info */
|
||||||
|
struct trx_dl_burst_req {
|
||||||
|
uint32_t fn; /*!< TDMA frame number */
|
||||||
|
uint8_t tn; /*!< TDMA timeslot number */
|
||||||
|
uint8_t att; /*!< Tx power attenuation */
|
||||||
|
|
||||||
|
/*! Burst hard-bits buffer */
|
||||||
|
ubit_t burst[EGPRS_BURST_LEN];
|
||||||
|
size_t burst_len;
|
||||||
|
};
|
||||||
|
|
||||||
/*! Handle an UL burst received by PHY */
|
/*! Handle an UL burst received by PHY */
|
||||||
int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi);
|
int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi);
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,8 @@
|
||||||
typedef int trx_sched_rts_func(struct l1sched_trx *l1t, uint8_t tn,
|
typedef int trx_sched_rts_func(struct l1sched_trx *l1t, uint8_t tn,
|
||||||
uint32_t fn, enum trx_chan_type chan);
|
uint32_t fn, enum trx_chan_type chan);
|
||||||
|
|
||||||
typedef ubit_t *trx_sched_dl_func(struct l1sched_trx *l1t, uint8_t tn,
|
typedef int trx_sched_dl_func(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
uint32_t fn, enum trx_chan_type chan,
|
uint8_t bid, struct trx_dl_burst_req *br);
|
||||||
uint8_t bid, uint16_t *nbits);
|
|
||||||
|
|
||||||
typedef int trx_sched_ul_func(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
typedef int trx_sched_ul_func(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
uint8_t bid, const struct trx_ul_burst_ind *bi);
|
uint8_t bid, const struct trx_ul_burst_ind *bi);
|
||||||
|
@ -56,20 +55,21 @@ int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
int16_t ta_offs_256bits, uint16_t ber10k, float rssi,
|
int16_t ta_offs_256bits, uint16_t ber10k, float rssi,
|
||||||
uint8_t is_sub);
|
uint8_t is_sub);
|
||||||
|
|
||||||
ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_idle_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
|
uint8_t bid, struct trx_dl_burst_req *br);
|
||||||
ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_fcch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
|
uint8_t bid, struct trx_dl_burst_req *br);
|
||||||
ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_sch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
|
uint8_t bid, struct trx_dl_burst_req *br);
|
||||||
ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
|
uint8_t bid, struct trx_dl_burst_req *br);
|
||||||
ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
|
uint8_t bid, struct trx_dl_burst_req *br);
|
||||||
ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
|
uint8_t bid, struct trx_dl_burst_req *br);
|
||||||
ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
|
uint8_t bid, struct trx_dl_burst_req *br);
|
||||||
|
|
||||||
int rx_rach_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
int rx_rach_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
uint8_t bid, const struct trx_ul_burst_ind *bi);
|
uint8_t bid, const struct trx_ul_burst_ind *bi);
|
||||||
int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
|
@ -81,7 +81,6 @@ int rx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
int rx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
uint8_t bid, const struct trx_ul_burst_ind *bi);
|
uint8_t bid, const struct trx_ul_burst_ind *bi);
|
||||||
|
|
||||||
const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn,
|
void _sched_dl_burst(struct l1sched_trx *l1t, struct trx_dl_burst_req *br);
|
||||||
uint32_t fn, uint16_t *nbits);
|
|
||||||
int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn);
|
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_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate);
|
||||||
|
|
|
@ -1154,23 +1154,21 @@ int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* process downlink burst */
|
/* process downlink burst */
|
||||||
const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn,
|
void _sched_dl_burst(struct l1sched_trx *l1t, struct trx_dl_burst_req *br)
|
||||||
uint32_t fn, uint16_t *nbits)
|
|
||||||
{
|
{
|
||||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||||
struct l1sched_chan_state *l1cs;
|
struct l1sched_chan_state *l1cs;
|
||||||
const struct trx_sched_frame *frame;
|
const struct trx_sched_frame *frame;
|
||||||
uint8_t offset, period, bid;
|
uint8_t offset, period, bid;
|
||||||
trx_sched_dl_func *func;
|
trx_sched_dl_func *func;
|
||||||
enum trx_chan_type chan;
|
enum trx_chan_type chan;
|
||||||
ubit_t *bits = NULL;
|
|
||||||
|
|
||||||
if (!l1ts->mf_index)
|
if (!l1ts->mf_index)
|
||||||
goto no_data;
|
goto no_data;
|
||||||
|
|
||||||
/* get frame from multiframe */
|
/* get frame from multiframe */
|
||||||
period = l1ts->mf_period;
|
period = l1ts->mf_period;
|
||||||
offset = fn % period;
|
offset = br->fn % period;
|
||||||
frame = l1ts->mf_frames + offset;
|
frame = l1ts->mf_frames + offset;
|
||||||
|
|
||||||
chan = frame->dl_chan;
|
chan = frame->dl_chan;
|
||||||
|
@ -1180,42 +1178,37 @@ const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn,
|
||||||
l1cs = &l1ts->chan_state[chan];
|
l1cs = &l1ts->chan_state[chan];
|
||||||
|
|
||||||
/* check if channel is active */
|
/* check if channel is active */
|
||||||
if (!TRX_CHAN_IS_ACTIVE(l1cs, chan)) {
|
if (!TRX_CHAN_IS_ACTIVE(l1cs, chan))
|
||||||
if (nbits)
|
|
||||||
*nbits = GSM_BURST_LEN;
|
|
||||||
goto no_data;
|
goto no_data;
|
||||||
}
|
|
||||||
|
|
||||||
/* get burst from function */
|
/* get burst from function */
|
||||||
bits = func(l1t, tn, fn, chan, bid, nbits);
|
if (func(l1t, chan, bid, br) != 0)
|
||||||
|
goto no_data;
|
||||||
|
|
||||||
/* encrypt */
|
/* encrypt */
|
||||||
if (bits && l1cs->dl_encr_algo) {
|
if (br->burst_len && l1cs->dl_encr_algo) {
|
||||||
ubit_t ks[114];
|
ubit_t ks[114];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
osmo_a5(l1cs->dl_encr_algo, l1cs->dl_encr_key, fn, ks, NULL);
|
osmo_a5(l1cs->dl_encr_algo, l1cs->dl_encr_key, br->fn, ks, NULL);
|
||||||
for (i = 0; i < 57; i++) {
|
for (i = 0; i < 57; i++) {
|
||||||
bits[i + 3] ^= ks[i];
|
br->burst[i + 3] ^= ks[i];
|
||||||
bits[i + 88] ^= ks[i + 57];
|
br->burst[i + 88] ^= ks[i + 57];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
no_data:
|
no_data:
|
||||||
/* in case of C0, we need a dummy burst to maintain RF power */
|
/* in case of C0, we need a dummy burst to maintain RF power */
|
||||||
if (bits == NULL && l1t->trx == l1t->trx->bts->c0) {
|
if (!br->burst_len && l1t->trx == l1t->trx->bts->c0) {
|
||||||
#if 0
|
#if 0
|
||||||
if (chan != TRXC_IDLE) // hack
|
if (chan != TRXC_IDLE) // hack
|
||||||
LOGP(DL1C, LOGL_DEBUG, "No burst data for %s fn=%u ts=%u "
|
LOGP(DL1C, LOGL_DEBUG, "No burst data for %s fn=%u ts=%u "
|
||||||
"burst=%d on C0, so filling with dummy burst\n",
|
"burst=%d on C0, so filling with dummy burst\n",
|
||||||
trx_chan_desc[chan].name, fn, tn, bid);
|
trx_chan_desc[chan].name, fn, tn, bid);
|
||||||
#endif
|
#endif
|
||||||
bits = (ubit_t *) dummy_burst;
|
memcpy(br->burst, dummy_burst, ARRAY_SIZE(dummy_burst));
|
||||||
if (nbits)
|
br->burst_len = ARRAY_SIZE(dummy_burst);
|
||||||
*nbits = ARRAY_SIZE(dummy_burst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return bits;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TDMA_FN_SUM(a, b) \
|
#define TDMA_FN_SUM(a, b) \
|
||||||
|
|
|
@ -35,34 +35,32 @@
|
||||||
#include <sched_utils.h>
|
#include <sched_utils.h>
|
||||||
|
|
||||||
/* obtain a to-be-transmitted FCCH (frequency correction channel) burst */
|
/* obtain a to-be-transmitted FCCH (frequency correction channel) burst */
|
||||||
ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_fcch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting FCCH\n");
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, br->tn, chan, br->fn, "Transmitting FCCH\n");
|
||||||
|
|
||||||
if (nbits)
|
memcpy(br->burst, _sched_fcch_burst, GSM_BURST_LEN);
|
||||||
*nbits = GSM_BURST_LEN;
|
br->burst_len = GSM_BURST_LEN;
|
||||||
|
|
||||||
/* BURST BYPASS */
|
return 0;
|
||||||
|
|
||||||
return (ubit_t *) _sched_fcch_burst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* obtain a to-be-transmitted SCH (synchronization channel) burst */
|
/* obtain a to-be-transmitted SCH (synchronization channel) burst */
|
||||||
ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_sch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
static ubit_t bits[GSM_BURST_LEN], burst[78];
|
ubit_t burst[78];
|
||||||
uint8_t sb_info[4];
|
uint8_t sb_info[4];
|
||||||
struct gsm_time t;
|
struct gsm_time t;
|
||||||
uint8_t t3p, bsic;
|
uint8_t t3p, bsic;
|
||||||
|
|
||||||
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting SCH\n");
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, br->tn, chan, br->fn, "Transmitting SCH\n");
|
||||||
|
|
||||||
/* BURST BYPASS */
|
/* BURST BYPASS */
|
||||||
|
|
||||||
/* create SB info from GSM time and BSIC */
|
/* create SB info from GSM time and BSIC */
|
||||||
gsm_fn2gsmtime(&t, fn);
|
gsm_fn2gsmtime(&t, br->fn);
|
||||||
t3p = t.t3 / 10;
|
t3p = t.t3 / 10;
|
||||||
bsic = l1t->trx->bts->bsic;
|
bsic = l1t->trx->bts->bsic;
|
||||||
sb_info[0] =
|
sb_info[0] =
|
||||||
|
@ -81,14 +79,11 @@ ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
gsm0503_sch_encode(burst, sb_info);
|
gsm0503_sch_encode(burst, sb_info);
|
||||||
|
|
||||||
/* compose burst */
|
/* compose burst */
|
||||||
memset(bits, 0, 3);
|
memcpy(br->burst + 3, burst, 39);
|
||||||
memcpy(bits + 3, burst, 39);
|
memcpy(br->burst + 42, _sched_sch_train, 64);
|
||||||
memcpy(bits + 42, _sched_sch_train, 64);
|
memcpy(br->burst + 106, burst + 39, 39);
|
||||||
memcpy(bits + 106, burst + 39, 39);
|
|
||||||
memset(bits + 145, 0, 3);
|
|
||||||
|
|
||||||
if (nbits)
|
br->burst_len = GSM_BURST_LEN;
|
||||||
*nbits = GSM_BURST_LEN;
|
|
||||||
|
|
||||||
return bits;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,30 +154,29 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* obtain a to-be-transmitted PDTCH (packet data) burst */
|
/* obtain a to-be-transmitted PDTCH (packet data) burst */
|
||||||
ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||||
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
|
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[br->tn];
|
||||||
struct msgb *msg = NULL; /* make GCC happy */
|
struct msgb *msg = NULL; /* make GCC happy */
|
||||||
ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;
|
ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;
|
||||||
enum trx_burst_type *burst_type = &l1ts->chan_state[chan].dl_burst_type;
|
enum trx_burst_type *burst_type = &l1ts->chan_state[chan].dl_burst_type;
|
||||||
static ubit_t bits[EGPRS_BURST_LEN];
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
/* send burst, if we already got a frame */
|
/* send burst, if we already got a frame */
|
||||||
if (bid > 0) {
|
if (bid > 0) {
|
||||||
if (!*bursts_p)
|
if (!*bursts_p)
|
||||||
return NULL;
|
return 0;
|
||||||
goto send_burst;
|
goto send_burst;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get mac block from queue */
|
/* get mac block from queue */
|
||||||
msg = _sched_dequeue_prim(l1t, tn, fn, chan);
|
msg = _sched_dequeue_prim(l1t, br->tn, br->fn, chan);
|
||||||
if (msg)
|
if (msg)
|
||||||
goto got_msg;
|
goto got_msg;
|
||||||
|
|
||||||
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No prim for transmit.\n");
|
LOGL1S(DL1P, LOGL_INFO, l1t, br->tn, chan, br->fn, "No prim for transmit.\n");
|
||||||
|
|
||||||
no_msg:
|
no_msg:
|
||||||
/* free burst memory */
|
/* free burst memory */
|
||||||
|
@ -185,7 +184,7 @@ no_msg:
|
||||||
talloc_free(*bursts_p);
|
talloc_free(*bursts_p);
|
||||||
*bursts_p = NULL;
|
*bursts_p = NULL;
|
||||||
}
|
}
|
||||||
return NULL;
|
return -ENODEV;
|
||||||
|
|
||||||
got_msg:
|
got_msg:
|
||||||
/* BURST BYPASS */
|
/* BURST BYPASS */
|
||||||
|
@ -195,7 +194,7 @@ got_msg:
|
||||||
*bursts_p = talloc_zero_size(tall_bts_ctx,
|
*bursts_p = talloc_zero_size(tall_bts_ctx,
|
||||||
GSM0503_EGPRS_BURSTS_NBITS);
|
GSM0503_EGPRS_BURSTS_NBITS);
|
||||||
if (!*bursts_p)
|
if (!*bursts_p)
|
||||||
return NULL;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* encode bursts */
|
/* encode bursts */
|
||||||
|
@ -205,7 +204,7 @@ got_msg:
|
||||||
|
|
||||||
/* check validity of message */
|
/* check validity of message */
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim invalid length, please FIX! "
|
LOGL1S(DL1P, LOGL_FATAL, l1t, br->tn, chan, br->fn, "Prim invalid length, please FIX! "
|
||||||
"(len=%ld)\n", (long)(msg->tail - msg->l2h));
|
"(len=%ld)\n", (long)(msg->tail - msg->l2h));
|
||||||
/* free message */
|
/* free message */
|
||||||
msgb_free(msg);
|
msgb_free(msg);
|
||||||
|
@ -223,27 +222,23 @@ send_burst:
|
||||||
/* compose burst */
|
/* compose burst */
|
||||||
if (*burst_type == TRX_BURST_8PSK) {
|
if (*burst_type == TRX_BURST_8PSK) {
|
||||||
burst = *bursts_p + bid * 348;
|
burst = *bursts_p + bid * 348;
|
||||||
memset(bits, 1, 9);
|
memset(br->burst, 1, 9);
|
||||||
memcpy(bits + 9, burst, 174);
|
memcpy(br->burst + 9, burst, 174);
|
||||||
memcpy(bits + 183, _sched_egprs_tsc[gsm_ts_tsc(ts)], 78);
|
memcpy(br->burst + 183, _sched_egprs_tsc[gsm_ts_tsc(ts)], 78);
|
||||||
memcpy(bits + 261, burst + 174, 174);
|
memcpy(br->burst + 261, burst + 174, 174);
|
||||||
memset(bits + 435, 1, 9);
|
memset(br->burst + 435, 1, 9);
|
||||||
|
|
||||||
if (nbits)
|
br->burst_len = EGPRS_BURST_LEN;
|
||||||
*nbits = EGPRS_BURST_LEN;
|
|
||||||
} else {
|
} else {
|
||||||
burst = *bursts_p + bid * 116;
|
burst = *bursts_p + bid * 116;
|
||||||
memset(bits, 0, 3);
|
memcpy(br->burst + 3, burst, 58);
|
||||||
memcpy(bits + 3, burst, 58);
|
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
||||||
memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
memcpy(br->burst + 87, burst + 58, 58);
|
||||||
memcpy(bits + 87, burst + 58, 58);
|
|
||||||
memset(bits + 145, 0, 3);
|
|
||||||
|
|
||||||
if (nbits)
|
br->burst_len = GSM_BURST_LEN;
|
||||||
*nbits = GSM_BURST_LEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, br->tn, chan, br->fn, "Transmitting burst=%u.\n", bid);
|
||||||
|
|
||||||
return bits;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -491,25 +491,24 @@ send_frame:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* obtain a to-be-transmitted TCH/F (Full Traffic Channel) burst */
|
/* obtain a to-be-transmitted TCH/F (Full Traffic Channel) burst */
|
||||||
ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
||||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||||
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
|
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[br->tn];
|
||||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
||||||
uint8_t tch_mode = chan_state->tch_mode;
|
uint8_t tch_mode = chan_state->tch_mode;
|
||||||
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
|
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
|
||||||
static ubit_t bits[GSM_BURST_LEN];
|
|
||||||
|
|
||||||
/* send burst, if we already got a frame */
|
/* send burst, if we already got a frame */
|
||||||
if (bid > 0) {
|
if (bid > 0) {
|
||||||
if (!*bursts_p)
|
if (!*bursts_p)
|
||||||
return NULL;
|
return 0;
|
||||||
goto send_burst;
|
goto send_burst;
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch);
|
tx_tch_common(l1t, br->tn, br->fn, chan, bid, &msg_tch, &msg_facch);
|
||||||
|
|
||||||
/* BURST BYPASS */
|
/* BURST BYPASS */
|
||||||
|
|
||||||
|
@ -518,7 +517,7 @@ ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
if (!*bursts_p) {
|
if (!*bursts_p) {
|
||||||
*bursts_p = talloc_zero_size(tall_bts_ctx, 928);
|
*bursts_p = talloc_zero_size(tall_bts_ctx, 928);
|
||||||
if (!*bursts_p)
|
if (!*bursts_p)
|
||||||
return NULL;
|
return -ENOMEM;
|
||||||
} else {
|
} else {
|
||||||
memcpy(*bursts_p, *bursts_p + 464, 464);
|
memcpy(*bursts_p, *bursts_p + 464, 464);
|
||||||
memset(*bursts_p + 464, 0, 464);
|
memset(*bursts_p + 464, 0, 464);
|
||||||
|
@ -526,7 +525,7 @@ ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
|
|
||||||
/* no message at all */
|
/* no message at all */
|
||||||
if (!msg_tch && !msg_facch) {
|
if (!msg_tch && !msg_facch) {
|
||||||
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No TCH or FACCH prim for transmit.\n");
|
LOGL1S(DL1P, LOGL_INFO, l1t, br->tn, chan, br->fn, "No TCH or FACCH prim for transmit.\n");
|
||||||
goto send_burst;
|
goto send_burst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,7 +538,7 @@ ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
* the first FN 0,8,17 defines that CMR is included in frame.
|
* the first FN 0,8,17 defines that CMR is included in frame.
|
||||||
*/
|
*/
|
||||||
gsm0503_tch_afs_encode(*bursts_p, msg_tch->l2h + 2,
|
gsm0503_tch_afs_encode(*bursts_p, msg_tch->l2h + 2,
|
||||||
msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(fn),
|
msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(br->fn),
|
||||||
chan_state->codec, chan_state->codecs,
|
chan_state->codec, chan_state->codecs,
|
||||||
chan_state->dl_ft,
|
chan_state->dl_ft,
|
||||||
chan_state->dl_cmr);
|
chan_state->dl_cmr);
|
||||||
|
@ -555,16 +554,13 @@ ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
send_burst:
|
send_burst:
|
||||||
/* compose burst */
|
/* compose burst */
|
||||||
burst = *bursts_p + bid * 116;
|
burst = *bursts_p + bid * 116;
|
||||||
memset(bits, 0, 3);
|
memcpy(br->burst + 3, burst, 58);
|
||||||
memcpy(bits + 3, burst, 58);
|
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
||||||
memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
memcpy(br->burst + 87, burst + 58, 58);
|
||||||
memcpy(bits + 87, burst + 58, 58);
|
|
||||||
memset(bits + 145, 0, 3);
|
|
||||||
|
|
||||||
if (nbits)
|
br->burst_len = GSM_BURST_LEN;
|
||||||
*nbits = GSM_BURST_LEN;
|
|
||||||
|
|
||||||
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, br->tn, chan, br->fn, "Transmitting burst=%u.\n", bid);
|
||||||
|
|
||||||
return bits;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,30 +313,29 @@ extern void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
struct msgb **_msg_tch, struct msgb **_msg_facch);
|
struct msgb **_msg_tch, struct msgb **_msg_facch);
|
||||||
|
|
||||||
/* obtain a to-be-transmitted TCH/H (Half Traffic Channel) burst */
|
/* obtain a to-be-transmitted TCH/H (Half Traffic Channel) burst */
|
||||||
ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
||||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||||
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
|
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[br->tn];
|
||||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
||||||
uint8_t tch_mode = chan_state->tch_mode;
|
uint8_t tch_mode = chan_state->tch_mode;
|
||||||
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
|
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
|
||||||
static ubit_t bits[GSM_BURST_LEN];
|
|
||||||
|
|
||||||
/* send burst, if we already got a frame */
|
/* send burst, if we already got a frame */
|
||||||
if (bid > 0) {
|
if (bid > 0) {
|
||||||
if (!*bursts_p)
|
if (!*bursts_p)
|
||||||
return NULL;
|
return 0;
|
||||||
goto send_burst;
|
goto send_burst;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get TCH and/or FACCH */
|
/* get TCH and/or FACCH */
|
||||||
tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch);
|
tx_tch_common(l1t, br->tn, br->fn, chan, bid, &msg_tch, &msg_facch);
|
||||||
|
|
||||||
/* check for FACCH alignment */
|
/* check for FACCH alignment */
|
||||||
if (msg_facch && ((((fn + 4) % 26) >> 2) & 1)) {
|
if (msg_facch && ((((br->fn + 4) % 26) >> 2) & 1)) {
|
||||||
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot transmit FACCH starting on "
|
LOGL1S(DL1P, LOGL_ERROR, l1t, br->tn, chan, br->fn, "Cannot transmit FACCH starting on "
|
||||||
"even frames, please fix RTS!\n");
|
"even frames, please fix RTS!\n");
|
||||||
msgb_free(msg_facch);
|
msgb_free(msg_facch);
|
||||||
msg_facch = NULL;
|
msg_facch = NULL;
|
||||||
|
@ -349,7 +348,7 @@ ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
if (!*bursts_p) {
|
if (!*bursts_p) {
|
||||||
*bursts_p = talloc_zero_size(tall_bts_ctx, 696);
|
*bursts_p = talloc_zero_size(tall_bts_ctx, 696);
|
||||||
if (!*bursts_p)
|
if (!*bursts_p)
|
||||||
return NULL;
|
return -ENOMEM;
|
||||||
} else {
|
} else {
|
||||||
memcpy(*bursts_p, *bursts_p + 232, 232);
|
memcpy(*bursts_p, *bursts_p + 232, 232);
|
||||||
if (chan_state->dl_ongoing_facch) {
|
if (chan_state->dl_ongoing_facch) {
|
||||||
|
@ -362,7 +361,7 @@ ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
|
|
||||||
/* no message at all */
|
/* no message at all */
|
||||||
if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {
|
if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {
|
||||||
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No TCH or FACCH prim for transmit.\n");
|
LOGL1S(DL1P, LOGL_INFO, l1t, br->tn, chan, br->fn, "No TCH or FACCH prim for transmit.\n");
|
||||||
goto send_burst;
|
goto send_burst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,7 +376,7 @@ ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
* in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is
|
* in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is
|
||||||
* included in frame. */
|
* included in frame. */
|
||||||
gsm0503_tch_ahs_encode(*bursts_p, msg_tch->l2h + 2,
|
gsm0503_tch_ahs_encode(*bursts_p, msg_tch->l2h + 2,
|
||||||
msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(fn),
|
msgb_l2len(msg_tch) - 2, fn_is_codec_mode_request(br->fn),
|
||||||
chan_state->codec, chan_state->codecs,
|
chan_state->codec, chan_state->codecs,
|
||||||
chan_state->dl_ft,
|
chan_state->dl_ft,
|
||||||
chan_state->dl_cmr);
|
chan_state->dl_cmr);
|
||||||
|
@ -393,16 +392,13 @@ ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
send_burst:
|
send_burst:
|
||||||
/* compose burst */
|
/* compose burst */
|
||||||
burst = *bursts_p + bid * 116;
|
burst = *bursts_p + bid * 116;
|
||||||
memset(bits, 0, 3);
|
memcpy(br->burst + 3, burst, 58);
|
||||||
memcpy(bits + 3, burst, 58);
|
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
||||||
memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
memcpy(br->burst + 87, burst + 58, 58);
|
||||||
memcpy(bits + 87, burst + 58, 58);
|
|
||||||
memset(bits + 145, 0, 3);
|
|
||||||
|
|
||||||
if (nbits)
|
br->burst_len = GSM_BURST_LEN;
|
||||||
*nbits = GSM_BURST_LEN;
|
|
||||||
|
|
||||||
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, br->tn, chan, br->fn, "Transmitting burst=%u.\n", bid);
|
||||||
|
|
||||||
return bits;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,28 +145,27 @@ int rx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* obtain a to-be-transmitted xCCH (e.g SACCH or SDCCH) burst */
|
/* obtain a to-be-transmitted xCCH (e.g SACCH or SDCCH) burst */
|
||||||
ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||||
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
|
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[br->tn];
|
||||||
struct msgb *msg = NULL; /* make GCC happy */
|
struct msgb *msg = NULL; /* make GCC happy */
|
||||||
ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;
|
ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts;
|
||||||
static ubit_t bits[GSM_BURST_LEN];
|
|
||||||
|
|
||||||
/* send burst, if we already got a frame */
|
/* send burst, if we already got a frame */
|
||||||
if (bid > 0) {
|
if (bid > 0) {
|
||||||
if (!*bursts_p)
|
if (!*bursts_p)
|
||||||
return NULL;
|
return 0;
|
||||||
goto send_burst;
|
goto send_burst;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get mac block from queue */
|
/* get mac block from queue */
|
||||||
msg = _sched_dequeue_prim(l1t, tn, fn, chan);
|
msg = _sched_dequeue_prim(l1t, br->tn, br->fn, chan);
|
||||||
if (msg)
|
if (msg)
|
||||||
goto got_msg;
|
goto got_msg;
|
||||||
|
|
||||||
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "No prim for transmit.\n");
|
LOGL1S(DL1P, LOGL_INFO, l1t, br->tn, chan, br->fn, "No prim for transmit.\n");
|
||||||
|
|
||||||
no_msg:
|
no_msg:
|
||||||
/* free burst memory */
|
/* free burst memory */
|
||||||
|
@ -174,12 +173,12 @@ no_msg:
|
||||||
talloc_free(*bursts_p);
|
talloc_free(*bursts_p);
|
||||||
*bursts_p = NULL;
|
*bursts_p = NULL;
|
||||||
}
|
}
|
||||||
return NULL;
|
return -ENODEV;
|
||||||
|
|
||||||
got_msg:
|
got_msg:
|
||||||
/* check validity of message */
|
/* check validity of message */
|
||||||
if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {
|
if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {
|
||||||
LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! "
|
LOGL1S(DL1P, LOGL_FATAL, l1t, br->tn, chan, br->fn, "Prim not 23 bytes, please FIX! "
|
||||||
"(len=%d)\n", msgb_l2len(msg));
|
"(len=%d)\n", msgb_l2len(msg));
|
||||||
/* free message */
|
/* free message */
|
||||||
msgb_free(msg);
|
msgb_free(msg);
|
||||||
|
@ -197,7 +196,7 @@ got_msg:
|
||||||
|
|
||||||
/* Note: RSSI is set to 0 to indicate to the higher
|
/* Note: RSSI is set to 0 to indicate to the higher
|
||||||
* layers that this is a faked ph_data_ind */
|
* layers that this is a faked ph_data_ind */
|
||||||
_sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0,
|
_sched_compose_ph_data_ind(l1t, br->tn, 0, chan, NULL, 0,
|
||||||
0, 0, 0, 10000,
|
0, 0, 0, 10000,
|
||||||
PRES_INFO_INVALID);
|
PRES_INFO_INVALID);
|
||||||
}
|
}
|
||||||
|
@ -207,7 +206,7 @@ got_msg:
|
||||||
if (!*bursts_p) {
|
if (!*bursts_p) {
|
||||||
*bursts_p = talloc_zero_size(tall_bts_ctx, 464);
|
*bursts_p = talloc_zero_size(tall_bts_ctx, 464);
|
||||||
if (!*bursts_p)
|
if (!*bursts_p)
|
||||||
return NULL;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* encode bursts */
|
/* encode bursts */
|
||||||
|
@ -219,16 +218,13 @@ got_msg:
|
||||||
send_burst:
|
send_burst:
|
||||||
/* compose burst */
|
/* compose burst */
|
||||||
burst = *bursts_p + bid * 116;
|
burst = *bursts_p + bid * 116;
|
||||||
memset(bits, 0, 3);
|
memcpy(br->burst + 3, burst, 58);
|
||||||
memcpy(bits + 3, burst, 58);
|
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
||||||
memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
|
memcpy(br->burst + 87, burst + 58, 58);
|
||||||
memcpy(bits + 87, burst + 58, 58);
|
|
||||||
memset(bits + 145, 0, 3);
|
|
||||||
|
|
||||||
if (nbits)
|
br->burst_len = GSM_BURST_LEN;
|
||||||
*nbits = GSM_BURST_LEN;
|
|
||||||
|
|
||||||
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting burst=%u.\n", bid);
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, br->tn, chan, br->fn, "Transmitting burst=%u.\n", bid);
|
||||||
|
|
||||||
return bits;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,25 +48,19 @@
|
||||||
#include "trx_if.h"
|
#include "trx_if.h"
|
||||||
|
|
||||||
/* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */
|
/* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */
|
||||||
ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_idle_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting IDLE\n");
|
LOGL1S(DL1P, LOGL_DEBUG, l1t, br->tn, chan, br->fn, "Transmitting IDLE\n");
|
||||||
|
return 0;
|
||||||
if (nbits)
|
|
||||||
*nbits = GSM_BURST_LEN;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* schedule all frames of all TRX for given FN */
|
/* schedule all frames of all TRX for given FN */
|
||||||
static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn)
|
static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn)
|
||||||
{
|
{
|
||||||
|
struct trx_dl_burst_req br;
|
||||||
struct gsm_bts_trx *trx;
|
struct gsm_bts_trx *trx;
|
||||||
uint8_t tn;
|
uint8_t tn;
|
||||||
const ubit_t *bits;
|
|
||||||
uint8_t gain;
|
|
||||||
uint16_t nbits = 0;
|
|
||||||
|
|
||||||
/* send time indication */
|
/* send time indication */
|
||||||
l1if_mph_time_ind(bts, fn);
|
l1if_mph_time_ind(bts, fn);
|
||||||
|
@ -91,15 +85,21 @@ static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn)
|
||||||
/* ready-to-send */
|
/* ready-to-send */
|
||||||
_sched_rts(l1t, tn,
|
_sched_rts(l1t, tn,
|
||||||
(fn + plink->u.osmotrx.rts_advance) % GSM_HYPERFRAME);
|
(fn + plink->u.osmotrx.rts_advance) % GSM_HYPERFRAME);
|
||||||
|
|
||||||
|
/* TODO: Tx attenuation is always 0? */
|
||||||
|
br = (struct trx_dl_burst_req) {
|
||||||
|
.fn = fn, .tn = tn,
|
||||||
|
.att = 0,
|
||||||
|
};
|
||||||
|
|
||||||
/* get burst for FN */
|
/* get burst for FN */
|
||||||
bits = _sched_dl_burst(l1t, tn, fn, &nbits);
|
_sched_dl_burst(l1t, &br);
|
||||||
if (!bits) {
|
if (br.burst_len == 0) {
|
||||||
/* if no bits, send no burst */
|
/* if no bits, send no burst */
|
||||||
continue;
|
continue;
|
||||||
} else
|
}
|
||||||
gain = 0;
|
|
||||||
if (nbits)
|
trx_if_send_burst(l1h, &br);
|
||||||
trx_if_send_burst(l1h, tn, fn, gain, bits, nbits);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1101,27 +1101,23 @@ skip_burst:
|
||||||
|
|
||||||
/*! Send burst data for given FN/timeslot to TRX
|
/*! Send burst data for given FN/timeslot to TRX
|
||||||
* \param[inout] l1h TRX Layer1 handle referring to TX
|
* \param[inout] l1h TRX Layer1 handle referring to TX
|
||||||
* \param[in] tn Timeslot Number (0..7)
|
* \param[in] br Downlink burst request structure
|
||||||
* \param[in] fn GSM Frame Number
|
|
||||||
* \param[in] pwr Transmit Power to use
|
|
||||||
* \param[in] bits Unpacked bits to be transmitted
|
|
||||||
* \param[in] nbits Number of \a bits
|
|
||||||
* \returns 0 on success; negative on error */
|
* \returns 0 on success; negative on error */
|
||||||
int trx_if_send_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr,
|
int trx_if_send_burst(struct trx_l1h *l1h, const struct trx_dl_burst_req *br)
|
||||||
const ubit_t *bits, uint16_t nbits)
|
|
||||||
{
|
{
|
||||||
ssize_t snd_len;
|
ssize_t snd_len;
|
||||||
uint8_t hdr_ver = l1h->config.trxd_hdr_ver_use;
|
uint8_t hdr_ver = l1h->config.trxd_hdr_ver_use;
|
||||||
uint8_t buf[TRX_DATA_MSG_MAX_LEN];
|
uint8_t buf[TRX_DATA_MSG_MAX_LEN];
|
||||||
|
|
||||||
if ((nbits != GSM_BURST_LEN) && (nbits != EGPRS_BURST_LEN)) {
|
if ((br->burst_len != GSM_BURST_LEN) && (br->burst_len != EGPRS_BURST_LEN)) {
|
||||||
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR, "Tx burst length %u invalid\n", nbits);
|
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR, "Tx burst length %zu invalid\n",
|
||||||
|
br->burst_len);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG,
|
LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG,
|
||||||
"Tx burst (hdr_ver=%u): tn=%u fn=%u pwr=%u\n",
|
"Tx burst (hdr_ver=%u): tn=%u fn=%u att=%u\n",
|
||||||
hdr_ver, tn, fn, pwr);
|
hdr_ver, br->tn, br->fn, br->att);
|
||||||
|
|
||||||
switch (hdr_ver) {
|
switch (hdr_ver) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -1135,16 +1131,16 @@ int trx_if_send_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr,
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[0] = ((hdr_ver & 0x0f) << 4) | tn;
|
buf[0] = ((hdr_ver & 0x0f) << 4) | br->tn;
|
||||||
osmo_store32be(fn, buf + 1);
|
osmo_store32be(br->fn, buf + 1);
|
||||||
buf[5] = pwr;
|
buf[5] = br->att;
|
||||||
|
|
||||||
/* copy ubits {0,1} */
|
/* copy ubits {0,1} */
|
||||||
memcpy(buf + 6, bits, nbits);
|
memcpy(buf + 6, br->burst, br->burst_len);
|
||||||
|
|
||||||
/* we must be sure that TRX is on */
|
/* we must be sure that TRX is on */
|
||||||
if (trx_if_powered(l1h)) {
|
if (trx_if_powered(l1h)) {
|
||||||
snd_len = send(l1h->trx_ofd_data.fd, buf, nbits + 6, 0);
|
snd_len = send(l1h->trx_ofd_data.fd, buf, br->burst_len + 6, 0);
|
||||||
if (snd_len <= 0) {
|
if (snd_len <= 0) {
|
||||||
strerror_r(errno, (char *)buf, sizeof(buf));
|
strerror_r(errno, (char *)buf, sizeof(buf));
|
||||||
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
|
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef TRX_IF_H
|
#ifndef TRX_IF_H
|
||||||
#define TRX_IF_H
|
#define TRX_IF_H
|
||||||
|
|
||||||
|
struct trx_dl_burst_req;
|
||||||
struct trx_l1h;
|
struct trx_l1h;
|
||||||
|
|
||||||
struct trx_ctrl_msg {
|
struct trx_ctrl_msg {
|
||||||
|
@ -33,8 +34,7 @@ int trx_if_cmd_rxtune(struct trx_l1h *l1h, uint16_t arfcn);
|
||||||
int trx_if_cmd_txtune(struct trx_l1h *l1h, uint16_t arfcn);
|
int trx_if_cmd_txtune(struct trx_l1h *l1h, uint16_t arfcn);
|
||||||
int trx_if_cmd_handover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss);
|
int trx_if_cmd_handover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss);
|
||||||
int trx_if_cmd_nohandover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss);
|
int trx_if_cmd_nohandover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss);
|
||||||
int trx_if_send_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr,
|
int trx_if_send_burst(struct trx_l1h *l1h, const struct trx_dl_burst_req *br);
|
||||||
const ubit_t *bits, uint16_t nbits);
|
|
||||||
int trx_if_powered(struct trx_l1h *l1h);
|
int trx_if_powered(struct trx_l1h *l1h);
|
||||||
|
|
||||||
/* The latest supported TRXD header format version */
|
/* The latest supported TRXD header format version */
|
||||||
|
|
|
@ -173,72 +173,72 @@ static void tx_to_virt_um_voice_frame(struct l1sched_trx *l1t, uint8_t tn, uint3
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */
|
/* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */
|
||||||
ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_idle_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_fcch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_sch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
struct msgb *msg;
|
struct msgb *msg;
|
||||||
|
|
||||||
if (bid > 0)
|
if (bid > 0)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
/* get mac block from queue */
|
/* get mac block from queue */
|
||||||
msg = _sched_dequeue_prim(l1t, tn, fn, chan);
|
msg = _sched_dequeue_prim(l1t, br->tn, br->fn, chan);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n");
|
LOGL1S(DL1P, LOGL_INFO, l1t, br->tn, chan, br->fn, "has not been served !! No prim\n");
|
||||||
return NULL;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check validity of message */
|
/* check validity of message */
|
||||||
if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {
|
if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) {
|
||||||
LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! (len=%d)\n",
|
LOGL1S(DL1P, LOGL_FATAL, l1t, br->tn, chan, br->fn, "Prim not 23 bytes, please FIX! (len=%d)\n",
|
||||||
msgb_l2len(msg));
|
msgb_l2len(msg));
|
||||||
/* free message */
|
/* free message */
|
||||||
msgb_free(msg);
|
msgb_free(msg);
|
||||||
return NULL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* transmit the msg received on dl from bsc to layer1 (virt Um) */
|
/* transmit the msg received on dl from bsc to layer1 (virt Um) */
|
||||||
tx_to_virt_um(l1t, tn, fn, chan, msg);
|
tx_to_virt_um(l1t, br->tn, br->fn, chan, msg);
|
||||||
|
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
struct msgb *msg = NULL; /* make GCC happy */
|
struct msgb *msg = NULL; /* make GCC happy */
|
||||||
|
|
||||||
if (bid > 0)
|
if (bid > 0)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
/* get mac block from queue */
|
/* get mac block from queue */
|
||||||
msg = _sched_dequeue_prim(l1t, tn, fn, chan);
|
msg = _sched_dequeue_prim(l1t, br->tn, br->fn, chan);
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n");
|
LOGL1S(DL1P, LOGL_INFO, l1t, br->tn, chan, br->fn, "has not been served !! No prim\n");
|
||||||
return NULL;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_to_virt_um(l1t, tn, fn, chan, msg);
|
tx_to_virt_um(l1t, br->tn, br->fn, chan, msg);
|
||||||
|
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
|
@ -418,53 +418,51 @@ send_frame:
|
||||||
*_msg_facch = msg_facch;
|
*_msg_facch = msg_facch;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
||||||
|
|
||||||
if (bid > 0)
|
if (bid > 0)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch,
|
tx_tch_common(l1t, br->tn, br->fn, chan, bid, &msg_tch, &msg_facch,
|
||||||
(((fn + 4) % 26) >> 2) & 1);
|
(((br->fn + 4) % 26) >> 2) & 1);
|
||||||
|
|
||||||
/* no message at all */
|
/* no message at all */
|
||||||
if (!msg_tch && !msg_facch) {
|
if (!msg_tch && !msg_facch) {
|
||||||
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n");
|
LOGL1S(DL1P, LOGL_INFO, l1t, br->tn, chan, br->fn, "has not been served !! No prim\n");
|
||||||
goto send_burst;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg_facch) {
|
if (msg_facch) {
|
||||||
tx_to_virt_um(l1t, tn, fn, chan, msg_facch);
|
tx_to_virt_um(l1t, br->tn, br->fn, chan, msg_facch);
|
||||||
msgb_free(msg_tch);
|
msgb_free(msg_tch);
|
||||||
} else if (msg_tch)
|
} else if (msg_tch)
|
||||||
tx_to_virt_um_voice_frame(l1t, tn, fn, chan, msg_tch);
|
tx_to_virt_um_voice_frame(l1t, br->tn, br->fn, chan, msg_tch);
|
||||||
|
|
||||||
send_burst:
|
return 0;
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
int tx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
|
||||||
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
|
uint8_t bid, struct trx_dl_burst_req *br)
|
||||||
{
|
{
|
||||||
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
struct msgb *msg_tch = NULL, *msg_facch = NULL;
|
||||||
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
|
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, br->tn);
|
||||||
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan];
|
||||||
//uint8_t tch_mode = chan_state->tch_mode;
|
//uint8_t tch_mode = chan_state->tch_mode;
|
||||||
|
|
||||||
/* send burst, if we already got a frame */
|
/* send burst, if we already got a frame */
|
||||||
if (bid > 0)
|
if (bid > 0)
|
||||||
return NULL;
|
return 0;
|
||||||
|
|
||||||
/* get TCH and/or FACCH */
|
/* get TCH and/or FACCH */
|
||||||
tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch,
|
tx_tch_common(l1t, br->tn, br->fn, chan, bid, &msg_tch, &msg_facch,
|
||||||
(((fn + 4) % 26) >> 2) & 1);
|
(((br->fn + 4) % 26) >> 2) & 1);
|
||||||
|
|
||||||
/* check for FACCH alignment */
|
/* check for FACCH alignment */
|
||||||
if (msg_facch && ((((fn + 4) % 26) >> 2) & 1)) {
|
if (msg_facch && ((((br->fn + 4) % 26) >> 2) & 1)) {
|
||||||
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot transmit FACCH starting on "
|
LOGL1S(DL1P, LOGL_ERROR, l1t, br->tn, chan, br->fn, "Cannot transmit FACCH starting on "
|
||||||
"even frames, please fix RTS!\n");
|
"even frames, please fix RTS!\n");
|
||||||
msgb_free(msg_facch);
|
msgb_free(msg_facch);
|
||||||
msg_facch = NULL;
|
msg_facch = NULL;
|
||||||
|
@ -472,18 +470,17 @@ ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
|
||||||
|
|
||||||
/* no message at all */
|
/* no message at all */
|
||||||
if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {
|
if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) {
|
||||||
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n");
|
LOGL1S(DL1P, LOGL_INFO, l1t, br->tn, chan, br->fn, "has not been served !! No prim\n");
|
||||||
goto send_burst;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg_facch) {
|
if (msg_facch) {
|
||||||
tx_to_virt_um(l1t, tn, fn, chan, msg_facch);
|
tx_to_virt_um(l1t, br->tn, br->fn, chan, msg_facch);
|
||||||
msgb_free(msg_tch);
|
msgb_free(msg_tch);
|
||||||
} else if (msg_tch)
|
} else if (msg_tch)
|
||||||
tx_to_virt_um_voice_frame(l1t, tn, fn, chan, msg_tch);
|
tx_to_virt_um_voice_frame(l1t, br->tn, br->fn, chan, msg_tch);
|
||||||
|
|
||||||
send_burst:
|
return 0;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -550,11 +547,10 @@ static int vbts_sched_fn(struct gsm_bts *bts, uint32_t fn)
|
||||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||||
struct phy_instance *pinst = trx_phy_instance(trx);
|
struct phy_instance *pinst = trx_phy_instance(trx);
|
||||||
struct l1sched_trx *l1t = &pinst->u.virt.sched;
|
struct l1sched_trx *l1t = &pinst->u.virt.sched;
|
||||||
int tn;
|
struct trx_dl_burst_req br = { .fn = fn };
|
||||||
uint16_t nbits;
|
|
||||||
|
|
||||||
/* do for each of the 8 timeslots */
|
/* do for each of the 8 timeslots */
|
||||||
for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) {
|
for (br.tn = 0; br.tn < ARRAY_SIZE(l1t->ts); br.tn++) {
|
||||||
/* Generate RTS indication to higher layers */
|
/* Generate RTS indication to higher layers */
|
||||||
/* This will basically do 2 things (check l1_if:bts_model_l1sap_down):
|
/* This will basically do 2 things (check l1_if:bts_model_l1sap_down):
|
||||||
* 1) Get pending messages from layer 2 (from the lapdm queue)
|
* 1) Get pending messages from layer 2 (from the lapdm queue)
|
||||||
|
@ -562,13 +558,13 @@ static int vbts_sched_fn(struct gsm_bts *bts, uint32_t fn)
|
||||||
* --> Handle and process non-transparent RSL-Messages (activate channel, )
|
* --> Handle and process non-transparent RSL-Messages (activate channel, )
|
||||||
* --> Forward transparent RSL-DATA-Messages to the ms by appending them to
|
* --> Forward transparent RSL-DATA-Messages to the ms by appending them to
|
||||||
* the l1-dl-queue */
|
* the l1-dl-queue */
|
||||||
_sched_rts(l1t, tn, (fn + RTS_ADVANCE) % GSM_HYPERFRAME);
|
_sched_rts(l1t, br.tn, (fn + RTS_ADVANCE) % GSM_HYPERFRAME);
|
||||||
/* schedule transmit backend functions */
|
/* schedule transmit backend functions */
|
||||||
/* Process data in the l1-dlqueue and forward it
|
/* Process data in the l1-dlqueue and forward it
|
||||||
* to MS */
|
* to MS */
|
||||||
/* the returned bits are not used here, the routines called will directly forward their
|
/* the returned bits are not used here, the routines called will directly forward their
|
||||||
* bits to the virt Um */
|
* bits to the virt Um */
|
||||||
_sched_dl_burst(l1t, tn, fn, &nbits);
|
_sched_dl_burst(l1t, &br);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue