diff --git a/doc/timeslot.msc b/doc/timeslot.msc index 02e7bb3ea..0fd1458e5 100644 --- a/doc/timeslot.msc +++ b/doc/timeslot.msc @@ -1,5 +1,5 @@ msc { - bts [label="MS/BTS"], bsc[label="BSC"], bsc_ts[label="BSC timeslot FSM"], bsc_lchan[label="BSC lchan FSM"]; + bts [label="MS/BTS"], bsc[label="BSC"], bsc_ts[label="BSC timeslot FSM"], bsc_lchan[label="BSC lchan FSM"], pcu_sock[label="PCU socket"]; bsc_ts abox bsc_ts [label="NOT_INITIALIZED"]; @@ -88,6 +88,24 @@ msc { bsc_ts rbox bsc_ts [label="Continue at 'IN_USE' above"]; ...; ...; + bts rbox bsc_lchan [label="on PCU disconnect (Ericsson RBS) + for all timeslots in state PDCH:" ]; + bsc_ts abox bsc_ts [label="PDCH"]; + bsc_ts <- pcu_sock [label="TS_EV_PDCH_DEACT"]; + bts note bsc_ts [label="PDCH release, see WAIT_PDCH_DEACT above"]; + ...; + bsc_ts abox bsc_ts [label="UNUSED"]; + ...; + ...; + bts rbox bsc_lchan [label="on PCU reconnect (Ericsson RBS) + for all timeslots in state UNUSED:" ]; + bsc_ts abox bsc_ts [label="UNUSED"]; + bsc_ts <- pcu_sock [label="TS_EV_PDCH_ACT"]; + bts note bsc_ts [label="PDCH activation, see WAIT_PDCH_ACT above"]; + ...; + bsc_ts abox bsc_ts [label="PDCH"]; + ...; + ...; bts rbox bsc_lchan [label="on erratic event"]; bsc_ts -> bsc_lchan [label="LCHAN_EV_TS_ERROR"]; diff --git a/include/osmocom/bsc/pcu_if.h b/include/osmocom/bsc/pcu_if.h index 3c34cdf4c..2a2afa869 100644 --- a/include/osmocom/bsc/pcu_if.h +++ b/include/osmocom/bsc/pcu_if.h @@ -14,6 +14,9 @@ struct pcu_sock_state { struct llist_head upqueue; /* queue for sending messages */ }; +/* Check if BTS has a PCU connection */ +bool pcu_connected(struct gsm_bts *bts); + /* PCU relevant information has changed; Inform PCU (if connected) */ void pcu_info_update(struct gsm_bts *bts); diff --git a/include/osmocom/bsc/timeslot_fsm.h b/include/osmocom/bsc/timeslot_fsm.h index cea1e4c4d..c1b61b812 100644 --- a/include/osmocom/bsc/timeslot_fsm.h +++ b/include/osmocom/bsc/timeslot_fsm.h @@ -36,10 +36,18 @@ enum ts_fsm_event { TS_EV_RSL_DOWN, TS_EV_LCHAN_REQUESTED, TS_EV_LCHAN_UNUSED, + + /* RSL responses received from the BTS: */ TS_EV_PDCH_ACT_ACK, TS_EV_PDCH_ACT_NACK, TS_EV_PDCH_DEACT_ACK, TS_EV_PDCH_DEACT_NACK, + + /* BSC co-located PCU disconnects from PCU socket, deactivate PDCH */ + TS_EV_PDCH_DEACT, + + /* BSC co-located PCU (re)connects to PCU socket, activate PDCH */ + TS_EV_PDCH_ACT, }; void ts_fsm_alloc(struct gsm_bts_trx_ts *ts); @@ -52,3 +60,6 @@ bool ts_is_pchan_switching(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config bool ts_usable_as_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config as_pchan, bool allow_pchan_switch); void ts_set_pchan_is(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pchan_is); + +void ts_pdch_act(struct gsm_bts_trx_ts *ts); +void ts_pdch_deact(struct gsm_bts_trx_ts *ts); diff --git a/src/osmo-bsc/pcu_sock.c b/src/osmo-bsc/pcu_sock.c index 1d5e56c3f..51b59c6ef 100644 --- a/src/osmo-bsc/pcu_sock.c +++ b/src/osmo-bsc/pcu_sock.c @@ -44,6 +44,7 @@ #include #include #include +#include static int pcu_sock_send(struct gsm_bts *bts, struct msgb *msg); @@ -58,11 +59,14 @@ static const char *sapi_string[] = { [PCU_IF_SAPI_PCH_DT] = "PCH_DT", }; -/* Check if BTS has a PCU connection */ -static bool pcu_connected(struct gsm_bts *bts) +bool pcu_connected(struct gsm_bts *bts) { struct pcu_sock_state *state = bts->pcu_state; + /* BSC co-located PCU is only supported for Ericsson RBS */ + if (!is_ericsson_bts(bts)) + return false; + if (!state) return false; if (state->conn_bfd.fd <= 0) @@ -751,8 +755,7 @@ static void pcu_sock_close(struct pcu_sock_state *state) struct osmo_fd *bfd = &state->conn_bfd; struct gsm_bts *bts; struct gsm_bts_trx *trx; - struct gsm_bts_trx_ts *ts; - int i, j; + int j; /* FIXME: allow multiple BTS */ bts = llist_entry(state->net->bts_list.next, struct gsm_bts, list); @@ -773,15 +776,14 @@ static void pcu_sock_close(struct pcu_sock_state *state) #endif /* release PDCH */ - for (i = 0; i < 8; i++) { - trx = gsm_bts_trx_num(bts, i); - if (!trx) - break; - for (j = 0; j < 8; j++) { - ts = &trx->ts[j]; + llist_for_each_entry(trx, &bts->trx_list, list) { + for (j = 0; j < ARRAY_SIZE(trx->ts); j++) { + struct gsm_bts_trx_ts *ts = &trx->ts[j]; + /* BSC co-located PCU applies only to Ericsson RBS, which supports only GSM_PCHAN_OSMO_DYN. + * So we need to deact only on this pchan kind. */ if (ts->mo.nm_state.operational == NM_OPSTATE_ENABLED - && ts->pchan_is == GSM_PCHAN_PDCH) { - printf("l1sap_chan_rel(trx,gsm_lchan2chan_nr(ts->lchan));\n"); + && ts->pchan_on_init == GSM_PCHAN_OSMO_DYN) { + ts_pdch_deact(ts); } } } @@ -908,9 +910,15 @@ static int pcu_sock_accept(struct osmo_fd *bfd, unsigned int flags) struct pcu_sock_state *state = (struct pcu_sock_state *)bfd->data; struct osmo_fd *conn_bfd = &state->conn_bfd; struct sockaddr_un un_addr; + struct gsm_bts *bts; + struct gsm_bts_trx *trx; + int j; socklen_t len; int rc; + /* FIXME: allow multiple BTS */ + bts = llist_entry(state->net->bts_list.next, struct gsm_bts, list); + len = sizeof(un_addr); rc = accept(bfd->fd, (struct sockaddr *) &un_addr, &len); if (rc < 0) { @@ -939,6 +947,18 @@ static int pcu_sock_accept(struct osmo_fd *bfd, unsigned int flags) LOGP(DPCU, LOGL_NOTICE, "PCU socket connected to external PCU\n"); + /* activate PDCH */ + llist_for_each_entry(trx, &bts->trx_list, list) { + for (j = 0; j < ARRAY_SIZE(trx->ts); j++) { + struct gsm_bts_trx_ts *ts = &trx->ts[j]; + /* (See comment in pcu_sock_close above) */ + if (ts->mo.nm_state.operational == NM_OPSTATE_ENABLED + && ts->pchan_on_init == GSM_PCHAN_OSMO_DYN) { + ts_pdch_act(ts); + } + } + } + return 0; } diff --git a/src/osmo-bsc/timeslot_fsm.c b/src/osmo-bsc/timeslot_fsm.c index 28e2aaa70..16d736033 100644 --- a/src/osmo-bsc/timeslot_fsm.c +++ b/src/osmo-bsc/timeslot_fsm.c @@ -341,6 +341,11 @@ static void ts_fsm_unused_pdch_act(struct osmo_fsm_inst *fi) return; } + if (!pcu_connected(bts)) { + LOG_TS(ts, LOGL_DEBUG, "PCU not connected: not activating PDCH.\n"); + return; + } + osmo_fsm_inst_state_chg(fi, TS_ST_WAIT_PDCH_ACT, CHAN_ACT_DEACT_TIMEOUT, T_CHAN_ACT_DEACT); } @@ -408,6 +413,10 @@ static void ts_fsm_unused(struct osmo_fsm_inst *fi, uint32_t event, void *data) /* ignored. */ return; + case TS_EV_PDCH_ACT: + ts_fsm_unused_pdch_act(fi); + return; + default: OSMO_ASSERT(false); } @@ -531,6 +540,10 @@ static void ts_fsm_pdch(struct osmo_fsm_inst *fi, uint32_t event, void *data) } } + case TS_EV_PDCH_DEACT: + ts_fsm_pdch_deact(fi); + return; + case TS_EV_LCHAN_UNUSED: /* ignored */ return; @@ -889,6 +902,7 @@ static const struct osmo_fsm_state ts_fsm_states[] = { .in_event_mask = 0 | S(TS_EV_LCHAN_REQUESTED) | S(TS_EV_LCHAN_UNUSED) + | S(TS_EV_PDCH_ACT) , .out_state_mask = 0 | S(TS_ST_WAIT_PDCH_ACT) @@ -921,6 +935,7 @@ static const struct osmo_fsm_state ts_fsm_states[] = { .in_event_mask = 0 | S(TS_EV_LCHAN_REQUESTED) | S(TS_EV_LCHAN_UNUSED) + | S(TS_EV_PDCH_DEACT) , .out_state_mask = 0 | S(TS_ST_WAIT_PDCH_DEACT) @@ -992,6 +1007,8 @@ static const struct value_string ts_fsm_event_names[] = { OSMO_VALUE_STRING(TS_EV_PDCH_ACT_NACK), OSMO_VALUE_STRING(TS_EV_PDCH_DEACT_ACK), OSMO_VALUE_STRING(TS_EV_PDCH_DEACT_NACK), + OSMO_VALUE_STRING(TS_EV_PDCH_DEACT), + OSMO_VALUE_STRING(TS_EV_PDCH_ACT), {} }; @@ -1105,3 +1122,23 @@ bool ts_usable_as_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config as_ return true; } + +void ts_pdch_act(struct gsm_bts_trx_ts *ts) +{ + /* We send the activation event only when the timeslot is UNUSED. In all other cases the timeslot FSM + * will automatically handle the activation at some later point. */ + if (ts->fi->state != TS_ST_UNUSED) + return; + + osmo_fsm_inst_dispatch(ts->fi, TS_EV_PDCH_ACT, NULL); +} + +void ts_pdch_deact(struct gsm_bts_trx_ts *ts) +{ + /* We send the deactivation event only when the timeslot is active as PDCH. The timeslot FSM will check + * if the PCU is available before activating the PDCH again. */ + if (ts->fi->state != TS_ST_PDCH) + return; + + osmo_fsm_inst_dispatch(ts->fi, TS_EV_PDCH_DEACT, NULL); +}