diff options
Diffstat (limited to 'src/osmo-bts-virtual/scheduler_virtbts.c')
-rw-r--r-- | src/osmo-bts-virtual/scheduler_virtbts.c | 420 |
1 files changed, 180 insertions, 240 deletions
diff --git a/src/osmo-bts-virtual/scheduler_virtbts.c b/src/osmo-bts-virtual/scheduler_virtbts.c index 259a573a..87596a79 100644 --- a/src/osmo-bts-virtual/scheduler_virtbts.c +++ b/src/osmo-bts-virtual/scheduler_virtbts.c @@ -1,7 +1,8 @@ -/* Scheduler worker functiosn for Virtua OsmoBTS */ +/* Scheduler worker functions for Virtua OsmoBTS */ /* (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 * @@ -13,7 +14,7 @@ * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. @@ -21,6 +22,7 @@ */ #include <stdlib.h> #include <unistd.h> +#include <string.h> #include <errno.h> #include <stdint.h> #include <ctype.h> @@ -46,25 +48,18 @@ #define MODULO_HYPERFRAME 0 -static const char *gsmtap_hdr_stringify(const struct gsmtap_hdr *gh) -{ - static char buf[256]; - snprintf(buf, sizeof(buf), "(ARFCN=%u, ts=%u, ss=%u, type=%u/%u)", - gh->arfcn & GSMTAP_ARFCN_MASK, gh->timeslot, gh->sub_slot, gh->type, gh->sub_type); - return buf; -} - /** * 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. - * TODO: we might want to remove unused argument uint8_t tn */ -static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, struct msgb *msg) +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[chan]; + 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 tranceiver 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) */ @@ -76,177 +71,181 @@ static void tx_to_virt_um(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, rsl_dec_chan_nr(chdesc->chan_nr, &rsl_chantype, &subslot, ×lot); /* the timeslot is not encoded in the chan_nr of the chdesc, and so has to be overwritten */ - timeslot = tn; + timeslot = br->tn; /* 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(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_rsl2gsmtap(rsl_chantype, chdesc->link_id); /* the logical channel type */ + 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, 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; + } #if MODULO_HYPERFRAME /* Restart fn after every superframe (26 * 51 frames) to simulate hyperframe overflow each 6 seconds. */ - fn %= 26 * 51; + br->fn %= 26 * 51; #endif - outmsg = gsmtap_makemsg(arfcn, timeslot, gsmtap_chantype, subslot, fn, signal_dbm, snr, data, data_len); + 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 gsmtap_hdr *gh = (struct gsmtap_hdr *)msgb_data(outmsg); + 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) - LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, - "%s GSMTAP msg could not send to virtual Um\n", gsmtap_hdr_stringify(gh)); - else if (rc == 0) - bts_shutdown(l1t->trx->bts, "VirtPHY write socket died\n"); + LOGL1SB(DL1P, LOGL_ERROR, l1ts, br, + "GSMTAP msg could not send to virtual Um: %s\n", strerror(-rc)); else - LOGL1S(DL1P, LOGL_DEBUG, l1t, tn, chan, fn, - "%s Sending GSMTAP message to virtual Um\n", gsmtap_hdr_stringify(gh)); + LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, + "Sending GSMTAP message to virtual Um\n"); } else - LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "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); } -/* - * TX on downlink - */ +static void tx_to_virt_um(struct l1sched_ts *l1ts, + struct trx_dl_burst_req *br, + struct msgb *msg) +{ + _tx_to_virt_um(l1ts, br, msg, false); +} + -/* 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) +static struct gsm_lchan *lchan_from_l1t(const struct l1sched_ts *l1ts, + const enum trx_chan_type chan) { - return NULL; + struct gsm_bts_trx_ts *ts = l1ts->ts; + uint8_t subslot = 0; + + if (chan == TRXC_TCHH_1) + subslot = 1; + + return &ts->lchan[subslot]; } -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) +/* Determine the gsmtap_um_voice_type of a gsm_lchan */ +static int get_um_voice_type(const struct gsm_lchan *lchan) { - return NULL; + switch (lchan->tch_mode) { + case GSM48_CMODE_SPEECH_V1: + if (lchan->type == GSM_LCHAN_TCH_H) + return GSMTAP_UM_VOICE_HR; + else + return GSMTAP_UM_VOICE_FR; + case GSM48_CMODE_SPEECH_EFR: + return GSMTAP_UM_VOICE_EFR; + case GSM48_CMODE_SPEECH_AMR: + return GSMTAP_UM_VOICE_AMR; + default: + return -1; + } } -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) +static void tx_to_virt_um_voice_frame(struct l1sched_ts *l1ts, + struct trx_dl_burst_req *br, + struct msgb *msg) { - return NULL; + struct gsm_lchan *lchan = lchan_from_l1t(l1ts, br->chan); + int um_voice_type; + + OSMO_ASSERT(lchan); + um_voice_type = get_um_voice_type(lchan); + if (um_voice_type < 0) { + LOGPLCHAN(lchan, DL1P, LOGL_ERROR, "Cannot determine Um voice type from lchan\n"); + um_voice_type = 0xff; + } + + /* the first byte indicates the type of voice codec (gsmtap_um_voice_type) */ + msgb_pull_to_l2(msg); + msgb_push_u8(msg, um_voice_type); + msg->l2h = msg->data; + _tx_to_virt_um(l1ts, br, msg, true); } -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) +/* + * TX on downlink + */ + +int tx_fcch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) +{ + return 0; +} + +int tx_sch_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) +{ + return 0; +} + +int tx_data_fn(struct l1sched_ts *l1ts, struct trx_dl_burst_req *br) { struct msgb *msg; - if (bid > 0) - return NULL; + if (br->bid > 0) + return 0; /* get mac block from queue */ - msg = _sched_dequeue_prim(l1t, tn, fn, chan); + msg = _sched_dequeue_prim(l1ts, br); if (!msg) { - LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n"); - return NULL; + 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) { - LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "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); - 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(l1ts, br, 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_ts *l1ts, struct trx_dl_burst_req *br) { struct msgb *msg = NULL; /* make GCC happy */ - if (bid > 0) - return NULL; + if (br->bid > 0) + return 0; /* get mac block from queue */ - msg = _sched_dequeue_prim(l1t, tn, fn, chan); + msg = _sched_dequeue_prim(l1ts, br); if (!msg) { - LOGL1S(DL1P, LOGL_INFO, l1t, tn, chan, fn, "has not been served !! No prim\n"); - return NULL; + LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "has not been served !! No prim\n"); + return -ENODEV; } - tx_to_virt_um(l1t, tn, fn, chan, msg); + tx_to_virt_um(l1ts, br, msg); - return NULL; + return 0; } -static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, struct msgb **_msg_tch, - struct msgb **_msg_facch, int codec_mode_request) +static void tx_tch_common(struct l1sched_ts *l1ts, + const struct trx_dl_burst_req *br, + struct msgb **_msg_tch, struct msgb **_msg_facch) { - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL; - struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; + struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan]; uint8_t rsl_cmode = chan_state->rsl_cmode; uint8_t tch_mode = chan_state->tch_mode; struct osmo_phsap_prim *l1sap; -#if 0 - /* handle loss detection of received TCH frames */ - if (rsl_cmode == RSL_CMOD_SPD_SPEECH - && ++(chan_state->lost_frames) > 5) { - uint8_t tch_data[GSM_FR_BYTES]; - int len; - - LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Missing TCH bursts detected, sending " - "BFI for %s\n", trx_chan_desc[chan].name); - - /* indicate bad frame */ - switch (tch_mode) { - case GSM48_CMODE_SPEECH_V1: /* FR / HR */ - if (chan != TRXC_TCHF) { /* HR */ - tch_data[0] = 0x70; /* F = 0, FT = 111 */ - memset(tch_data + 1, 0, 14); - len = 15; - break; - } - memset(tch_data, 0, GSM_FR_BYTES); - len = GSM_FR_BYTES; - break; - case GSM48_CMODE_SPEECH_EFR: /* EFR */ - if (chan != TRXC_TCHF) - goto inval_mode1; - memset(tch_data, 0, GSM_EFR_BYTES); - len = GSM_EFR_BYTES; - break; - case GSM48_CMODE_SPEECH_AMR: /* AMR */ - len = amr_compose_payload(tch_data, - chan_state->codec[chan_state->dl_cmr], - chan_state->codec[chan_state->dl_ft], 1); - if (len < 2) - break; - memset(tch_data + 2, 0, len - 2); - _sched_compose_tch_ind(l1t, tn, 0, chan, tch_data, len); - break; - default: -inval_mode1: - LOGP(DL1P, LOGL_ERROR, "TCH mode invalid, please " - "fix!\n"); - len = 0; - } - if (len) - _sched_compose_tch_ind(l1t, tn, 0, chan, tch_data, len); - } -#endif /* get frame and unlink from queue */ - msg1 = _sched_dequeue_prim(l1t, tn, fn, chan); - msg2 = _sched_dequeue_prim(l1t, tn, fn, chan); + 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) { @@ -254,8 +253,8 @@ inval_mode1: if (msg2) { l1sap = msgb_l1sap_prim(msg2); if (l1sap->oph.primitive == PRIM_TCH) { - LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, - "TCH twice, please FIX! "); + LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, + "TCH twice, please FIX!\n"); msgb_free(msg2); } else msg_facch = msg2; @@ -265,8 +264,8 @@ inval_mode1: if (msg2) { l1sap = msgb_l1sap_prim(msg2); if (l1sap->oph.primitive != PRIM_TCH) { - LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, - "FACCH twice, please FIX! "); + LOGL1SB(DL1P, LOGL_FATAL, l1ts, br, + "FACCH twice, please FIX!\n"); msgb_free(msg2); } else msg_tch = msg2; @@ -282,8 +281,8 @@ inval_mode1: /* check validity of message */ if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) { - LOGL1S(DL1P, LOGL_FATAL, l1t, tn, chan, fn, "Prim not 23 bytes, please FIX! (len=%d)\n", - msgb_l2len(msg_facch)); + 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); msg_facch = NULL; @@ -298,18 +297,18 @@ inval_mode1: #endif if (rsl_cmode != RSL_CMOD_SPD_SPEECH) { - LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, "Dropping speech frame, " + LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Dropping speech frame, " "because we are not in speech mode\n"); goto free_bad_msg; } switch (tch_mode) { case GSM48_CMODE_SPEECH_V1: /* FR / HR */ - if (chan != TRXC_TCHF) { /* HR */ + if (br->chan != TRXC_TCHF) { /* HR */ len = 15; if (msgb_l2len(msg_tch) >= 1 && (msg_tch->l2h[0] & 0xf0) != 0x00) { - LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, + LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Transmitting 'bad HR frame'\n"); goto free_bad_msg; } @@ -318,76 +317,37 @@ inval_mode1: len = GSM_FR_BYTES; if (msgb_l2len(msg_tch) >= 1 && (msg_tch->l2h[0] >> 4) != 0xd) { - LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, + LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Transmitting 'bad FR frame'\n"); goto free_bad_msg; } break; case GSM48_CMODE_SPEECH_EFR: /* EFR */ - if (chan != TRXC_TCHF) + if (br->chan != TRXC_TCHF) goto inval_mode2; len = GSM_EFR_BYTES; if (msgb_l2len(msg_tch) >= 1 && (msg_tch->l2h[0] >> 4) != 0xc) { - LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, + LOGL1SB(DL1P, LOGL_NOTICE, l1ts, br, "Transmitting 'bad EFR frame'\n"); goto free_bad_msg; } break; case GSM48_CMODE_SPEECH_AMR: /* AMR */ -#if 0 - len = amr_decompose_payload(msg_tch->l2h, - msgb_l2len(msg_tch), &cmr_codec, &ft_codec, - &bfi); - cmr = -1; - ft = -1; - for (i = 0; i < chan_state->codecs; i++) { - if (chan_state->codec[i] == cmr_codec) - cmr = i; - if (chan_state->codec[i] == ft_codec) - ft = i; - } - if (cmr >= 0) { /* new request */ - chan_state->dl_cmr = cmr; - /* disable AMR loop */ - trx_loop_amr_set(chan_state, 0); - } else { - /* enable AMR loop */ - trx_loop_amr_set(chan_state, 1); - } - if (ft < 0) { - LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, - "Codec (FT = %d) of RTP frame not in list. ", ft_codec); - goto free_bad_msg; - } - if (codec_mode_request && chan_state->dl_ft != ft) { - LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, - "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) { - LOGL1S(DL1P, LOGL_NOTICE, l1t, tn, chan, fn, - "Transmitting 'bad AMR frame'\n"); - goto free_bad_msg; - } -#else - LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "AMR not supported!\n"); - goto free_bad_msg; -#endif + /* TODO: check length for consistency */ + goto send_frame; break; default: inval_mode2: - LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "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) { - LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "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) { - LOGL1S(DL1P, LOGL_ERROR, l1t, tn, chan, fn, "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 */ @@ -402,72 +362,56 @@ 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_ts *l1ts, struct trx_dl_burst_req *br) { struct msgb *msg_tch = NULL, *msg_facch = NULL; - if (bid > 0) - return NULL; + if (br->bid > 0) + return 0; - tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch, - (((fn + 4) % 26) >> 2) & 1); + tx_tch_common(l1ts, br, &msg_tch, &msg_facch); /* 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; + LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "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(l1ts, br, msg_facch); msgb_free(msg_tch); - } else - tx_to_virt_um(l1t, tn, fn, chan, msg_tch); - -send_burst: + } else if (msg_tch) + tx_to_virt_um_voice_frame(l1ts, br, msg_tch); - 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_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, tn); - struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; + struct l1sched_chan_state *chan_state = &l1ts->chan_state[br->chan]; //uint8_t tch_mode = chan_state->tch_mode; /* send burst, if we already got a frame */ - if (bid > 0) - return NULL; + if (br->bid > 0) + return 0; /* get TCH and/or FACCH */ - tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch, - (((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 " - "even frames, please fix RTS!\n"); - msgb_free(msg_facch); - msg_facch = NULL; - } + tx_tch_common(l1ts, br, &msg_tch, &msg_facch); /* 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; + LOGL1SB(DL1P, LOGL_INFO, l1ts, br, "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(l1ts, br, msg_facch); msgb_free(msg_tch); } else if (msg_tch) - tx_to_virt_um(l1t, tn, fn, chan, msg_tch); + tx_to_virt_um_voice_frame(l1ts, br, msg_tch); -send_burst: - return NULL; + return 0; } @@ -479,38 +423,33 @@ send_burst: * directly into the L1SAP, bypassing the TDMA multiplex logic oriented * towards receiving bursts */ -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_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, enum trx_chan_type chan, - uint8_t bid, 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, enum trx_chan_type chan, - uint8_t bid, 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, enum trx_chan_type chan, - uint8_t bid, 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, enum trx_chan_type chan, - uint8_t bid, 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) { } @@ -519,7 +458,6 @@ void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int ac ***********************************************************************/ #define RTS_ADVANCE 5 /* about 20ms */ -#define FRAME_DURATION_uS 4615 static int vbts_sched_fn(struct gsm_bts *bts, uint32_t fn) { @@ -532,13 +470,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; - 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(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) @@ -546,13 +482,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(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, tn, fn, &nbits); + _sched_dl_burst(l1ts, &br); } } @@ -562,8 +498,9 @@ static int vbts_sched_fn(struct gsm_bts *bts, uint32_t fn) static void vbts_fn_timer_cb(void *data) { struct gsm_bts *bts = data; + struct bts_virt_priv *bts_virt = (struct bts_virt_priv *)bts->model_priv; struct timeval tv_now; - struct timeval *tv_clock = &bts->vbts.tv_clock; + struct timeval *tv_clock = &bts_virt->tv_clock; int32_t elapsed_us; gettimeofday(&tv_now, NULL); @@ -574,41 +511,44 @@ static void vbts_fn_timer_cb(void *data) + (tv_now.tv_usec - tv_clock->tv_usec); /* not so good somehow a lot of time passed between two timer callbacks */ - if (elapsed_us > 2 *FRAME_DURATION_uS) + if (elapsed_us > 2 *GSM_TDMA_FN_DURATION_uS) LOGP(DL1P, LOGL_NOTICE, "vbts_fn_timer_cb after %d us\n", elapsed_us); /* schedule the current frame/s (fn = frame number) * this loop will be called at least once, but can also be executed * multiple times if more than one frame duration (4615us) passed till the last callback */ - while (elapsed_us > FRAME_DURATION_uS / 2) { + while (elapsed_us > GSM_TDMA_FN_DURATION_uS / 2) { const struct timeval tv_frame = { .tv_sec = 0, - .tv_usec = FRAME_DURATION_uS, + .tv_usec = GSM_TDMA_FN_DURATION_uS, }; timeradd(tv_clock, &tv_frame, tv_clock); /* increment the frame number in the BTS model instance */ - bts->vbts.last_fn = (bts->vbts.last_fn + 1) % GSM_HYPERFRAME; - vbts_sched_fn(bts, bts->vbts.last_fn); - elapsed_us -= FRAME_DURATION_uS; + vbts_sched_fn(bts, GSM_TDMA_FN_INC(bts_virt->last_fn)); + elapsed_us -= GSM_TDMA_FN_DURATION_uS; } /* re-schedule the timer */ /* timer is set to frame duration - elapsed time to guarantee that this cb method will be * periodically executed every 4.615ms */ - osmo_timer_schedule(&bts->vbts.fn_timer, 0, FRAME_DURATION_uS - elapsed_us); + osmo_timer_schedule(&bts_virt->fn_timer, 0, GSM_TDMA_FN_DURATION_uS - elapsed_us); } int vbts_sched_start(struct gsm_bts *bts) { + struct bts_virt_priv *bts_virt = (struct bts_virt_priv *)bts->model_priv; LOGP(DL1P, LOGL_NOTICE, "starting VBTS scheduler\n"); - memset(&bts->vbts.fn_timer, 0, sizeof(bts->vbts.fn_timer)); - bts->vbts.fn_timer.cb = vbts_fn_timer_cb; - bts->vbts.fn_timer.data = bts; + if (!bts_virt) + return -EINVAL; + + memset(&bts_virt->fn_timer, 0, sizeof(bts_virt->fn_timer)); + bts_virt->fn_timer.cb = vbts_fn_timer_cb; + bts_virt->fn_timer.data = bts; - gettimeofday(&bts->vbts.tv_clock, NULL); + gettimeofday(&bts_virt->tv_clock, NULL); /* trigger the first timer after 4615us (a frame duration) */ - osmo_timer_schedule(&bts->vbts.fn_timer, 0, FRAME_DURATION_uS); + osmo_timer_schedule(&bts_virt->fn_timer, 0, GSM_TDMA_FN_DURATION_uS); return 0; } |