diff options
Diffstat (limited to 'src/osmo-bts-sysmo/l1_if.c')
-rw-r--r-- | src/osmo-bts-sysmo/l1_if.c | 319 |
1 files changed, 192 insertions, 127 deletions
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 2e4765d9..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); @@ -683,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; @@ -697,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: @@ -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; } @@ -1860,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); } } @@ -1897,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; } |