[3/3] port sysmobts to phy_link/phy_instance abstraction
diff mbox

Message ID 1454524641-14400-3-git-send-email-laforge@gnumonks.org
State Superseded
Headers show

Commit Message

Harald Welte Feb. 3, 2016, 6:37 p.m. UTC
From: Harald Welte <laforge@gnumonks.org>

---
 include/osmo-bts/phy_link.h       |   1 +
 src/osmo-bts-sysmo/l1_if.c        |  59 ++++++++++++---
 src/osmo-bts-sysmo/l1_if.h        |  22 +++++-
 src/osmo-bts-sysmo/main.c         |  34 ++-------
 src/osmo-bts-sysmo/oml.c          |   1 +
 src/osmo-bts-sysmo/sysmobts_vty.c | 146 +++++++++++++++++++++++---------------
 6 files changed, 166 insertions(+), 97 deletions(-)

Patch
diff mbox

diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h
index b9fc412..ec3a915 100644
--- a/include/osmo-bts/phy_link.h
+++ b/include/osmo-bts/phy_link.h
@@ -82,6 +82,7 @@  struct phy_instance {
 
 	union {
 		struct {
+			struct femtol1_hdl *hdl;
 		} sysmobts;
 		struct {
 			struct trx_l1h *hdl;
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c
index 8457a74..b64136b 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -1,6 +1,6 @@ 
 /* Interface handler for Sysmocom L1 */
 
-/* (C) 2011-2014 by Harald Welte <laforge@gnumonks.org>
+/* (C) 2011-2016 by Harald Welte <laforge@gnumonks.org>
  * (C) 2014 by Holger Hans Peter Freyther
  *
  * All Rights Reserved
@@ -41,6 +41,7 @@ 
 #include <osmo-bts/oml.h>
 #include <osmo-bts/rsl.h>
 #include <osmo-bts/gsm_data.h>
+#include <osmo-bts/phy_link.h>
 #include <osmo-bts/paging.h>
 #include <osmo-bts/measurement.h>
 #include <osmo-bts/pcu_if.h>
@@ -579,7 +580,7 @@  static int handle_mph_time_ind(struct femtol1_hdl *fl1,
 				GsmL1_MphTimeInd_t *time_ind,
 				struct msgb *msg)
 {
-	struct gsm_bts_trx *trx = fl1->priv;
+	struct gsm_bts_trx *trx = femtol1_hdl_trx(fl1);
 	struct gsm_bts *bts = trx->bts;
 	struct osmo_phsap_prim l1sap;
 	uint32_t fn;
@@ -705,7 +706,7 @@  static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1,
 				     GsmL1_PhReadyToSendInd_t *rts_ind,
 				     struct msgb *l1p_msg)
 {
-	struct gsm_bts_trx *trx = fl1->priv;
+	struct gsm_bts_trx *trx = femtol1_hdl_trx(fl1);
 	struct gsm_bts *bts = trx->bts;
 	struct msgb *resp_msg;
 	GsmL1_PhDataReq_t *data_req;
@@ -834,7 +835,7 @@  static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr,
 static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind,
 			      struct msgb *l1p_msg)
 {
-	struct gsm_bts_trx *trx = fl1->priv;
+	struct gsm_bts_trx *trx = femtol1_hdl_trx(fl1);
 	uint8_t chan_nr, link_id;
 	struct msgb *sap_msg;
 	struct osmo_phsap_prim *l1sap;
@@ -900,7 +901,7 @@  static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
 static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind,
 			    struct msgb *l1p_msg)
 {
-	struct gsm_bts_trx *trx = fl1->priv;
+	struct gsm_bts_trx *trx = femtol1_hdl_trx(fl1);
 	struct gsm_bts *bts = trx->bts;
 	struct gsm_bts_role_bts *btsb = bts->role;
 	struct gsm_lchan *lchan;
@@ -1021,7 +1022,8 @@  int l1if_handle_l1prim(int wq, struct femtol1_hdl *fl1h, struct msgb *msg)
 			if (wlc->cb) {
 				/* call-back function must take
 				 * ownership of msgb */
-				rc = wlc->cb(fl1h->priv, msg, wlc->cb_data);
+				rc = wlc->cb(femtol1_hdl_trx(fl1h), msg,
+					     wlc->cb_data);
 			} else {
 				rc = 0;
 				msgb_free(msg);
@@ -1053,7 +1055,8 @@  int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg)
 			if (wlc->cb) {
 				/* call-back function must take
 				 * ownership of msgb */
-				rc = wlc->cb(fl1h->priv, msg, wlc->cb_data);
+				rc = wlc->cb(femtol1_hdl_trx(fl1h), msg,
+					     wlc->cb_data);
 			} else {
 				rc = 0;
 				msgb_free(msg);
@@ -1166,7 +1169,7 @@  int l1if_activate_rf(struct femtol1_hdl *hdl, int on)
 {
 	struct msgb *msg = sysp_msgb_alloc();
 	SuperFemto_Prim_t *sysp = msgb_sysprim(msg);
-	struct gsm_bts_trx *trx = hdl->priv;
+	struct gsm_bts_trx *trx = hdl->phy_inst->trx;
 
 	if (on) {
 		sysp->id = SuperFemto_PrimId_ActivateRfReq;
@@ -1478,7 +1481,7 @@  static int get_hwinfo_eeprom(struct femtol1_hdl *fl1h)
 	return 0;
 }
 
-struct femtol1_hdl *l1if_open(void *priv)
+struct femtol1_hdl *l1if_open(struct phy_instance *pinst)
 {
 	struct femtol1_hdl *fl1h;
 	int rc;
@@ -1495,12 +1498,12 @@  struct femtol1_hdl *l1if_open(void *priv)
 			 FEMTOBTS_API_VERSION & 0xff);
 #endif
 
-	fl1h = talloc_zero(priv, struct femtol1_hdl);
+	fl1h = talloc_zero(pinst, struct femtol1_hdl);
 	if (!fl1h)
 		return NULL;
 	INIT_LLIST_HEAD(&fl1h->wlc_list);
 
-	fl1h->priv = priv;
+	fl1h->phy_inst = pinst;
 	fl1h->clk_cal = 0;
 	fl1h->clk_use_eeprom = 1;
 	fl1h->min_qual_rach = MIN_QUAL_RACH;
@@ -1535,6 +1538,8 @@  struct femtol1_hdl *l1if_open(void *priv)
 		return NULL;
 	}
 
+	l1if_reset(fl1h);
+
 	return fl1h;
 }
 
@@ -1662,3 +1667,35 @@  int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h)
 }
 
 #endif
+
+int bts_model_phy_link_open(struct phy_link *plink)
+{
+	struct phy_instance *pinst = phy_instance_by_num(plink, 0);
+	struct gsm_bts *bts;
+
+	OSMO_ASSERT(pinst);
+
+	phy_link_state_set(plink, PHY_LINK_CONNECTING);
+
+	pinst->u.sysmobts.hdl = l1if_open(pinst);
+	if (!pinst->u.sysmobts.hdl) {
+		LOGP(DL1C, LOGL_FATAL, "Cannot open L1 interface\n");
+		return -EIO;
+	}
+
+	bts = pinst->trx->bts;
+	if (pinst->trx == bts->c0) {
+		int rc;
+		rc = sysmobts_get_nominal_power(bts->c0);
+		if (rc < 0) {
+			LOGP(DL1C, LOGL_NOTICE, "Cannot determine nominal "
+			     "transmit power. Assuming 23dBm.\n");
+		}
+		bts->c0->nominal_power = rc;
+		bts->c0->power_params.trx_p_max_out_mdBm = to_mdB(rc);
+	}
+
+	phy_link_state_set(plink, PHY_LINK_CONNECTED);
+
+	return 0;
+}
diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h
index 3f2938f..de4f2a3 100644
--- a/src/osmo-bts-sysmo/l1_if.h
+++ b/src/osmo-bts-sysmo/l1_if.h
@@ -7,6 +7,8 @@ 
 #include <osmocom/core/timer.h>
 #include <osmocom/gsm/gsm_utils.h>
 
+#include <osmo-bts/phy_link.h>
+
 #include <sysmocom/femtobts/gsml1prim.h>
 
 enum {
@@ -52,7 +54,7 @@  struct femtol1_hdl {
 	char *calib_path;
 	struct llist_head wlc_list;
 
-	void *priv;			/* user reference */
+	struct phy_instance *phy_inst;		/* Reference to PHY instance */
 
 	struct osmo_timer_list alive_timer;
 	unsigned int alive_prim_cnt;
@@ -78,6 +80,9 @@  struct femtol1_hdl {
 	struct calib_send_state st;
 
 	uint8_t last_rf_mute[8];
+
+	/* for l1_fwd */
+	void *priv;
 };
 
 #define msgb_l1prim(msg)	((GsmL1_Prim_t *)(msg)->l1h)
@@ -91,7 +96,7 @@  int l1if_req_compl(struct femtol1_hdl *fl1h, struct msgb *msg,
 int l1if_gsm_req_compl(struct femtol1_hdl *fl1h, struct msgb *msg,
 		l1if_compl_cb *cb, void *cb_data);
 
-struct femtol1_hdl *l1if_open(void *priv);
+struct femtol1_hdl *l1if_open(struct phy_instance *pinst);
 int l1if_close(struct femtol1_hdl *hdl);
 int l1if_reset(struct femtol1_hdl *hdl);
 int l1if_activate_rf(struct femtol1_hdl *hdl, int on);
@@ -134,4 +139,17 @@  int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h);
 /* public helpers for test */
 int bts_check_for_ciph_cmd(struct femtol1_hdl *fl1h,
 			      struct msgb *msg, struct gsm_lchan *lchan);
+
+static inline struct femtol1_hdl *trx_femtol1_hdl(struct gsm_bts_trx *trx)
+{
+	struct phy_instance *pinst = trx_phy_instance(trx);
+	OSMO_ASSERT(pinst);
+	return pinst->u.sysmobts.hdl;
+}
+
+static inline struct gsm_bts_trx *femtol1_hdl_trx(struct femtol1_hdl *fl1h)
+{
+	OSMO_ASSERT(fl1h->phy_inst);
+	return fl1h->phy_inst->trx;
+}
 #endif /* _FEMTO_L1_H */
diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c
index d468a71..bde7a94 100644
--- a/src/osmo-bts-sysmo/main.c
+++ b/src/osmo-bts-sysmo/main.c
@@ -86,21 +86,13 @@  void clk_cal_use_eeprom(struct gsm_bts *bts)
 int bts_model_init(struct gsm_bts *bts)
 {
 	struct gsm_bts_role_bts *btsb;
-	struct femtol1_hdl *fl1h;
 	struct stat st;
-	struct osmo_fd accept_fd, read_fd;
+	static struct osmo_fd accept_fd, read_fd;
 	int rc;
 
 	btsb = bts_role_bts(bts);
 	btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3);
 
-	clk_cal_use_eeprom(bts);
-
-	if (stat(SYSMOBTS_RF_LOCK_PATH, &st) == 0) {
-		LOGP(DL1C, LOGL_NOTICE, "Not starting BTS due to RF_LOCK file present\n");
-		exit(23);
-	}
-
 	rc = oml_router_init(bts, OML_ROUTER_PATH, &accept_fd, &read_fd);
 	if (rc < 0) {
 		fprintf(stderr, "Error creating the OML router: %s rc=%d\n",
@@ -108,23 +100,12 @@  int bts_model_init(struct gsm_bts *bts)
 		exit(1);
 	}
 
-	fl1h = l1if_open(bts->c0);
-	if (!fl1h) {
-		LOGP(DL1C, LOGL_FATAL, "Cannot open L1 Interface\n");
-		return -EIO;
-	}
-	fl1h->dsp_trace_f = dsp_trace;
-
-	bts->c0->role_bts.l1h = fl1h;
+	clk_cal_use_eeprom(bts);
 
-	rc = sysmobts_get_nominal_power(bts->c0);
-	if (rc < 0) {
-		LOGP(DL1C, LOGL_NOTICE, "Cannot determine nominal "
-		     "transmit power. Assuming 23dBm.\n");
-		rc = 23;
+	if (stat(SYSMOBTS_RF_LOCK_PATH, &st) == 0) {
+		LOGP(DL1C, LOGL_NOTICE, "Not starting BTS due to RF_LOCK file present\n");
+		exit(23);
 	}
-	bts->c0->nominal_power = rc;
-	bts->c0->power_params.trx_p_max_out_mdBm = to_mdB(rc);
 
 	bts_model_vty_init(bts);
 
@@ -133,10 +114,6 @@  int bts_model_init(struct gsm_bts *bts)
 
 int bts_model_oml_estab(struct gsm_bts *bts)
 {
-	struct femtol1_hdl *fl1h = bts->c0->role_bts.l1h;
-
-	l1if_reset(fl1h);
-
 	return 0;
 }
 
@@ -205,6 +182,7 @@  int bts_model_handle_options(int argc, char **argv)
 		switch (c) {
 		case 'p':
 			dsp_trace = strtoul(optarg, NULL, 16);
+#warning use dsp_trace!!!
 			break;
 		case 'M':
 			pcu_direct = 1;
diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c
index adc0241..cd03b22 100644
--- a/src/osmo-bts-sysmo/oml.c
+++ b/src/osmo-bts-sysmo/oml.c
@@ -36,6 +36,7 @@ 
 #include <osmo-bts/amr.h>
 #include <osmo-bts/bts.h>
 #include <osmo-bts/bts_model.h>
+#include <osmo-bts/phy_link.h>
 #include <osmo-bts/handover.h>
 #include <osmo-bts/l1sap.h>
 
diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c
index 4a37b5d..19122dc 100644
--- a/src/osmo-bts-sysmo/sysmobts_vty.c
+++ b/src/osmo-bts-sysmo/sysmobts_vty.c
@@ -40,6 +40,7 @@ 
 #include <osmocom/vty/misc.h>
 
 #include <osmo-bts/gsm_data.h>
+#include <osmo-bts/phy_link.h>
 #include <osmo-bts/logging.h>
 #include <osmo-bts/vty.h>
 
@@ -84,24 +85,24 @@  DEFUN(cfg_bts_no_auto_band, cfg_bts_no_auto_band_cmd,
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_trx_clkcal_eeprom, cfg_trx_clkcal_eeprom_cmd,
+DEFUN(cfg_phy_clkcal_eeprom, cfg_phy_clkcal_eeprom_cmd,
 	"clock-calibration eeprom",
 	"Use the eeprom clock calibration value\n")
 {
-	struct gsm_bts_trx *trx = vty->index;
-	struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+	struct phy_instance *pinst = vty->index;
+	struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl;
 
 	fl1h->clk_use_eeprom = 1;
 
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_trx_clkcal_def, cfg_trx_clkcal_def_cmd,
+DEFUN(cfg_phy_clkcal_def, cfg_phy_clkcal_def_cmd,
 	"clock-calibration default",
 	"Set the clock calibration value\n" "Default Clock DAC value\n")
 {
-	struct gsm_bts_trx *trx = vty->index;
-	struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+	struct phy_instance *pinst = vty->index;
+	struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl;
 
 	fl1h->clk_use_eeprom = 0;
 	fl1h->clk_cal = 0xffff;
@@ -110,13 +111,13 @@  DEFUN(cfg_trx_clkcal_def, cfg_trx_clkcal_def_cmd,
 }
 
 #ifdef HW_SYSMOBTS_V1
-DEFUN(cfg_trx_clkcal, cfg_trx_clkcal_cmd,
+DEFUN(cfg_phy_clkcal, cfg_phy_clkcal_cmd,
 	"clock-calibration <0-4095>",
 	"Set the clock calibration value\n" "Clock DAC value\n")
 {
 	unsigned int clkcal = atoi(argv[0]);
-	struct gsm_bts_trx *trx = vty->index;
-	struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+	struct phy_instance *pinst = vty->index;
+	struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl;
 
 	fl1h->clk_use_eeprom = 0;
 	fl1h->clk_cal = clkcal & 0xfff;
@@ -124,13 +125,13 @@  DEFUN(cfg_trx_clkcal, cfg_trx_clkcal_cmd,
 	return CMD_SUCCESS;
 }
 #else
-DEFUN(cfg_trx_clkcal, cfg_trx_clkcal_cmd,
+DEFUN(cfg_phy_clkcal, cfg_phy_clkcal_cmd,
 	"clock-calibration <-4095-4095>",
 	"Set the clock calibration value\n" "Offset in PPB\n")
 {
 	int clkcal = atoi(argv[0]);
-	struct gsm_bts_trx *trx = vty->index;
-	struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+	struct phy_instance *pinst = vty->index;
+	struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl;
 
 	fl1h->clk_use_eeprom = 0;
 	fl1h->clk_cal = clkcal;
@@ -139,7 +140,7 @@  DEFUN(cfg_trx_clkcal, cfg_trx_clkcal_cmd,
 }
 #endif
 
-DEFUN(cfg_trx_clksrc, cfg_trx_clksrc_cmd,
+DEFUN(cfg_phy_clksrc, cfg_phy_clksrc_cmd,
 	"clock-source (tcxo|ocxo|ext|gps)",
 	"Set the clock source value\n"
 	"Use the TCXO\n"
@@ -147,8 +148,8 @@  DEFUN(cfg_trx_clksrc, cfg_trx_clksrc_cmd,
 	"Use an external clock\n"
 	"Use the GPS pps\n")
 {
-	struct gsm_bts_trx *trx = vty->index;
-	struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+	struct phy_instance *pinst = vty->index;
+	struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl;
 	int rc;
 
 	rc = get_string_value(femtobts_clksrc_names, argv[0]);
@@ -160,12 +161,12 @@  DEFUN(cfg_trx_clksrc, cfg_trx_clksrc_cmd,
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_trx_cal_path, cfg_trx_cal_path_cmd,
+DEFUN(cfg_phy_cal_path, cfg_phy_cal_path_cmd,
 	"trx-calibration-path PATH",
 	"Set the path name to TRX calibration data\n" "Path name\n")
 {
-	struct gsm_bts_trx *trx = vty->index;
-	struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+	struct phy_instance *pinst = vty->index;
+	struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl;
 
 	if (fl1h->calib_path)
 		talloc_free(fl1h->calib_path);
@@ -188,26 +189,26 @@  DEFUN_DEPRECATED(cfg_trx_ul_power_target, cfg_trx_ul_power_target_cmd,
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_trx_min_qual_rach, cfg_trx_min_qual_rach_cmd,
+DEFUN(cfg_phy_min_qual_rach, cfg_phy_min_qual_rach_cmd,
 	"min-qual-rach <-100-100>",
 	"Set the minimum quality level of RACH burst to be accpeted\n"
 	"C/I level in tenth of dB\n")
 {
-	struct gsm_bts_trx *trx = vty->index;
-	struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+	struct phy_instance *pinst = vty->index;
+	struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl;
 
 	fl1h->min_qual_rach = strtof(argv[0], NULL) / 10.0f;
 
 	return CMD_SUCCESS;
 }
 
-DEFUN(cfg_trx_min_qual_norm, cfg_trx_min_qual_norm_cmd,
+DEFUN(cfg_phy_min_qual_norm, cfg_phy_min_qual_norm_cmd,
 	"min-qual-norm <-100-100>",
 	"Set the minimum quality level of normal burst to be accpeted\n"
 	"C/I level in tenth of dB\n")
 {
-	struct gsm_bts_trx *trx = vty->index;
-	struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+	struct phy_instance *pinst = vty->index;
+	struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl;
 
 	fl1h->min_qual_norm = strtof(argv[0], NULL) / 10.0f;
 
@@ -286,18 +287,24 @@  DEFUN(show_dsp_trace_f, show_dsp_trace_f_cmd,
 
 DEFUN(dsp_trace_f, dsp_trace_f_cmd, "HIDDEN", TRX_STR)
 {
-	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 phy_instance *pinst;
 	struct femtol1_hdl *fl1h;
 	unsigned int flag ;
 
-	if (!trx) {
-		vty_out(vty, "Cannot find TRX number %u%s",
-			trx_nr, VTY_NEWLINE);
+	if (!plink) {
+		vty_out(vty, "Cannot find PHY link number %u%s",
+			phy_nr, VTY_NEWLINE);
 		return CMD_WARNING;
 	}
-
-	fl1h = trx_femtol1_hdl(trx);
+	pinst = phy_instance_by_num(plink, 0);
+	if (!pinst) {
+		vty_out(vty, "Cannot find PHY instance number 0%s",
+			VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	fl1h = pinst->u.sysmobts.hdl;
 	flag = get_string_value(femtobts_tracef_names, argv[1]);
 	l1if_set_trace_flags(fl1h, fl1h->dsp_trace_f | flag);
 
@@ -306,18 +313,24 @@  DEFUN(dsp_trace_f, dsp_trace_f_cmd, "HIDDEN", TRX_STR)
 
 DEFUN(no_dsp_trace_f, no_dsp_trace_f_cmd, "HIDDEN", NO_STR TRX_STR)
 {
-	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 phy_instance *pinst;
 	struct femtol1_hdl *fl1h;
 	unsigned int flag ;
 
-	if (!trx) {
-		vty_out(vty, "Cannot find TRX number %u%s",
-			trx_nr, VTY_NEWLINE);
+	if (!plink) {
+		vty_out(vty, "Cannot find PHY link number %u%s",
+			phy_nr, VTY_NEWLINE);
 		return CMD_WARNING;
 	}
-
-	fl1h = trx_femtol1_hdl(trx);
+	pinst = phy_instance_by_num(plink, 0);
+	if (!pinst) {
+		vty_out(vty, "Cannot find PHY instance number 0%s",
+			VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	fl1h = pinst->u.sysmobts.hdl;
 	flag = get_string_value(femtobts_tracef_names, argv[1]);
 	l1if_set_trace_flags(fl1h, fl1h->dsp_trace_f & ~flag);
 
@@ -325,20 +338,28 @@  DEFUN(no_dsp_trace_f, no_dsp_trace_f_cmd, "HIDDEN", NO_STR TRX_STR)
 }
 
 DEFUN(show_sys_info, show_sys_info_cmd,
-	"show trx <0-0> system-information",
+	"show phy <0-255> instance <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]);
+	int inst_nr = atoi(argv[1]);
+	struct phy_link *plink = phy_link_by_num(phy_nr);
+	struct phy_instance *pinst;
 	struct femtol1_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 link %u%s",
+			phy_nr, VTY_NEWLINE);
 		return CMD_WARNING;
 	}
-	fl1h = trx_femtol1_hdl(trx);
+	pinst = phy_instance_by_num(plink, inst_nr);
+	if (!plink) {
+		vty_out(vty, "Cannot find PHY instance %u%s",
+			phy_nr, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	fl1h = pinst->u.sysmobts.hdl;
 
 	vty_out(vty, "DSP Version: %u.%u.%u, FPGA Version: %u.%u.%u%s",
 		fl1h->hw_info.dsp_version[0],
@@ -471,7 +492,14 @@  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)
 {
-	struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+	if (trx->nominal_power != sysmobts_get_nominal_power(trx))
+		vty_out(vty, "  nominal-tx-power %d%s", trx->nominal_power,
+			VTY_NEWLINE);
+}
+
+static void write_phy_inst(struct vty *vty, struct phy_instance *pinst)
+{
+	struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl;
 
 	if (fl1h->clk_use_eeprom)
 		vty_out(vty, "  clock-calibration eeprom%s", VTY_NEWLINE);
@@ -488,9 +516,14 @@  void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx)
 		VTY_NEWLINE);
 	vty_out(vty, "  min-qual-norm %.0f%s", fl1h->min_qual_norm * 10.0f,
 		VTY_NEWLINE);
-	if (trx->nominal_power != sysmobts_get_nominal_power(trx))
-		vty_out(vty, "  nominal-tx-power %d%s", trx->nominal_power,
-			VTY_NEWLINE);
+}
+
+void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink)
+{
+	struct phy_instance *pinst;
+
+	llist_for_each_entry(pinst, &plink->instances, list)
+		write_phy_inst(vty, pinst);
 }
 
 int bts_model_vty_init(struct gsm_bts *bts)
@@ -529,15 +562,16 @@  int bts_model_vty_init(struct gsm_bts *bts)
 	install_element(BTS_NODE, &cfg_bts_auto_band_cmd);
 	install_element(BTS_NODE, &cfg_bts_no_auto_band_cmd);
 
-	install_element(TRX_NODE, &cfg_trx_clkcal_cmd);
-	install_element(TRX_NODE, &cfg_trx_clkcal_eeprom_cmd);
-	install_element(TRX_NODE, &cfg_trx_clkcal_def_cmd);
-	install_element(TRX_NODE, &cfg_trx_clksrc_cmd);
-	install_element(TRX_NODE, &cfg_trx_cal_path_cmd);
 	install_element(TRX_NODE, &cfg_trx_ul_power_target_cmd);
-	install_element(TRX_NODE, &cfg_trx_min_qual_rach_cmd);
-	install_element(TRX_NODE, &cfg_trx_min_qual_norm_cmd);
 	install_element(TRX_NODE, &cfg_trx_nominal_power_cmd);
 
+	install_element(PHY_INST_NODE, &cfg_phy_clkcal_cmd);
+	install_element(PHY_INST_NODE, &cfg_phy_clkcal_eeprom_cmd);
+	install_element(PHY_INST_NODE, &cfg_phy_clkcal_def_cmd);
+	install_element(PHY_INST_NODE, &cfg_phy_clksrc_cmd);
+	install_element(PHY_INST_NODE, &cfg_phy_cal_path_cmd);
+	install_element(PHY_INST_NODE, &cfg_phy_min_qual_rach_cmd);
+	install_element(PHY_INST_NODE, &cfg_phy_min_qual_norm_cmd);
+
 	return 0;
 }