diff options
Diffstat (limited to 'src/osmo-bts-sysmo/l1_if.c')
-rw-r--r-- | src/osmo-bts-sysmo/l1_if.c | 421 |
1 files changed, 250 insertions, 171 deletions
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index df39e2f4..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/>. @@ -51,6 +51,7 @@ #include <osmo-bts/msg_utils.h> #include <osmo-bts/dtx_dl_amr_fsm.h> #include <osmo-bts/tx_power.h> +#include <osmo-bts/nm_common_fsm.h> #include <sysmocom/femtobts/superfemto.h> #include <sysmocom/femtobts/gsml1prim.h> @@ -343,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; @@ -391,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; } @@ -454,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); @@ -466,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); @@ -504,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) @@ -513,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 */ @@ -550,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; } @@ -606,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); @@ -682,7 +689,7 @@ static enum gsm_phys_chan_config pick_pchan(struct gsm_bts_trx_ts *ts) if (ts->flags & TS_F_PDCH_ACTIVE) return GSM_PCHAN_PDCH; return GSM_PCHAN_TCH_F; - case GSM_PCHAN_TCH_F_TCH_H_PDCH: + case GSM_PCHAN_OSMO_DYN: return ts->dyn.pchan_is; default: return ts->pchan; @@ -696,7 +703,7 @@ static uint8_t chan_nr_by_sapi(struct gsm_bts_trx_ts *ts, 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); + OSMO_ASSERT(pchan != GSM_PCHAN_OSMO_DYN); switch (sapi) { case GsmL1_Sapi_Bcch: @@ -796,6 +803,45 @@ static uint8_t chan_nr_by_sapi(struct gsm_bts_trx_ts *ts, return (cbits << 3) | u8Tn; } +static const enum l1sap_common_sapi common_sapi_by_sapi_t[] = { + [GsmL1_Sapi_Idle] = L1SAP_COMMON_SAPI_IDLE, + [GsmL1_Sapi_Fcch] = L1SAP_COMMON_SAPI_FCCH, + [GsmL1_Sapi_Sch] = L1SAP_COMMON_SAPI_SCH, + [GsmL1_Sapi_Sacch] = L1SAP_COMMON_SAPI_SACCH, + [GsmL1_Sapi_Sdcch] = L1SAP_COMMON_SAPI_SDCCH, + [GsmL1_Sapi_Bcch] = L1SAP_COMMON_SAPI_BCCH, + [GsmL1_Sapi_Pch] = L1SAP_COMMON_SAPI_PCH, + [GsmL1_Sapi_Agch] = L1SAP_COMMON_SAPI_AGCH, + [GsmL1_Sapi_Cbch] = L1SAP_COMMON_SAPI_CBCH, + [GsmL1_Sapi_Rach] = L1SAP_COMMON_SAPI_RACH, + [GsmL1_Sapi_TchF] = L1SAP_COMMON_SAPI_TCH_F, + [GsmL1_Sapi_FacchF] = L1SAP_COMMON_SAPI_FACCH_F, + [GsmL1_Sapi_TchH] = L1SAP_COMMON_SAPI_TCH_H, + [GsmL1_Sapi_FacchH] = L1SAP_COMMON_SAPI_FACCH_H, + [GsmL1_Sapi_Nch] = L1SAP_COMMON_SAPI_NCH, + [GsmL1_Sapi_Pdtch] = L1SAP_COMMON_SAPI_PDTCH, + [GsmL1_Sapi_Pacch] = L1SAP_COMMON_SAPI_PACCH, + [GsmL1_Sapi_Pbcch] = L1SAP_COMMON_SAPI_PBCCH, + [GsmL1_Sapi_Pagch] = L1SAP_COMMON_SAPI_PAGCH, + [GsmL1_Sapi_Ppch] = L1SAP_COMMON_SAPI_PPCH, + [GsmL1_Sapi_Pnch] = L1SAP_COMMON_SAPI_PNCH, + [GsmL1_Sapi_Ptcch] = L1SAP_COMMON_SAPI_PTCCH, + [GsmL1_Sapi_Prach] = L1SAP_COMMON_SAPI_PRACH, +}; + +static enum l1sap_common_sapi get_common_sapi(GsmL1_Sapi_t sapi) +{ + if (sapi >= GsmL1_Sapi_NUM) + return L1SAP_COMMON_SAPI_UNKNOWN; + return common_sapi_by_sapi_t[sapi]; +} + +static void set_log_ctx_sapi(GsmL1_Sapi_t sapi) +{ + l1sap_log_ctx_sapi = get_common_sapi(sapi); + log_set_context(LOG_CTX_L1_SAPI, &l1sap_log_ctx_sapi); +} + static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, GsmL1_PhReadyToSendInd_t *rts_ind, struct msgb *l1p_msg) @@ -812,6 +858,8 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, uint8_t chan_nr, link_id; uint32_t fn; + set_log_ctx_sapi(rts_ind->sapi); + /* check if primitive should be handled by common part */ chan_nr = chan_nr_by_sapi(&trx->ts[rts_ind->u8Tn], rts_ind->sapi, rts_ind->subCh, rts_ind->u8Tn, rts_ind->u32Fn); @@ -896,31 +944,8 @@ empty_frame: goto tx; } -static void dump_meas_res(int ll, GsmL1_MeasParam_t *m) -{ - LOGPC(DL1C, ll, ", Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, " - "BER %-3.2f, Timing %d\n", m->fRssi, m->fLinkQuality, - m->fBer, m->i16BurstTiming); -} - -static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr, - uint32_t fn, GsmL1_MeasParam_t *m) -{ - struct osmo_phsap_prim l1sap; - memset(&l1sap, 0, sizeof(l1sap)); - osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, - PRIM_OP_INDICATION, NULL); - l1sap.u.info.type = PRIM_INFO_MEAS; - l1sap.u.info.u.meas_ind.chan_nr = chan_nr; - l1sap.u.info.u.meas_ind.ta_offs_256bits = m->i16BurstTiming * 64; - l1sap.u.info.u.meas_ind.ber10k = (unsigned int) (m->fBer * 10000); - l1sap.u.info.u.meas_ind.inv_rssi = (uint8_t) (m->fRssi * -1); - l1sap.u.info.u.meas_ind.fn = fn; - - /* l1sap wants to take msgb ownership. However, as there is no - * msg, it will msgb_free(l1sap.oph.msg == NULL) */ - return l1sap_up(trx, &l1sap); -} +#define LOG_FMT_MEAS "Meas: RSSI %-3.2f dBm, Qual %-3.2f dB, BER %-3.2f, Timing %d" +#define LOG_PARAM_MEAS(meas_param) (meas_param)->fRssi, (meas_param)->fLinkQuality, (meas_param)->fBer, (meas_param)->i16BurstTiming static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg) @@ -933,6 +958,8 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i struct gsm_time g_time; int rc = 0; + set_log_ctx_sapi(data_ind->sapi); + chan_nr = chan_nr_by_sapi(&trx->ts[data_ind->u8Tn], data_ind->sapi, data_ind->subCh, data_ind->u8Tn, data_ind->u32Fn); if (!chan_nr) { @@ -944,14 +971,12 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i fn = data_ind->u32Fn; link_id = (data_ind->sapi == GsmL1_Sapi_Sacch) ? LID_SACCH : LID_DEDIC; - process_meas_res(trx, chan_nr, fn, &data_ind->measParam); - gsm_fn2gsmtime(&g_time, fn); - DEBUGPGT(DL1P, &g_time, "Rx PH-DATA.ind %s (hL2 %08x): %s\n", + DEBUGPGT(DL1P, &g_time, "Rx PH-DATA.ind %s (hL2 %08x): %s, " LOG_FMT_MEAS "\n", get_value_string(femtobts_l1sapi_names, data_ind->sapi), data_ind->hLayer2, - osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size)); - dump_meas_res(LOGL_DEBUG, &data_ind->measParam); + osmo_hexdump(data_ind->msgUnitParam.u8Buffer, data_ind->msgUnitParam.u8Size), + LOG_PARAM_MEAS(&data_ind->measParam)); /* check for TCH */ if (data_ind->sapi == GsmL1_Sapi_TchF @@ -962,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); @@ -971,11 +1015,10 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i l1sap->u.data.chan_nr = chan_nr; l1sap->u.data.fn = fn; l1sap->u.data.rssi = (int8_t) (data_ind->measParam.fRssi); - if (!pcu_direct) { /* FIXME: if pcu_direct=1, then this is not set, what to do in pcu_tx_data_ind() in this case ?*/ - l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000; - l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming * 64; - l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10; - } + l1sap->u.data.ber10k = data_ind->measParam.fBer * 10000; + l1sap->u.data.ta_offs_256bits = data_ind->measParam.i16BurstTiming * 64; + l1sap->u.data.lqual_cb = data_ind->measParam.fLinkQuality * 10; + /* copy data from L1 primitive to L1SAP primitive */ sap_msg->l2h = msgb_put(sap_msg, data_ind->msgUnitParam.u8Size); memcpy(sap_msg->l2h, data_ind->msgUnitParam.u8Buffer, @@ -996,7 +1039,9 @@ static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind, int rc; struct ph_rach_ind_param rach_ind_param; - dump_meas_res(LOGL_DEBUG, &ra_ind->measParam); + set_log_ctx_sapi(ra_ind->sapi); + LOGPFN(DL1C, LOGL_DEBUG, ra_ind->u32Fn, "Rx PH-RA.ind, " LOG_FMT_MEAS "\n", + LOG_PARAM_MEAS(&ra_ind->measParam)); if ((ra_ind->msgUnitParam.u8Size != 1) && (ra_ind->msgUnitParam.u8Size != 2)) { @@ -1192,13 +1237,127 @@ 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) { SuperFemto_Prim_t *sysp = msgb_sysprim(resp); GsmL1_Status_t status; int on = 0; - unsigned int i; if (sysp->id == SuperFemto_PrimId_ActivateRfCnf) on = 1; @@ -1217,21 +1376,18 @@ 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 */ - 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 (i = 0; i < ARRAY_SIZE(trx->ts); i++) - oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY); +#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); - oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); - oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); + osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL); + osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL); } msgb_free(resp); @@ -1325,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) @@ -1444,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) @@ -1483,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; } @@ -1846,7 +1908,8 @@ static void fill_trx_power_params(struct gsm_bts_trx *trx, LOGP(DL1C, LOGL_NOTICE, "Assuming 1002 for sysmoBTS " "Model number %u\n", fl1h->hw_info.model_nr); /* fall-through */ - case 1002: + case 1002: /* sysmoBTS 1002 */ + case 1003: /* sysmoBTS 1002 with GPS and PoE */ set_power_param(&trx->power_params, 23, 0); } } @@ -1883,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; } |