aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2017-08-14 16:38:54 +0200
committerHarald Welte <laforge@gnumonks.org>2017-08-15 18:29:21 +0000
commit69ec4a419edee4f00a104c59a78b530eaf85382a (patch)
treecfa6a197b56ee8dfedfa0186626cfaf7d07d5041
parent506a7f98b22076576ae3b438981250a97b6dd739 (diff)
octphy: implement support for dynamic timeslots
Implement API functions bts_model_ts_connect() and bts_model_ts_disconnect() in order to support dynamic timeslot allocation. Change-Id: Ia109d4bfade7bc28442127581f4bb0289146ea71
-rw-r--r--src/osmo-bts-octphy/l1_if.c27
-rw-r--r--src/osmo-bts-octphy/l1_oml.c112
2 files changed, 126 insertions, 13 deletions
diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c
index cb792d79..e4ab5385 100644
--- a/src/osmo-bts-octphy/l1_if.c
+++ b/src/osmo-bts-octphy/l1_if.c
@@ -329,11 +329,30 @@ int l1if_activate_rf(struct gsm_bts_trx *trx, int on)
return 0;
}
-static uint8_t chan_nr_by_sapi(enum gsm_phys_chan_config pchan,
+static enum gsm_phys_chan_config pick_pchan(struct gsm_bts_trx_ts *ts)
+{
+ switch (ts->pchan) {
+ case GSM_PCHAN_TCH_F_PDCH:
+ if (ts->flags & TS_F_PDCH_ACTIVE)
+ return GSM_PCHAN_PDCH;
+ return GSM_PCHAN_TCH_F;
+ case GSM_PCHAN_TCH_F_TCH_H_PDCH:
+ return ts->dyn.pchan_is;
+ default:
+ return ts->pchan;
+ }
+}
+
+static uint8_t chan_nr_by_sapi(struct gsm_bts_trx_ts *ts,
tOCTVC1_GSM_SAPI_ENUM sapi, uint8_t subCh,
uint8_t u8Tn, uint32_t u32Fn)
{
uint8_t cbits = 0;
+ enum gsm_phys_chan_config pchan = pick_pchan(ts);
+
+ OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_PDCH);
+ OSMO_ASSERT(pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH);
+
switch (sapi) {
case cOCTVC1_GSM_SAPI_ENUM_BCCH:
cbits = 0x10;
@@ -476,7 +495,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
if (!L1SAP_IS_CHAN_TCHF(chan_nr) && !L1SAP_IS_CHAN_PDCH(chan_nr))
subCh = l1sap_chan2ss(chan_nr);
} else if (L1SAP_IS_CHAN_TCHF(chan_nr) || L1SAP_IS_CHAN_PDCH(chan_nr)) {
- if (trx->ts[u8Tn].pchan == GSM_PCHAN_PDCH) {
+ if (ts_is_pdch(&trx->ts[u8Tn])) {
if (L1SAP_IS_PTCCH(u32Fn)) {
sapi = cOCTVC1_GSM_SAPI_ENUM_PTCCH;
} else {
@@ -932,7 +951,7 @@ static int handle_ph_readytosend_ind(struct octphy_hdl *fl1,
get_value_string(octphy_l1sapi_names, sapi));
/* in case we need to forward primitive to common part */
- chan_nr = chan_nr_by_sapi(trx->ts[ts_num].pchan, sapi, sc, ts_num, fn);
+ chan_nr = chan_nr_by_sapi(&trx->ts[ts_num], sapi, sc, ts_num, fn);
if (chan_nr) {
if (sapi == cOCTVC1_GSM_SAPI_ENUM_SACCH)
link_id = LID_SACCH;
@@ -1053,7 +1072,7 @@ static int handle_ph_data_ind(struct octphy_hdl *fl1,
fn = data_ind->Data.ulFrameNumber;
/* chan_nr and link_id */
- chan_nr = chan_nr_by_sapi(trx->ts[ts_num].pchan, sapi, sc, ts_num, fn);
+ chan_nr = chan_nr_by_sapi(&trx->ts[ts_num], sapi, sc, ts_num, fn);
if (!chan_nr) {
LOGP(DL1C, LOGL_ERROR,
"Rx PH-DATA.ind for unknown L1 SAPI %s\n",
diff --git a/src/osmo-bts-octphy/l1_oml.c b/src/osmo-bts-octphy/l1_oml.c
index 03ff5476..d1d5bf6a 100644
--- a/src/osmo-bts-octphy/l1_oml.c
+++ b/src/osmo-bts-octphy/l1_oml.c
@@ -1406,21 +1406,24 @@ static int pchan_act_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *d
return opstart_compl(mo);
}
-static int ts_connect(struct gsm_bts_trx_ts *ts)
+static int ts_connect_as(struct gsm_bts_trx_ts *ts,
+ enum gsm_phys_chan_config pchan,
+ l1if_compl_cb * cb, void *data)
{
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;
+ (tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD *) oc;
- oc = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD *) msgb_put(msg, sizeof(*oc));
+ oc = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD*)
+ msgb_put(msg, sizeof(*oc));
l1if_fill_msg_hdr(&oc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
cOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CID);
oc->TrxId.byTrxId = pinst->u.octphy.trx_id;
oc->PchId.byTimeslotNb = ts->nr;
- oc->ulChannelType = pchan_to_logChComb[ts->pchan];
+ oc->ulChannelType = pchan_to_logChComb[pchan];
/* TODO: how should we know the payload type here? Also, why
* would the payload type have to be the same for both halves of
@@ -1436,11 +1439,71 @@ static int ts_connect(struct gsm_bts_trx_ts *ts)
}
LOGP(DL1C, LOGL_INFO, "PCHAN-ACT.req(trx=%u, ts=%u, chcomb=%u)\n",
- ts->trx->nr, ts->nr, ts->pchan);
+ ts->trx->nr, ts->nr, pchan);
mOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD_SWAP(oc);
- return l1if_req_compl(fl1h, msg, pchan_act_compl_cb, NULL);
+ return l1if_req_compl(fl1h, msg, cb, data);
+}
+
+/* Dynamic timeslots: Disconnect callback, reports completed disconnection
+ * to higher layers */
+static int ts_disconnect_cb(struct octphy_hdl *fl1, struct msgb *resp,
+ void *data)
+{
+ tOCTVC1_GSM_MSG_TRX_DEACTIVATE_PHYSICAL_CHANNEL_RSP *ar =
+ (tOCTVC1_GSM_MSG_TRX_DEACTIVATE_PHYSICAL_CHANNEL_RSP *) resp->l2h;
+ uint8_t ts_nr;
+ struct gsm_bts_trx *trx;
+ struct gsm_bts_trx_ts *ts;
+
+ trx = trx_by_l1h(fl1, ar->TrxId.byTrxId);
+ ts_nr = ar->PchId.byTimeslotNb;
+ ts = &trx->ts[ts_nr];
+
+ cb_ts_disconnected(ts);
+
+ return 0;
+}
+
+/* Dynamic timeslots: Connect callback, reports completed disconnection to
+ * higher layers */
+static int ts_connect_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;
+
+ /* in a completion call-back, we take msgb ownership and must
+ * 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(ts_nr <= ARRAY_SIZE(trx->ts));
+
+ ts = &trx->ts[ts_nr];
+
+ LOGP(DL1C, LOGL_INFO, "PCHAN-ACT.conf(trx=%u, ts=%u, chcomb=%u) = %s\n",
+ ts->trx->nr, ts->nr, ts->pchan,
+ octvc1_rc2string(ar->Header.ulReturnCode));
+
+ if (ar->Header.ulReturnCode != cOCTVC1_RC_OK) {
+ LOGP(DL1C, LOGL_ERROR,
+ "PCHAN-ACT failed: %s\n\n",
+ octvc1_rc2string(ar->Header.ulReturnCode));
+ LOGP(DL1C, LOGL_ERROR, "Exiting... \n\n");
+ msgb_free(resp);
+ exit(-1);
+ }
+
+ msgb_free(resp);
+
+ cb_ts_connected(ts);
+
+ return 0;
}
/***********************************************************************
@@ -1583,13 +1646,15 @@ int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg,
int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj)
{
int rc = -1;
+ struct gsm_bts_trx_ts *ts;
switch (mo->obj_class) {
case NM_OC_RADIO_CARRIER:
rc = trx_init(obj);
break;
case NM_OC_CHANNEL:
- rc = ts_connect(obj);
+ ts = (struct gsm_bts_trx_ts*) obj;
+ rc = ts_connect_as(ts, ts->pchan, pchan_act_compl_cb, NULL);
break;
case NM_OC_BTS:
case NM_OC_SITE_MANAGER:
@@ -1614,11 +1679,40 @@ int bts_model_change_power(struct gsm_bts_trx *trx, int p_trxout_mdBm)
int bts_model_ts_disconnect(struct gsm_bts_trx_ts *ts)
{
- return -ENOTSUP;
+ 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_DEACTIVATE_PHYSICAL_CHANNEL_CMD *oc =
+ (tOCTVC1_GSM_MSG_TRX_DEACTIVATE_PHYSICAL_CHANNEL_CMD *) oc;
+
+ oc = (tOCTVC1_GSM_MSG_TRX_DEACTIVATE_PHYSICAL_CHANNEL_CMD *)
+ msgb_put(msg, sizeof(*oc));
+ l1if_fill_msg_hdr(&oc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND,
+ cOCTVC1_GSM_MSG_TRX_DEACTIVATE_PHYSICAL_CHANNEL_CID);
+
+ oc->TrxId.byTrxId = pinst->u.octphy.trx_id;
+ oc->PchId.byTimeslotNb = ts->nr;
+
+ LOGP(DL1C, LOGL_INFO, "PCHAN-DEACT.req(trx=%u, ts=%u, chcomb=%u)\n",
+ ts->trx->nr, ts->nr, ts->pchan);
+
+ mOCTVC1_GSM_MSG_TRX_DEACTIVATE_PHYSICAL_CHANNEL_CMD_SWAP(oc);
+
+ return l1if_req_compl(fl1h, msg, ts_disconnect_cb, NULL);
}
int bts_model_ts_connect(struct gsm_bts_trx_ts *ts,
enum gsm_phys_chan_config as_pchan)
{
- return -ENOTSUP;
+ if (as_pchan == GSM_PCHAN_TCH_F_PDCH
+ || as_pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) {
+ LOGP(DL1C, LOGL_ERROR,
+ "%s Requested TS connect as %s,"
+ " expected a specific pchan instead\n",
+ gsm_ts_and_pchan_name(ts), gsm_pchan_name(as_pchan));
+ exit(1);
+ return -EINVAL;
+ }
+
+ return ts_connect_as(ts, as_pchan, ts_connect_cb, NULL);
}