aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bts-sysmo/l1_if.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bts-sysmo/l1_if.c')
-rw-r--r--src/osmo-bts-sysmo/l1_if.c312
1 files changed, 188 insertions, 124 deletions
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c
index 5c998243..9ca1c323 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -13,7 +13,7 @@
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -344,7 +344,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
abort();
}
- len = msgb_l2len(msg);
+ len = (msg->l2h) ? msgb_l2len(msg) : 0;
chan_nr = l1sap->u.data.chan_nr;
link_id = l1sap->u.data.link_id;
@@ -392,9 +392,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
else
sapi = GsmL1_Sapi_Agch;
} else {
- LOGPFN(DL1C, LOGL_NOTICE, u32Fn, "unknown prim %d op %d "
- "chan_nr %d link_id %d\n", l1sap->oph.primitive,
- l1sap->oph.operation, chan_nr, link_id);
+ LOGPLCFN(lchan, u32Fn, DL1C, LOGL_NOTICE, "unknown prim %d op %d " "chan_nr %d link_id %d\n",
+ l1sap->oph.primitive, l1sap->oph.operation, chan_nr, link_id);
msgb_free(l1msg);
return -EINVAL;
}
@@ -455,9 +454,8 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
memcpy(l1p->u.phDataReq.msgUnitParam.u8Buffer, msg->l2h,
msgb_l2len(msg));
}
- LOGPFN(DL1P, LOGL_DEBUG, u32Fn, "PH-DATA.req(%s)\n",
- osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer,
- l1p->u.phDataReq.msgUnitParam.u8Size));
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_DEBUG, "PH-DATA.req(%s)\n",
+ osmo_hexdump(l1p->u.phDataReq.msgUnitParam.u8Buffer, l1p->u.phDataReq.msgUnitParam.u8Size));
} else {
/* empty frame */
GsmL1_Prim_t *l1p = msgb_l1prim(l1msg);
@@ -467,7 +465,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
/* send message to DSP's queue */
if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], l1msg) != 0) {
- LOGPFN(DL1P, LOGL_ERROR, u32Fn, "MQ_L1_WRITE queue full. Dropping msg.\n");
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n");
msgb_free(l1msg);
} else
dtx_int_signal(lchan);
@@ -505,7 +503,6 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
/* create new message and fill data */
if (msg) {
- msgb_pull(msg, sizeof(*l1sap));
/* create new message */
nmsg = l1p_msgb_alloc();
if (!nmsg)
@@ -514,7 +511,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
rc = l1if_tch_encode(lchan,
l1p->u.phDataReq.msgUnitParam.u8Buffer,
&l1p->u.phDataReq.msgUnitParam.u8Size,
- msg->data, msg->len, u32Fn, use_cache,
+ msgb_l2(msg), msgb_l2len(msg), u32Fn, use_cache,
l1sap->u.tch.marker);
if (rc < 0) {
/* no data encoded for L1: smth will be generated below */
@@ -551,7 +548,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
}
/* send message to DSP's queue */
if (osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg) != 0) {
- LOGPFN(DL1P, LOGL_ERROR, u32Fn, "MQ_L1_WRITE queue full. Dropping msg.\n");
+ LOGPLCFN(lchan, u32Fn, DL1P, LOGL_ERROR, "MQ_L1_WRITE queue full. Dropping msg.\n");
msgb_free(nmsg);
return -ENOBUFS;
}
@@ -607,6 +604,15 @@ static int mph_info_req(struct gsm_bts_trx *trx, struct msgb *msg,
else
l1if_rsl_chan_rel(lchan);
break;
+ case PRIM_INFO_ACT_UL_ACC:
+ case PRIM_INFO_DEACT_UL_ACC:
+ chan_nr = l1sap->u.info.u.ulacc_req.chan_nr;
+ lchan = get_lchan_by_chan_nr(trx, chan_nr);
+ if (l1sap->u.info.type == PRIM_INFO_ACT_UL_ACC)
+ l1if_set_ul_acc(lchan, true);
+ else
+ l1if_set_ul_acc(lchan, false);
+ break;
default:
LOGP(DL1C, LOGL_NOTICE, "unknown MPH-INFO.req %d\n",
l1sap->u.info.type);
@@ -981,6 +987,25 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i
return rc;
}
+ /* If we got FACCH, the RTP clock needs to account for it,
+ * and if we have rtp continuous-streaming enabled,
+ * an actual BFI packet will be emitted.
+ *
+ * Only the case of TCH/F is currently handled; the task of
+ * supporting TCH/H is left as a FIXME for other/later
+ * developers. The difficulty with supporting FACCH/H is that
+ * only one GsmL1_Sapi_FacchH message will be received,
+ * covering 40 ms of time, but two RTP "tick" output calls
+ * will need to be made, with appropriately adjusted frame
+ * numbers. As a further consideration for rtp continuous-streaming
+ * mode, having the two RTP BFI packets sent directly back to back,
+ * as opposed to proper 20 ms timing, may be so undesirable
+ * that some deployments may rather disable TCH/H (use only TCH/F)
+ * than deal with the extra pain, or use TCH/H only on SDR-based
+ * BTS with osmo-bts-trx where correct timing is easily achieved. */
+ if (data_ind->sapi == GsmL1_Sapi_FacchF)
+ l1if_tch_rx_facch(trx, chan_nr, l1p_msg);
+
/* fill L1SAP header */
sap_msg = l1sap_msgb_alloc(data_ind->msgUnitParam.u8Size);
l1sap = msgb_l1sap_prim(sap_msg);
@@ -1212,6 +1237,121 @@ int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg)
return l1if_handle_ind(fl1h, msg);
}
+static void mute_handle_ts(struct gsm_bts_trx_ts *ts, int is_muted)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ts->lchan); i++) {
+ struct gsm_lchan *lchan = &ts->lchan[i];
+
+ if (!is_muted)
+ continue;
+
+ if (lchan->state != LCHAN_S_ACTIVE)
+ continue;
+
+ /* skip channels that might be active for another reason */
+ if (lchan->type == GSM_LCHAN_CCCH)
+ continue;
+ if (lchan->type == GSM_LCHAN_PDTCH)
+ continue;
+
+ if (lchan->s <= 0)
+ continue;
+
+ lchan->s = 0;
+ rsl_tx_conn_fail(lchan, RSL_ERR_RADIO_LINK_FAIL);
+ }
+}
+
+#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3, 6, 0)
+static int mute_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
+ void *data)
+{
+ struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
+ SuperFemto_Prim_t *sysp = msgb_sysprim(resp);
+ GsmL1_Status_t status;
+
+ status = sysp->u.muteRfCnf.status;
+
+ if (status != GsmL1_Status_Success) {
+ LOGP(DL1C, LOGL_ERROR, "Rx RF-MUTE.conf with status %s\n",
+ get_value_string(femtobts_l1status_names, status));
+ if (trx->mo.fi->state != NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED)
+ oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 0);
+ } else {
+ int i;
+
+ LOGP(DL1C, LOGL_INFO, "Rx RF-MUTE.conf with status=%s\n",
+ get_value_string(femtobts_l1status_names, status));
+ bts_update_status(BTS_STATUS_RF_MUTE, fl1h->last_rf_mute[0]);
+ if (trx->mo.fi->state != NM_RCARRIER_ST_OP_DISABLED_NOTINSTALLED)
+ oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 1);
+
+ osmo_static_assert(
+ ARRAY_SIZE(trx->ts) >= ARRAY_SIZE(fl1h->last_rf_mute),
+ ts_array_size);
+
+ for (i = 0; i < ARRAY_SIZE(fl1h->last_rf_mute); ++i)
+ mute_handle_ts(&trx->ts[i], fl1h->last_rf_mute[i]);
+ }
+
+ msgb_free(resp);
+
+ return 0;
+}
+#endif
+
+/* mute/unmute RF time slots */
+int l1if_mute_rf(struct femtol1_hdl *hdl, uint8_t mute[8], l1if_compl_cb *cb)
+{
+
+ LOGP(DL1C, LOGL_INFO, "Tx RF-MUTE.req (%d, %d, %d, %d, %d, %d, %d, %d)\n",
+ mute[0], mute[1], mute[2], mute[3],
+ mute[4], mute[5], mute[6], mute[7]
+ );
+
+#if SUPERFEMTO_API_VERSION < SUPERFEMTO_API(3, 6, 0)
+ const uint8_t unmuted[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ struct gsm_bts_trx *trx = hdl->phy_inst->trx;
+ int i;
+ LOGP(DL1C, LOGL_ERROR, "RF-MUTE.req not supported by SuperFemto\n");
+ /* always acknowledge an un-MUTE (which is a no-op if MUTE is not supported */
+ if (!memcmp(mute, unmuted, ARRAY_SIZE(unmuted))) {
+ bts_update_status(BTS_STATUS_RF_MUTE, mute[0]);
+ oml_mo_rf_lock_chg(&trx->mo, mute, 1);
+ for (i = 0; i < ARRAY_SIZE(unmuted); ++i)
+ mute_handle_ts(&trx->ts[i], mute[i]);
+ return 0;
+ }
+ return -ENOTSUP;
+#else
+ struct msgb *msg = sysp_msgb_alloc();
+ SuperFemto_Prim_t *sysp = msgb_sysprim(msg);
+ sysp->id = SuperFemto_PrimId_MuteRfReq;
+ memcpy(sysp->u.muteRfReq.u8Mute, mute, sizeof(sysp->u.muteRfReq.u8Mute));
+ /* save for later use */
+ memcpy(hdl->last_rf_mute, mute, sizeof(hdl->last_rf_mute));
+
+ return l1if_req_compl(hdl, msg, cb ? cb : mute_rf_compl_cb, NULL);
+#endif /* < 3.6.0 */
+}
+
+static int activate_rf_mute_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data)
+{
+#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3, 6, 0)
+ mute_rf_compl_cb(trx, resp, data);
+#endif
+
+ /* signal availability */
+ osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);
+ osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);
+
+ return 0;
+}
+
+int trx_rf_lock(struct gsm_bts_trx *trx, int locked, l1if_compl_cb *cb);
+
static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
void *data)
{
@@ -1236,12 +1376,14 @@ static int activate_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
LOGP(DL1C, LOGL_FATAL, "RF-ACT.conf with status %s\n",
get_value_string(femtobts_l1status_names, status));
bts_shutdown(trx->bts, "RF-ACT failure");
- } else
+ } else {
bts_update_status(BTS_STATUS_RF_ACTIVE, 1);
-
- /* signal availability */
- osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_SW_ACT, NULL);
- osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_SW_ACT, NULL);
+#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3, 6, 0)
+ trx_rf_lock(trx, 1, activate_rf_mute_compl_cb);
+#else
+ activate_rf_mute_compl_cb(trx, resp, NULL);
+#endif
+ }
} else {
bts_update_status(BTS_STATUS_RF_ACTIVE, 0);
osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL);
@@ -1339,104 +1481,6 @@ int l1if_activate_rf(struct femtol1_hdl *hdl, int on)
return l1if_req_compl(hdl, msg, activate_rf_compl_cb, NULL);
}
-static void mute_handle_ts(struct gsm_bts_trx_ts *ts, int is_muted)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ts->lchan); i++) {
- struct gsm_lchan *lchan = &ts->lchan[i];
-
- if (!is_muted)
- continue;
-
- if (lchan->state != LCHAN_S_ACTIVE)
- continue;
-
- /* skip channels that might be active for another reason */
- if (lchan->type == GSM_LCHAN_CCCH)
- continue;
- if (lchan->type == GSM_LCHAN_PDTCH)
- continue;
-
- if (lchan->s <= 0)
- continue;
-
- lchan->s = 0;
- rsl_tx_conn_fail(lchan, RSL_ERR_RADIO_LINK_FAIL);
- }
-}
-
-#if SUPERFEMTO_API_VERSION >= SUPERFEMTO_API(3,6,0)
-static int mute_rf_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
- void *data)
-{
- struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx);
- SuperFemto_Prim_t *sysp = msgb_sysprim(resp);
- GsmL1_Status_t status;
-
- status = sysp->u.muteRfCnf.status;
-
- if (status != GsmL1_Status_Success) {
- LOGP(DL1C, LOGL_ERROR, "Rx RF-MUTE.conf with status %s\n",
- get_value_string(femtobts_l1status_names, status));
- oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 0);
- } else {
- int i;
-
- LOGP(DL1C, LOGL_INFO, "Rx RF-MUTE.conf with status=%s\n",
- get_value_string(femtobts_l1status_names, status));
- bts_update_status(BTS_STATUS_RF_MUTE, fl1h->last_rf_mute[0]);
- oml_mo_rf_lock_chg(&trx->mo, fl1h->last_rf_mute, 1);
-
- osmo_static_assert(
- ARRAY_SIZE(trx->ts) >= ARRAY_SIZE(fl1h->last_rf_mute),
- ts_array_size);
-
- for (i = 0; i < ARRAY_SIZE(fl1h->last_rf_mute); ++i)
- mute_handle_ts(&trx->ts[i], fl1h->last_rf_mute[i]);
- }
-
- msgb_free(resp);
-
- return 0;
-}
-#endif
-
-/* mute/unmute RF time slots */
-int l1if_mute_rf(struct femtol1_hdl *hdl, uint8_t mute[8], l1if_compl_cb *cb)
-{
-
- LOGP(DL1C, LOGL_INFO, "Tx RF-MUTE.req (%d, %d, %d, %d, %d, %d, %d, %d)\n",
- mute[0], mute[1], mute[2], mute[3],
- mute[4], mute[5], mute[6], mute[7]
- );
-
-#if SUPERFEMTO_API_VERSION < SUPERFEMTO_API(3,6,0)
- const uint8_t unmuted[8] = { 0,0,0,0,0,0,0,0 };
- struct gsm_bts_trx *trx = hdl->phy_inst->trx;
- int i;
- LOGP(DL1C, LOGL_ERROR, "RF-MUTE.req not supported by SuperFemto\n");
- /* always acknowledge an un-MUTE (which is a no-op if MUTE is not supported */
- if (!memcmp(mute, unmuted, ARRAY_SIZE(unmuted))) {
- bts_update_status(BTS_STATUS_RF_MUTE, mute[0]);
- oml_mo_rf_lock_chg(&trx->mo, mute, 1);
- for (i = 0; i < ARRAY_SIZE(unmuted); ++i)
- mute_handle_ts(&trx->ts[i], mute[i]);
- return 0;
- }
- return -ENOTSUP;
-#else
- struct msgb *msg = sysp_msgb_alloc();
- SuperFemto_Prim_t *sysp = msgb_sysprim(msg);
- sysp->id = SuperFemto_PrimId_MuteRfReq;
- memcpy(sysp->u.muteRfReq.u8Mute, mute, sizeof(sysp->u.muteRfReq.u8Mute));
- /* save for later use */
- memcpy(hdl->last_rf_mute, mute, sizeof(hdl->last_rf_mute));
-
- return l1if_req_compl(hdl, msg, cb ? cb : mute_rf_compl_cb, NULL);
-#endif /* < 3.6.0 */
-}
-
/* call-back on arrival of DSP+FPGA version + band capability */
static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
void *data)
@@ -1458,10 +1502,12 @@ static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
fl1h->hw_info.ver_minor = sic->boardVersion.option;
#endif
- LOGP(DL1C, LOGL_INFO, "DSP v%u.%u.%u, FPGA v%u.%u.%u\nn",
- sic->dspVersion.major, sic->dspVersion.minor,
- sic->dspVersion.build, sic->fpgaVersion.major,
- sic->fpgaVersion.minor, sic->fpgaVersion.build);
+ snprintf(trx->pinst->version, sizeof(trx->pinst->version), "%u.%u dsp %u.%u.%u fpga %u.%u.%u",
+ fl1h->hw_info.ver_major, fl1h->hw_info.ver_minor,
+ fl1h->hw_info.dsp_version[0], fl1h->hw_info.dsp_version[1], fl1h->hw_info.dsp_version[2],
+ fl1h->hw_info.fpga_version[0], fl1h->hw_info.fpga_version[1], fl1h->hw_info.fpga_version[2]);
+
+ LOGP(DL1C, LOGL_INFO, "%s\n", trx->pinst->version);
#ifdef HW_SYSMOBTS_V1
if (sic->rfBand.gsm850)
@@ -1497,6 +1543,8 @@ static int info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp,
msgb_free(resp);
+ phy_link_state_set(trx->pinst->phy_link, PHY_LINK_CONNECTED);
+
/* FIXME: clock related */
return 0;
}
@@ -1898,12 +1946,28 @@ int bts_model_phy_link_open(struct phy_link *plink)
hdl = pinst->u.sysmobts.hdl;
osmo_strlcpy(bts->sub_model, sysmobts_model(hdl->hw_info.model_nr, hdl->hw_info.trx_nr), sizeof(bts->sub_model));
- snprintf(pinst->version, sizeof(pinst->version), "%u.%u dsp %u.%u.%u fpga %u.%u.%u",
- hdl->hw_info.ver_major, hdl->hw_info.ver_minor,
- hdl->hw_info.dsp_version[0], hdl->hw_info.dsp_version[1], hdl->hw_info.dsp_version[2],
- hdl->hw_info.fpga_version[0], hdl->hw_info.fpga_version[1], hdl->hw_info.fpga_version[2]);
- phy_link_state_set(plink, PHY_LINK_CONNECTED);
+ /* Frequency bands indicated to the BSC */
+ for (unsigned int i = 0; i < sizeof(hdl->hw_info.band_support) * 8; i++) {
+ if (~hdl->hw_info.band_support & (1 << i))
+ continue;
+ switch (1 << i) {
+ case GSM_BAND_850:
+ pinst->trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_850;
+ break;
+ case GSM_BAND_900:
+ pinst->trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_PGSM;
+ /* XXX: does GSM_BAND_900 include NM_IPAC_F_FREQ_BAND_EGSM? */
+ /* XXX: does GSM_BAND_900 include NM_IPAC_F_FREQ_BAND_RGSM? */
+ break;
+ case GSM_BAND_1800:
+ pinst->trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_DCS;
+ break;
+ case GSM_BAND_1900:
+ pinst->trx->support.freq_bands |= NM_IPAC_F_FREQ_BAND_PCS;
+ break;
+ }
+ }
return 0;
}