From patchwork Wed Feb 3 18:37:19 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Harald Welte X-Patchwork-Id: 578324 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.osmocom.org (lists.osmocom.org [IPv6:2a01:4f8:191:444b::2:7]) by ozlabs.org (Postfix) with ESMTP id F3A6F140324 for ; Thu, 4 Feb 2016 06:15:15 +1100 (AEDT) Received: from lists.osmocom.org (lists.osmocom.org [144.76.43.76]) by lists.osmocom.org (Postfix) with ESMTP id BFED714423; Wed, 3 Feb 2016 19:15:13 +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 40B1A1440B for ; Wed, 3 Feb 2016 19:15:12 +0000 (UTC) Received: from uucp by ganesha.gnumonks.org with local-bsmtp (Exim 4.72) (envelope-from ) id 1aR2tT-0006Fm-3r; Wed, 03 Feb 2016 20:15:11 +0100 Received: from laforge by localhost.localdomain with local (Exim 4.86) (envelope-from ) id 1aR2Is-0003kv-Gf; Wed, 03 Feb 2016 19:37:22 +0100 From: laforge@gnumonks.org To: openbsc@lists.osmocom.org Subject: [PATCH 1/3] Introduce new phy_link and phy_instance abstraction Date: Wed, 3 Feb 2016 19:37:19 +0100 Message-Id: <1454524641-14400-1-git-send-email-laforge@gnumonks.org> X-Mailer: git-send-email 2.7.0 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 way we can model a flexible mapping between any number of PHYs, each having multiple instances, and then map BTSs with TRXx on top of those PHYs. --- doc/examples/octphy/osmo-bts.cfg | 8 +- include/osmo-bts/Makefile.am | 2 +- include/osmo-bts/bts.h | 3 +- include/osmo-bts/bts_model.h | 5 + include/osmo-bts/gsm_data.h | 15 -- include/osmo-bts/phy_link.h | 115 +++++++++++ include/osmo-bts/scheduler.h | 4 +- include/osmo-bts/vty.h | 7 +- src/common/Makefile.am | 2 +- src/common/bts.c | 33 +++- src/common/main.c | 20 ++ src/common/phy_link.c | 155 +++++++++++++++ src/common/scheduler.c | 6 +- src/common/vty.c | 194 ++++++++++++++++++- src/osmo-bts-octphy/l1_if.c | 133 ++++++++----- src/osmo-bts-octphy/l1_if.h | 31 ++- src/osmo-bts-octphy/l1_oml.c | 96 +++++---- src/osmo-bts-octphy/main.c | 1 + src/osmo-bts-octphy/octphy_hw_api.c | 14 +- src/osmo-bts-octphy/octphy_vty.c | 198 +++++++++++-------- src/osmo-bts-trx/l1_if.c | 84 ++++---- src/osmo-bts-trx/l1_if.h | 18 +- src/osmo-bts-trx/main.c | 56 ++---- src/osmo-bts-trx/scheduler_trx.c | 16 +- src/osmo-bts-trx/trx_if.c | 124 +++++++++--- src/osmo-bts-trx/trx_if.h | 1 + src/osmo-bts-trx/trx_vty.c | 377 ++++++++++++++++++++++-------------- 27 files changed, 1220 insertions(+), 498 deletions(-) create mode 100644 include/osmo-bts/phy_link.h create mode 100644 src/common/phy_link.c diff --git a/doc/examples/octphy/osmo-bts.cfg b/doc/examples/octphy/osmo-bts.cfg index 07bcae0..4f27c8d 100644 --- a/doc/examples/octphy/osmo-bts.cfg +++ b/doc/examples/octphy/osmo-bts.cfg @@ -20,9 +20,13 @@ log stderr line vty no login ! +phy 0 + octphy hw-addr 00:0C:90:2e:80:1e + octphy net-device eth0.2342 + instance 0 bts 0 band 1800 ipa unit-id 1234 0 oml remote-ip 127.0.0.1 - phy-hw-addr 00:0C:90:2e:80:1e - phy-netdev eth0.2342 + trx 0 + phy 0 instance 0 diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am index af88a1a..d0b55ff 100644 --- a/include/osmo-bts/Makefile.am +++ b/include/osmo-bts/Makefile.am @@ -1,4 +1,4 @@ noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h logging.h measurement.h \ oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h pcuif_proto.h \ handover.h msg_utils.h tx_power.h control_if.h cbch.h l1sap.h \ - power_control.h scheduler.h scheduler_backend.h + power_control.h scheduler.h scheduler_backend.h phy_link.h diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h index 9e21186..af0b305 100644 --- a/include/osmo-bts/bts.h +++ b/include/osmo-bts/bts.h @@ -21,13 +21,12 @@ void destroy_bts(struct gsm_bts *bts); int work_bts(struct gsm_bts *bts); int bts_link_estab(struct gsm_bts *bts); int trx_link_estab(struct gsm_bts_trx *trx); +int trx_set_available(struct gsm_bts_trx *trx, int avail); void bts_new_si(void *arg); void bts_setup_slot(struct gsm_bts_trx_ts *slot, uint8_t comb); int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg); struct msgb *bts_agch_dequeue(struct gsm_bts *bts); -void bts_update_agch_max_queue_length(struct gsm_bts *bts); -int bts_agch_max_queue_length(int T, int bcch_conf); int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt, int is_ag_res); diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h index 41b5e93..dfea988 100644 --- a/include/osmo-bts/bts_model.h +++ b/include/osmo-bts/bts_model.h @@ -8,6 +8,9 @@ #include +struct phy_link; +struct phy_instance; + /* BTS model specific functions needed by the common code */ int bts_model_init(struct gsm_bts *bts); @@ -32,6 +35,8 @@ int bts_model_vty_init(struct gsm_bts *bts); void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts); void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx); +void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink); +void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst); int bts_model_oml_estab(struct gsm_bts *bts); diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h index 6a7bca8..f9e6ed1 100644 --- a/include/osmo-bts/gsm_data.h +++ b/include/osmo-bts/gsm_data.h @@ -119,21 +119,6 @@ enum lchan_ciph_state { #include "openbsc/gsm_data_shared.h" -struct femtol1_hdl; - -static inline struct femtol1_hdl *trx_femtol1_hdl(struct gsm_bts_trx *trx) -{ - return trx->role_bts.l1h; -} - -struct trx_l1h; - -static inline struct trx_l1h *trx_l1h_hdl(struct gsm_bts_trx *trx) -{ - return trx->role_bts.l1h; -} - - void lchan_set_state(struct gsm_lchan *lchan, enum gsm_lchan_state state); /* cipher code */ diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h new file mode 100644 index 0000000..b9fc412 --- /dev/null +++ b/include/osmo-bts/phy_link.h @@ -0,0 +1,115 @@ +#pragma once + +#include +#include + +#include + +#include + +struct gsm_bts_trx; + +enum phy_link_type { + PHY_LINK_T_NONE, + PHY_LINK_T_SYSMOBTS, + PHY_LINK_T_OSMOTRX, +}; + +enum phy_link_state { + PHY_LINK_SHUTDOWN, + PHY_LINK_CONNECTING, + PHY_LINK_CONNECTED, +}; + +/* A PHY link represents the connection to a given PHYsical layer + * implementation. That PHY link contains 1...N PHY instances, one for + * each TRX */ +struct phy_link { + struct llist_head list; + int num; + enum phy_link_type type; + enum phy_link_state state; + struct llist_head instances; + char *description; + union { + struct { + } sysmobts; + struct { + char *transceiver_ip; + uint16_t base_port_local; + uint16_t base_port_remote; + struct osmo_fd trx_ofd_clk; + + uint32_t clock_advance; + uint32_t rts_advance; + + int rxgain_valid; + int rxgain; + int rxgain_sent; + + int power_valid; + int power; + int power_oml; + int power_sent; + } osmotrx; + struct { + /* MAC address of the PHY */ + struct sockaddr_ll phy_addr; + /* Network device name */ + char *netdev_name; + + /* configuration */ + uint32_t rf_port_index; + uint32_t rx_gain_db; + uint32_t tx_atten_db; + + struct octphy_hdl *hdl; + } octphy; + } u; +}; + +struct phy_instance { + /* liked inside phy_link.linstances */ + struct llist_head list; + int num; + char *description; + + /* pointer to the PHY link to which we belong */ + struct phy_link *phy_link; + + /* back-pointer to the TRX to which we're associated */ + struct gsm_bts_trx *trx; + + union { + struct { + } sysmobts; + struct { + struct trx_l1h *hdl; + } osmotrx; + struct { + /* logical transceiver number within one PHY */ + uint32_t trx_id; + } octphy; + } u; +}; + +struct phy_link *phy_link_by_num(int num); +struct phy_link *phy_link_create(void *ctx, int num); +void phy_link_destroy(struct phy_link *plink); +void phy_link_state_set(struct phy_link *plink, enum phy_link_state state); +int phy_links_open(void); + +struct phy_instance *phy_instance_by_num(struct phy_link *plink, int num); +struct phy_instance *phy_instance_create(struct phy_link *plink, int num); +void phy_instance_link_to_trx(struct phy_instance *pinst, struct gsm_bts_trx *trx); +void phy_instance_destroy(struct phy_instance *pinst); +const char *phy_instance_name(struct phy_instance *pinst); + +void phy_user_statechg_notif(struct phy_instance *pinst, enum phy_link_state link_state); + +static inline struct phy_instance *trx_phy_instance(struct gsm_bts_trx *trx) +{ + return trx->role_bts.l1h; +} + +int bts_model_phy_link_open(struct phy_link *plink); diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h index 13ef051..b11e6f1 100644 --- a/include/osmo-bts/scheduler.h +++ b/include/osmo-bts/scheduler.h @@ -1,6 +1,8 @@ #ifndef TRX_SCHEDULER_H #define TRX_SCHEDULER_H +#include + /* These types define the different channels on a multiframe. * Each channel has queues and can be activated individually. */ @@ -133,7 +135,7 @@ extern uint32_t transceiver_last_fn; /*! \brief Initialize the scheudler data structures */ -int trx_sched_init(struct l1sched_trx *l1t); +int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx); /*! \brief De-initialize the scheudler data structures */ void trx_sched_exit(struct l1sched_trx *l1t); diff --git a/include/osmo-bts/vty.h b/include/osmo-bts/vty.h index 546729c..5d8d4a7 100644 --- a/include/osmo-bts/vty.h +++ b/include/osmo-bts/vty.h @@ -5,7 +5,12 @@ #include enum bts_vty_node { - BTS_NODE = _LAST_OSMOVTY_NODE + 1, + /* PHY_NODE must come before BTS node to ensure the phy + * instances are created at the time the TRX nodes want to refer + * to them */ + PHY_NODE = _LAST_OSMOVTY_NODE + 1, + PHY_INST_NODE, + BTS_NODE, TRX_NODE, }; diff --git a/src/common/Makefile.am b/src/common/Makefile.am index fea205c..8df6513 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -8,6 +8,6 @@ libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \ load_indication.c pcu_sock.c handover.c msg_utils.c \ load_indication.c pcu_sock.c handover.c msg_utils.c \ tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c \ - l1sap.c cbch.c power_control.c main.c + l1sap.c cbch.c power_control.c main.c phy_link.c libl1sched_a_SOURCES = scheduler.c diff --git a/src/common/bts.c b/src/common/bts.c index 43f4c25..a775329 100644 --- a/src/common/bts.c +++ b/src/common/bts.c @@ -44,6 +44,8 @@ #include #include +static void bts_update_agch_max_queue_length(struct gsm_bts *bts); +static int bts_agch_max_queue_length(int T, int bcch_conf); struct gsm_network bts_gsmnet = { .bts_list = { &bts_gsmnet.bts_list, &bts_gsmnet.bts_list }, @@ -72,6 +74,8 @@ static int bts_signal_cbfn(unsigned int subsys, unsigned int signal, return 0; } +/* Initialize the BTS (and TRX) data structures, called before config + * file reading */ int bts_init(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb; @@ -255,6 +259,31 @@ int trx_link_estab(struct gsm_bts_trx *trx) return 0; } +/* set the availability of the TRX (used by PHY driver) */ +int trx_set_available(struct gsm_bts_trx *trx, int avail) +{ + int tn; + + LOGP(DSUM, LOGL_INFO, "TRX(%d): Setting available = %d\n", + trx->nr, avail); + if (avail) { + oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK); + oml_mo_tx_sw_act_rep(&trx->mo); + oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK); + oml_mo_tx_sw_act_rep(&trx->bb_transc.mo); + + for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) + oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY); + } else { + oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); + oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OFF_LINE); + + for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) + oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); + } + return 0; +} + int lchan_init_lapdm(struct gsm_lchan *lchan) { struct lapdm_channel *lc = &lchan->lapdm_ch; @@ -271,7 +300,7 @@ int lchan_init_lapdm(struct gsm_lchan *lchan) #define CCCH_RACH_RATIO_COMBINED256 (256*1/9) #define CCCH_RACH_RATIO_SEPARATE256 (256*10/55) -int bts_agch_max_queue_length(int T, int bcch_conf) +static int bts_agch_max_queue_length(int T, int bcch_conf) { int S, ccch_rach_ratio256, i; int T_group = 0; @@ -310,7 +339,7 @@ int bts_agch_max_queue_length(int T, int bcch_conf) return (T + 2 * S) * ccch_rach_ratio256 / 256; } -void bts_update_agch_max_queue_length(struct gsm_bts *bts) +static void bts_update_agch_max_queue_length(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb = bts_role_bts(bts); struct gsm48_system_information_type_3 *si3; diff --git a/src/common/main.c b/src/common/main.c index fabe482..e454a28 100644 --- a/src/common/main.c +++ b/src/common/main.c @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -284,6 +285,19 @@ int bts_main(int argc, char **argv) exit(1); } + if (!phy_link_by_num(0)) { + fprintf(stderr, "You need to configure at last phy0\n"); + exit(1); + } + + llist_for_each_entry(trx, &bts->trx_list, list) { + if (!trx->role_bts.l1h) { + fprintf(stderr, "TRX %u has no associated PHY instance\n", + trx->nr); + exit(1); + } + } + write_pid_file("osmo-bts"); bts_controlif_setup(bts); @@ -317,6 +331,12 @@ int bts_main(int argc, char **argv) exit(2); } + rc = phy_links_open(); + if (rc < 0) { + fprintf(stderr, "unable ot open PHY link(s)\n"); + exit(2); + } + if (daemonize) { rc = osmo_daemonize(); if (rc < 0) { diff --git a/src/common/phy_link.c b/src/common/phy_link.c new file mode 100644 index 0000000..9442349 --- /dev/null +++ b/src/common/phy_link.c @@ -0,0 +1,155 @@ +#include + +#include +#include + +#include +#include +#include +#include +#include + +static LLIST_HEAD(g_phy_links); + +struct phy_link *phy_link_by_num(int num) +{ + struct phy_link *plink; + + llist_for_each_entry(plink, &g_phy_links, list) { + if (plink->num == num) + return plink; + } + + return NULL; +} + +struct phy_link *phy_link_create(void *ctx, int num) +{ + struct phy_link *plink = talloc_zero(ctx, struct phy_link); + + if (phy_link_by_num(num)) + return NULL; + + plink = talloc_zero(ctx, struct phy_link); + plink->num = num; + plink->state = PHY_LINK_SHUTDOWN; + INIT_LLIST_HEAD(&plink->instances); + llist_add_tail(&plink->list, &g_phy_links); + + return plink; +} + +const struct value_string phy_link_state_vals[] = { + { PHY_LINK_SHUTDOWN, "shutdown" }, + { PHY_LINK_CONNECTING, "connectiong" }, + { PHY_LINK_CONNECTED, "connected" }, + { 0, NULL } +}; + +void phy_link_state_set(struct phy_link *plink, enum phy_link_state state) +{ + struct phy_instance *pinst; + + LOGP(DL1C, LOGL_INFO, "PHY link state change %s -> %s\n", + get_value_string(phy_link_state_vals, plink->state), + get_value_string(phy_link_state_vals, state)); + + /* notify all TRX associated with this phy */ + llist_for_each_entry(pinst, &plink->instances, list) { + struct gsm_bts_trx *trx = pinst->trx; + if (!trx) + continue; + + switch (state) { + case PHY_LINK_CONNECTED: + LOGP(DL1C, LOGL_INFO, "trx_set_avail(1)\n"); + trx_set_available(trx, 1); + break; + default: + LOGP(DL1C, LOGL_INFO, "trx_set_avail(0)\n"); + trx_set_available(trx, 0); + break; + } + } + + plink->state = state; +} + +struct phy_instance *phy_instance_by_num(struct phy_link *plink, int num) +{ + struct phy_instance *pinst; + + llist_for_each_entry(pinst, &plink->instances, list) { + if (pinst->num == num) + return pinst; + } + return NULL; +} + +struct phy_instance *phy_instance_create(struct phy_link *plink, int num) +{ + struct phy_instance *pinst = talloc_zero(plink, struct phy_instance); + + if (phy_instance_by_num(plink, num)) + return NULL; + + pinst = talloc_zero(plink, struct phy_instance); + pinst->num = num; + pinst->phy_link = plink; + llist_add_tail(&pinst->list, &plink->instances); + + return pinst; +} + +void phy_instance_link_to_trx(struct phy_instance *pinst, struct gsm_bts_trx *trx) +{ + trx->role_bts.l1h = pinst; + pinst->trx = trx; +} + +void phy_instance_destroy(struct phy_instance *pinst) +{ + /* remove from list of instances in the link */ + llist_del(&pinst->list); + + /* remove reverse link from TRX */ + OSMO_ASSERT(pinst->trx->role_bts.l1h == pinst); + pinst->trx->role_bts.l1h = NULL; + pinst->trx = NULL; + + talloc_free(pinst); +} + +void phy_link_destroy(struct phy_link *plink) +{ + struct phy_instance *pinst, *pinst2; + + llist_for_each_entry_safe(pinst, pinst2, &plink->instances, list) + phy_instance_destroy(pinst); + + talloc_free(plink); +} + +int phy_links_open(void) +{ + struct phy_link *plink; + + llist_for_each_entry(plink, &g_phy_links, list) { + int rc; + + rc = bts_model_phy_link_open(plink); + if (rc < 0) + return rc; + } + + return 0; +} + +const char *phy_instance_name(struct phy_instance *pinst) +{ + static char buf[32]; + + snprintf(buf, sizeof(buf), "phy%u.%u", pinst->phy_link->num, + pinst->num); + return buf; +} diff --git a/src/common/scheduler.c b/src/common/scheduler.c index 64d89ac..de09fbf 100644 --- a/src/common/scheduler.c +++ b/src/common/scheduler.c @@ -134,11 +134,13 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = { * init / exit */ -int trx_sched_init(struct l1sched_trx *l1t) +int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx) { uint8_t tn; int i; + l1t->trx = trx; + LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1t->trx->nr); for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { @@ -191,7 +193,7 @@ void trx_sched_exit(struct l1sched_trx *l1t) void trx_sched_reset(struct l1sched_trx *l1t) { trx_sched_exit(l1t); - trx_sched_init(l1t); + trx_sched_init(l1t, l1t->trx); } struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn, diff --git a/src/common/vty.c b/src/common/vty.c index 4fd65d0..94ccdbe 100644 --- a/src/common/vty.c +++ b/src/common/vty.c @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -53,6 +54,13 @@ int bts_vty_go_parent(struct vty *vty) { switch (vty->node) { + case PHY_INST_NODE: + vty->node = PHY_NODE; + { + struct phy_instance *pinst = vty->index; + vty->index = pinst->phy_link; + } + break; case TRX_NODE: vty->node = BTS_NODE; { @@ -60,6 +68,7 @@ int bts_vty_go_parent(struct vty *vty) vty->index = trx->bts; } break; + case PHY_NODE: default: vty->node = CONFIG_NODE; } @@ -71,6 +80,8 @@ int bts_vty_is_config_node(struct vty *vty, int node) switch (node) { case TRX_NODE: case BTS_NODE: + case PHY_NODE: + case PHY_INST_NODE: return 1; default: return 0; @@ -81,6 +92,17 @@ gDEFUN(ournode_exit, ournode_exit_cmd, "exit", "Exit current node, go down to provious node") { switch (vty->node) { + case PHY_INST_NODE: + vty->node = PHY_NODE; + { + struct phy_instance *pinst = vty->index; + vty->index = pinst->phy_link; + } + break; + case PHY_NODE: + vty->node = CONFIG_NODE; + vty->index = NULL; + break; case TRX_NODE: vty->node = BTS_NODE; { @@ -141,6 +163,7 @@ static struct cmd_node trx_node = { 1, }; + DEFUN(cfg_bts_trx, cfg_bts_trx_cmd, "trx <0-254>", "Select a TRX to configure\n" "TRX number\n") @@ -151,7 +174,7 @@ DEFUN(cfg_bts_trx, cfg_bts_trx_cmd, trx = gsm_bts_trx_num(bts, trx_nr); if (!trx) { - vty_out(vty, "Unknown TRX %u. Aavialable TRX are: 0..%d%s", + vty_out(vty, "Unknown TRX %u. Aavialable TRX are: 0..%u%s", trx_nr, bts->num_trx - 1, VTY_NEWLINE); return CMD_WARNING; } @@ -232,6 +255,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) llist_for_each_entry(trx, &bts->trx_list, list) { struct trx_power_params *tpp = &trx->power_params; + struct phy_instance *pinst = trx_phy_instance(trx); vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE); if (trx->power_params.user_gain_mdB) @@ -246,6 +270,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " ms-power-control %s%s", trx->ms_power_control == 0 ? "dsp" : "osmo", VTY_NEWLINE); + vty_out(vty, " phy %u instance %u%s", pinst->phy_link->num, + pinst->num, VTY_NEWLINE); bts_model_config_write_trx(vty, trx); } @@ -262,6 +288,35 @@ static int config_write_bts(struct vty *vty) return CMD_SUCCESS; } +static void config_write_phy_single(struct vty *vty, struct phy_link *plink) +{ + int i; + + vty_out(vty, "phy %u%s", plink->num, VTY_NEWLINE); + bts_model_config_write_phy(vty, plink); + + for (i = 0; i < 255; i++) { + struct phy_instance *pinst = phy_instance_by_num(plink, i); + if (!pinst) + break; + vty_out(vty, " instance %u%s", pinst->num, VTY_NEWLINE); + } +} + +static int config_write_phy(struct vty *vty) +{ + int i; + + for (i = 0; i < 255; i++) { + struct phy_link *plink = phy_link_by_num(i); + if (!plink) + break; + config_write_phy_single(vty, plink); + } + + return CMD_SUCCESS; +} + static int config_write_dummy(struct vty *vty) { return CMD_SUCCESS; @@ -532,6 +587,33 @@ DEFUN(cfg_trx_ms_power_control, cfg_trx_ms_power_control_cmd, return CMD_SUCCESS; } +DEFUN(cfg_trx_phy, cfg_trx_phy_cmd, + "phy <0-255> instance <0-255>", + "Configure PHY Link+Instance for this TRX\n" + "PHY Link number\n" "PHY instance\n" "PHY Instance number") +{ + struct gsm_bts_trx *trx = vty->index; + struct phy_link *plink = phy_link_by_num(atoi(argv[0])); + struct phy_instance *pinst; + + if (!plink) { + vty_out(vty, "phy%s does not exist%s", + argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + pinst = phy_instance_by_num(plink, atoi(argv[1])); + if (!pinst) { + vty_out(vty, "phy%s instance %s does not exit%s", + argv[0], argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + + trx->role_bts.l1h = pinst; + pinst->trx = trx; + + return CMD_SUCCESS; +} /* ====================================================================== * SHOW @@ -702,6 +784,106 @@ DEFUN(cfg_trx_no_gsmtap_sapi, cfg_trx_no_gsmtap_sapi_cmd, return CMD_SUCCESS; } +static struct cmd_node phy_node = { + PHY_NODE, + "%s(phy)#", + 1, +}; + +static struct cmd_node phy_inst_node = { + PHY_INST_NODE, + "%s(phy-inst)#", + 1, +}; + +DEFUN(cfg_phy, cfg_phy_cmd, + "phy <0-255>", + "Select a PHY to configure\n" "PHY number\n") +{ + int phy_nr = atoi(argv[0]); + struct phy_link *plink; + + plink = phy_link_by_num(phy_nr); + if (!plink) + plink = phy_link_create(tall_bts_ctx, phy_nr); + if (!plink) + return CMD_WARNING; + + vty->index = plink; + vty->index_sub = &plink->description; + vty->node = PHY_NODE; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_inst, cfg_phy_inst_cmd, + "instance <0-255>", + "Select a PHY instance to configure\n" "PHY Instance number\n") +{ + int inst_nr = atoi(argv[0]); + struct phy_link *plink = vty->index; + struct phy_instance *pinst; + + pinst = phy_instance_by_num(plink, inst_nr); + if (!pinst) { + pinst = phy_instance_create(plink, inst_nr); + if (!pinst) { + vty_out(vty, "Unable to create phy%u instance %u%s", + plink->num, inst_nr, VTY_NEWLINE); + return CMD_WARNING; + } + } + + vty->index = pinst; + vty->index_sub = &pinst->description; + vty->node = PHY_INST_NODE; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_no_inst, cfg_phy_no_inst_cmd, + "no instance <0-255>" + NO_STR "Select a PHY instance to remove\n", "PHY Instance number\n") +{ + int inst_nr = atoi(argv[0]); + struct phy_link *plink = vty->index; + struct phy_instance *pinst; + + pinst = phy_instance_by_num(plink, inst_nr); + if (!pinst) { + vty_out(vty, "No such instance %u%s", inst_nr, VTY_NEWLINE); + return CMD_WARNING; + } + + phy_instance_destroy(pinst); + + return CMD_SUCCESS; +} + +#if 0 +DEFUN(cfg_phy_type, cfg_phy_type_cmd, + "type (sysmobts|osmo-trx|virtual)", + "configure the type of the PHY\n" + "sysmocom sysmoBTS PHY\n" + "OsmoTRX based PHY\n" + "Virtual PHY (GSMTAP based)\n") +{ + struct phy_link *plink = vty->index; + + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Cannot change type of active PHY%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(argv[0], "sysmobts")) + plink->type = PHY_LINK_T_SYSMOBTS; + else if (!strcmp(argv[0], "osmo-trx")) + plink->type = PHY_LINK_T_OSMOTRX; + else if (!strcmp(argv[0], "virtual")) + plink->type = PHY_LINK_T_VIRTUAL; +} +#endif + DEFUN(bts_t_t_l_jitter_buf, bts_t_t_l_jitter_buf_cmd, "bts <0-0> trx <0-0> ts <0-7> lchan <0-1> rtp jitter-buffer <0-10000>", @@ -813,10 +995,20 @@ int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat) install_element(TRX_NODE, &cfg_trx_pr_step_size_cmd); install_element(TRX_NODE, &cfg_trx_pr_step_interval_cmd); install_element(TRX_NODE, &cfg_trx_ms_power_control_cmd); + install_element(TRX_NODE, &cfg_trx_phy_cmd); install_element(ENABLE_NODE, &bts_t_t_l_jitter_buf_cmd); install_element(ENABLE_NODE, &bts_t_t_l_loopback_cmd); install_element(ENABLE_NODE, &no_bts_t_t_l_loopback_cmd); + install_element(CONFIG_NODE, &cfg_phy_cmd); + install_node(&phy_node, config_write_phy); + install_default(PHY_NODE); + install_element(PHY_NODE, &cfg_phy_inst_cmd); + install_element(PHY_NODE, &cfg_phy_no_inst_cmd); + + install_node(&phy_inst_node, config_write_dummy); + install_default(PHY_INST_NODE); + return 0; } diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c index db6e032..f73e4f9 100644 --- a/src/osmo-bts-octphy/l1_if.c +++ b/src/osmo-bts-octphy/l1_if.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -109,6 +110,17 @@ osmocom_to_octphy_band(enum gsm_band osmo_band, unsigned int arfcn) } }; +struct gsm_bts_trx *trx_by_l1h(struct octphy_hdl *fl1h, unsigned int trx_id) +{ + struct phy_instance *pinst; + + pinst = phy_instance_by_num(fl1h->phy_link, trx_id); + if (!pinst) + return NULL; + + return pinst->trx; +} + struct gsm_lchan *get_lchan_by_lchid(struct gsm_bts_trx *trx, tOCTVC1_GSM_LOGICAL_CHANNEL_ID *lch_id) { @@ -282,10 +294,9 @@ int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg, } /* For OctPHY, this only about sending state changes to BSC */ -int l1if_activate_rf(struct octphy_hdl *fl1h, int on) +int l1if_activate_rf(struct gsm_bts_trx *trx, int on) { int i; - struct gsm_bts_trx *trx = fl1h->priv; if (on) { /* signal availability */ oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK); @@ -422,7 +433,8 @@ static void empty_req_from_rts_ind(tOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_E static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, struct osmo_phsap_prim *l1sap) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *l1msg = l1p_msgb_alloc(); uint32_t u32Fn; uint8_t u8Tn, subCh, sapi = 0; @@ -489,7 +501,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_fill_msg_hdr(&data_req->Header, l1msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CID); - data_req->TrxId.byTrxId = trx->nr; + data_req->TrxId.byTrxId = pinst->u.octphy.trx_id; data_req->LchId.byTimeslotNb = u8Tn; data_req->LchId.bySAPI = sapi; data_req->LchId.bySubChannelNb = subCh; @@ -508,7 +520,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_fill_msg_hdr(&empty_frame_req->Header, l1msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_EMPTY_FRAME_CID); - empty_frame_req->TrxId.byTrxId = trx->nr; + empty_frame_req->TrxId.byTrxId = pinst->u.octphy.trx_id; empty_frame_req->LchId.byTimeslotNb = u8Tn; empty_frame_req->LchId.bySAPI = sapi; empty_frame_req->LchId.bySubChannelNb = subCh; @@ -527,7 +539,8 @@ done: static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, struct osmo_phsap_prim *l1sap) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct gsm_lchan *lchan; uint32_t u32Fn; uint8_t u8Tn, subCh, sapi, ss; @@ -565,7 +578,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_fill_msg_hdr(&data_req->Header, nmsg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CID); - data_req->TrxId.byTrxId = trx->nr; + data_req->TrxId.byTrxId = pinst->u.octphy.trx_id; data_req->LchId.byTimeslotNb = u8Tn; data_req->LchId.bySAPI = sapi; data_req->LchId.bySubChannelNb = subCh; @@ -590,7 +603,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_fill_msg_hdr(&empty_frame_req->Header, nmsg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_EMPTY_FRAME_CID); - empty_frame_req->TrxId.byTrxId = trx->nr; + empty_frame_req->TrxId.byTrxId = pinst->u.octphy.trx_id; empty_frame_req->LchId.byTimeslotNb = u8Tn; empty_frame_req->LchId.bySAPI = sapi; empty_frame_req->LchId.bySubChannelNb = subCh; @@ -686,32 +699,37 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) return rc; } +int bts_model_phy_link_open(struct phy_link *plink) +{ + if (plink->u.octphy.hdl) + l1if_close(plink->u.octphy.hdl); + + phy_link_state_set(plink, PHY_LINK_CONNECTING); + + plink->u.octphy.hdl = l1if_open(plink); + if (!plink->u.octphy.hdl) { + phy_link_state_set(plink, PHY_LINK_SHUTDOWN); + return -1; + } + + /* do we need to iterate over the list of instances and do some + * instance-specific initialization? */ + + /* FIXME: delay this until we know the PHY responds */ + phy_link_state_set(plink, PHY_LINK_CONNECTED); + + return 0; +} + int bts_model_init(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb; - struct octphy_hdl *fl1h; LOGP(DL1C, LOGL_NOTICE, "model_init()\n"); btsb = bts_role_bts(bts); btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3); - fl1h = talloc_zero(bts, struct octphy_hdl); - if (!fl1h) - return -ENOMEM; - - INIT_LLIST_HEAD(&fl1h->wlc_list); - INIT_LLIST_HEAD(&fl1h->wlc_postponed); - fl1h->priv = bts->c0; - bts->c0->role_bts.l1h = fl1h; - /* FIXME: what is the nominal transmit power of the PHY/board? */ - bts->c0->nominal_power = 15; - - /* configure some reasonable defaults, to be overridden by VTY */ - fl1h->config.rf_port_index = 0; - fl1h->config.rx_gain_db = 70; - fl1h->config.tx_atten_db = 0; - bts_model_vty_init(bts); return 0; @@ -750,23 +768,15 @@ static void dump_meas_res(int ll, tOCTVC1_GSM_MEASUREMENT_INFO * m) static int handle_mph_time_ind(struct octphy_hdl *fl1, uint8_t trx_id, uint32_t fn) { - struct gsm_bts_trx *trx = fl1->priv; - struct gsm_bts *bts = trx->bts; + struct gsm_bts_trx *trx = trx_by_l1h(fl1, trx_id); struct osmo_phsap_prim l1sap; /* increment the primitive count for the alive timer */ fl1->alive_prim_cnt++; /* ignore every time indication, except for c0 */ - if (trx != bts->c0) - return 0; - - if (trx_id != trx->nr) { - LOGP(DL1C, LOGL_FATAL, - "TRX id %d from response does not match the L1 context trx %d\n", - trx_id, trx->nr); + if (trx != trx->bts->c0) return 0; - } memset(&l1sap, 0, sizeof(l1sap)); osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, @@ -783,7 +793,7 @@ static int handle_ph_readytosend_ind(struct octphy_hdl *fl1, tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_READY_TO_SEND_INDICATION_EVT *evt, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = trx_by_l1h(fl1, evt->TrxId.byTrxId); struct gsm_bts *bts = trx->bts; struct osmo_phsap_prim *l1sap; struct gsm_time g_time; @@ -908,7 +918,7 @@ static int handle_ph_data_ind(struct octphy_hdl *fl1, tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_DATA_INDICATION_EVT *data_ind, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = trx_by_l1h(fl1, data_ind->TrxId.byTrxId); uint8_t chan_nr, link_id; struct osmo_phsap_prim *l1sap; uint32_t fn; @@ -992,7 +1002,7 @@ static int handle_ph_rach_ind(struct octphy_hdl *fl1, tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_RACH_INDICATION_EVT *ra_ind, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = trx_by_l1h(fl1, ra_ind->TrxId.byTrxId); struct gsm_bts *bts = trx->bts; struct gsm_bts_role_bts *btsb = bts_role_bts(bts); struct gsm_lchan *lchan; @@ -1131,7 +1141,7 @@ static int rx_octvc1_resp(struct msgb *msg, uint32_t msg_id, uint32_t trans_id) if (wlc->cb) { /* call-back function must take msgb * ownership. */ - rc = wlc->cb(fl1h->priv, msg, wlc->cb_data); + rc = wlc->cb(fl1h, msg, wlc->cb_data); } else { rc = 0; msgb_free(msg); @@ -1534,15 +1544,35 @@ static int octphy_write_cb(struct osmo_fd *fd, struct msgb *msg) return rc; } -int l1if_open(struct octphy_hdl *fl1h) +struct octphy_hdl *l1if_open(struct phy_link *plink) { + struct octphy_hdl *fl1h; struct ifreq ifr; int sfd, rc; - char *phy_dev = fl1h->netdev_name; + char *phy_dev = plink->u.octphy.netdev_name; + + fl1h = talloc_zero(plink, struct octphy_hdl); + if (!fl1h) + return NULL; + + INIT_LLIST_HEAD(&fl1h->wlc_list); + INIT_LLIST_HEAD(&fl1h->wlc_postponed); + fl1h->phy_link = plink; +#if 0 + bts->c0->role_bts.l1h = fl1h; + /* FIXME: what is the nominal transmit power of the PHY/board? */ + bts->c0->nominal_power = 15; + + /* configure some reasonable defaults, to be overridden by VTY */ + fl1h->config.rf_port_index = 0; + fl1h->config.rx_gain_db = 70; + fl1h->config.tx_atten_db = 0; +#endif if (!phy_dev) { LOGP(DL1C, LOGL_ERROR, "You have to specify a phy-netdev\n"); - return -EINVAL; + talloc_free(fl1h); + return NULL; } LOGP(DL1C, LOGL_NOTICE, "Opening L1 interface for OctPHY (%s)\n", @@ -1553,7 +1583,8 @@ int l1if_open(struct octphy_hdl *fl1h) if (sfd < 0) { LOGP(DL1C, LOGL_FATAL, "Error opening PHY socket: %s\n", strerror(errno)); - return -EIO; + talloc_free(fl1h); + return NULL; } /* resolve the string device name to an ifindex */ @@ -1564,18 +1595,21 @@ int l1if_open(struct octphy_hdl *fl1h) LOGP(DL1C, LOGL_FATAL, "Error using network device %s: %s\n", phy_dev, strerror(errno)); close(sfd); - return -EIO; + talloc_free(fl1h); + return NULL; } fl1h->session_id = rand(); - /* set fl1h->phy_addr, which we use as sendto() destionation */ + /* set fl1h->phy_addr, which we use as sendto() destination */ fl1h->phy_addr.sll_family = AF_PACKET; fl1h->phy_addr.sll_protocol = htons(cOCTPKT_HDR_ETHERTYPE); fl1h->phy_addr.sll_ifindex = ifr.ifr_ifindex; fl1h->phy_addr.sll_hatype = ARPHRD_ETHER; - fl1h->phy_addr.sll_halen = 6; - /* sll_addr is filled by bts_model_vty code */ + fl1h->phy_addr.sll_halen = ETH_ALEN; + /* plink->phy_addr.sll_addr is filled by bts_model_vty code */ + memcpy(fl1h->phy_addr.sll_addr, plink->u.octphy.phy_addr.sll_addr, + ETH_ALEN); /* Write queue / osmo_fd registration */ osmo_wqueue_init(&fl1h->phy_wq, 10); @@ -1588,10 +1622,11 @@ int l1if_open(struct octphy_hdl *fl1h) rc = osmo_fd_register(&fl1h->phy_wq.bfd); if (rc < 0) { close(sfd); - return -EIO; + talloc_free(fl1h); + return NULL; } - return 0; + return fl1h; } int l1if_close(struct octphy_hdl *fl1h) diff --git a/src/osmo-bts-octphy/l1_if.h b/src/osmo-bts-octphy/l1_if.h index 4277865..2dee178 100644 --- a/src/osmo-bts-octphy/l1_if.h +++ b/src/osmo-bts-octphy/l1_if.h @@ -13,16 +13,16 @@ #include #include +#include #include struct octphy_hdl { + /* MAC address of the PHY */ + struct sockaddr_ll phy_addr; + /* packet socket to talk with PHY */ struct osmo_wqueue phy_wq; - /* MAC address of th PHY */ - struct sockaddr_ll phy_addr; - /* Network device name */ - char *netdev_name; /* address parameters of the PHY */ uint32_t session_id; @@ -33,12 +33,6 @@ struct octphy_hdl { uint32_t clkmgr_state; struct { - uint32_t rf_port_index; - uint32_t rx_gain_db; - uint32_t tx_atten_db; - } config; - - struct { struct { char *name; char *description; @@ -72,8 +66,8 @@ struct octphy_hdl { struct llist_head wlc_postponed; int wlc_postponed_len; - /* private pointer, points back to TRX */ - void *priv; + /* back pointer to the PHY link */ + struct phy_link *phy_link; struct osmo_timer_list alive_timer; uint32_t alive_prim_cnt; @@ -82,15 +76,10 @@ struct octphy_hdl { int opened; }; -static inline struct octphy_hdl *trx_octphy_hdl(struct gsm_bts_trx *trx) -{ - return trx->role_bts.l1h; -} - void l1if_fill_msg_hdr(tOCTVC1_MSG_HEADER *mh, struct msgb *msg, struct octphy_hdl *fl1h, uint32_t msg_type, uint32_t api_cmd); -typedef int l1if_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg, void *data); +typedef int l1if_compl_cb(struct octphy_hdl *fl1, struct msgb *l1_msg, void *data); /* send a request primitive to the L1 and schedule completion call-back */ int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg, @@ -100,19 +89,21 @@ int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg, struct gsm_lchan *get_lchan_by_lchid(struct gsm_bts_trx *trx, tOCTVC1_GSM_LOGICAL_CHANNEL_ID *lch_id); -int l1if_open(struct octphy_hdl *fl1h); +struct octphy_hdl *l1if_open(struct phy_link *plink); int l1if_close(struct octphy_hdl *hdl); int l1if_trx_open(struct gsm_bts_trx *trx); int l1if_trx_close_all(struct gsm_bts *bts); int l1if_enable_events(struct gsm_bts_trx *trx); -int l1if_activate_rf(struct octphy_hdl *fl1h, int on); +int l1if_activate_rf(struct gsm_bts_trx *trx, int on); int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_DATA_INDICATION_EVT * data_ind); +struct gsm_bts_trx *trx_by_l1h(struct octphy_hdl *fl1h, unsigned int trx_id); + struct msgb *l1p_msgb_alloc(void); /* tch.c */ diff --git a/src/osmo-bts-octphy/l1_oml.c b/src/osmo-bts-octphy/l1_oml.c index 318c384..627b238 100644 --- a/src/osmo-bts-octphy/l1_oml.c +++ b/src/osmo-bts-octphy/l1_oml.c @@ -348,10 +348,11 @@ static void sapi_clear_queue(struct llist_head *queue) } } -static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int lchan_act_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP *ar = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP *) resp->l2h; + struct gsm_bts_trx *trx; struct gsm_lchan *lchan; uint8_t sapi; uint8_t direction; @@ -361,7 +362,7 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void * * release it before returning */ mOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP_SWAP(ar); - OSMO_ASSERT(ar->TrxId.byTrxId == trx->nr); + trx = trx_by_l1h(fl1, ar->TrxId.byTrxId); lchan = get_lchan_by_lchid(trx, &ar->LchId); sapi = ar->LchId.bySAPI; @@ -411,7 +412,8 @@ err: static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd) { - struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_CMD *lac; @@ -420,7 +422,7 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd) l1if_fill_msg_hdr(&lac->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_CID); - lac->TrxId.byTrxId = lchan->ts->trx->nr; + lac->TrxId.byTrxId = pinst->u.octphy.trx_id; lac->LchId.byTimeslotNb = lchan->ts->nr; lac->LchId.bySubChannelNb = lchan_to_GsmL1_SubCh_t(lchan); lac->LchId.bySAPI = cmd->sapi; @@ -451,10 +453,11 @@ static tOCTVC1_GSM_CIPHERING_ID_ENUM rsl2l1_ciph[] = { [4] = cOCTVC1_GSM_CIPHERING_ID_ENUM_A5_3 }; -static int set_ciph_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int set_ciph_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_RSP *pcr = (tOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_RSP *) resp->l2h; + struct gsm_bts_trx *trx; struct gsm_bts_trx_ts *ts; struct gsm_lchan *lchan; @@ -470,6 +473,7 @@ static int set_ciph_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d exit(-1); } + trx = trx_by_l1h(fl1, pcr->TrxId.byTrxId); OSMO_ASSERT(pcr->TrxId.byTrxId == trx->nr); ts = &trx->ts[pcr->PchId.byTimeslotNb]; /* for some strange reason the response does not tell which @@ -508,8 +512,8 @@ err: static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *cmd) { - struct gsm_bts_trx *trx = lchan->ts->trx; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_CMD *pcc; @@ -518,6 +522,7 @@ static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *c l1if_fill_msg_hdr(&pcc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_CID); + pcc->TrxId.byTrxId = pinst->u.octphy.trx_id; pcc->PchId.byTimeslotNb = lchan->ts->nr; pcc->ulSubchannelNb = lchan_to_GsmL1_SubCh_t(lchan); pcc->ulDirection = cmd->dir; @@ -627,7 +632,8 @@ static int check_sapi_release(struct gsm_lchan *lchan, int sapi, int dir) static int lchan_deactivate_sapis(struct gsm_lchan *lchan) { - struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type]; int i, res; @@ -654,10 +660,11 @@ static int lchan_deactivate_sapis(struct gsm_lchan *lchan) return res; } -static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int lchan_deact_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP *ldr = (tOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP *) resp->l2h; + struct gsm_bts_trx *trx; struct gsm_lchan *lchan; struct sapi_cmd *cmd; uint8_t status; @@ -666,7 +673,7 @@ static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void * release it before returning */ mOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP_SWAP(ldr); - OSMO_ASSERT(ldr->TrxId.byTrxId == trx->nr); + trx = trx_by_l1h(fl1, ldr->TrxId.byTrxId); lchan = get_lchan_by_lchid(trx, &ldr->LchId); @@ -725,7 +732,8 @@ err: static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd) { - struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_CMD *ldc; @@ -734,6 +742,7 @@ static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd l1if_fill_msg_hdr(&ldc->Header, msg, fl1h,cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_CID); + ldc->TrxId.byTrxId = pinst->u.octphy.trx_id; ldc->LchId.byTimeslotNb = lchan->ts->nr; ldc->LchId.bySubChannelNb = lchan_to_GsmL1_SubCh_t(lchan); ldc->LchId.byDirection = cmd->dir; @@ -1031,7 +1040,8 @@ static void enqueue_sapi_act_cmd(struct gsm_lchan *lchan, int sapi, int dir) int lchan_activate(struct gsm_lchan *lchan) { - struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type]; unsigned int i; @@ -1069,7 +1079,7 @@ int l1if_rsl_chan_act(struct gsm_lchan *lchan) return 0; } -static int enable_events_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int enable_events_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_MAIN_MSG_API_SYSTEM_MODIFY_SESSION_EVT_RSP *mser = (tOCTVC1_MAIN_MSG_API_SYSTEM_MODIFY_SESSION_EVT_RSP *) resp->l2h; @@ -1088,7 +1098,8 @@ static int enable_events_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, vo int l1if_enable_events(struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_MAIN_MSG_API_SYSTEM_MODIFY_SESSION_EVT_CMD *mse; @@ -1112,9 +1123,8 @@ int l1if_enable_events(struct gsm_bts_trx *trx) dst = talloc_strdup(ctx, (const char *) src); \ } while (0) -static int app_info_sys_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int app_info_sys_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data) { - struct octphy_hdl *fl1h = resp->dst; tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_RSP *aisr = (tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_RSP *) resp->l2h; @@ -1136,7 +1146,8 @@ static int app_info_sys_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, voi int l1if_check_app_sys_version(struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_CMD *ais; @@ -1152,9 +1163,8 @@ int l1if_check_app_sys_version(struct gsm_bts_trx *trx) return l1if_req_compl(fl1h, msg, app_info_sys_compl_cb, 0); } -static int app_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int app_info_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data) { - struct octphy_hdl *fl1h = resp->dst; tOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP *air = (tOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP *) resp->l2h; @@ -1178,7 +1188,8 @@ static int app_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d int l1if_check_app_version(struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_MAIN_MSG_APPLICATION_INFO_CMD *ai; @@ -1194,8 +1205,11 @@ int l1if_check_app_version(struct gsm_bts_trx *trx) } /* call-back once the TRX_OPEN_CID response arrives */ -static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int trx_open_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data) { + struct gsm_bts_trx *trx; + struct phy_instance *pinst; + tOCTVC1_GSM_MSG_TRX_OPEN_RSP *or = (tOCTVC1_GSM_MSG_TRX_OPEN_RSP *) resp->l2h; @@ -1203,8 +1217,8 @@ static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d * release it before returning */ mOCTVC1_GSM_MSG_TRX_OPEN_RSP_SWAP(or); - - OSMO_ASSERT(or->TrxId.byTrxId == trx->nr); + trx = trx_by_l1h(fl1h, or->TrxId.byTrxId); + pinst = trx_phy_instance(trx); LOGP(DL1C, LOGL_INFO, "TRX-OPEN.resp(trx=%u) = %s\n", trx->nr, octvc1_rc2string(or->Header.ulReturnCode)); @@ -1221,7 +1235,6 @@ static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d opstart_compl(&trx->mo); - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); octphy_hw_get_pcb_info(fl1h); octphy_hw_get_rf_port_info(fl1h, 0); octphy_hw_get_rf_ant_rx_config(fl1h, 0, 0); @@ -1238,22 +1251,24 @@ static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d int l1if_trx_open(struct gsm_bts_trx *trx) { /* putting it all together */ - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct phy_link *plink = pinst->phy_link; + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_OPEN_CMD *oc; oc = (tOCTVC1_GSM_MSG_TRX_OPEN_CMD *) msgb_put(msg, sizeof(*oc)); l1if_fill_msg_hdr(&oc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_OPEN_CID); - oc->ulRfPortIndex = fl1h->config.rf_port_index; - oc->TrxId.byTrxId = trx->nr; + oc->ulRfPortIndex = plink->u.octphy.rf_port_index; + oc->TrxId.byTrxId = pinst->u.octphy.trx_id; oc->Config.ulBand = osmocom_to_octphy_band(trx->bts->band, trx->arfcn); oc->Config.usArfcn = trx->arfcn; oc->Config.usTsc = trx->bts->bsic & 0x7; oc->Config.usBcchArfcn = trx->bts->c0->arfcn; - oc->RfConfig.ulRxGainDb = fl1h->config.rx_gain_db; + oc->RfConfig.ulRxGainDb = plink->u.octphy.rx_gain_db; /* FIXME: compute this based on nominal transmit power, etc. */ - oc->RfConfig.ulTxAttndB = fl1h->config.tx_atten_db; + oc->RfConfig.ulTxAttndB = plink->u.octphy.tx_atten_db; LOGP(DL1C, LOGL_INFO, "Tx TRX-OPEN.req(trx=%u, rf_port=%u, arfcn=%u, " "tsc=%u, rx_gain=%u, tx_atten=%u)\n", @@ -1266,7 +1281,7 @@ int l1if_trx_open(struct gsm_bts_trx *trx) return l1if_req_compl(fl1h, msg, trx_open_compl_cb, NULL); } -static int trx_close_all_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int trx_close_all_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *car = (tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *) resp->l2h; @@ -1283,7 +1298,9 @@ static int trx_close_all_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *da int l1if_trx_close_all(struct gsm_bts *bts) { - struct octphy_hdl *fl1h = trx_octphy_hdl(bts->c0); +#warning "Truly iterate over all TRX in this BTS" + struct phy_instance *pinst = trx_phy_instance(bts->c0); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *cac; @@ -1325,11 +1342,12 @@ static int trx_init(struct gsm_bts_trx *trx) * PHYSICAL CHANNE ACTIVATION ***********************************************************************/ -static int pchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int pchan_act_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP *ar = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP *) resp->l2h; uint8_t ts_nr; + struct gsm_bts_trx *trx; struct gsm_bts_trx_ts *ts; struct gsm_abis_mo *mo; @@ -1337,9 +1355,8 @@ static int pchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void * * release it before returning */ mOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP_SWAP(ar); + trx = trx_by_l1h(fl1, ar->TrxId.byTrxId); ts_nr = ar->PchId.byTimeslotNb; - - OSMO_ASSERT(ar->TrxId.byTrxId == trx->nr); OSMO_ASSERT(ts_nr <= ARRAY_SIZE(trx->ts)); ts = &trx->ts[ts_nr]; @@ -1367,7 +1384,8 @@ static int pchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void * static int ts_connect(struct gsm_bts_trx_ts *ts) { - struct octphy_hdl *fl1h = trx_octphy_hdl(ts->trx); + struct phy_instance *pinst = trx_phy_instance(ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD *oc = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD *) oc; @@ -1376,7 +1394,7 @@ static int ts_connect(struct gsm_bts_trx_ts *ts) l1if_fill_msg_hdr(&oc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CID); - oc->TrxId.byTrxId = ts->trx->nr; + oc->TrxId.byTrxId = pinst->u.octphy.trx_id; oc->PchId.byTimeslotNb = ts->nr; oc->ulChannelType = pchan_to_logChComb[ts->pchan]; @@ -1430,8 +1448,7 @@ int bts_model_oml_estab(struct gsm_bts *bts) int i; for (i = 0; i < bts->num_trx; i++) { struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, i); - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); - l1if_activate_rf(fl1h, 1); + l1if_activate_rf(trx, 1); } return 0; } @@ -1447,8 +1464,7 @@ int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, int bts_model_trx_deact_rf(struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1 = trx_octphy_hdl(trx); - return l1if_activate_rf(fl1, 0); + return l1if_activate_rf(trx, 0); } int bts_model_trx_close(struct gsm_bts_trx *trx) diff --git a/src/osmo-bts-octphy/main.c b/src/osmo-bts-octphy/main.c index 1f516e4..d237e42 100644 --- a/src/osmo-bts-octphy/main.c +++ b/src/osmo-bts-octphy/main.c @@ -56,6 +56,7 @@ static struct gsm_bts *bts; int bts_model_print_help() { + return 0; } int bts_model_handle_options(int argc, char **argv) diff --git a/src/osmo-bts-octphy/octphy_hw_api.c b/src/osmo-bts-octphy/octphy_hw_api.c index 5291742..ec7c4be 100644 --- a/src/osmo-bts-octphy/octphy_hw_api.c +++ b/src/osmo-bts-octphy/octphy_hw_api.c @@ -35,7 +35,7 @@ #include /* Chapter 12.1 */ -static int get_pcb_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int get_pcb_info_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_PCB_INFO_RSP *pir = (tOCTVC1_HW_MSG_PCB_INFO_RSP *) resp->l2h; @@ -69,7 +69,7 @@ int octphy_hw_get_pcb_info(struct octphy_hdl *fl1h) } /* Chapter 12.9 */ -static int rf_port_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int rf_port_info_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_RF_PORT_INFO_RSP *pir = @@ -114,7 +114,7 @@ static const struct value_string radio_std_vals[] = { }; /* Chapter 12.10 */ -static int rf_port_stats_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int rf_port_stats_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_RF_PORT_STATS_RSP *psr = @@ -167,7 +167,7 @@ static const struct value_string rx_gain_mode_vals[] = { }; /* Chapter 12.13 */ -static int rf_ant_rx_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int rf_ant_rx_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_RSP *arc = @@ -209,7 +209,7 @@ int octphy_hw_get_rf_ant_rx_config(struct octphy_hdl *fl1h, uint32_t port_idx, } /* Chapter 12.14 */ -static int rf_ant_tx_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int rf_ant_tx_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_TX_CONFIG_RSP *atc = @@ -292,7 +292,7 @@ static const struct value_string clocksync_state_vals[] = { }; /* Chapter 12.15 */ -static int get_clock_sync_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int get_clock_sync_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_RSP *cir = @@ -326,7 +326,7 @@ int octphy_hw_get_clock_sync_info(struct octphy_hdl *fl1h) } /* Chapter 12.16 */ -static int get_clock_sync_stats_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int get_clock_sync_stats_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP *csr = diff --git a/src/osmo-bts-octphy/octphy_vty.c b/src/osmo-bts-octphy/octphy_vty.c index dbc903a..e2000e9 100644 --- a/src/osmo-bts-octphy/octphy_vty.c +++ b/src/osmo-bts-octphy/octphy_vty.c @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -51,149 +52,189 @@ SHOW_STR \ TRX_STR +#define OCT_STR "OCTPHY Um interface\n" + static struct gsm_bts *vty_bts; /* configuration */ -DEFUN(cfg_bts_phy_hwaddr, cfg_bts_phy_hwaddr_cmd, - "phy-hw-addr HWADDR", - "Configure the hardware addess of the OCTPHY\n" +DEFUN(cfg_phy_hwaddr, cfg_phy_hwaddr_cmd, + "octphy hw-addr HWADDR", + OCT_STR "Configure the hardware addess of the OCTPHY\n" "hardware address in aa:bb:cc:dd:ee:ff format\n") { - struct gsm_bts *bts = vty->index; - struct gsm_bts_trx *trx = bts->c0; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; int rc; - rc = osmo_macaddr_parse(fl1h->phy_addr.sll_addr, argv[0]); + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + rc = osmo_macaddr_parse(plink->u.octphy.phy_addr.sll_addr, argv[0]); if (rc < 0) return CMD_WARNING; return CMD_SUCCESS; } -DEFUN(cfg_bts_phy_netdev, cfg_bts_phy_netdev_cmd, - "phy-netdev NAME", - "Configure the hardware device towards the OCTPHY\n" +DEFUN(cfg_phy_netdev, cfg_phy_netdev_cmd, + "octphy net-device NAME", + OCT_STR "Configure the hardware device towards the OCTPHY\n" "Ethernet device name\n") { - struct gsm_bts *bts = vty->index; - struct gsm_bts_trx *trx = bts->c0; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; - if (fl1h->netdev_name) - talloc_free(fl1h->netdev_name); - fl1h->netdev_name = talloc_strdup(fl1h, argv[0]); + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (plink->u.octphy.netdev_name) + talloc_free(plink->u.octphy.netdev_name); + plink->u.octphy.netdev_name = talloc_strdup(plink, argv[0]); return CMD_SUCCESS; } -DEFUN(cfg_trx_rf_port_idx, cfg_trx_rf_port_idx_cmd, - "rf-port-index <0-255>", - "Configure the RF Port for this TRX\n" +DEFUN(cfg_phy_rf_port_idx, cfg_phy_rf_port_idx_cmd, + "octphy rf-port-index <0-255>", + OCT_STR "Configure the RF Port for this TRX\n" "RF Port Index\n") { - struct gsm_bts_trx *trx = vty->index; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; - fl1h->config.rf_port_index = atoi(argv[0]); + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + plink->u.octphy.rf_port_index = atoi(argv[0]); return CMD_SUCCESS; } -DEFUN(cfg_trx_rx_gain_db, cfg_trx_rx_gain_db_cmd, - "rx-gain <0-73>", - "Configure the Rx Gain in dB\n" +DEFUN(cfg_phy_rx_gain_db, cfg_phy_rx_gain_db_cmd, + "octphy rx-gain <0-73>", + OCT_STR "Configure the Rx Gain in dB\n" "Rx gain in dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; + + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } - fl1h->config.rx_gain_db = atoi(argv[0]); + plink->u.octphy.rx_gain_db = atoi(argv[0]); return CMD_SUCCESS; } -DEFUN(cfg_trx_tx_atten_db, cfg_trx_tx_atten_db_cmd, - "tx-attenuation <0-359>", - "Configure the Tx Attenuation in quarter-dB\n" +DEFUN(cfg_phy_tx_atten_db, cfg_phy_tx_atten_db_cmd, + "octphy tx-attenuation <0-359>", + OCT_STR "Configure the Tx Attenuation in quarter-dB\n" "Tx attenuation in quarter-dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; + + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } - fl1h->config.tx_atten_db = atoi(argv[0]); + plink->u.octphy.tx_atten_db = atoi(argv[0]); return CMD_SUCCESS; } -DEFUN(get_rf_port_stats, get_rf_port_stats_cmd, - "get-rf-port-stats <0-1>", - "Obtain statistics for the RF Port\n" +DEFUN(show_rf_port_stats, show_rf_port_stats_cmd, + "show phy <0-255> rf-port-stats <0-1>", + "Show statistics for the RF Port\n" "RF Port Number\n") { - struct octphy_hdl *fl1h = trx_octphy_hdl(vty_bts->c0); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); - octphy_hw_get_rf_port_stats(fl1h, atoi(argv[0])); + octphy_hw_get_rf_port_stats(plink->u.octphy.hdl, atoi(argv[1])); + + /* FIXME */ + vty_out(vty, "Please check the log file for the response%s", + VTY_NEWLINE); return CMD_SUCCESS; } -DEFUN(get_clk_sync_stats, get_clk_sync_stats_cmd, - "get-clk-sync-stats", +DEFUN(show_clk_sync_stats, show_clk_sync_stats_cmd, + "show phy <0-255> clk-sync-stats", "Obtain statistics for the Clock Sync Manager\n") { - struct octphy_hdl *fl1h = trx_octphy_hdl(vty_bts->c0); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); + + octphy_hw_get_clock_sync_stats(plink->u.octphy.hdl); - octphy_hw_get_clock_sync_stats(fl1h); + /* FIXME */ + vty_out(vty, "Please check the log file for the response%s", + VTY_NEWLINE); return CMD_SUCCESS; } +void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink) +{ + if (plink->u.octphy.netdev_name) + vty_out(vty, " netdev %s%s", plink->u.octphy.netdev_name, + VTY_NEWLINE); + + vty_out(vty, " hw-addr %02x:%02x:%02x:%02x:%02x:%02x%s", + plink->u.octphy.phy_addr.sll_addr[0], + plink->u.octphy.phy_addr.sll_addr[1], + plink->u.octphy.phy_addr.sll_addr[2], + plink->u.octphy.phy_addr.sll_addr[3], + plink->u.octphy.phy_addr.sll_addr[4], + plink->u.octphy.phy_addr.sll_addr[5], + VTY_NEWLINE); + vty_out(vty, " rx-gain %u%s", plink->u.octphy.rx_gain_db, + VTY_NEWLINE); + vty_out(vty, " tx-attenuation %u%s", plink->u.octphy.tx_atten_db, + VTY_NEWLINE); + vty_out(vty, " rf-port-index %u%s", plink->u.octphy.rf_port_index, + VTY_NEWLINE); +} + void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb = bts_role_bts(bts); - struct octphy_hdl *fl1h = trx_octphy_hdl(bts->c0); - - if (fl1h->netdev_name) - vty_out(vty, " phy-netdev %s%s", fl1h->netdev_name, - VTY_NEWLINE); if (btsb->auto_band) vty_out(vty, " auto-band%s", VTY_NEWLINE); - vty_out(vty, " phy-hw-addr %02x:%02x:%02x:%02x:%02x:%02x%s", - fl1h->phy_addr.sll_addr[0], fl1h->phy_addr.sll_addr[1], - fl1h->phy_addr.sll_addr[2], fl1h->phy_addr.sll_addr[3], - fl1h->phy_addr.sll_addr[4], fl1h->phy_addr.sll_addr[5], - VTY_NEWLINE); } void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); - - vty_out(vty, " rx-gain %u%s", fl1h->config.rx_gain_db, - VTY_NEWLINE); - vty_out(vty, " tx-attenuation %u%s", fl1h->config.tx_atten_db, - VTY_NEWLINE); } DEFUN(show_sys_info, show_sys_info_cmd, - "show trx <0-255> system-information", + "show phy <0-255> system-information", SHOW_TRX_STR "Display information about system\n") { - int trx_nr = atoi(argv[0]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); struct octphy_hdl *fl1h; - int i; - if (!trx) { - vty_out(vty, "Cannot find TRX number %u%s", - trx_nr, VTY_NEWLINE); + if (!plink) { + vty_out(vty, "Cannot find PHY number %u%s", + phy_nr, VTY_NEWLINE); return CMD_WARNING; } - fl1h = trx_octphy_hdl(trx); + fl1h = plink->u.octphy.hdl; vty_out(vty, "System Platform: '%s', Version: '%s'%s", fl1h->info.system.platform, fl1h->info.system.version, @@ -210,15 +251,14 @@ int bts_model_vty_init(struct gsm_bts *bts) { vty_bts = bts; - install_element(BTS_NODE, &cfg_bts_phy_hwaddr_cmd); - install_element(BTS_NODE, &cfg_bts_phy_netdev_cmd); + install_element(PHY_NODE, &cfg_phy_hwaddr_cmd); + install_element(PHY_NODE, &cfg_phy_netdev_cmd); + install_element(PHY_NODE, &cfg_phy_rf_port_idx_cmd); + install_element(PHY_NODE, &cfg_phy_rx_gain_db_cmd); + install_element(PHY_NODE, &cfg_phy_tx_atten_db_cmd); - install_element(TRX_NODE, &cfg_trx_rf_port_idx_cmd); - install_element(TRX_NODE, &cfg_trx_rx_gain_db_cmd); - install_element(TRX_NODE, &cfg_trx_tx_atten_db_cmd); - - install_element_ve(&get_rf_port_stats_cmd); - install_element_ve(&get_clk_sync_stats_cmd); + install_element_ve(&show_rf_port_stats_cmd); + install_element_ve(&show_clk_sync_stats_cmd); install_element_ve(&show_sys_info_cmd); return 0; @@ -226,13 +266,5 @@ int bts_model_vty_init(struct gsm_bts *bts) int bts_model_ctrl_cmds_install(struct gsm_bts *bts) { - /* FIXME: really ugly hack: We can only initialize the L1 intrface - * after reading the config file, and this is the only call-back after - * vty_read_config_fioe() at this point. Will be cleaned up with the - * phy interface generalization patches coming up soon as part of the - * multi-trx work */ - struct octphy_hdl *fl1h = bts->c0->role_bts.l1h; - l1if_open(fl1h); - return 0; } diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c index edd4b7b..befaffd 100644 --- a/src/osmo-bts-trx/l1_if.c +++ b/src/osmo-bts-trx/l1_if.c @@ -59,7 +59,7 @@ static const uint8_t transceiver_chan_types[_GSM_PCHAN_MAX] = { * create/destroy trx l1 instance */ -struct trx_l1h *l1if_open(struct gsm_bts_trx *trx) +struct trx_l1h *l1if_open(struct phy_instance *pinst) { struct trx_l1h *l1h; int rc; @@ -67,11 +67,9 @@ struct trx_l1h *l1if_open(struct gsm_bts_trx *trx) l1h = talloc_zero(tall_bts_ctx, struct trx_l1h); if (!l1h) return NULL; - l1h->trx = trx; - l1h->l1s.trx = trx; - trx->role_bts.l1h = l1h; + l1h->phy_inst = pinst; - trx_sched_init(&l1h->l1s); + trx_sched_init(&l1h->l1s, pinst->trx); rc = trx_if_open(l1h); if (rc < 0) { @@ -83,7 +81,6 @@ struct trx_l1h *l1if_open(struct gsm_bts_trx *trx) err: l1if_close(l1h); - trx->role_bts.l1h = NULL; return NULL; } @@ -100,7 +97,8 @@ void l1if_reset(struct trx_l1h *l1h) static void check_transceiver_availability_trx(struct trx_l1h *l1h, int avail) { - struct gsm_bts_trx *trx = l1h->trx; + struct phy_instance *pinst = l1h->phy_inst; + struct gsm_bts_trx *trx = pinst->trx; uint8_t tn; /* HACK, we should change state when we receive first clock from @@ -132,10 +130,10 @@ static void check_transceiver_availability_trx(struct trx_l1h *l1h, int avail) int check_transceiver_availability(struct gsm_bts *bts, int avail) { struct gsm_bts_trx *trx; - struct trx_l1h *l1h; llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; check_transceiver_availability_trx(l1h, avail); } return 0; @@ -147,6 +145,7 @@ int check_transceiver_availability(struct gsm_bts *bts, int avail) */ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) { + struct phy_link *plink = l1h->phy_inst->phy_link; uint8_t tn; if (!transceiver_available) @@ -177,18 +176,23 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) } /* after power on */ - if (l1h->config.rxgain_valid && !l1h->config.rxgain_sent) { - trx_if_cmd_setrxgain(l1h, l1h->config.rxgain); - l1h->config.rxgain_sent = 1; - } - if (l1h->config.power_valid && !l1h->config.power_sent) { - trx_if_cmd_setpower(l1h, l1h->config.power); - l1h->config.power_sent = 1; + if (l1h->phy_inst->num == 0) { + if (plink->u.osmotrx.rxgain_valid && + !plink->u.osmotrx.rxgain_sent) { + trx_if_cmd_setrxgain(l1h, plink->u.osmotrx.rxgain); + plink->u.osmotrx.rxgain_sent = 1; + } + if (plink->u.osmotrx.power_valid && + !plink->u.osmotrx.power_sent) { + trx_if_cmd_setpower(l1h, plink->u.osmotrx.power); + plink->u.osmotrx.power_sent = 1; + } } if (l1h->config.maxdly_valid && !l1h->config.maxdly_sent) { trx_if_cmd_setmaxdly(l1h, l1h->config.maxdly); l1h->config.maxdly_sent = 1; } + for (tn = 0; tn < TRX_NR_TS; tn++) { if (l1h->config.slottype_valid[tn] && !l1h->config.slottype_sent[tn]) { @@ -203,8 +207,10 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) if (!l1h->config.poweron && !l1h->config.poweron_sent) { trx_if_cmd_poweroff(l1h); l1h->config.poweron_sent = 1; - l1h->config.rxgain_sent = 0; - l1h->config.power_sent = 0; + if (l1h->phy_inst->num == 0) { + plink->u.osmotrx.rxgain_sent = 0; + plink->u.osmotrx.power_sent = 0; + } l1h->config.maxdly_sent = 0; for (tn = 0; tn < TRX_NR_TS; tn++) l1h->config.slottype_sent[tn] = 0; @@ -216,17 +222,20 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) int l1if_provision_transceiver(struct gsm_bts *bts) { struct gsm_bts_trx *trx; - struct trx_l1h *l1h; uint8_t tn; llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct phy_link *plink = pinst->phy_link; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; l1h->config.arfcn_sent = 0; l1h->config.tsc_sent = 0; l1h->config.bsic_sent = 0; l1h->config.poweron_sent = 0; - l1h->config.rxgain_sent = 0; - l1h->config.power_sent = 0; + if (l1h->phy_inst->num == 0) { + plink->u.osmotrx.rxgain_sent = 0; + plink->u.osmotrx.power_sent = 0; + } l1h->config.maxdly_sent = 0; for (tn = 0; tn < TRX_NR_TS; tn++) l1h->config.slottype_sent[tn] = 0; @@ -242,7 +251,8 @@ int l1if_provision_transceiver(struct gsm_bts *bts) /* initialize the layer1 */ static int trx_init(struct gsm_bts_trx *trx) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; /* power on transceiver, if not already */ if (!l1h->config.poweron) { @@ -264,7 +274,8 @@ static int trx_init(struct gsm_bts_trx *trx) /* deactivate transceiver */ int bts_model_trx_close(struct gsm_bts_trx *trx) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; enum gsm_phys_chan_config pchan = trx->ts[0].pchan; /* close all logical channels and reset timeslots */ @@ -308,7 +319,6 @@ int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan) static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr) { struct gsm_bts_trx *trx; - struct trx_l1h *l1h; uint8_t bsic = bts->bsic; struct gsm_bts_role_bts *btsb = bts_role_bts(bts); @@ -318,7 +328,8 @@ static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr) } llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; if (l1h->config.bsic != bsic || !l1h->config.bsic_valid) { l1h->config.bsic = bsic; l1h->config.bsic_valid = 1; @@ -335,7 +346,9 @@ static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr) /* set trx attributes */ static uint8_t trx_set_trx(struct gsm_bts_trx *trx) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct phy_link *plink = pinst->phy_link; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; uint16_t arfcn = trx->arfcn; if (l1h->config.arfcn != arfcn || !l1h->config.arfcn_valid) { @@ -345,10 +358,10 @@ static uint8_t trx_set_trx(struct gsm_bts_trx *trx) l1if_provision_transceiver_trx(l1h); } - if (l1h->config.power_oml) { - l1h->config.power = trx->max_power_red; - l1h->config.power_valid = 1; - l1h->config.power_sent = 0; + if (plink->u.osmotrx.power_oml && pinst->num == 0) { + plink->u.osmotrx.power = trx->max_power_red; + plink->u.osmotrx.power_valid = 1; + plink->u.osmotrx.power_sent = 0; l1if_provision_transceiver_trx(l1h); } @@ -358,7 +371,8 @@ static uint8_t trx_set_trx(struct gsm_bts_trx *trx) /* set ts attributes */ static uint8_t trx_set_ts(struct gsm_bts_trx_ts *ts) { - struct trx_l1h *l1h = trx_l1h_hdl(ts->trx); + struct phy_instance *pinst = trx_phy_instance(ts->trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; uint8_t tn = ts->nr; uint16_t tsc = ts->tsc; enum gsm_phys_chan_config pchan = ts->pchan; @@ -439,6 +453,7 @@ static int l1if_set_ciphering(struct trx_l1h *l1h, struct gsm_lchan *lchan, static int mph_info_chan_confirm(struct trx_l1h *l1h, uint8_t chan_nr, enum osmo_mph_info_type type, uint8_t cause) { + struct phy_instance *pinst = l1h->phy_inst; struct osmo_phsap_prim l1sap; memset(&l1sap, 0, sizeof(l1sap)); @@ -448,7 +463,7 @@ static int mph_info_chan_confirm(struct trx_l1h *l1h, uint8_t chan_nr, l1sap.u.info.u.act_cnf.chan_nr = chan_nr; l1sap.u.info.u.act_cnf.cause = cause; - return l1sap_up(l1h->trx, &l1sap); + return l1sap_up(pinst->trx, &l1sap); } int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn) @@ -503,7 +518,8 @@ int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint /* primitive from common part */ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; struct msgb *msg = l1sap->oph.msg; uint8_t chan_nr; uint8_t tn, ss; diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h index f492687..187303c 100644 --- a/src/osmo-bts-trx/l1_if.h +++ b/src/osmo-bts-trx/l1_if.h @@ -2,6 +2,7 @@ #define L1_IF_H_TRX #include +#include struct trx_config { uint8_t poweron; /* poweron(1) or poweroff(0) */ @@ -19,15 +20,6 @@ struct trx_config { uint8_t bsic; int bsic_sent; - int rxgain_valid; - int rxgain; - int rxgain_sent; - - int power_valid; - int power; - int power_oml; - int power_sent; - int maxdly_valid; int maxdly; int maxdly_sent; @@ -42,7 +34,8 @@ struct trx_config { struct trx_l1h { struct llist_head trx_ctrl_list; - struct gsm_bts_trx *trx; + //struct gsm_bts_trx *trx; + struct phy_instance *phy_inst; struct osmo_fd trx_ofd_ctrl; struct osmo_timer_list trx_ctrl_timer; @@ -55,7 +48,7 @@ struct trx_l1h { struct l1sched_trx l1s; }; -struct trx_l1h *l1if_open(struct gsm_bts_trx *trx); +struct trx_l1h *l1if_open(struct phy_instance *pinst); void l1if_close(struct trx_l1h *l1h); void l1if_reset(struct trx_l1h *l1h); int check_transceiver_availability(struct gsm_bts *bts, int avail); @@ -69,7 +62,8 @@ int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint static inline struct l1sched_trx *trx_l1sched_hdl(struct gsm_bts_trx *trx) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx->role_bts.l1h; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; return &l1h->l1s; } diff --git a/src/osmo-bts-trx/main.c b/src/osmo-bts-trx/main.c index aa6987c..40cbcac 100644 --- a/src/osmo-bts-trx/main.c +++ b/src/osmo-bts-trx/main.c @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -58,42 +59,13 @@ #include "l1_if.h" #include "trx_if.h" -int bts_model_init(struct gsm_bts *bts) -{ - void *l1h; - struct gsm_bts_trx *trx; - struct gsm_bts_role_bts *btsb = bts_role_bts(bts); - - btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2); - if (!settsc_enabled && !setbsic_enabled) - settsc_enabled = setbsic_enabled = 1; - - llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = l1if_open(trx); - if (!l1h) { - LOGP(DL1C, LOGL_FATAL, "Cannot open L1 Interface\n"); - goto error; - } - +#if 0 trx->role_bts.l1h = l1h; trx->nominal_power = 23; l1if_reset(l1h); - } - - bts_model_vty_init(bts); +#endif - return 0; - -error: - llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx->role_bts.l1h; - if (l1h) - l1if_close(l1h); - } - - return -EIO; -} /* dummy, since no direct dsp support */ uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx) @@ -103,10 +75,6 @@ uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx) void bts_model_print_help() { - printf( - " -I --local-trx-ip Local IP for transceiver to connect (default=%s)\n" - , transceiver_ip - ); } int bts_model_handle_options(int argc, char **argv) @@ -116,21 +84,16 @@ int bts_model_handle_options(int argc, char **argv) while (1) { int option_idx = 0, c; static const struct option long_options[] = { - /* specific to this hardware */ - { "local-trx-ip", 1, 0, 'I' }, { 0, 0, 0, 0 } }; - c = getopt_long(argc, argv, "I:", + c = getopt_long(argc, argv, "", long_options, &option_idx); if (c == -1) break; switch (c) { - case 'I': - transceiver_ip = strdup(optarg); - break; default: num_errors++; break; @@ -140,6 +103,17 @@ int bts_model_handle_options(int argc, char **argv) return num_errors; } +int bts_model_init(struct gsm_bts *bts) +{ + struct gsm_bts_role_bts *btsb = bts_role_bts(bts); + + btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2); + + bts_model_vty_init(bts); + + return 0; +} + int main(int argc, char **argv) { return bts_main(argc, argv); diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index ac9212b..87d21ff 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -1268,8 +1268,9 @@ static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn) /* 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); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + struct l1sched_trx *l1t = &l1h->l1s; /* we don't schedule, if power is off */ if (!trx_if_powered(l1h)) @@ -1323,10 +1324,12 @@ no_clock: /* 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)); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + trx_if_flush(l1h); + trx_sched_reset(&l1h->l1s); if (trx->nr == 0) - trx_if_cmd_poweroff(trx_l1h_hdl(trx)); + trx_if_cmd_poweroff(l1h); } /* tell BSC */ @@ -1461,7 +1464,8 @@ new_clock: void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate) { - struct trx_l1h *l1h = trx_l1h_hdl(l1t->trx); + struct phy_instance *pinst = trx_phy_instance(l1t->trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; if (activate) trx_if_cmd_handover(l1h, tn, ss); diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c index dbe6f68..6743d0b 100644 --- a/src/osmo-bts-trx/trx_if.c +++ b/src/osmo-bts-trx/trx_if.c @@ -2,6 +2,7 @@ * OpenBTS TRX interface handling * * Copyright (C) 2013 Andreas Eversberg + * Copyright (C) 2016 Harald Welte * * All Rights Reserved * @@ -34,6 +35,7 @@ #include #include +#include #include #include #include @@ -45,7 +47,6 @@ //#define TOA_RSSI_DEBUG int transceiver_available = 0; -const char *transceiver_ip = "127.0.0.1"; int settsc_enabled = 0; int setbsic_enabled = 0; @@ -56,8 +57,9 @@ int setbsic_enabled = 0; static uint16_t base_port_local = 5800; /* open socket */ -static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port, - int (*cb)(struct osmo_fd *fd, unsigned int what)) +static int trx_udp_open(void *priv, struct osmo_fd *ofd, const char *host, + uint16_t port_local, uint16_t port_remote, + int (*cb)(struct osmo_fd *fd, unsigned int what)) { struct sockaddr_storage sas; struct sockaddr *sa = (struct sockaddr *)&sas; @@ -71,8 +73,8 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port, ofd->data = priv; /* Listen / Binds */ - rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, 0, transceiver_ip, - port, OSMO_SOCK_F_BIND); + rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, 0, host, + port_local, OSMO_SOCK_F_BIND); if (rc < 0) return rc; @@ -84,10 +86,10 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port, if (sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; - sin->sin_port = htons(ntohs(sin->sin_port) - 100); + sin->sin_port = htons(port_remote); } else if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - sin6->sin6_port = htons(ntohs(sin6->sin6_port) - 100); + sin6->sin6_port = htons(port_remote); } else { return -EINVAL; } @@ -96,7 +98,6 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port, if (rc) return rc; - return 0; } @@ -115,13 +116,11 @@ static void trx_udp_close(struct osmo_fd *ofd) * clock */ -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; + struct phy_link *plink = ofd->data; + struct phy_instance *pinst = phy_instance_by_num(plink, 0); char buf[1500]; int len; uint32_t fn; @@ -146,7 +145,7 @@ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what) "correctly, correcting to fn=%u\n", fn); } - trx_sched_clock(l1h->trx->bts, fn); + trx_sched_clock(pinst->trx->bts, fn); return 0; } @@ -168,8 +167,8 @@ static void trx_ctrl_send(struct trx_l1h *l1h) return; tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg, list); - LOGP(DTRX, LOGL_DEBUG, "Sending control '%s' to trx=%u\n", tcm->cmd, - l1h->trx->nr); + LOGP(DTRX, LOGL_DEBUG, "Sending control '%s' to %s\n", tcm->cmd, + phy_instance_name(l1h->phy_inst)); /* send command */ send(l1h->trx_ofd_ctrl.fd, tcm->cmd, strlen(tcm->cmd)+1, 0); @@ -184,8 +183,8 @@ static void trx_ctrl_timer_cb(void *data) { struct trx_l1h *l1h = data; - LOGP(DTRX, LOGL_NOTICE, "No response from transceiver for trx=%d\n", - l1h->trx->nr); + LOGP(DTRX, LOGL_NOTICE, "No response from transceiver for %s\n", + phy_instance_name(l1h->phy_inst)); trx_ctrl_send(l1h); } @@ -232,7 +231,8 @@ static int trx_ctrl_cmd(struct trx_l1h *l1h, int critical, const char *cmd, int trx_if_cmd_poweroff(struct trx_l1h *l1h) { - if (l1h->trx->nr == 0) + struct phy_instance *pinst = l1h->phy_inst; + if (pinst->num == 0) return trx_ctrl_cmd(l1h, 1, "POWEROFF", ""); else return 0; @@ -240,7 +240,8 @@ int trx_if_cmd_poweroff(struct trx_l1h *l1h) int trx_if_cmd_poweron(struct trx_l1h *l1h) { - if (l1h->trx->nr == 0) + struct phy_instance *pinst = l1h->phy_inst; + if (pinst->num == 0) return trx_ctrl_cmd(l1h, 1, "POWERON", ""); else return 0; @@ -324,6 +325,7 @@ int trx_if_cmd_nohandover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss) static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what) { struct trx_l1h *l1h = ofd->data; + struct phy_instance *pinst = l1h->phy_inst; char buf[1500]; int len, resp; @@ -374,11 +376,12 @@ static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what) sscanf(p + 1, "%d", &resp); if (resp) { LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE, - "transceiver (trx=%d) rejected TRX command " - "with response: '%s'\n", l1h->trx->nr, buf); + "transceiver (%s) rejected TRX command " + "with response: '%s'\n", + phy_instance_name(pinst), buf); rsp_error: if (tcm->critical) { - bts_shutdown(l1h->trx->bts, "SIGINT"); + bts_shutdown(pinst->trx->bts, "SIGINT"); /* keep tcm list, so process is stopped */ return -EIO; } @@ -493,11 +496,67 @@ int trx_if_data(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr, * open/close */ +int bts_model_phy_link_open(struct phy_link *plink) +{ + struct phy_instance *pinst; + int rc; + + phy_link_state_set(plink, PHY_LINK_CONNECTING); + + /* open the shared/common clock socket */ + rc = trx_udp_open(plink, &plink->u.osmotrx.trx_ofd_clk, + plink->u.osmotrx.transceiver_ip, + plink->u.osmotrx.base_port_local, + plink->u.osmotrx.base_port_remote, + trx_clk_read_cb); + if (rc < 0) { + phy_link_state_set(plink, PHY_LINK_SHUTDOWN); + return -1; + } + + /* open the individual instances with their ctrl+data sockets */ + llist_for_each_entry(pinst, &plink->instances, list) { + pinst->u.osmotrx.hdl = l1if_open(pinst); + if (!pinst->u.osmotrx.hdl) + goto cleanup; + } + + return 0; + +cleanup: + phy_link_state_set(plink, PHY_LINK_SHUTDOWN); + llist_for_each_entry(pinst, &plink->instances, list) { + if (pinst->u.osmotrx.hdl) { + trx_if_close(pinst->u.osmotrx.hdl); + pinst->u.osmotrx.hdl = NULL; + } + } + trx_udp_close(&plink->u.osmotrx.trx_ofd_clk); + return -1; +} + +static uint16_t compute_port(struct phy_instance *pinst, int remote, int is_data) +{ + struct phy_link *plink = pinst->phy_link; + uint16_t inc = 1; + + if (is_data) + inc = 2; + + if (remote) + return plink->u.osmotrx.base_port_remote + (pinst->num << 1) + inc; + else + return plink->u.osmotrx.base_port_local + (pinst->num << 1) + inc; +} + int trx_if_open(struct trx_l1h *l1h) { + struct phy_instance *pinst = l1h->phy_inst; + struct phy_link *plink = pinst->phy_link; int rc; - LOGP(DTRX, LOGL_NOTICE, "Open transceiver for trx=%u\n", l1h->trx->nr); + LOGP(DTRX, LOGL_NOTICE, "Open transceiver for %s\n", + phy_instance_name(pinst)); /* initialize ctrl queue */ INIT_LLIST_HEAD(&l1h->trx_ctrl_list); @@ -511,19 +570,24 @@ int trx_if_open(struct trx_l1h *l1h) LOGP(DTRX, LOGL_NOTICE, "Waiting for transceiver send clock\n"); } rc = trx_udp_open(l1h, &l1h->trx_ofd_ctrl, - base_port_local + (l1h->trx->nr << 1) + 1, trx_ctrl_read_cb); + plink->u.osmotrx.transceiver_ip, + compute_port(pinst, 0, 0), + compute_port(pinst, 1, 0), trx_ctrl_read_cb); if (rc < 0) goto err; rc = trx_udp_open(l1h, &l1h->trx_ofd_data, - base_port_local + (l1h->trx->nr << 1) + 2, trx_data_read_cb); + plink->u.osmotrx.transceiver_ip, + compute_port(pinst, 0, 1), + compute_port(pinst, 1, 1), trx_data_read_cb); if (rc < 0) goto err; /* enable all slots */ l1h->config.slotmask = 0xff; - if (l1h->trx->nr == 0) - trx_if_cmd_poweroff(l1h); + /* FIXME: why was this only for TRX0 ? */ + //if (l1h->trx->nr == 0) + trx_if_cmd_poweroff(l1h); return 0; @@ -548,13 +612,13 @@ void trx_if_flush(struct trx_l1h *l1h) void trx_if_close(struct trx_l1h *l1h) { - LOGP(DTRX, LOGL_NOTICE, "Close transceiver for trx=%u\n", l1h->trx->nr); + struct phy_instance *pinst = l1h->phy_inst; + LOGP(DTRX, LOGL_NOTICE, "Close transceiver for %s\n", + phy_instance_name(pinst)); trx_if_flush(l1h); /* close sockets */ - if (l1h->trx->nr == 0) - trx_udp_close(&trx_ofd_clk); trx_udp_close(&l1h->trx_ofd_ctrl); trx_udp_close(&l1h->trx_ofd_data); } diff --git a/src/osmo-bts-trx/trx_if.h b/src/osmo-bts-trx/trx_if.h index 3862e2b..1ea0da9 100644 --- a/src/osmo-bts-trx/trx_if.h +++ b/src/osmo-bts-trx/trx_if.h @@ -6,6 +6,7 @@ extern const char *transceiver_ip; extern int settsc_enabled; extern int setbsic_enabled; +struct trx_l1h; struct trx_ctrl_msg { struct llist_head list; diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c index a4a7909..b273e94 100644 --- a/src/osmo-bts-trx/trx_vty.c +++ b/src/osmo-bts-trx/trx_vty.c @@ -45,6 +45,8 @@ #include "trx_if.h" #include "loops.h" +#define OSMOTRX_STR "OsmoTRX Transceiver configuration\n" + static struct gsm_bts *vty_bts; DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver", @@ -53,7 +55,6 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver", struct gsm_bts *bts = vty_bts; struct gsm_bts_trx *trx; struct trx_l1h *l1h; - uint8_t tn; if (!transceiver_available) { vty_out(vty, "transceiver is not connected%s", VTY_NEWLINE); @@ -63,7 +64,8 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver", } llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + l1h = pinst->u.osmotrx.hdl; vty_out(vty, "TRX %d%s", trx->nr, VTY_NEWLINE); vty_out(vty, " %s%s", (l1h->config.poweron) ? "poweron":"poweroff", @@ -85,56 +87,70 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver", VTY_NEWLINE); else vty_out(vty, " bisc : undefined%s", VTY_NEWLINE); - if (l1h->config.rxgain_valid) - vty_out(vty, " rxgain : %d%s", l1h->config.rxgain, + } + + return CMD_SUCCESS; +} + + +static void show_phy_inst_single(struct vty *vty, struct phy_instance *pinst) +{ + uint8_t tn; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + + vty_out(vty, "PHY Instance %s%s", + phy_instance_name(pinst), VTY_NEWLINE); + if (l1h->config.maxdly_valid) + vty_out(vty, " maxdly : %d%s", l1h->config.maxdly, + VTY_NEWLINE); + else + vty_out(vty, " maxdly : undefined%s", VTY_NEWLINE); + for (tn = 0; tn < TRX_NR_TS; tn++) { + if (!((1 << tn) & l1h->config.slotmask)) + vty_out(vty, " slot #%d: unsupported%s", tn, VTY_NEWLINE); - else - vty_out(vty, " rxgain : undefined%s", VTY_NEWLINE); - if (l1h->config.power_valid) - vty_out(vty, " power : %d%s", l1h->config.power, + else if (l1h->config.slottype_valid[tn]) + vty_out(vty, " slot #%d: type %d%s", tn, + l1h->config.slottype[tn], VTY_NEWLINE); else - vty_out(vty, " power : undefined%s", VTY_NEWLINE); - if (l1h->config.maxdly_valid) - vty_out(vty, " maxdly : %d%s", l1h->config.maxdly, + vty_out(vty, " slot #%d: undefined%s", tn, VTY_NEWLINE); - else - vty_out(vty, " maxdly : undefined%s", VTY_NEWLINE); - for (tn = 0; tn < TRX_NR_TS; tn++) { - if (!((1 << tn) & l1h->config.slotmask)) - vty_out(vty, " slot #%d: unsupported%s", tn, - VTY_NEWLINE); - else if (l1h->config.slottype_valid[tn]) - vty_out(vty, " slot #%d: type %d%s", tn, - l1h->config.slottype[tn], - VTY_NEWLINE); - else - vty_out(vty, " slot #%d: undefined%s", tn, - VTY_NEWLINE); - } } - - return CMD_SUCCESS; } -DEFUN(cfg_bts_fn_advance, cfg_bts_fn_advance_cmd, - "fn-advance <0-30>", - "Set the number of frames to be transmitted to transceiver in advance " - "of current FN\n" - "Advance in frames\n") +static void show_phy_single(struct vty *vty, struct phy_link *plink) { - trx_clock_advance = atoi(argv[0]); + struct phy_instance *pinst; - return CMD_SUCCESS; + vty_out(vty, "PHY %u%s", plink->num, VTY_NEWLINE); + + if (plink->u.osmotrx.rxgain_valid) + vty_out(vty, " rx-gain : %d dB%s", + plink->u.osmotrx.rxgain, VTY_NEWLINE); + else + vty_out(vty, " rx-gain : undefined%s", VTY_NEWLINE); + if (plink->u.osmotrx.power_valid) + vty_out(vty, " tx-attenuation : %d dB%s", + plink->u.osmotrx.power, VTY_NEWLINE); + else + vty_out(vty, " tx-attenuation : undefined%s", VTY_NEWLINE); + + llist_for_each_entry(pinst, &plink->instances, list) + show_phy_inst_single(vty, pinst); } -DEFUN(cfg_bts_rts_advance, cfg_bts_rts_advance_cmd, - "rts-advance <0-30>", - "Set the number of frames to be requested (PCU) in advance of current " - "FN. Do not change this, unless you have a good reason!\n" - "Advance in frames\n") +DEFUN(show_phy, show_phy_cmd, "show phy", + SHOW_STR "Display information about the available PHYs") { - trx_rts_advance = atoi(argv[0]); + int i; + + for (i = 0; i < 255; i++) { + struct phy_link *plink = phy_link_by_num(i); + if (!plink) + break; + show_phy_single(vty, plink); + } return CMD_SUCCESS; } @@ -220,63 +236,14 @@ DEFUN(cfg_bts_no_setbsic, cfg_bts_no_setbsic_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_rxgain, cfg_trx_rxgain_cmd, - "rxgain <0-50>", - "Set the receiver gain in dB\n" - "Gain in dB\n") -{ - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); - - l1h->config.rxgain = atoi(argv[0]); - l1h->config.rxgain_valid = 1; - l1h->config.rxgain_sent = 0; - l1if_provision_transceiver_trx(l1h); - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_power, cfg_trx_power_cmd, - "power <0-50>", - "Set the transmitter power dampening\n" - "Power dampening in dB\n") -{ - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); - - l1h->config.power = atoi(argv[0]); - l1h->config.power_oml = 0; - l1h->config.power_valid = 1; - l1h->config.power_sent = 0; - l1if_provision_transceiver_trx(l1h); - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_poweroml_, cfg_trx_power_oml_cmd, - "power oml", - "Set the transmitter power dampening\n" - "Given by NM_ATT_RF_MAXPOWR_R (max power reduction) via OML\n") -{ - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); - - l1h->config.power = trx->max_power_red; - l1h->config.power_oml = 1; - l1h->config.power_valid = 1; - l1h->config.power_sent = 0; - l1if_provision_transceiver_trx(l1h); - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_maxdly, cfg_trx_maxdly_cmd, - "maxdly <0-31>", +DEFUN(cfg_phyinst_maxdly, cfg_phyinst_maxdly_cmd, + "osmotrx maxdly <0-31>", "Set the maximum delay of GSM symbols\n" "GSM symbols (approx. 1.1km per symbol)\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = vty->index; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; l1h->config.maxdly = atoi(argv[0]); l1h->config.maxdly_valid = 1; @@ -286,7 +253,7 @@ DEFUN(cfg_trx_maxdly, cfg_trx_maxdly_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_slotmask, cfg_trx_slotmask_cmd, +DEFUN(cfg_phyinst_slotmask, cfg_phyinst_slotmask_cmd, "slotmask (1|0) (1|0) (1|0) (1|0) (1|0) (1|0) (1|0) (1|0)", "Set the supported slots\n" "TS0 supported\nTS0 unsupported\nTS1 supported\nTS1 unsupported\n" @@ -294,8 +261,8 @@ DEFUN(cfg_trx_slotmask, cfg_trx_slotmask_cmd, "TS4 supported\nTS4 unsupported\nTS5 supported\nTS5 unsupported\n" "TS6 supported\nTS6 unsupported\nTS7 supported\nTS7 unsupported\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = vty->index; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; uint8_t tn; l1h->config.slotmask = 0; @@ -306,76 +273,167 @@ DEFUN(cfg_trx_slotmask, cfg_trx_slotmask_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_no_rxgain, cfg_trx_no_rxgain_cmd, - "no rxgain <0-50>", - NO_STR "Unset the receiver gain in dB\n" + +DEFUN(cfg_phy_fn_advance, cfg_phy_fn_advance_cmd, + "osmotrx fn-advance <0-30>", + OSMOTRX_STR + "Set the number of frames to be transmitted to transceiver in advance " + "of current FN\n" + "Advance in frames\n") +{ + trx_clock_advance = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_rts_advance, cfg_phy_rts_advance_cmd, + "osmotrx rts-advance <0-30>", + OSMOTRX_STR + "Set the number of frames to be requested (PCU) in advance of current " + "FN. Do not change this, unless you have a good reason!\n" + "Advance in frames\n") +{ + trx_rts_advance = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_rxgain, cfg_phy_rxgain_cmd, + "osmotrx rx-gain <0-50>", + OSMOTRX_STR + "Set the receiver gain in dB\n" "Gain in dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_link *plink = vty->index; - l1h->config.rxgain_valid = 0; + plink->u.osmotrx.rxgain = atoi(argv[0]); + plink->u.osmotrx.rxgain_valid = 1; + plink->u.osmotrx.rxgain_sent = 0; return CMD_SUCCESS; } -DEFUN(cfg_trx_no_power, cfg_trx_no_power_cmd, - "no power <0-50>", - NO_STR "Unset the transmitter power dampening\n" - "Power dampening in dB\n") +DEFUN(cfg_phy_tx_atten, cfg_phy_tx_atten_cmd, + "osmotrx tx-attenuation <0-50>", + OSMOTRX_STR + "Set the transmitter attenuation\n" + "Fixed attenuation in dB, overriding OML\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_link *plink = vty->index; - l1h->config.power_valid = 0; + plink->u.osmotrx.power = atoi(argv[0]); + plink->u.osmotrx.power_oml = 0; + plink->u.osmotrx.power_valid = 1; + plink->u.osmotrx.power_sent = 0; return CMD_SUCCESS; } -DEFUN(cfg_trx_no_maxdly, cfg_trx_no_maxdly_cmd, - "no maxdly <0-31>", - NO_STR "Unset the maximum delay of GSM symbols\n" - "GSM symbols (approx. 1.1km per symbol)\n") +DEFUN(cfg_phy_tx_atten_oml, cfg_phy_tx_atten_oml_cmd, + "osmotrx tx-attenuation oml", + OSMOTRX_STR + "Set the transmitter attenuation\n" + "Use NM_ATT_RF_MAXPOWR_R (max power reduction) from BSC via OML\n") +{ + struct phy_link *plink = vty->index; + + plink->u.osmotrx.power_oml = 1; + plink->u.osmotrx.power_valid = 1; + plink->u.osmotrx.power_sent = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_no_rxgain, cfg_phy_no_rxgain_cmd, + "no osmotrx rx-gain", + NO_STR OSMOTRX_STR "Unset the receiver gain in dB\n") +{ + struct phy_link *plink = vty->index; + + plink->u.osmotrx.rxgain_valid = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_no_tx_atten, cfg_phy_no_tx_atten_cmd, + "no osmotrx tx-attenuation", + NO_STR OSMOTRX_STR "Unset the transmitter attenuation\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_link *plink = vty->index; + + plink->u.osmotrx.power_valid = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phyinst_no_maxdly, cfg_phyinst_no_maxdly_cmd, + "no osmotrx maxdly", + NO_STR "Unset the maximum delay of GSM symbols\n") +{ + struct phy_instance *pinst = vty->index; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; l1h->config.maxdly_valid = 0; return CMD_SUCCESS; } -void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) +DEFUN(cfg_phy_transc_ip, cfg_phy_transc_ip_cmd, + "osmotrx ip HOST", + OSMOTRX_STR + "Set remote IP address\n" + "IP address of OsmoTRX\n") { - vty_out(vty, " fn-advance %d%s", trx_clock_advance, VTY_NEWLINE); - vty_out(vty, " rts-advance %d%s", trx_rts_advance, VTY_NEWLINE); + struct phy_link *plink = vty->index; - if (trx_ms_power_loop) - vty_out(vty, " ms-power-loop %d%s", trx_target_rssi, - VTY_NEWLINE); - else - vty_out(vty, " no ms-power-loop%s", VTY_NEWLINE); - vty_out(vty, " %stiming-advance-loop%s", (trx_ta_loop) ? "":"no ", - VTY_NEWLINE); - if (settsc_enabled) - vty_out(vty, " settsc%s", VTY_NEWLINE); - if (setbsic_enabled) - vty_out(vty, " setbsic%s", VTY_NEWLINE); + if (plink->u.osmotrx.transceiver_ip) + talloc_free(plink->u.osmotrx.transceiver_ip); + plink->u.osmotrx.transceiver_ip = talloc_strdup(plink, argv[0]); + + return CMD_SUCCESS; } -void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) +DEFUN(cfg_phy_base_port, cfg_phy_base_port_cmd, + "osmotrx base-port (local|remote) <0-65535>", + OSMOTRX_STR "Set base UDP port number\n" "Local UDP port\n" + "Remote UDP port\n" "UDP base port number\n") { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_link *plink = vty->index; + + if (!strcmp(argv[0], "local")) + plink->u.osmotrx.base_port_local = atoi(argv[1]); + else + plink->u.osmotrx.base_port_remote = atoi(argv[1]); + + return CMD_SUCCESS; +} - if (l1h->config.rxgain_valid) - vty_out(vty, " rxgain %d%s", l1h->config.rxgain, VTY_NEWLINE); - if (l1h->config.power_valid) { - if (l1h->config.power_oml) - vty_out(vty, " power oml%s", VTY_NEWLINE); +void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink) +{ + if (plink->u.osmotrx.transceiver_ip) + vty_out(vty, " osmotrx ip %s%s", + plink->u.osmotrx.transceiver_ip, VTY_NEWLINE); + + vty_out(vty, " osmotrx fn-advance %d%s", + plink->u.osmotrx.clock_advance, VTY_NEWLINE); + vty_out(vty, " osmotrx rts-advance %d%s", + plink->u.osmotrx.rts_advance, VTY_NEWLINE); + if (plink->u.osmotrx.rxgain_valid) + vty_out(vty, " osmotrx rx-gain %d%s", + plink->u.osmotrx.rxgain, VTY_NEWLINE); + if (plink->u.osmotrx.power_valid) { + if (plink->u.osmotrx.power_oml) + vty_out(vty, " osmotrx tx-attenuation oml%s", VTY_NEWLINE); else - vty_out(vty, " power %d%s", l1h->config.power, - VTY_NEWLINE); + vty_out(vty, " osmotrx tx-attenuation %d%s", + plink->u.osmotrx.power, VTY_NEWLINE); } +} + +void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst) +{ + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + if (l1h->config.maxdly_valid) vty_out(vty, " maxdly %d%s", l1h->config.maxdly, VTY_NEWLINE); if (l1h->config.slotmask != 0xff) @@ -391,14 +449,32 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) VTY_NEWLINE); } +void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) +{ + if (trx_ms_power_loop) + vty_out(vty, " ms-power-loop %d%s", trx_target_rssi, + VTY_NEWLINE); + else + vty_out(vty, " no ms-power-loop%s", VTY_NEWLINE); + vty_out(vty, " %stiming-advance-loop%s", (trx_ta_loop) ? "":"no ", + VTY_NEWLINE); + if (settsc_enabled) + vty_out(vty, " settsc%s", VTY_NEWLINE); + if (setbsic_enabled) + vty_out(vty, " setbsic%s", VTY_NEWLINE); +} + +void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) +{ +} + int bts_model_vty_init(struct gsm_bts *bts) { vty_bts = bts; install_element_ve(&show_transceiver_cmd); + install_element_ve(&show_phy_cmd); - install_element(BTS_NODE, &cfg_bts_fn_advance_cmd); - install_element(BTS_NODE, &cfg_bts_rts_advance_cmd); install_element(BTS_NODE, &cfg_bts_ms_power_loop_cmd); install_element(BTS_NODE, &cfg_bts_no_ms_power_loop_cmd); install_element(BTS_NODE, &cfg_bts_timing_advance_loop_cmd); @@ -408,14 +484,19 @@ int bts_model_vty_init(struct gsm_bts *bts) install_element(BTS_NODE, &cfg_bts_no_settsc_cmd); install_element(BTS_NODE, &cfg_bts_no_setbsic_cmd); - install_element(TRX_NODE, &cfg_trx_rxgain_cmd); - install_element(TRX_NODE, &cfg_trx_power_cmd); - install_element(TRX_NODE, &cfg_trx_power_oml_cmd); - install_element(TRX_NODE, &cfg_trx_maxdly_cmd); - install_element(TRX_NODE, &cfg_trx_slotmask_cmd); - install_element(TRX_NODE, &cfg_trx_no_rxgain_cmd); - install_element(TRX_NODE, &cfg_trx_no_power_cmd); - install_element(TRX_NODE, &cfg_trx_no_maxdly_cmd); + install_element(PHY_NODE, &cfg_phy_base_port_cmd); + install_element(PHY_NODE, &cfg_phy_fn_advance_cmd); + install_element(PHY_NODE, &cfg_phy_rts_advance_cmd); + install_element(PHY_NODE, &cfg_phy_transc_ip_cmd); + install_element(PHY_NODE, &cfg_phy_rxgain_cmd); + install_element(PHY_NODE, &cfg_phy_tx_atten_cmd); + install_element(PHY_NODE, &cfg_phy_tx_atten_oml_cmd); + install_element(PHY_NODE, &cfg_phy_no_rxgain_cmd); + install_element(PHY_NODE, &cfg_phy_no_tx_atten_cmd); + + install_element(PHY_INST_NODE, &cfg_phyinst_slotmask_cmd); + install_element(PHY_INST_NODE, &cfg_phyinst_maxdly_cmd); + install_element(PHY_INST_NODE, &cfg_phyinst_no_maxdly_cmd); return 0; }