diff options
Diffstat (limited to 'src/osmo-bts-trx/l1_if.c')
-rw-r--r-- | src/osmo-bts-trx/l1_if.c | 297 |
1 files changed, 146 insertions, 151 deletions
diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c index 754e9d7a..54f5bd24 100644 --- a/src/osmo-bts-trx/l1_if.c +++ b/src/osmo-bts-trx/l1_if.c @@ -45,6 +45,7 @@ #include <osmo-bts/scheduler.h> #include <osmo-bts/pcu_if.h> #include <osmo-bts/nm_common_fsm.h> +#include <osmo-bts/handover.h> #include "l1_if.h" #include "trx_if.h" @@ -87,38 +88,23 @@ struct trx_l1h *trx_l1h_alloc(void *tall_ctx, struct phy_instance *pinst) return l1h; } -static void check_transceiver_availability_trx(struct trx_l1h *l1h, int avail) +int bts_model_lchan_deactivate(struct gsm_lchan *lchan) { - struct phy_instance *pinst = l1h->phy_inst; - struct gsm_bts_trx *trx = pinst->trx; + int rc; + /* set lchan inactive */ + lchan_set_state(lchan, LCHAN_S_NONE); - /* HACK, we should change state when we receive first clock from - * transceiver */ - if (avail) { - /* signal availability */ - if (!pinst->u.osmotrx.sw_act_reported) { - 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); - pinst->u.osmotrx.sw_act_reported = true; - } - } else { - osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL); - osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL); - } -} + /* Disable it on the scheduler: */ + rc = trx_sched_set_lchan(lchan, gsm_lchan2chan_nr(lchan), LID_DEDIC, false); -int bts_model_lchan_deactivate(struct gsm_lchan *lchan) -{ + /* Reactivate CCCH due to SI3 update in RSL */ if (lchan->rel_act_kind == LCHAN_REL_ACT_REACT) { lchan->rel_act_kind = LCHAN_REL_ACT_RSL; - /* FIXME: perform whatever is needed (if any) to set proper PCH/AGCH allocation according to - 3GPP TS 44.018 Table 10.5.2.11.1 using num_agch(lchan->ts->trx, "TRX L1"); function */ - return 0; + trx_sched_set_lchan(lchan, gsm_lchan2chan_nr(lchan), LID_DEDIC, true); + lchan_set_state(lchan, LCHAN_S_ACTIVE); + return rc; } - /* set lchan inactive */ - lchan_set_state(lchan, LCHAN_S_NONE); - - return trx_sched_set_lchan(lchan, gsm_lchan2chan_nr(lchan), LID_DEDIC, false); + return rc; } int bts_model_lchan_deactivate_sacch(struct gsm_lchan *lchan) @@ -185,10 +171,6 @@ static int trx_init(struct gsm_bts_trx *trx) if (rc != 0) return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_NACK, (void*)(intptr_t)NM_NACK_CANT_PERFORM); - - if (trx == trx->bts->c0) - lchan_init_lapdm(&trx->ts[0].lchan[CCCH_LCHAN]); - /* Send OPSTART ack */ return osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_OPSTART_ACK, NULL); } @@ -211,13 +193,15 @@ void bts_model_trx_close(struct gsm_bts_trx *trx) osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CLOSE, NULL); /* Set to Operational State: Disabled */ - check_transceiver_availability_trx(l1h, 0); + osmo_fsm_inst_dispatch(trx->mo.fi, NM_EV_DISABLE, NULL); + osmo_fsm_inst_dispatch(trx->bb_transc.mo.fi, NM_EV_DISABLE, NULL); } -/* on RSL failure, deactivate transceiver */ void bts_model_abis_close(struct gsm_bts *bts) { - bts_shutdown(bts, "Abis close"); + /* Go into shutdown state deactivating transceivers until Abis link + * becomes up again */ + bts_shutdown_ext(bts, "Abis close", false, true); } int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan) @@ -228,17 +212,21 @@ int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan) } /* set bts attributes */ -static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr) +static uint8_t trx_set_bts(struct gsm_bts *bts) { - struct gsm_bts_trx *trx; + struct phy_instance *pinst = trx_phy_instance(bts->c0); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; uint8_t bsic = bts->bsic; + struct gsm_bts_trx *trx; + + /* ARFCN for C0 is assigned during Set BTS Attr, see oml.c */ + osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_ARFCN, (void *)(intptr_t)pinst->trx->arfcn); llist_for_each_entry(trx, &bts->trx_list, list) { - struct phy_instance *pinst = trx_phy_instance(trx); - struct phy_link *plink = pinst->phy_link; - struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + pinst = trx_phy_instance(trx); + l1h = pinst->u.osmotrx.hdl; + osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_BSIC, (void*)(intptr_t)bsic); - check_transceiver_availability_trx(l1h, phy_link_state_get(plink) != PHY_LINK_SHUTDOWN); } return 0; @@ -252,7 +240,9 @@ static uint8_t trx_set_trx(struct gsm_bts_trx *trx) struct phy_link *plink = pinst->phy_link; uint16_t arfcn = trx->arfcn; - osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_ARFCN, (void*)(intptr_t)arfcn); + /* ARFCN for C0 is assigned during Set BTS Attr, see oml.c */ + if (trx != trx->bts->c0) + osmo_fsm_inst_dispatch(l1h->provision_fi, TRX_PROV_EV_CFG_ARFCN, (void *)(intptr_t)arfcn); /* Begin to ramp up the power if power reduction is set by OML and TRX is already running. Otherwise skip, power ramping will be started @@ -286,18 +276,33 @@ static uint8_t trx_set_ts_as_pchan(struct gsm_bts_trx_ts *ts, if (rc) return NM_NACK_RES_NOTAVAIL; - /* activate lchan for CCCH */ - if (pchan == GSM_PCHAN_CCCH || pchan == GSM_PCHAN_CCCH_SDCCH4 || - pchan == GSM_PCHAN_CCCH_SDCCH4_CBCH) { + /* activate lchans for [CBCH/]BCCH/CCCH */ + switch (pchan) { + case GSM_PCHAN_SDCCH8_SACCH8C_CBCH: + /* using RSL_CHAN_OSMO_CBCH4 is correct here, because the scheduler + * does not distinguish between SDCCH/4+CBCH abd SDCCH/8+CBCH. */ + trx_sched_set_lchan(&ts->lchan[CBCH_LCHAN], + RSL_CHAN_OSMO_CBCH4, LID_DEDIC, true); + break; + case GSM_PCHAN_CCCH_SDCCH4_CBCH: + trx_sched_set_lchan(&ts->lchan[CBCH_LCHAN], + RSL_CHAN_OSMO_CBCH4, LID_DEDIC, true); + /* fall-through */ + case GSM_PCHAN_CCCH_SDCCH4: + case GSM_PCHAN_CCCH: + trx_sched_set_bcch_ccch(&ts->lchan[CCCH_LCHAN], true); ts->lchan[CCCH_LCHAN].rel_act_kind = LCHAN_REL_ACT_OML; lchan_set_state(&ts->lchan[CCCH_LCHAN], LCHAN_S_ACTIVE); + break; + default: + break; } slottype = transceiver_chan_types[pchan]; struct trx_prov_ev_cfg_ts_data data = { .tn = tn, .slottype = slottype }; - if (ts->tsc_set != 0 || ts->tsc != BTS_TSC(ts->trx->bts)) { + if (ts->tsc_set != 0) { /* On TRXC we use 3GPP compliant numbering, so +1 */ data.tsc_set = ts->tsc_set + 1; data.tsc_val = ts->tsc; @@ -342,8 +347,8 @@ static uint8_t trx_set_ts(struct gsm_bts_trx_ts *ts) /* enable ciphering */ static int l1if_set_ciphering(struct gsm_lchan *lchan, uint8_t chan_nr, int downlink) { - /* ciphering already enabled in both directions */ - if (lchan->ciph_state == LCHAN_CIPH_RXTX_CONF) + /* ignore the request when the channel is not active */ + if (lchan->state != LCHAN_S_ACTIVE) return -EINVAL; if (!downlink) { @@ -415,98 +420,98 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) switch (l1sap->u.info.type) { case PRIM_INFO_ACT_CIPH: chan_nr = l1sap->u.info.u.ciph_req.chan_nr; - lchan = get_lchan_by_chan_nr(trx, chan_nr); + break; + case PRIM_INFO_ACT_UL_ACC: + case PRIM_INFO_DEACT_UL_ACC: + chan_nr = l1sap->u.info.u.ulacc_req.chan_nr; + break; + default: + /* u.act_req used by PRIM_INFO_{ACTIVATE,DEACTIVATE,MODIFY} */ + chan_nr = l1sap->u.info.u.act_req.chan_nr; + } + lchan = get_lchan_by_chan_nr(trx, chan_nr); + if (OSMO_UNLIKELY(lchan == NULL)) { + LOGP(DL1C, LOGL_ERROR, + "Rx MPH-INFO.req (type=0x%02x) for non-existent lchan (%s)\n", + l1sap->u.info.type, rsl_chan_nr_str(chan_nr)); + rc = -ENODEV; + break; + } + + switch (l1sap->u.info.type) { + case PRIM_INFO_ACT_CIPH: if (l1sap->u.info.u.ciph_req.uplink) l1if_set_ciphering(lchan, chan_nr, 0); if (l1sap->u.info.u.ciph_req.downlink) l1if_set_ciphering(lchan, chan_nr, 1); break; + case PRIM_INFO_ACT_UL_ACC: + trx_sched_set_ul_access(lchan, chan_nr, true); + break; + case PRIM_INFO_DEACT_UL_ACC: + trx_sched_set_ul_access(lchan, chan_nr, false); + break; case PRIM_INFO_ACTIVATE: - case PRIM_INFO_DEACTIVATE: - case PRIM_INFO_MODIFY: - chan_nr = l1sap->u.info.u.act_req.chan_nr; - lchan = get_lchan_by_chan_nr(trx, chan_nr); - if (l1sap->u.info.type == PRIM_INFO_ACTIVATE) { - if ((chan_nr & 0xE0) == 0x80) { - LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Cannot activate" - " channel %s\n", rsl_chan_nr_str(chan_nr)); - break; - } - - /* attempt to allocate an Error Concealment Unit instance, if available */ - lchan->ecu_state = osmo_ecu_init(trx, lchan2ecu_codec(lchan)); - - /* trx_chan_desc[] in scheduler.c uses the RSL_CHAN_OSMO_PDCH cbits - * (0xc0) to indicate the need for PDTCH and PTCCH SAPI activation. - * However, 0xc0 is a cbits pattern exclusively used for Osmocom style - * dyn TS (a non-standard RSL Chan Activ mod); hence, for IPA style dyn - * TS, the chan_nr will never reflect 0xc0 and we would omit the - * PDTCH,PTTCH SAPIs. To properly de-/activate the PDTCH SAPIs in - * scheduler.c, make sure the 0xc0 cbits are set for de-/activating PDTCH - * lchans, i.e. both Osmocom and IPA style dyn TS. (For Osmocom style dyn - * TS, the chan_nr typically already reflects 0xc0, while it doesn't for - * IPA style.) */ - if (lchan->type == GSM_LCHAN_PDTCH) - chan_nr = RSL_CHAN_OSMO_PDCH | (chan_nr & ~RSL_CHAN_NR_MASK); - - /* activate dedicated channel */ - trx_sched_set_lchan(lchan, chan_nr, LID_DEDIC, true); - /* activate associated channel */ - trx_sched_set_lchan(lchan, chan_nr, LID_SACCH, true); - /* set mode */ - trx_sched_set_mode(lchan->ts, chan_nr, - lchan->rsl_cmode, lchan->tch_mode, - lchan->tch.amr_mr.num_modes, - lchan->tch.amr_mr.bts_mode[0].mode, - lchan->tch.amr_mr.bts_mode[1].mode, - lchan->tch.amr_mr.bts_mode[2].mode, - lchan->tch.amr_mr.bts_mode[3].mode, - amr_get_initial_mode(lchan), - (lchan->ho.active == 1)); - /* init lapdm */ - lchan_init_lapdm(lchan); - /* set lchan active */ - lchan_set_state(lchan, LCHAN_S_ACTIVE); - /* set initial ciphering */ - l1if_set_ciphering(lchan, chan_nr, 0); - l1if_set_ciphering(lchan, chan_nr, 1); - if (lchan->encr.alg_id) - lchan->ciph_state = LCHAN_CIPH_RXTX_CONF; - else - lchan->ciph_state = LCHAN_CIPH_NONE; - - /* confirm */ - mph_info_chan_confirm(trx, chan_nr, PRIM_INFO_ACTIVATE, 0); - break; - } - if (l1sap->u.info.type == PRIM_INFO_MODIFY) { - /* ECU for possibly new codec */ - if (lchan->ecu_state) - osmo_ecu_destroy(lchan->ecu_state); - lchan->ecu_state = osmo_ecu_init(trx, lchan2ecu_codec(lchan)); - /* change mode */ - trx_sched_set_mode(lchan->ts, chan_nr, - lchan->rsl_cmode, lchan->tch_mode, - lchan->tch.amr_mr.num_modes, - lchan->tch.amr_mr.bts_mode[0].mode, - lchan->tch.amr_mr.bts_mode[1].mode, - lchan->tch.amr_mr.bts_mode[2].mode, - lchan->tch.amr_mr.bts_mode[3].mode, - amr_get_initial_mode(lchan), - 0); + if ((chan_nr & 0xE0) == 0x80) { + LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Cannot activate" + " channel %s\n", rsl_chan_nr_str(chan_nr)); + rc = -EPERM; break; } - /* here, type == PRIM_INFO_DEACTIVATE */ + + /* activate dedicated channel */ + trx_sched_set_lchan(lchan, chan_nr, LID_DEDIC, true); + /* activate associated channel */ + trx_sched_set_lchan(lchan, chan_nr, LID_SACCH, true); + /* set mode */ + trx_sched_set_mode(lchan->ts, chan_nr, + lchan->rsl_cmode, lchan->tch_mode, + lchan->tch.amr_mr.num_modes, + lchan->tch.amr_mr.mode[0].mode, + lchan->tch.amr_mr.mode[1].mode, + lchan->tch.amr_mr.mode[2].mode, + lchan->tch.amr_mr.mode[3].mode, + amr_get_initial_mode(lchan), + (lchan->ho.active == HANDOVER_ENABLED)); + /* set lchan active */ + lchan_set_state(lchan, LCHAN_S_ACTIVE); + /* set initial ciphering */ + l1if_set_ciphering(lchan, chan_nr, 0); + l1if_set_ciphering(lchan, chan_nr, 1); + if (lchan->encr.alg_id) + lchan->ciph_state = LCHAN_CIPH_RXTX_CONF; + else + lchan->ciph_state = LCHAN_CIPH_NONE; + + /* confirm */ + mph_info_chan_confirm(trx, chan_nr, PRIM_INFO_ACTIVATE, 0); + break; + case PRIM_INFO_MODIFY: + /* change mode */ + trx_sched_set_mode(lchan->ts, chan_nr, + lchan->rsl_cmode, lchan->tch_mode, + lchan->tch.amr_mr.num_modes, + lchan->tch.amr_mr.mode[0].mode, + lchan->tch.amr_mr.mode[1].mode, + lchan->tch.amr_mr.mode[2].mode, + lchan->tch.amr_mr.mode[3].mode, + amr_get_initial_mode(lchan), + 0); + /* update ciphering params */ + l1if_set_ciphering(lchan, chan_nr, 0); + l1if_set_ciphering(lchan, chan_nr, 1); + if (lchan->encr.alg_id) + lchan->ciph_state = LCHAN_CIPH_RXTX_CONF; + else + lchan->ciph_state = LCHAN_CIPH_NONE; + break; + case PRIM_INFO_DEACTIVATE: if ((chan_nr & 0xE0) == 0x80) { LOGPLCHAN(lchan, DL1C, LOGL_ERROR, "Cannot deactivate" " channel %s\n", rsl_chan_nr_str(chan_nr)); + rc = -EPERM; break; } - /* clear ECU state (if any) */ - if (lchan->ecu_state) { - osmo_ecu_destroy(lchan->ecu_state); - lchan->ecu_state = NULL; - } /* deactivate associated channel */ bts_model_lchan_deactivate_sacch(lchan); if (!l1sap->u.info.u.act_req.sacch_only) { @@ -551,61 +556,51 @@ int bts_model_check_oml(struct gsm_bts *bts, uint8_t msg_type, } /* callback from OML */ -int bts_model_apply_oml(struct gsm_bts *bts, struct msgb *msg, - struct tlv_parsed *new_attr, int kind, void *obj) +int bts_model_apply_oml(struct gsm_bts *bts, const struct msgb *msg, + struct gsm_abis_mo *mo, void *obj) { struct abis_om_fom_hdr *foh = msgb_l3(msg); - int cause = 0; + int rc; switch (foh->msg_type) { case NM_MT_SET_BTS_ATTR: - cause = trx_set_bts(obj, new_attr); + rc = trx_set_bts(obj); break; case NM_MT_SET_RADIO_ATTR: - cause = trx_set_trx(obj); + rc = trx_set_trx(obj); break; case NM_MT_SET_CHAN_ATTR: - cause = trx_set_ts(obj); + rc = trx_set_ts(obj); + break; + default: + rc = 0; break; } - return oml_fom_ack_nack(msg, cause); + return rc; } /* callback from OML */ int bts_model_opstart(struct gsm_bts *bts, struct gsm_abis_mo *mo, void *obj) { - struct gsm_bts_bb_trx *bb_transc; struct gsm_bts_trx *trx; - struct gsm_bts_trx_ts *ts; int rc; switch (mo->obj_class) { case NM_OC_SITE_MANAGER: - rc = osmo_fsm_inst_dispatch(bts->site_mgr.mo.fi, NM_EV_OPSTART_ACK, NULL); - break; case NM_OC_BTS: - rc = osmo_fsm_inst_dispatch(bts->mo.fi, NM_EV_OPSTART_ACK, NULL); - break; - case NM_OC_RADIO_CARRIER: - /* activate transceiver */ - trx = (struct gsm_bts_trx *) obj; - rc = trx_init(trx); - break; case NM_OC_BASEB_TRANSC: - bb_transc = (struct gsm_bts_bb_trx *) obj; - rc = osmo_fsm_inst_dispatch(bb_transc->mo.fi, NM_EV_OPSTART_ACK, NULL); - break; case NM_OC_CHANNEL: - ts = (struct gsm_bts_trx_ts *) obj; - rc = osmo_fsm_inst_dispatch(ts->mo.fi, NM_EV_OPSTART_ACK, NULL); - break; case NM_OC_GPRS_NSE: case NM_OC_GPRS_CELL: case NM_OC_GPRS_NSVC: - oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK); - rc = oml_mo_opstart_ack(mo); + rc = osmo_fsm_inst_dispatch(mo->fi, NM_EV_OPSTART_ACK, NULL); + break; + case NM_OC_RADIO_CARRIER: + /* activate transceiver */ + trx = (struct gsm_bts_trx *) obj; + rc = trx_init(trx); break; default: rc = oml_mo_opstart_nack(mo, NM_NACK_OBJCLASS_NOTSUPP); |