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:
Vadim Yanitskiy 2020-06-13 21:45:33 +07:00 committed by fixeria
parent 36c5ec4881
commit ae781bc5cd
12 changed files with 214 additions and 241 deletions

View File

@ -250,6 +250,17 @@ struct trx_ul_burst_ind {
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 */
int trx_sched_ul_burst(struct l1sched_trx *l1t, struct trx_ul_burst_ind *bi);

View File

@ -9,9 +9,8 @@
typedef int trx_sched_rts_func(struct l1sched_trx *l1t, uint8_t tn,
uint32_t fn, enum trx_chan_type chan);
typedef ubit_t *trx_sched_dl_func(struct l1sched_trx *l1t, uint8_t tn,
uint32_t fn, enum trx_chan_type chan,
uint8_t bid, uint16_t *nbits);
typedef int trx_sched_dl_func(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br);
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);
@ -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,
uint8_t is_sub);
ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits);
int tx_idle_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br);
int tx_fcch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br);
int tx_sch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br);
int tx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br);
int tx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br);
int tx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br);
int tx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br);
int rx_rach_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, const struct trx_ul_burst_ind *bi);
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,
uint8_t bid, const struct trx_ul_burst_ind *bi);
const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn,
uint32_t fn, uint16_t *nbits);
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);

View File

@ -1154,23 +1154,21 @@ int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn)
}
/* process downlink burst */
const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn,
uint32_t fn, uint16_t *nbits)
void _sched_dl_burst(struct l1sched_trx *l1t, 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 l1sched_chan_state *l1cs;
const struct trx_sched_frame *frame;
uint8_t offset, period, bid;
trx_sched_dl_func *func;
enum trx_chan_type chan;
ubit_t *bits = NULL;
if (!l1ts->mf_index)
goto no_data;
/* get frame from multiframe */
period = l1ts->mf_period;
offset = fn % period;
offset = br->fn % period;
frame = l1ts->mf_frames + offset;
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];
/* check if channel is active */
if (!TRX_CHAN_IS_ACTIVE(l1cs, chan)) {
if (nbits)
*nbits = GSM_BURST_LEN;
if (!TRX_CHAN_IS_ACTIVE(l1cs, chan))
goto no_data;
}
/* get burst from function */
bits = func(l1t, tn, fn, chan, bid, nbits);
if (func(l1t, chan, bid, br) != 0)
goto no_data;
/* encrypt */
if (bits && l1cs->dl_encr_algo) {
if (br->burst_len && l1cs->dl_encr_algo) {
ubit_t ks[114];
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++) {
bits[i + 3] ^= ks[i];
bits[i + 88] ^= ks[i + 57];
br->burst[i + 3] ^= ks[i];
br->burst[i + 88] ^= ks[i + 57];
}
}
no_data:
/* 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 (chan != TRXC_IDLE) // hack
LOGP(DL1C, LOGL_DEBUG, "No burst data for %s fn=%u ts=%u "
"burst=%d on C0, so filling with dummy burst\n",
trx_chan_desc[chan].name, fn, tn, bid);
#endif
bits = (ubit_t *) dummy_burst;
if (nbits)
*nbits = ARRAY_SIZE(dummy_burst);
memcpy(br->burst, dummy_burst, ARRAY_SIZE(dummy_burst));
br->burst_len = ARRAY_SIZE(dummy_burst);
}
return bits;
}
#define TDMA_FN_SUM(a, b) \

View File

@ -35,34 +35,32 @@
#include <sched_utils.h>
/* 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,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_fcch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
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)
*nbits = GSM_BURST_LEN;
memcpy(br->burst, _sched_fcch_burst, GSM_BURST_LEN);
br->burst_len = GSM_BURST_LEN;
/* BURST BYPASS */
return (ubit_t *) _sched_fcch_burst;
return 0;
}
/* obtain a to-be-transmitted SCH (synchronization channel) burst */
ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_sch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
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];
struct gsm_time t;
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 */
/* create SB info from GSM time and BSIC */
gsm_fn2gsmtime(&t, fn);
gsm_fn2gsmtime(&t, br->fn);
t3p = t.t3 / 10;
bsic = l1t->trx->bts->bsic;
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);
/* compose burst */
memset(bits, 0, 3);
memcpy(bits + 3, burst, 39);
memcpy(bits + 42, _sched_sch_train, 64);
memcpy(bits + 106, burst + 39, 39);
memset(bits + 145, 0, 3);
memcpy(br->burst + 3, burst, 39);
memcpy(br->burst + 42, _sched_sch_train, 64);
memcpy(br->burst + 106, burst + 39, 39);
if (nbits)
*nbits = GSM_BURST_LEN;
br->burst_len = GSM_BURST_LEN;
return bits;
return 0;
}

View File

@ -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 */
ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br)
{
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
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[chan].dl_bursts;
enum trx_burst_type *burst_type = &l1ts->chan_state[chan].dl_burst_type;
static ubit_t bits[EGPRS_BURST_LEN];
int rc = 0;
/* send burst, if we already got a frame */
if (bid > 0) {
if (!*bursts_p)
return NULL;
return 0;
goto send_burst;
}
/* 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)
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:
/* free burst memory */
@ -185,7 +184,7 @@ no_msg:
talloc_free(*bursts_p);
*bursts_p = NULL;
}
return NULL;
return -ENODEV;
got_msg:
/* BURST BYPASS */
@ -195,7 +194,7 @@ got_msg:
*bursts_p = talloc_zero_size(tall_bts_ctx,
GSM0503_EGPRS_BURSTS_NBITS);
if (!*bursts_p)
return NULL;
return -ENOMEM;
}
/* encode bursts */
@ -205,7 +204,7 @@ got_msg:
/* check validity of message */
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));
/* free message */
msgb_free(msg);
@ -223,27 +222,23 @@ send_burst:
/* compose burst */
if (*burst_type == TRX_BURST_8PSK) {
burst = *bursts_p + bid * 348;
memset(bits, 1, 9);
memcpy(bits + 9, burst, 174);
memcpy(bits + 183, _sched_egprs_tsc[gsm_ts_tsc(ts)], 78);
memcpy(bits + 261, burst + 174, 174);
memset(bits + 435, 1, 9);
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 + 261, burst + 174, 174);
memset(br->burst + 435, 1, 9);
if (nbits)
*nbits = EGPRS_BURST_LEN;
br->burst_len = EGPRS_BURST_LEN;
} else {
burst = *bursts_p + bid * 116;
memset(bits, 0, 3);
memcpy(bits + 3, burst, 58);
memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
memcpy(bits + 87, burst + 58, 58);
memset(bits + 145, 0, 3);
memcpy(br->burst + 3, burst, 58);
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
memcpy(br->burst + 87, burst + 58, 58);
if (nbits)
*nbits = GSM_BURST_LEN;
br->burst_len = 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;
}

View File

@ -491,25 +491,24 @@ send_frame:
}
/* 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,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br)
{
struct msgb *msg_tch = NULL, *msg_facch = NULL;
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
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[chan];
uint8_t tch_mode = chan_state->tch_mode;
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
static ubit_t bits[GSM_BURST_LEN];
/* send burst, if we already got a frame */
if (bid > 0) {
if (!*bursts_p)
return NULL;
return 0;
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 */
@ -518,7 +517,7 @@ ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
if (!*bursts_p) {
*bursts_p = talloc_zero_size(tall_bts_ctx, 928);
if (!*bursts_p)
return NULL;
return -ENOMEM;
} else {
memcpy(*bursts_p, *bursts_p + 464, 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 */
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;
}
@ -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.
*/
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->dl_ft,
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:
/* compose burst */
burst = *bursts_p + bid * 116;
memset(bits, 0, 3);
memcpy(bits + 3, burst, 58);
memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
memcpy(bits + 87, burst + 58, 58);
memset(bits + 145, 0, 3);
memcpy(br->burst + 3, burst, 58);
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
memcpy(br->burst + 87, burst + 58, 58);
if (nbits)
*nbits = GSM_BURST_LEN;
br->burst_len = 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;
}

View File

@ -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);
/* 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,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br)
{
struct msgb *msg_tch = NULL, *msg_facch = NULL;
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
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[chan];
uint8_t tch_mode = chan_state->tch_mode;
ubit_t *burst, **bursts_p = &chan_state->dl_bursts;
static ubit_t bits[GSM_BURST_LEN];
/* send burst, if we already got a frame */
if (bid > 0) {
if (!*bursts_p)
return NULL;
return 0;
goto send_burst;
}
/* 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 */
if (msg_facch && ((((fn + 4) % 26) >> 2) & 1)) {
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot transmit FACCH starting on "
if (msg_facch && ((((br->fn + 4) % 26) >> 2) & 1)) {
LOGL1S(DL1P, LOGL_ERROR, l1t, br->tn, chan, br->fn, "Cannot transmit FACCH starting on "
"even frames, please fix RTS!\n");
msgb_free(msg_facch);
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) {
*bursts_p = talloc_zero_size(tall_bts_ctx, 696);
if (!*bursts_p)
return NULL;
return -ENOMEM;
} else {
memcpy(*bursts_p, *bursts_p + 232, 232);
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 */
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;
}
@ -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
* included in frame. */
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->dl_ft,
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:
/* compose burst */
burst = *bursts_p + bid * 116;
memset(bits, 0, 3);
memcpy(bits + 3, burst, 58);
memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
memcpy(bits + 87, burst + 58, 58);
memset(bits + 145, 0, 3);
memcpy(br->burst + 3, burst, 58);
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
memcpy(br->burst + 87, burst + 58, 58);
if (nbits)
*nbits = GSM_BURST_LEN;
br->burst_len = 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;
}

View File

@ -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 */
ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br)
{
struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn);
struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn];
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[chan].dl_bursts;
static ubit_t bits[GSM_BURST_LEN];
/* send burst, if we already got a frame */
if (bid > 0) {
if (!*bursts_p)
return NULL;
return 0;
goto send_burst;
}
/* 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)
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:
/* free burst memory */
@ -174,12 +173,12 @@ no_msg:
talloc_free(*bursts_p);
*bursts_p = NULL;
}
return NULL;
return -ENODEV;
got_msg:
/* check validity of message */
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));
/* free message */
msgb_free(msg);
@ -197,7 +196,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, tn, 0, chan, NULL, 0,
_sched_compose_ph_data_ind(l1t, br->tn, 0, chan, NULL, 0,
0, 0, 0, 10000,
PRES_INFO_INVALID);
}
@ -207,7 +206,7 @@ got_msg:
if (!*bursts_p) {
*bursts_p = talloc_zero_size(tall_bts_ctx, 464);
if (!*bursts_p)
return NULL;
return -ENOMEM;
}
/* encode bursts */
@ -219,16 +218,13 @@ got_msg:
send_burst:
/* compose burst */
burst = *bursts_p + bid * 116;
memset(bits, 0, 3);
memcpy(bits + 3, burst, 58);
memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
memcpy(bits + 87, burst + 58, 58);
memset(bits + 145, 0, 3);
memcpy(br->burst + 3, burst, 58);
memcpy(br->burst + 61, _sched_tsc[gsm_ts_tsc(ts)], 26);
memcpy(br->burst + 87, burst + 58, 58);
if (nbits)
*nbits = GSM_BURST_LEN;
br->burst_len = 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;
}

View File

@ -48,25 +48,19 @@
#include "trx_if.h"
/* 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,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_idle_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br)
{
LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, "Transmitting IDLE\n");
if (nbits)
*nbits = GSM_BURST_LEN;
return NULL;
LOGL1S(DL1P, LOGL_DEBUG, l1t, br->tn, chan, br->fn, "Transmitting IDLE\n");
return 0;
}
/* schedule all frames of all TRX for given FN */
static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn)
{
struct trx_dl_burst_req br;
struct gsm_bts_trx *trx;
uint8_t tn;
const ubit_t *bits;
uint8_t gain;
uint16_t nbits = 0;
/* send time indication */
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 */
_sched_rts(l1t, tn,
(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 */
bits = _sched_dl_burst(l1t, tn, fn, &nbits);
if (!bits) {
_sched_dl_burst(l1t, &br);
if (br.burst_len == 0) {
/* if no bits, send no burst */
continue;
} else
gain = 0;
if (nbits)
trx_if_send_burst(l1h, tn, fn, gain, bits, nbits);
}
trx_if_send_burst(l1h, &br);
}
}

View File

@ -1101,27 +1101,23 @@ skip_burst:
/*! Send burst data for given FN/timeslot to TRX
* \param[inout] l1h TRX Layer1 handle referring to TX
* \param[in] tn Timeslot Number (0..7)
* \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
* \param[in] br Downlink burst request structure
* \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,
const ubit_t *bits, uint16_t nbits)
int trx_if_send_burst(struct trx_l1h *l1h, const struct trx_dl_burst_req *br)
{
ssize_t snd_len;
uint8_t hdr_ver = l1h->config.trxd_hdr_ver_use;
uint8_t buf[TRX_DATA_MSG_MAX_LEN];
if ((nbits != GSM_BURST_LEN) && (nbits != EGPRS_BURST_LEN)) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR, "Tx burst length %u invalid\n", nbits);
if ((br->burst_len != GSM_BURST_LEN) && (br->burst_len != EGPRS_BURST_LEN)) {
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR, "Tx burst length %zu invalid\n",
br->burst_len);
return -1;
}
LOGPPHI(l1h->phy_inst, DTRX, LOGL_DEBUG,
"Tx burst (hdr_ver=%u): tn=%u fn=%u pwr=%u\n",
hdr_ver, tn, fn, pwr);
"Tx burst (hdr_ver=%u): tn=%u fn=%u att=%u\n",
hdr_ver, br->tn, br->fn, br->att);
switch (hdr_ver) {
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;
}
buf[0] = ((hdr_ver & 0x0f) << 4) | tn;
osmo_store32be(fn, buf + 1);
buf[5] = pwr;
buf[0] = ((hdr_ver & 0x0f) << 4) | br->tn;
osmo_store32be(br->fn, buf + 1);
buf[5] = br->att;
/* 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 */
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) {
strerror_r(errno, (char *)buf, sizeof(buf));
LOGPPHI(l1h->phy_inst, DTRX, LOGL_ERROR,

View File

@ -1,6 +1,7 @@
#ifndef TRX_IF_H
#define TRX_IF_H
struct trx_dl_burst_req;
struct trx_l1h;
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_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_send_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr,
const ubit_t *bits, uint16_t nbits);
int trx_if_send_burst(struct trx_l1h *l1h, const struct trx_dl_burst_req *br);
int trx_if_powered(struct trx_l1h *l1h);
/* The latest supported TRXD header format version */

View File

@ -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 */
ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_idle_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
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,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_fcch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
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,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_sch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
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,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_data_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br)
{
struct msgb *msg;
if (bid > 0)
return NULL;
return 0;
/* 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) {
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n");
return NULL;
LOGL1S(DL1P, LOGL_INFO, l1t, br->tn, chan, br->fn, "has not been served !! No prim\n");
return -ENODEV;
}
/* check validity of message */
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));
/* free message */
msgb_free(msg);
return NULL;
return -EINVAL;
}
/* 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,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_pdtch_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br)
{
struct msgb *msg = NULL; /* make GCC happy */
if (bid > 0)
return NULL;
return 0;
/* 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) {
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n");
return NULL;
LOGL1S(DL1P, LOGL_INFO, l1t, br->tn, chan, br->fn, "has not been served !! No prim\n");
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,
@ -418,53 +418,51 @@ send_frame:
*_msg_facch = msg_facch;
}
ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_tchf_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br)
{
struct msgb *msg_tch = NULL, *msg_facch = NULL;
if (bid > 0)
return NULL;
return 0;
tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch,
(((fn + 4) % 26) >> 2) & 1);
tx_tch_common(l1t, br->tn, br->fn, chan, bid, &msg_tch, &msg_facch,
(((br->fn + 4) % 26) >> 2) & 1);
/* no message at all */
if (!msg_tch && !msg_facch) {
LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n");
goto send_burst;
LOGL1S(DL1P, LOGL_INFO, l1t, br->tn, chan, br->fn, "has not been served !! No prim\n");
return -ENODEV;
}
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);
} 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 NULL;
return 0;
}
ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn,
enum trx_chan_type chan, uint8_t bid, uint16_t *nbits)
int tx_tchh_fn(struct l1sched_trx *l1t, enum trx_chan_type chan,
uint8_t bid, struct trx_dl_burst_req *br)
{
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];
//uint8_t tch_mode = chan_state->tch_mode;
/* send burst, if we already got a frame */
if (bid > 0)
return NULL;
return 0;
/* get TCH and/or FACCH */
tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch,
(((fn + 4) % 26) >> 2) & 1);
tx_tch_common(l1t, br->tn, br->fn, chan, bid, &msg_tch, &msg_facch,
(((br->fn + 4) % 26) >> 2) & 1);
/* check for FACCH alignment */
if (msg_facch && ((((fn + 4) % 26) >> 2) & 1)) {
LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "Cannot transmit FACCH starting on "
if (msg_facch && ((((br->fn + 4) % 26) >> 2) & 1)) {
LOGL1S(DL1P, LOGL_ERROR, l1t, br->tn, chan, br->fn, "Cannot transmit FACCH starting on "
"even frames, please fix RTS!\n");
msgb_free(msg_facch);
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 */
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");
goto send_burst;
LOGL1S(DL1P, LOGL_INFO, l1t, br->tn, chan, br->fn, "has not been served !! No prim\n");
return -ENODEV;
}
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);
} 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 NULL;
return 0;
}
@ -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) {
struct phy_instance *pinst = trx_phy_instance(trx);
struct l1sched_trx *l1t = &pinst->u.virt.sched;
int tn;
uint16_t nbits;
struct trx_dl_burst_req br = { .fn = fn };
/* 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 */
/* This will basically do 2 things (check l1_if:bts_model_l1sap_down):
* 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, )
* --> Forward transparent RSL-DATA-Messages to the ms by appending them to
* 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 */
/* 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, tn, fn, &nbits);
_sched_dl_burst(l1t, &br);
}
}