From patchwork Wed Feb 3 18:24:04 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Harald Welte X-Patchwork-Id: 578279 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.osmocom.org (lists.osmocom.org [144.76.43.76]) by ozlabs.org (Postfix) with ESMTP id 12B3D140783 for ; Thu, 4 Feb 2016 05:24:47 +1100 (AEDT) Received: from lists.osmocom.org (lists.osmocom.org [144.76.43.76]) by lists.osmocom.org (Postfix) with ESMTP id D61FD1416D; Wed, 3 Feb 2016 18:24:45 +0000 (UTC) X-Original-To: openbsc@lists.osmocom.org Delivered-To: openbsc@lists.osmocom.org Received: from ganesha.gnumonks.org (ganesha.gnumonks.org [213.95.27.120]) by lists.osmocom.org (Postfix) with ESMTP id 72481140FB for ; Wed, 3 Feb 2016 18:24:39 +0000 (UTC) Received: from uucp by ganesha.gnumonks.org with local-bsmtp (Exim 4.72) (envelope-from ) id 1aR26Y-0004B5-4Y; Wed, 03 Feb 2016 19:24:38 +0100 Received: from laforge by localhost.localdomain with local (Exim 4.86) (envelope-from ) id 1aR268-0003PA-6U; Wed, 03 Feb 2016 19:24:12 +0100 From: laforge@gnumonks.org To: openbsc@lists.osmocom.org Subject: [PATCH 5/7] TRX: scheduler: Move trx_sched_clock() to scheduler_trx.c Date: Wed, 3 Feb 2016 19:24:04 +0100 Message-Id: <1454523846-13022-5-git-send-email-laforge@gnumonks.org> X-Mailer: git-send-email 2.7.0 In-Reply-To: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> References: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> X-BeenThere: openbsc@lists.osmocom.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Development of the OpenBSC GSM base station controller List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openbsc-bounces@lists.osmocom.org Sender: "OpenBSC" From: Harald Welte This funciton (and associated static functions) are TRX specific, and scheduler.c should only contain generic code. --- src/osmo-bts-trx/scheduler.c | 230 +---------------------------------- src/osmo-bts-trx/scheduler.h | 2 +- src/osmo-bts-trx/scheduler_backend.h | 2 + src/osmo-bts-trx/scheduler_trx.c | 220 +++++++++++++++++++++++++++++++++ src/osmo-bts-trx/trx_if.c | 5 +- 5 files changed, 229 insertions(+), 230 deletions(-) diff --git a/src/osmo-bts-trx/scheduler.c b/src/osmo-bts-trx/scheduler.c index d4af2b7..10f8972 100644 --- a/src/osmo-bts-trx/scheduler.c +++ b/src/osmo-bts-trx/scheduler.c @@ -36,27 +36,12 @@ #include #include -#include "l1_if.h" #include "scheduler.h" #include "scheduler_backend.h" -#include "trx_if.h" +//#include "trx_if.h" extern void *tall_bts_ctx; -static struct gsm_bts *bts; - -/* clock states */ -static uint32_t transceiver_lost; -uint32_t transceiver_last_fn; -static struct timeval transceiver_clock_tv; -static struct osmo_timer_list transceiver_clock_timer; - -/* clock advance for the transceiver */ -uint32_t trx_clock_advance = 20; - -/* advance RTS to give some time for data processing. (especially PCU) */ -uint32_t trx_rts_advance = 5; /* about 20ms */ - static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan); static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, @@ -1460,7 +1445,7 @@ int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink, } /* process ready-to-send */ -static int trx_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) { struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); const struct trx_sched_frame *frame; @@ -1498,8 +1483,7 @@ static int trx_sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn) } /* process downlink burst */ -static const ubit_t *trx_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, - uint32_t fn) +const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn) { struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); struct l1sched_chan_state *l1cs; @@ -1639,214 +1623,6 @@ next_frame: return 0; } -/* schedule all frames of all TRX for given FN */ -static int trx_sched_fn(uint32_t fn) -{ - struct gsm_bts_trx *trx; - uint8_t tn; - const ubit_t *bits; - uint8_t gain; - - /* send time indication */ - l1if_mph_time_ind(bts, fn); - - /* advance frame number, so the transceiver has more time until - * it must be transmitted. */ - fn = (fn + trx_clock_advance) % GSM_HYPERFRAME; - - /* process every TRX */ - llist_for_each_entry(trx, &bts->trx_list, list) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); - struct l1sched_trx *l1t = trx_l1sched_hdl(trx); - - /* we don't schedule, if power is off */ - if (!trx_if_powered(l1h)) - continue; - - /* process every TS of TRX */ - for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { - /* ready-to-send */ - trx_sched_rts(l1t, tn, - (fn + trx_rts_advance) % GSM_HYPERFRAME); - /* get burst for FN */ - bits = trx_sched_dl_burst(l1t, tn, fn); - if (!bits) { - /* if no bits, send no burst */ - continue; - } else - gain = 0; - trx_if_data(l1h, tn, fn, gain, bits); - } - } - - return 0; -} - - -/* - * frame clock - */ - -#define FRAME_DURATION_uS 4615 -#define MAX_FN_SKEW 50 -#define TRX_LOSS_FRAMES 400 - -extern int quit; -/* this timer fires for every FN to be processed */ -static void trx_ctrl_timer_cb(void *data) -{ - struct gsm_bts *bts = data; - struct timeval tv_now, *tv_clock = &transceiver_clock_tv; - int32_t elapsed; - - /* check if transceiver is still alive */ - if (transceiver_lost++ == TRX_LOSS_FRAMES) { - struct gsm_bts_trx *trx; - - LOGP(DL1C, LOGL_NOTICE, "No more clock from transceiver\n"); - -no_clock: - transceiver_available = 0; - - /* flush pending messages of transceiver */ - /* close all logical channels and reset timeslots */ - llist_for_each_entry(trx, &bts->trx_list, list) { - trx_if_flush(trx_l1h_hdl(trx)); - trx_sched_reset(trx_l1sched_hdl(trx)); - if (trx->nr == 0) - trx_if_cmd_poweroff(trx_l1h_hdl(trx)); - } - - /* tell BSC */ - check_transceiver_availability(bts, 0); - - return; - } - - gettimeofday(&tv_now, NULL); - - elapsed = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000 - + (tv_now.tv_usec - tv_clock->tv_usec); - - /* if someone played with clock, or if the process stalled */ - if (elapsed > FRAME_DURATION_uS * MAX_FN_SKEW || elapsed < 0) { - LOGP(DL1C, LOGL_NOTICE, "PC clock skew: elapsed uS %d\n", - elapsed); - goto no_clock; - } - - /* schedule next FN clock */ - while (elapsed > FRAME_DURATION_uS / 2) { - tv_clock->tv_usec += FRAME_DURATION_uS; - if (tv_clock->tv_usec >= 1000000) { - tv_clock->tv_sec++; - tv_clock->tv_usec -= 1000000; - } - transceiver_last_fn = (transceiver_last_fn + 1) % GSM_HYPERFRAME; - trx_sched_fn(transceiver_last_fn); - elapsed -= FRAME_DURATION_uS; - } - osmo_timer_schedule(&transceiver_clock_timer, 0, - FRAME_DURATION_uS - elapsed); -} - - -/* receive clock from transceiver */ -int trx_sched_clock(uint32_t fn) -{ - struct timeval tv_now, *tv_clock = &transceiver_clock_tv; - int32_t elapsed; - int32_t elapsed_fn; - - if (quit) - return 0; - - /* reset lost counter */ - transceiver_lost = 0; - - gettimeofday(&tv_now, NULL); - - /* clock becomes valid */ - if (!transceiver_available) { - LOGP(DL1C, LOGL_NOTICE, "initial GSM clock received: fn=%u\n", - fn); - - transceiver_available = 1; - - /* start provisioning transceiver */ - l1if_provision_transceiver(bts); - - /* tell BSC */ - check_transceiver_availability(bts, 1); - -new_clock: - transceiver_last_fn = fn; - trx_sched_fn(transceiver_last_fn); - - /* schedule first FN clock */ - memcpy(tv_clock, &tv_now, sizeof(struct timeval)); - memset(&transceiver_clock_timer, 0, - sizeof(transceiver_clock_timer)); - transceiver_clock_timer.cb = trx_ctrl_timer_cb; - transceiver_clock_timer.data = bts; - osmo_timer_schedule(&transceiver_clock_timer, 0, - FRAME_DURATION_uS); - - return 0; - } - - osmo_timer_del(&transceiver_clock_timer); - - /* calculate elapsed time since last_fn */ - elapsed = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000 - + (tv_now.tv_usec - tv_clock->tv_usec); - - /* how much frames have been elapsed since last fn processed */ - elapsed_fn = (fn + GSM_HYPERFRAME - transceiver_last_fn) % GSM_HYPERFRAME; - if (elapsed_fn >= 135774) - elapsed_fn -= GSM_HYPERFRAME; - - /* check for max clock skew */ - if (elapsed_fn > MAX_FN_SKEW || elapsed_fn < -MAX_FN_SKEW) { - LOGP(DL1C, LOGL_NOTICE, "GSM clock skew: old fn=%u, " - "new fn=%u\n", transceiver_last_fn, fn); - goto new_clock; - } - - LOGP(DL1C, LOGL_INFO, "GSM clock jitter: %d\n", - elapsed_fn * FRAME_DURATION_uS - elapsed); - - /* too many frames have been processed already */ - if (elapsed_fn < 0) { - /* set clock to the time or last FN should have been - * transmitted. */ - tv_clock->tv_sec = tv_now.tv_sec; - tv_clock->tv_usec = tv_now.tv_usec + - (0 - elapsed_fn) * FRAME_DURATION_uS; - if (tv_clock->tv_usec >= 1000000) { - tv_clock->tv_sec++; - tv_clock->tv_usec -= 1000000; - } - /* set time to the time our next FN has to be transmitted */ - osmo_timer_schedule(&transceiver_clock_timer, 0, - FRAME_DURATION_uS * (1 - elapsed_fn)); - - return 0; - } - - /* transmit what we still need to transmit */ - while (fn != transceiver_last_fn) { - transceiver_last_fn = (transceiver_last_fn + 1) % GSM_HYPERFRAME; - trx_sched_fn(transceiver_last_fn); - } - - /* schedule next FN to be transmitted */ - memcpy(tv_clock, &tv_now, sizeof(struct timeval)); - osmo_timer_schedule(&transceiver_clock_timer, 0, FRAME_DURATION_uS); - - return 0; -} - struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn) { OSMO_ASSERT(tn < ARRAY_SIZE(l1t->ts)); diff --git a/src/osmo-bts-trx/scheduler.h b/src/osmo-bts-trx/scheduler.h index c153b9e..13ef051 100644 --- a/src/osmo-bts-trx/scheduler.h +++ b/src/osmo-bts-trx/scheduler.h @@ -145,7 +145,7 @@ int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap); /*! \brief PHY informs us of new (current) GSM freme nunmber */ -int trx_sched_clock(uint32_t fn); +int trx_sched_clock(struct gsm_bts *bts, uint32_t fn); /*! \brief handle an UL burst received by PHY */ int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, diff --git a/src/osmo-bts-trx/scheduler_backend.h b/src/osmo-bts-trx/scheduler_backend.h index ea3e620..b808455 100644 --- a/src/osmo-bts-trx/scheduler_backend.h +++ b/src/osmo-bts-trx/scheduler_backend.h @@ -77,3 +77,5 @@ int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa); +const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn); +int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn); diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index a77f5a5..0aeb835 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -49,6 +49,18 @@ extern void *tall_bts_ctx; +/* clock states */ +static uint32_t transceiver_lost; +uint32_t transceiver_last_fn; +static struct timeval transceiver_clock_tv; +static struct osmo_timer_list transceiver_clock_timer; + +/* clock advance for the transceiver */ +uint32_t trx_clock_advance = 20; + +/* advance RTS to give some time for data processing. (especially PCU) */ +uint32_t trx_rts_advance = 5; /* about 20ms */ + /* Enable this to multiply TOA of RACH by 10. * This is usefull to check tenth of timing advances with RSSI test tool. * Note that regular phones will not work when using this test! */ @@ -1238,3 +1250,211 @@ bfi: (fn + GSM_HYPERFRAME - 10 - ((fn%26)==19) - ((fn%26)==20)) % GSM_HYPERFRAME, chan, tch_data, rc); } + +/* schedule all frames of all TRX for given FN */ +static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn) +{ + struct gsm_bts_trx *trx; + uint8_t tn; + const ubit_t *bits; + uint8_t gain; + + /* send time indication */ + l1if_mph_time_ind(bts, fn); + + /* advance frame number, so the transceiver has more time until + * it must be transmitted. */ + fn = (fn + trx_clock_advance) % GSM_HYPERFRAME; + + /* process every TRX */ + llist_for_each_entry(trx, &bts->trx_list, list) { + struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct l1sched_trx *l1t = trx_l1sched_hdl(trx); + + /* we don't schedule, if power is off */ + if (!trx_if_powered(l1h)) + continue; + + /* process every TS of TRX */ + for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { + /* ready-to-send */ + _sched_rts(l1t, tn, + (fn + trx_rts_advance) % GSM_HYPERFRAME); + /* get burst for FN */ + bits = _sched_dl_burst(l1t, tn, fn); + if (!bits) { + /* if no bits, send no burst */ + continue; + } else + gain = 0; + trx_if_data(l1h, tn, fn, gain, bits); + } + } + + return 0; +} + + +/* + * frame clock + */ + +#define FRAME_DURATION_uS 4615 +#define MAX_FN_SKEW 50 +#define TRX_LOSS_FRAMES 400 + +extern int quit; +/* this timer fires for every FN to be processed */ +static void trx_ctrl_timer_cb(void *data) +{ + struct gsm_bts *bts = data; + struct timeval tv_now, *tv_clock = &transceiver_clock_tv; + int32_t elapsed; + + /* check if transceiver is still alive */ + if (transceiver_lost++ == TRX_LOSS_FRAMES) { + struct gsm_bts_trx *trx; + + LOGP(DL1C, LOGL_NOTICE, "No more clock from transceiver\n"); + +no_clock: + transceiver_available = 0; + + /* flush pending messages of transceiver */ + /* close all logical channels and reset timeslots */ + llist_for_each_entry(trx, &bts->trx_list, list) { + trx_if_flush(trx_l1h_hdl(trx)); + trx_sched_reset(trx_l1sched_hdl(trx)); + if (trx->nr == 0) + trx_if_cmd_poweroff(trx_l1h_hdl(trx)); + } + + /* tell BSC */ + check_transceiver_availability(bts, 0); + + return; + } + + gettimeofday(&tv_now, NULL); + + elapsed = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000 + + (tv_now.tv_usec - tv_clock->tv_usec); + + /* if someone played with clock, or if the process stalled */ + if (elapsed > FRAME_DURATION_uS * MAX_FN_SKEW || elapsed < 0) { + LOGP(DL1C, LOGL_NOTICE, "PC clock skew: elapsed uS %d\n", + elapsed); + goto no_clock; + } + + /* schedule next FN clock */ + while (elapsed > FRAME_DURATION_uS / 2) { + tv_clock->tv_usec += FRAME_DURATION_uS; + if (tv_clock->tv_usec >= 1000000) { + tv_clock->tv_sec++; + tv_clock->tv_usec -= 1000000; + } + transceiver_last_fn = (transceiver_last_fn + 1) % GSM_HYPERFRAME; + trx_sched_fn(bts, transceiver_last_fn); + elapsed -= FRAME_DURATION_uS; + } + osmo_timer_schedule(&transceiver_clock_timer, 0, + FRAME_DURATION_uS - elapsed); +} + + +/* receive clock from transceiver */ +int trx_sched_clock(struct gsm_bts *bts, uint32_t fn) +{ + struct timeval tv_now, *tv_clock = &transceiver_clock_tv; + int32_t elapsed; + int32_t elapsed_fn; + + if (quit) + return 0; + + /* reset lost counter */ + transceiver_lost = 0; + + gettimeofday(&tv_now, NULL); + + /* clock becomes valid */ + if (!transceiver_available) { + LOGP(DL1C, LOGL_NOTICE, "initial GSM clock received: fn=%u\n", + fn); + + transceiver_available = 1; + + /* start provisioning transceiver */ + l1if_provision_transceiver(bts); + + /* tell BSC */ + check_transceiver_availability(bts, 1); + +new_clock: + transceiver_last_fn = fn; + trx_sched_fn(bts, transceiver_last_fn); + + /* schedule first FN clock */ + memcpy(tv_clock, &tv_now, sizeof(struct timeval)); + memset(&transceiver_clock_timer, 0, + sizeof(transceiver_clock_timer)); + transceiver_clock_timer.cb = trx_ctrl_timer_cb; + transceiver_clock_timer.data = bts; + osmo_timer_schedule(&transceiver_clock_timer, 0, + FRAME_DURATION_uS); + + return 0; + } + + osmo_timer_del(&transceiver_clock_timer); + + /* calculate elapsed time since last_fn */ + elapsed = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000 + + (tv_now.tv_usec - tv_clock->tv_usec); + + /* how much frames have been elapsed since last fn processed */ + elapsed_fn = (fn + GSM_HYPERFRAME - transceiver_last_fn) % GSM_HYPERFRAME; + if (elapsed_fn >= 135774) + elapsed_fn -= GSM_HYPERFRAME; + + /* check for max clock skew */ + if (elapsed_fn > MAX_FN_SKEW || elapsed_fn < -MAX_FN_SKEW) { + LOGP(DL1C, LOGL_NOTICE, "GSM clock skew: old fn=%u, " + "new fn=%u\n", transceiver_last_fn, fn); + goto new_clock; + } + + LOGP(DL1C, LOGL_INFO, "GSM clock jitter: %d\n", + elapsed_fn * FRAME_DURATION_uS - elapsed); + + /* too many frames have been processed already */ + if (elapsed_fn < 0) { + /* set clock to the time or last FN should have been + * transmitted. */ + tv_clock->tv_sec = tv_now.tv_sec; + tv_clock->tv_usec = tv_now.tv_usec + + (0 - elapsed_fn) * FRAME_DURATION_uS; + if (tv_clock->tv_usec >= 1000000) { + tv_clock->tv_sec++; + tv_clock->tv_usec -= 1000000; + } + /* set time to the time our next FN has to be transmitted */ + osmo_timer_schedule(&transceiver_clock_timer, 0, + FRAME_DURATION_uS * (1 - elapsed_fn)); + + return 0; + } + + /* transmit what we still need to transmit */ + while (fn != transceiver_last_fn) { + transceiver_last_fn = (transceiver_last_fn + 1) % GSM_HYPERFRAME; + trx_sched_fn(bts, transceiver_last_fn); + } + + /* schedule next FN to be transmitted */ + memcpy(tv_clock, &tv_now, sizeof(struct timeval)); + osmo_timer_schedule(&transceiver_clock_timer, 0, FRAME_DURATION_uS); + + return 0; +} diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c index 16c9fc7..c9cfaef 100644 --- a/src/osmo-bts-trx/trx_if.c +++ b/src/osmo-bts-trx/trx_if.c @@ -121,6 +121,7 @@ static struct osmo_fd trx_ofd_clk; /* get clock from clock socket */ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what) { + struct trx_l1h *l1h = ofd->data; char buf[1500]; int len; uint32_t fn; @@ -145,7 +146,7 @@ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what) "correctly, correcting to fn=%u\n", fn); } - trx_sched_clock(fn); + trx_sched_clock(l1h->trx->bts, fn); return 0; } @@ -503,7 +504,7 @@ int trx_if_open(struct trx_l1h *l1h) /* open sockets */ if (l1h->trx->nr == 0) { - rc = trx_udp_open(NULL, &trx_ofd_clk, base_port_local, + rc = trx_udp_open(l1h, &trx_ofd_clk, base_port_local, trx_clk_read_cb); if (rc < 0) return rc;