fixeria has submitted this change. ( https://gerrit.osmocom.org/c/osmocom-bb/+/32304 )
Change subject: trxcon/l1sched: rework the primitive API ......................................................................
trxcon/l1sched: rework the primitive API
The goal is to simplify primitive management, and allow passing data between different components without having to re-allocate memory and copy it over several times. This patch has been tested by running ttcn3-bts-test, no regressions observed.
* Use msgb and prim API from libosmocore, * Move l1sched_prim definitions to its own header file, * Move Tx queue from per-timeslot to per-lchan state, * Route prims via l1sched_prim_{to,from}_user() functions, * Remove GSMTAP stuff from sched_lchan_desc[].
Change-Id: I73576bd0ea10a5663ba6254283812c275cc3fa46 Related: OS#5500 --- M src/host/trxcon/include/osmocom/bb/l1sched/Makefile.am M src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h A src/host/trxcon/include/osmocom/bb/l1sched/prim.h M src/host/trxcon/src/sched_lchan_desc.c M src/host/trxcon/src/sched_lchan_pdtch.c M src/host/trxcon/src/sched_lchan_rach.c M src/host/trxcon/src/sched_lchan_sch.c M src/host/trxcon/src/sched_lchan_tchf.c M src/host/trxcon/src/sched_lchan_tchh.c M src/host/trxcon/src/sched_lchan_xcch.c M src/host/trxcon/src/sched_prim.c M src/host/trxcon/src/sched_trx.c M src/host/trxcon/src/trxcon_fsm.c M src/host/trxcon/src/trxcon_shim.c 14 files changed, 716 insertions(+), 768 deletions(-)
Approvals: Jenkins Builder: Verified laforge: Looks good to me, but someone else must approve pespin: Looks good to me, but someone else must approve fixeria: Looks good to me, approved
diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/Makefile.am b/src/host/trxcon/include/osmocom/bb/l1sched/Makefile.am index 76f54a7..39c32ba 100644 --- a/src/host/trxcon/include/osmocom/bb/l1sched/Makefile.am +++ b/src/host/trxcon/include/osmocom/bb/l1sched/Makefile.am @@ -1,4 +1,5 @@ noinst_HEADERS = \ l1sched.h \ logging.h \ + prim.h \ $(NULL) diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h index 4728f41..39aeeb9 100644 --- a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h +++ b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h @@ -14,6 +14,8 @@ #include <osmocom/core/linuxlist.h> #include <osmocom/core/timer.h>
+#include <osmocom/bb/l1sched/prim.h> + #define GPRS_L2_MAX_LEN 54 #define EDGE_L2_MAX_LEN 155
@@ -49,12 +51,6 @@ L1SCHED_BURST_8PSK, };
-enum l1sched_ts_prim_type { - L1SCHED_PRIM_DATA, - L1SCHED_PRIM_RACH8, - L1SCHED_PRIM_RACH11, -}; - /** * These types define the different channels on a multiframe. * Each channel has queues and can be activated individually. @@ -103,29 +99,6 @@ _L1SCHED_CHAN_MAX };
-enum l1sched_data_type { - L1SCHED_DT_PACKET_DATA, - L1SCHED_DT_SIGNALING, - L1SCHED_DT_TRAFFIC, - L1SCHED_DT_OTHER, /* SCH and RACH */ -}; - -enum l1sched_config_type { - /*! Channel combination for a timeslot */ - L1SCHED_CFG_PCHAN_COMB, -}; - -/* Represents a (re)configuration request */ -struct l1sched_config_req { - enum l1sched_config_type type; - union { - struct { - uint8_t tn; - enum gsm_phys_chan_config pchan; - } pchan_comb; - }; -}; - /* Represents a burst to be transmitted */ struct l1sched_burst_req { uint32_t fn; @@ -182,10 +155,6 @@ uint8_t chan_nr; /*! Link ID (like in RSL) */ uint8_t link_id; - /*! Sub-slot number (for SDCCH and TCH/H) */ - uint8_t ss_nr; - /*! GSMTAP channel type (see GSMTAP_CHANNEL_*) */ - uint8_t gsmtap_chan_type;
/*! How much memory do we need to store bursts */ size_t burst_buf_size; @@ -259,8 +228,10 @@ /*! Burst buffer for TX */ ubit_t *tx_bursts;
- /*! A primitive being sent */ - struct l1sched_ts_prim *prim; + /*! Queue of Tx primitives */ + struct llist_head tx_prims; + /*! Tx primitive being sent */ + struct msgb *prim;
/*! Mode for TCH channels (see GSM48_CMODE_*) */ uint8_t tch_mode; @@ -340,38 +311,10 @@ const struct l1sched_tdma_multiframe *mf_layout; /*! Channel states for logical channels */ struct llist_head lchans; - /*! Queue primitives for TX */ - struct llist_head tx_prims; /*! Backpointer to the scheduler */ struct l1sched_state *sched; };
-/* Represents one TX primitive in the queue of l1sched_ts */ -struct l1sched_ts_prim { - /*! Link to queue of TS */ - struct llist_head list; - /*! Type of primitive */ - enum l1sched_ts_prim_type type; - /*! Logical channel type */ - enum l1sched_lchan_type chan; - /*! TDMA Fn for L1SCHED_{PDTCH,PTCCH} */ - uint32_t fn; - /*! Payload length */ - size_t payload_len; - /*! Payload */ - uint8_t payload[0]; -}; - -/*! Represents a RACH (8-bit or 11-bit) primitive */ -struct l1sched_ts_prim_rach { - /*! RA value */ - uint16_t ra; - /*! Training Sequence (only for 11-bit RA) */ - uint8_t synch_seq; - /*! Transmission offset (how many frames to skip) */ - uint8_t offset; -}; - /*! Scheduler configuration */ struct l1sched_cfg { /*! Logging context (used as prefix for messages) */ @@ -426,8 +369,6 @@
/* Logical channel management functions */ enum gsm_phys_chan_config l1sched_chan_nr2pchan_config(uint8_t chan_nr); -enum l1sched_lchan_type l1sched_chan_nr2lchan_type(uint8_t chan_nr, - uint8_t link_id);
void l1sched_deactivate_all_lchans(struct l1sched_ts *ts); int l1sched_set_lchans(struct l1sched_ts *ts, uint8_t chan_nr, @@ -441,12 +382,6 @@ struct l1sched_lchan_state *l1sched_find_lchan_by_chan_nr(struct l1sched_state *sched, uint8_t chan_nr, uint8_t link_id);
-/* Primitive management functions */ -struct l1sched_ts_prim *l1sched_prim_push(struct l1sched_state *sched, - enum l1sched_ts_prim_type type, - uint8_t chan_nr, uint8_t link_id, - const uint8_t *pl, size_t pl_len); - #define L1SCHED_TCH_MODE_IS_SPEECH(mode) \ (mode == GSM48_CMODE_SPEECH_V1 \ || mode == GSM48_CMODE_SPEECH_EFR \ @@ -464,31 +399,12 @@ #define L1SCHED_CHAN_IS_SACCH(chan) \ (l1sched_lchan_desc[chan].link_id & L1SCHED_CH_LID_SACCH)
-#define L1SCHED_PRIM_IS_RACH11(prim) \ - (prim->type == L1SCHED_PRIM_RACH11) - -#define L1SCHED_PRIM_IS_RACH8(prim) \ - (prim->type == L1SCHED_PRIM_RACH8) - -#define L1SCHED_PRIM_IS_RACH(prim) \ - (L1SCHED_PRIM_IS_RACH8(prim) || L1SCHED_PRIM_IS_RACH11(prim)) - -#define L1SCHED_PRIM_IS_TCH(prim) \ - (L1SCHED_CHAN_IS_TCH(prim->chan) && prim->payload_len != GSM_MACBLOCK_LEN) - -#define L1SCHED_PRIM_IS_FACCH(prim) \ - (L1SCHED_CHAN_IS_TCH(prim->chan) && prim->payload_len == GSM_MACBLOCK_LEN) - -struct l1sched_ts_prim *l1sched_prim_dequeue(struct llist_head *queue, - uint32_t fn, struct l1sched_lchan_state *lchan); -int l1sched_prim_dummy(struct l1sched_lchan_state *lchan); -void l1sched_lchan_prim_drop(struct l1sched_lchan_state *lchan); -void l1sched_prim_flush_queue(struct llist_head *list); - int l1sched_handle_rx_burst(struct l1sched_state *sched, struct l1sched_burst_ind *bi); int l1sched_handle_rx_probe(struct l1sched_state *sched, struct l1sched_probe *probe); +int l1sched_handle_burst_req(struct l1sched_state *sched, + const struct l1sched_burst_req *br);
/* Shared declarations for lchan handlers */ extern const uint8_t l1sched_nb_training_bits[8][26]; @@ -521,17 +437,3 @@
void l1sched_pull_burst(struct l1sched_state *sched, struct l1sched_burst_req *br); void l1sched_pull_send_frame(struct l1sched_state *sched); - -/* External L1 API, must be implemented by the API user */ -int l1sched_handle_config_req(struct l1sched_state *sched, - const struct l1sched_config_req *cr); -int l1sched_handle_burst_req(struct l1sched_state *sched, - const struct l1sched_burst_req *br); - -/* External L2 API, must be implemented by the API user */ -int l1sched_handle_data_ind(struct l1sched_lchan_state *lchan, - const uint8_t *data, size_t data_len, - int n_errors, int n_bits_total, - enum l1sched_data_type dt); -int l1sched_handle_data_cnf(struct l1sched_lchan_state *lchan, - uint32_t fn, enum l1sched_data_type dt); diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/prim.h b/src/host/trxcon/include/osmocom/bb/l1sched/prim.h new file mode 100644 index 0000000..0981dc9 --- /dev/null +++ b/src/host/trxcon/include/osmocom/bb/l1sched/prim.h @@ -0,0 +1,130 @@ +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +#include <osmocom/core/msgb.h> +#include <osmocom/core/prim.h> +#include <osmocom/core/utils.h> + +#define l1sched_prim_from_msgb(msg) \ + ((struct l1sched_prim *)(msg)->l1h) + +#define l1sched_prim_data_from_msgb(msg) \ + ((uint8_t *)msgb_l2(msg)) + +#define l1sched_prim_type_from_msgb(msg) \ + l1sched_prim_from_msgb(msg)->oph.primitive + +#define L1SCHED_PRIM_STR_FMT "%s.%s" +#define L1SCHED_PRIM_STR_ARGS(prim) \ + l1sched_prim_type_name((prim)->oph.primitive), \ + osmo_prim_operation_name((prim)->oph.operation) + +enum l1sched_prim_type { + L1SCHED_PRIM_T_DATA, /* Req | Ind | Cnf */ + L1SCHED_PRIM_T_RACH, /* Req | Cnf */ + L1SCHED_PRIM_T_SCH, /* Ind */ + L1SCHED_PRIM_T_PCHAN_COMB, /* Ind */ +}; + +extern const struct value_string l1sched_prim_type_names[]; +static inline const char *l1sched_prim_type_name(enum l1sched_prim_type val) +{ + return get_value_string(l1sched_prim_type_names, val); +} + +/*! Common header for L1SCHED_PRIM_T_{DATA,RACH} */ +struct l1sched_prim_chdr { + /*! TDMA Frame Number */ + uint32_t frame_nr; + /*! RSL Channel Number */ + uint8_t chan_nr; + /*! RSL Link Identifier */ + uint8_t link_id; + /*! Traffic or signalling */ + bool traffic; +}; + +/*! Payload of L1SCHED_PRIM_T_DATA | Ind */ +struct l1sched_prim_data_ind { + /*! Common sub-header */ + struct l1sched_prim_chdr chdr; + int16_t toa256; + int8_t rssi; + int n_errors; + int n_bits_total; +}; + +/*! Payload of L1SCHED_PRIM_T_RACH | {Req,Cnf} */ +struct l1sched_prim_rach { + /*! Common sub-header */ + struct l1sched_prim_chdr chdr; + /*! Training Sequence (only for 11-bit RA) */ + uint8_t synch_seq; + /*! Transmission offset (how many frames to skip) */ + uint8_t offset; + /*! RA value is 11 bit */ + bool is_11bit; + /*! RA value */ + uint16_t ra; +}; + +struct l1sched_prim { + /*! Primitive header */ + struct osmo_prim_hdr oph; + /*! Type specific header */ + union { + /*! L1SCHED_PRIM_T_DATA | Req */ + struct l1sched_prim_chdr data_req; + /*! L1SCHED_PRIM_T_DATA | Cnf */ + struct l1sched_prim_chdr data_cnf; + /*! L1SCHED_PRIM_T_DATA | Ind */ + struct l1sched_prim_data_ind data_ind; + + /*! L1SCHED_PRIM_T_RACH | Req */ + struct l1sched_prim_rach rach_req; + /*! L1SCHED_PRIM_T_RACH | Cnf */ + struct l1sched_prim_rach rach_cnf; + + /*! L1SCHED_PRIM_T_SCH | Ind */ + struct { + /*! TDMA frame number */ + uint32_t frame_nr; + /*! BSIC */ + uint8_t bsic; + } sch_ind; + + /*! L1SCHED_PRIM_T_PCHAN_COMB | Ind */ + struct { + /*! Timeslot number */ + uint8_t tn; + /*! Channel combination for a timeslot */ + enum gsm_phys_chan_config pchan; + } pchan_comb_ind; + }; +}; + + +struct l1sched_state; +struct l1sched_lchan_state; + +void l1sched_prim_init(struct msgb *msg, + enum l1sched_prim_type type, + enum osmo_prim_operation op); + +struct msgb *l1sched_prim_alloc(enum l1sched_prim_type type, + enum osmo_prim_operation op, + size_t extra_size); + +struct msgb *l1sched_lchan_prim_dequeue(struct l1sched_lchan_state *lchan, uint32_t fn); +void l1sched_lchan_prim_assign_dummy(struct l1sched_lchan_state *lchan); +void l1sched_lchan_prim_drop(struct l1sched_lchan_state *lchan); + +int l1sched_lchan_emit_data_ind(struct l1sched_lchan_state *lchan, + const uint8_t *data, size_t data_len, + int n_errors, int n_bits_total, bool traffic); +int l1sched_lchan_emit_data_cnf(struct l1sched_lchan_state *lchan, uint32_t fn); + +int l1sched_prim_from_user(struct l1sched_state *sched, struct msgb *msg); +int l1sched_prim_to_user(struct l1sched_state *sched, struct msgb *msg); diff --git a/src/host/trxcon/src/sched_lchan_desc.c b/src/host/trxcon/src/sched_lchan_desc.c index e5f85b4..3b37c57 100644 --- a/src/host/trxcon/src/sched_lchan_desc.c +++ b/src/host/trxcon/src/sched_lchan_desc.c @@ -25,7 +25,6 @@ */
#include <osmocom/gsm/protocol/gsm_08_58.h> -#include <osmocom/core/gsmtap.h>
#include <osmocom/bb/l1sched/l1sched.h>
@@ -84,7 +83,6 @@ [L1SCHED_BCCH] = { .name = "BCCH", /* 3GPP TS 05.02, section 3.3.2.3 */ .desc = "Broadcast control channel", - .gsmtap_chan_type = GSMTAP_CHANNEL_BCCH, .chan_nr = RSL_CHAN_BCCH,
/* Rx only, xCCH convolutional coding (3GPP TS 05.03, section 4.4), @@ -97,7 +95,6 @@ [L1SCHED_RACH] = { .name = "RACH", /* 3GPP TS 05.02, section 3.3.3.1 */ .desc = "Random access channel", - .gsmtap_chan_type = GSMTAP_CHANNEL_RACH, .chan_nr = RSL_CHAN_RACH,
/* Tx only, RACH convolutional coding (3GPP TS 05.03, section 4.6). */ @@ -107,7 +104,6 @@ [L1SCHED_CCCH] = { .name = "CCCH", /* 3GPP TS 05.02, section 3.3.3.1 */ .desc = "Common control channel", - .gsmtap_chan_type = GSMTAP_CHANNEL_CCCH, .chan_nr = RSL_CHAN_PCH_AGCH,
/* Rx only, xCCH convolutional coding (3GPP TS 05.03, section 4.4), @@ -120,7 +116,6 @@ [L1SCHED_TCHF] = { .name = "TCH/F", /* 3GPP TS 05.02, section 3.2 */ .desc = "Full Rate traffic channel", - .gsmtap_chan_type = GSMTAP_CHANNEL_TCH_F, .chan_nr = RSL_CHAN_Bm_ACCHs, .link_id = L1SCHED_CH_LID_DEDIC,
@@ -143,10 +138,8 @@ [L1SCHED_TCHH_0] = { .name = "TCH/H(0)", /* 3GPP TS 05.02, section 3.2 */ .desc = "Half Rate traffic channel (sub-channel 0)", - .gsmtap_chan_type = GSMTAP_CHANNEL_TCH_H, .chan_nr = RSL_CHAN_Lm_ACCHs + (0 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 0,
/* Rx and Tx, multiple convolutional coding types (3GPP TS 05.03, * chapter 3), block diagonal interleaving (3GPP TS 05.02, clause 7): @@ -172,10 +165,8 @@ [L1SCHED_TCHH_1] = { .name = "TCH/H(1)", /* 3GPP TS 05.02, section 3.2 */ .desc = "Half Rate traffic channel (sub-channel 1)", - .gsmtap_chan_type = GSMTAP_CHANNEL_TCH_H, .chan_nr = RSL_CHAN_Lm_ACCHs + (1 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 1,
/* Same as for L1SCHED_TCHH_0, see above. */ .burst_buf_size = 6 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -186,10 +177,8 @@ [L1SCHED_SDCCH4_0] = { .name = "SDCCH/4(0)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Stand-alone dedicated control channel (sub-channel 0)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH4, .chan_nr = RSL_CHAN_SDCCH4_ACCH + (0 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 0,
/* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -200,10 +189,8 @@ [L1SCHED_SDCCH4_1] = { .name = "SDCCH/4(1)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Stand-alone dedicated control channel (sub-channel 1)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH4, .chan_nr = RSL_CHAN_SDCCH4_ACCH + (1 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 1,
/* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -214,10 +201,8 @@ [L1SCHED_SDCCH4_2] = { .name = "SDCCH/4(2)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Stand-alone dedicated control channel (sub-channel 2)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH4, .chan_nr = RSL_CHAN_SDCCH4_ACCH + (2 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 2,
/* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -228,10 +213,8 @@ [L1SCHED_SDCCH4_3] = { .name = "SDCCH/4(3)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Stand-alone dedicated control channel (sub-channel 3)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH4, .chan_nr = RSL_CHAN_SDCCH4_ACCH + (3 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 3,
/* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -242,10 +225,8 @@ [L1SCHED_SDCCH8_0] = { .name = "SDCCH/8(0)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Stand-alone dedicated control channel (sub-channel 0)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (0 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 0,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -256,10 +237,8 @@ [L1SCHED_SDCCH8_1] = { .name = "SDCCH/8(1)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Stand-alone dedicated control channel (sub-channel 1)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (1 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 1,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -270,10 +249,8 @@ [L1SCHED_SDCCH8_2] = { .name = "SDCCH/8(2)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Stand-alone dedicated control channel (sub-channel 2)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (2 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 2,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -284,10 +261,8 @@ [L1SCHED_SDCCH8_3] = { .name = "SDCCH/8(3)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Stand-alone dedicated control channel (sub-channel 3)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (3 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 3,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -298,10 +273,8 @@ [L1SCHED_SDCCH8_4] = { .name = "SDCCH/8(4)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Stand-alone dedicated control channel (sub-channel 4)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (4 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 4,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -312,10 +285,8 @@ [L1SCHED_SDCCH8_5] = { .name = "SDCCH/8(5)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Stand-alone dedicated control channel (sub-channel 5)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (5 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 5,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -326,10 +297,8 @@ [L1SCHED_SDCCH8_6] = { .name = "SDCCH/8(6)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Stand-alone dedicated control channel (sub-channel 6)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (6 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 6,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -340,10 +309,8 @@ [L1SCHED_SDCCH8_7] = { .name = "SDCCH/8(7)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Stand-alone dedicated control channel (sub-channel 7)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (7 << 3), .link_id = L1SCHED_CH_LID_DEDIC, - .ss_nr = 7,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -354,7 +321,6 @@ [L1SCHED_SACCHTF] = { .name = "SACCH/TF", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow TCH/F associated control channel", - .gsmtap_chan_type = GSMTAP_CHANNEL_TCH_F | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_Bm_ACCHs, .link_id = L1SCHED_CH_LID_SACCH,
@@ -367,10 +333,8 @@ [L1SCHED_SACCHTH_0] = { .name = "SACCH/TH(0)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow TCH/H associated control channel (sub-channel 0)", - .gsmtap_chan_type = GSMTAP_CHANNEL_TCH_H | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_Lm_ACCHs + (0 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 0,
/* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -381,10 +345,8 @@ [L1SCHED_SACCHTH_1] = { .name = "SACCH/TH(1)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow TCH/H associated control channel (sub-channel 1)", - .gsmtap_chan_type = GSMTAP_CHANNEL_TCH_H | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_Lm_ACCHs + (1 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 1,
/* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -395,10 +357,8 @@ [L1SCHED_SACCH4_0] = { .name = "SACCH/4(0)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow SDCCH/4 associated control channel (sub-channel 0)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH4 | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_SDCCH4_ACCH + (0 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 0,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -409,10 +369,8 @@ [L1SCHED_SACCH4_1] = { .name = "SACCH/4(1)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow SDCCH/4 associated control channel (sub-channel 1)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH4 | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_SDCCH4_ACCH + (1 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 1,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -423,10 +381,8 @@ [L1SCHED_SACCH4_2] = { .name = "SACCH/4(2)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow SDCCH/4 associated control channel (sub-channel 2)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH4 | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_SDCCH4_ACCH + (2 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 2,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -437,10 +393,8 @@ [L1SCHED_SACCH4_3] = { .name = "SACCH/4(3)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow SDCCH/4 associated control channel (sub-channel 3)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH4 | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_SDCCH4_ACCH + (3 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 3,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -451,10 +405,8 @@ [L1SCHED_SACCH8_0] = { .name = "SACCH/8(0)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow SDCCH/8 associated control channel (sub-channel 0)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8 | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (0 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 0,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -465,10 +417,8 @@ [L1SCHED_SACCH8_1] = { .name = "SACCH/8(1)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow SDCCH/8 associated control channel (sub-channel 1)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8 | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (1 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 1,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -479,10 +429,8 @@ [L1SCHED_SACCH8_2] = { .name = "SACCH/8(2)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow SDCCH/8 associated control channel (sub-channel 2)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8 | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (2 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 2,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -493,10 +441,8 @@ [L1SCHED_SACCH8_3] = { .name = "SACCH/8(3)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow SDCCH/8 associated control channel (sub-channel 3)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8 | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (3 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 3,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -507,10 +453,8 @@ [L1SCHED_SACCH8_4] = { .name = "SACCH/8(4)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow SDCCH/8 associated control channel (sub-channel 4)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8 | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (4 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 4,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -521,10 +465,8 @@ [L1SCHED_SACCH8_5] = { .name = "SACCH/8(5)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow SDCCH/8 associated control channel (sub-channel 5)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8 | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (5 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 5,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -535,10 +477,8 @@ [L1SCHED_SACCH8_6] = { .name = "SACCH/8(6)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow SDCCH/8 associated control channel (sub-channel 6)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8 | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (6 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 6,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -549,10 +489,8 @@ [L1SCHED_SACCH8_7] = { .name = "SACCH/8(7)", /* 3GPP TS 05.02, section 3.3.4.1 */ .desc = "Slow SDCCH/8 associated control channel (sub-channel 7)", - .gsmtap_chan_type = GSMTAP_CHANNEL_SDCCH8 | GSMTAP_CHANNEL_ACCH, .chan_nr = RSL_CHAN_SDCCH8_ACCH + (7 << 3), .link_id = L1SCHED_CH_LID_SACCH, - .ss_nr = 7,
/* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -563,7 +501,6 @@ [L1SCHED_PDTCH] = { .name = "PDTCH", /* 3GPP TS 05.02, sections 3.2.4, 3.3.2.4 */ .desc = "Packet data traffic & control channel", - .gsmtap_chan_type = GSMTAP_CHANNEL_PDTCH, .chan_nr = RSL_CHAN_OSMO_PDCH,
/* Rx and Tx, multiple coding schemes: CS-1..4 and MCS-1..9 (3GPP TS @@ -578,7 +515,6 @@ [L1SCHED_PTCCH] = { .name = "PTCCH", /* 3GPP TS 05.02, section 3.3.4.2 */ .desc = "Packet Timing advance control channel", - .gsmtap_chan_type = GSMTAP_CHANNEL_PTCCH, .chan_nr = RSL_CHAN_OSMO_PDCH, .link_id = L1SCHED_CH_LID_PTCCH,
@@ -595,9 +531,7 @@ [L1SCHED_SDCCH4_CBCH] = { .name = "SDCCH/4(CBCH)", /* 3GPP TS 05.02, section 3.3.5 */ .desc = "Cell Broadcast channel on SDCCH/4", - .gsmtap_chan_type = GSMTAP_CHANNEL_CBCH51, .chan_nr = RSL_CHAN_OSMO_CBCH4, - .ss_nr = 2,
/* Same as for L1SCHED_BCCH (xCCH), but Rx only. See above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, @@ -607,9 +541,7 @@ [L1SCHED_SDCCH8_CBCH] = { .name = "SDCCH/8(CBCH)", /* 3GPP TS 05.02, section 3.3.5 */ .desc = "Cell Broadcast channel on SDCCH/8", - .gsmtap_chan_type = GSMTAP_CHANNEL_CBCH52, .chan_nr = RSL_CHAN_OSMO_CBCH8, - .ss_nr = 2,
/* Same as for L1SCHED_BCCH (xCCH), but Rx only. See above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, diff --git a/src/host/trxcon/src/sched_lchan_pdtch.c b/src/host/trxcon/src/sched_lchan_pdtch.c index 722800f..6702d9d 100644 --- a/src/host/trxcon/src/sched_lchan_pdtch.c +++ b/src/host/trxcon/src/sched_lchan_pdtch.c @@ -96,7 +96,7 @@ l2_len = rc > 0 ? rc : 0;
/* Send a L2 frame to the higher layers */ - l1sched_handle_data_ind(lchan, l2, l2_len, n_errors, n_bits_total, L1SCHED_DT_PACKET_DATA); + l1sched_lchan_emit_data_ind(lchan, l2, l2_len, n_errors, n_bits_total, true);
return 0; } @@ -123,12 +123,10 @@ }
/* Encode payload */ - rc = gsm0503_pdtch_encode(buffer, lchan->prim->payload, - lchan->prim->payload_len); + rc = gsm0503_pdtch_encode(buffer, msgb_l2(lchan->prim), msgb_l2len(lchan->prim)); if (rc < 0) { - LOGP_LCHAND(lchan, LOGL_ERROR, "Failed to encode L2 payload (len=%zu): %s\n", - lchan->prim->payload_len, osmo_hexdump(lchan->prim->payload, - lchan->prim->payload_len)); + LOGP_LCHAND(lchan, LOGL_ERROR, "Failed to encode L2 payload (len=%u): %s\n", + msgb_l2len(lchan->prim), msgb_hexdump_l2(lchan->prim)); l1sched_lchan_prim_drop(lchan); return -EINVAL; } @@ -155,11 +153,8 @@
/* If we have sent the last (4/4) burst */ if ((*mask & 0x0f) == 0x0f) { - /* Confirm data / traffic sending */ - l1sched_handle_data_cnf(lchan, br->fn, L1SCHED_DT_PACKET_DATA); - - /* Forget processed primitive */ - l1sched_lchan_prim_drop(lchan); + /* Confirm data / traffic sending (pass ownership of the prim) */ + l1sched_lchan_emit_data_cnf(lchan, br->fn);
/* Reset mask */ *mask = 0x00; diff --git a/src/host/trxcon/src/sched_lchan_rach.c b/src/host/trxcon/src/sched_lchan_rach.c index 7448d83..109d100 100644 --- a/src/host/trxcon/src/sched_lchan_rach.c +++ b/src/host/trxcon/src/sched_lchan_rach.c @@ -73,56 +73,37 @@ struct l1sched_burst_req *br) { const uint8_t bsic = lchan->ts->sched->bsic; - struct l1sched_ts_prim_rach *rach; + struct l1sched_prim *prim; uint8_t *burst_ptr = br->burst; uint8_t payload[36]; int i, rc;
- rach = (struct l1sched_ts_prim_rach *)lchan->prim->payload; + prim = l1sched_prim_from_msgb(lchan->prim);
/* Delay sending according to offset value */ - if (rach->offset-- > 0) + if (prim->rach_req.offset-- > 0) return 0;
- if (L1SCHED_PRIM_IS_RACH11(lchan->prim)) { - /* Check requested synch. sequence */ - if (rach->synch_seq >= RACH_SYNCH_SEQ_NUM) { - LOGP_LCHAND(lchan, LOGL_ERROR, - "Unknown RACH synch. sequence=0x%02x\n", - rach->synch_seq); - l1sched_lchan_prim_drop(lchan); - return -ENOTSUP; - } - - /* Encode 11-bit payload */ - rc = gsm0503_rach_ext_encode(payload, rach->ra, bsic, true); - if (rc) { - LOGP_LCHAND(lchan, LOGL_ERROR, - "Could not encode 11-bit RACH burst (ra=%u bsic=%u)\n", - rach->ra, bsic); - l1sched_lchan_prim_drop(lchan); - return rc; - } - } else if (L1SCHED_PRIM_IS_RACH8(lchan->prim)) { - rach->synch_seq = RACH_SYNCH_SEQ_TS0; - - /* Encode 8-bit payload */ - rc = gsm0503_rach_ext_encode(payload, rach->ra, bsic, false); - if (rc) { - LOGP_LCHAND(lchan, LOGL_ERROR, - "Could not encode RACH burst (ra=%u bsic=%u)\n", - rach->ra, bsic); - l1sched_lchan_prim_drop(lchan); - return rc; - } - } else { + /* Check requested synch. sequence */ + if (prim->rach_req.synch_seq >= RACH_SYNCH_SEQ_NUM) { LOGP_LCHAND(lchan, LOGL_ERROR, - "Primitive has unexpected type=0x%02x\n", - lchan->prim->type); + "Unknown RACH synch. sequence=0x%02x\n", + prim->rach_req.synch_seq); l1sched_lchan_prim_drop(lchan); - return -EINVAL; + return -ENOTSUP; }
+ /* Encode the payload */ + rc = gsm0503_rach_ext_encode(payload, prim->rach_req.ra, + bsic, prim->rach_req.is_11bit); + if (rc) { + LOGP_LCHAND(lchan, LOGL_ERROR, + "Could not encode %s-bit RACH burst (ra=%u bsic=%u)\n", + prim->rach_req.is_11bit ? "11" : "8", + prim->rach_req.ra, bsic); + l1sched_lchan_prim_drop(lchan); + return rc; + }
/* BN0-7: extended tail bits */ memcpy(burst_ptr, rach_ext_tail_bits, RACH_EXT_TAIL_BITS_LEN); @@ -130,7 +111,7 @@
/* BN8-48: chosen synch. (training) sequence */ for (i = 0; i < RACH_SYNCH_SEQ_LEN; i++) - *(burst_ptr++) = rach_synch_seq_bits[rach->synch_seq][i] == '1'; + *(burst_ptr++) = rach_synch_seq_bits[prim->rach_req.synch_seq][i] == '1';
/* BN49-84: encrypted bits (the payload) */ memcpy(burst_ptr, payload, RACH_PAYLOAD_LEN); @@ -141,14 +122,11 @@ br->burst_len = GSM_NBITS_NB_GMSK_BURST;
LOGP_LCHAND(lchan, LOGL_NOTICE, "Scheduled %s-bit RACH (%s) at fn=%u\n", - L1SCHED_PRIM_IS_RACH11(lchan->prim) ? "11" : "8", - get_value_string(rach_synch_seq_names, rach->synch_seq), br->fn); + prim->rach_req.is_11bit ? "11" : "8", + get_value_string(rach_synch_seq_names, prim->rach_req.synch_seq), br->fn);
- /* Confirm RACH request */ - l1sched_handle_data_cnf(lchan, br->fn, L1SCHED_DT_OTHER); - - /* Forget processed primitive */ - l1sched_lchan_prim_drop(lchan); + /* Confirm RACH request (pass ownership of the prim) */ + l1sched_lchan_emit_data_cnf(lchan, br->fn);
return 0; } diff --git a/src/host/trxcon/src/sched_lchan_sch.c b/src/host/trxcon/src/sched_lchan_sch.c index de665cb..f433de6 100644 --- a/src/host/trxcon/src/sched_lchan_sch.c +++ b/src/host/trxcon/src/sched_lchan_sch.c @@ -61,6 +61,21 @@ time->fn = gsm_gsmtime2fn(time); }
+static int handle_sch_ind(struct l1sched_state *sched, uint32_t fn, uint8_t bsic) +{ + struct l1sched_prim *prim; + struct msgb *msg; + + msg = l1sched_prim_alloc(L1SCHED_PRIM_T_SCH, PRIM_OP_INDICATION, 0); + OSMO_ASSERT(msg != NULL); + + prim = l1sched_prim_from_msgb(msg); + prim->sch_ind.frame_nr = fn; + prim->sch_ind.bsic = bsic; + + return l1sched_prim_to_user(sched, msg); +} + int rx_sch_fn(struct l1sched_lchan_state *lchan, const struct l1sched_burst_ind *bi) { @@ -100,8 +115,5 @@ /* Update BSIC value in the scheduler state */ lchan->ts->sched->bsic = bsic;
- l1sched_handle_data_ind(lchan, (const uint8_t *)&time, sizeof(time), - 0, 39 * 2, L1SCHED_DT_OTHER); - - return 0; + return handle_sch_ind(lchan->ts->sched, time.fn, bsic); } diff --git a/src/host/trxcon/src/sched_lchan_tchf.c b/src/host/trxcon/src/sched_lchan_tchf.c index 8cb996b..326713d 100644 --- a/src/host/trxcon/src/sched_lchan_tchf.c +++ b/src/host/trxcon/src/sched_lchan_tchf.c @@ -171,9 +171,8 @@ goto bfi; } else if (rc == GSM_MACBLOCK_LEN) { /* FACCH received, forward it to the higher layers */ - l1sched_handle_data_ind(lchan, l2 + amr, GSM_MACBLOCK_LEN, - n_errors, n_bits_total, - L1SCHED_DT_SIGNALING); + l1sched_lchan_emit_data_ind(lchan, l2 + amr, GSM_MACBLOCK_LEN, + n_errors, n_bits_total, false);
/* Send BFI substituting a stolen TCH frame */ n_errors = -1; /* ensure fake measurements */ @@ -184,7 +183,8 @@ }
/* Send a traffic frame to the higher layers */ - return l1sched_handle_data_ind(lchan, l2, l2_len, n_errors, n_bits_total, L1SCHED_DT_TRAFFIC); + return l1sched_lchan_emit_data_ind(lchan, l2, l2_len, + n_errors, n_bits_total, true);
bfi: /* Didn't try to decode, fake measurements */ @@ -201,18 +201,16 @@
/* BFI is not applicable in signalling mode */ if (lchan->tch_mode == GSM48_CMODE_SIGN) { - return l1sched_handle_data_ind(lchan, NULL, 0, - n_errors, n_bits_total, - L1SCHED_DT_TRAFFIC); + return l1sched_lchan_emit_data_ind(lchan, NULL, 0, + n_errors, n_bits_total, false); }
/* Bad frame indication */ l2_len = l1sched_bad_frame_ind(l2, lchan);
/* Send a BFI frame to the higher layers */ - return l1sched_handle_data_ind(lchan, l2, l2_len, - n_errors, n_bits_total, - L1SCHED_DT_TRAFFIC); + return l1sched_lchan_emit_data_ind(lchan, l2, l2_len, + n_errors, n_bits_total, true); }
int tx_tchf_fn(struct l1sched_lchan_state *lchan, @@ -240,9 +238,9 @@ memcpy(buffer, buffer + 464, 464);
/* populate the buffer with bursts */ - if (L1SCHED_PRIM_IS_FACCH(lchan->prim)) { + if (msgb_l2len(lchan->prim) == GSM_MACBLOCK_LEN) { /* Encode payload */ - rc = gsm0503_tch_fr_encode(buffer, lchan->prim->payload, GSM_MACBLOCK_LEN, 1); + rc = gsm0503_tch_fr_encode(buffer, msgb_l2(lchan->prim), GSM_MACBLOCK_LEN, 1); } else if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) { int len; uint8_t cmr_codec; @@ -256,12 +254,11 @@ */ amr_fn_is_cmr = !sched_tchf_ul_amr_cmi_map[br->fn % 26];
- len = osmo_amr_rtp_dec(lchan->prim->payload, lchan->prim->payload_len, - &cmr_codec, &cmi, &ft_codec, - &bfi, &sti); + len = osmo_amr_rtp_dec(msgb_l2(lchan->prim), msgb_l2len(lchan->prim), + &cmr_codec, &cmi, &ft_codec, &bfi, &sti); if (len < 0) { - LOGP_LCHAND(lchan, LOGL_ERROR, "Cannot send invalid AMR payload (%zu): %s\n", - lchan->prim->payload_len, osmo_hexdump(lchan->prim->payload, lchan->prim->payload_len)); + LOGP_LCHAND(lchan, LOGL_ERROR, "Cannot send invalid AMR payload (%u): %s\n", + msgb_l2len(lchan->prim), msgb_hexdump_l2(lchan->prim)); goto free_bad_msg; } ft = -1; @@ -290,11 +287,14 @@ } else { lchan->amr.ul_cmr = cmr; } - rc = gsm0503_tch_afs_encode(buffer, lchan->prim->payload + 2, - lchan->prim->payload_len - 2, amr_fn_is_cmr, - lchan->amr.codec, lchan->amr.codecs, - lchan->amr.ul_ft, - lchan->amr.ul_cmr); + rc = gsm0503_tch_afs_encode(buffer, + msgb_l2(lchan->prim) + 2, + msgb_l2len(lchan->prim) - 2, + amr_fn_is_cmr, + lchan->amr.codec, + lchan->amr.codecs, + lchan->amr.ul_ft, + lchan->amr.ul_cmr); } else { /* Determine and check the payload length */ switch (lchan->tch_mode) { @@ -312,20 +312,19 @@ l1sched_lchan_prim_drop(lchan); return -EINVAL; } - if (lchan->prim->payload_len != l2_len) { - LOGP_LCHAND(lchan, LOGL_ERROR, "Primitive has odd length %zu " + if (msgb_l2len(lchan->prim) != l2_len) { + LOGP_LCHAND(lchan, LOGL_ERROR, "Primitive has odd length %u " "(expected %zu for TCH or %u for FACCH), so dropping...\n", - lchan->prim->payload_len, l2_len, GSM_MACBLOCK_LEN); + msgb_l2len(lchan->prim), l2_len, GSM_MACBLOCK_LEN); l1sched_lchan_prim_drop(lchan); return -EINVAL; } - rc = gsm0503_tch_fr_encode(buffer, lchan->prim->payload, l2_len, 1); + rc = gsm0503_tch_fr_encode(buffer, msgb_l2(lchan->prim), l2_len, 1); }
if (rc) { - LOGP_LCHAND(lchan, LOGL_ERROR, "Failed to encode L2 payload (len=%zu): %s\n", - lchan->prim->payload_len, osmo_hexdump(lchan->prim->payload, - lchan->prim->payload_len)); + LOGP_LCHAND(lchan, LOGL_ERROR, "Failed to encode L2 payload (len=%u): %s\n", + msgb_l2len(lchan->prim), msgb_hexdump_l2(lchan->prim)); free_bad_msg: l1sched_lchan_prim_drop(lchan); return -EINVAL; @@ -353,13 +352,8 @@
/* If we have sent the last (4/4) burst */ if (*mask == 0x0f) { - /* Confirm data / traffic sending */ - enum l1sched_data_type dt = L1SCHED_PRIM_IS_TCH(lchan->prim) ? - L1SCHED_DT_TRAFFIC : L1SCHED_DT_SIGNALING; - l1sched_handle_data_cnf(lchan, br->fn, dt); - - /* Forget processed primitive */ - l1sched_lchan_prim_drop(lchan); + /* Confirm data / traffic sending (pass ownership of the prim) */ + l1sched_lchan_emit_data_cnf(lchan, br->fn);
/* Reset mask */ *mask = 0x00; diff --git a/src/host/trxcon/src/sched_lchan_tchh.c b/src/host/trxcon/src/sched_lchan_tchh.c index 7302351..34781d3 100644 --- a/src/host/trxcon/src/sched_lchan_tchh.c +++ b/src/host/trxcon/src/sched_lchan_tchh.c @@ -366,9 +366,8 @@ l1sched_lchan_meas_avg(lchan, 6);
/* FACCH/H received, forward to the higher layers */ - l1sched_handle_data_ind(lchan, l2 + amr, GSM_MACBLOCK_LEN, - n_errors, n_bits_total, - L1SCHED_DT_SIGNALING); + l1sched_lchan_emit_data_ind(lchan, l2 + amr, GSM_MACBLOCK_LEN, + n_errors, n_bits_total, false);
/* Send BFI substituting 1/2 stolen TCH frames */ n_errors = -1; /* ensure fake measurements */ @@ -382,9 +381,8 @@ }
/* Send a traffic frame to the higher layers */ - return l1sched_handle_data_ind(lchan, l2, l2_len, - n_errors, n_bits_total, - L1SCHED_DT_TRAFFIC); + return l1sched_lchan_emit_data_ind(lchan, l2, l2_len, + n_errors, n_bits_total, true);
bfi_shift: /* Shift buffer */ @@ -409,18 +407,16 @@
/* BFI is not applicable in signalling mode */ if (lchan->tch_mode == GSM48_CMODE_SIGN) { - return l1sched_handle_data_ind(lchan, NULL, 0, - n_errors, n_bits_total, - L1SCHED_DT_SIGNALING); + return l1sched_lchan_emit_data_ind(lchan, NULL, 0, + n_errors, n_bits_total, false); }
/* Bad frame indication */ l2_len = l1sched_bad_frame_ind(l2, lchan);
/* Send a BFI frame to the higher layers */ - return l1sched_handle_data_ind(lchan, l2, l2_len, - n_errors, n_bits_total, - L1SCHED_DT_TRAFFIC); + return l1sched_lchan_emit_data_ind(lchan, l2, l2_len, + n_errors, n_bits_total, true); }
int tx_tchh_fn(struct l1sched_lchan_state *lchan, @@ -463,8 +459,8 @@ }
/* populate the buffer with bursts */ - if (L1SCHED_PRIM_IS_FACCH(lchan->prim)) { - rc = gsm0503_tch_hr_encode(buffer, lchan->prim->payload, lchan->prim->payload_len); + if (msgb_l2len(lchan->prim) == GSM_MACBLOCK_LEN) { + rc = gsm0503_tch_hr_encode(buffer, msgb_l2(lchan->prim), GSM_MACBLOCK_LEN); lchan->ul_facch_blocks = 6; } else if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) { int len; @@ -479,12 +475,11 @@ */ amr_fn_is_cmr = !sched_tchh_ul_amr_cmi_map[br->fn % 26];
- len = osmo_amr_rtp_dec(lchan->prim->payload, lchan->prim->payload_len, - &cmr_codec, &cmi, &ft_codec, - &bfi, &sti); + len = osmo_amr_rtp_dec(msgb_l2(lchan->prim), msgb_l2len(lchan->prim), + &cmr_codec, &cmi, &ft_codec, &bfi, &sti); if (len < 0) { - LOGP_LCHAND(lchan, LOGL_ERROR, "Cannot send invalid AMR payload (%zu): %s\n", - lchan->prim->payload_len, osmo_hexdump(lchan->prim->payload, lchan->prim->payload_len)); + LOGP_LCHAND(lchan, LOGL_ERROR, "Cannot send invalid AMR payload (%u): %s\n", + msgb_l2len(lchan->prim), msgb_hexdump_l2(lchan->prim)); goto free_bad_msg; } ft = -1; @@ -513,11 +508,14 @@ } else { lchan->amr.ul_cmr = cmr; } - rc = gsm0503_tch_ahs_encode(buffer, lchan->prim->payload + 2, - lchan->prim->payload_len - 2, amr_fn_is_cmr, - lchan->amr.codec, lchan->amr.codecs, - lchan->amr.ul_ft, - lchan->amr.ul_cmr); + rc = gsm0503_tch_ahs_encode(buffer, + msgb_l2(lchan->prim) + 2, + msgb_l2len(lchan->prim) - 2, + amr_fn_is_cmr, + lchan->amr.codec, + lchan->amr.codecs, + lchan->amr.ul_ft, + lchan->amr.ul_cmr); } else { /* Determine and check the payload length */ switch (lchan->tch_mode) { @@ -532,20 +530,19 @@ l1sched_lchan_prim_drop(lchan); return -EINVAL; } - if (lchan->prim->payload_len != l2_len) { - LOGP_LCHAND(lchan, LOGL_ERROR, "Primitive has odd length %zu " + if (msgb_l2len(lchan->prim) != l2_len) { + LOGP_LCHAND(lchan, LOGL_ERROR, "Primitive has odd length %u " "(expected %zu for TCH or %u for FACCH), so dropping...\n", - lchan->prim->payload_len, l2_len, GSM_MACBLOCK_LEN); + msgb_l2len(lchan->prim), l2_len, GSM_MACBLOCK_LEN); l1sched_lchan_prim_drop(lchan); return -EINVAL; } - rc = gsm0503_tch_hr_encode(buffer, lchan->prim->payload, l2_len); + rc = gsm0503_tch_hr_encode(buffer, msgb_l2(lchan->prim), l2_len); }
if (rc) { - LOGP_LCHAND(lchan, LOGL_ERROR, "Failed to encode L2 payload (len=%zu): %s\n", - lchan->prim->payload_len, osmo_hexdump(lchan->prim->payload, - lchan->prim->payload_len)); + LOGP_LCHAND(lchan, LOGL_ERROR, "Failed to encode L2 payload (len=%u): %s\n", + msgb_l2len(lchan->prim), msgb_hexdump_l2(lchan->prim)); free_bad_msg: l1sched_lchan_prim_drop(lchan); return -EINVAL; @@ -576,18 +573,11 @@ lchan->ul_facch_blocks--;
if ((*mask & 0x0f) == 0x0f) { - /** - * If no more FACCH/H blocks pending, - * confirm data / traffic sending - */ - if (!lchan->ul_facch_blocks) { - enum l1sched_data_type dt = L1SCHED_PRIM_IS_TCH(lchan->prim) ? - L1SCHED_DT_TRAFFIC : L1SCHED_DT_SIGNALING; - l1sched_handle_data_cnf(lchan, br->fn, dt); - } - - /* Forget processed primitive */ - l1sched_lchan_prim_drop(lchan); + /* Confirm data / traffic sending (pass ownership of the prim) */ + if (!lchan->ul_facch_blocks) + l1sched_lchan_emit_data_cnf(lchan, br->fn); + else /* do not confirm dropped prims */ + l1sched_lchan_prim_drop(lchan); }
return 0; diff --git a/src/host/trxcon/src/sched_lchan_xcch.c b/src/host/trxcon/src/sched_lchan_xcch.c index 936a899..0dca098 100644 --- a/src/host/trxcon/src/sched_lchan_xcch.c +++ b/src/host/trxcon/src/sched_lchan_xcch.c @@ -94,9 +94,8 @@ }
/* Send a L2 frame to the higher layers */ - return l1sched_handle_data_ind(lchan, l2, rc ? 0 : GSM_MACBLOCK_LEN, - n_errors, n_bits_total, - L1SCHED_DT_SIGNALING); + return l1sched_lchan_emit_data_ind(lchan, l2, rc ? 0 : GSM_MACBLOCK_LEN, + n_errors, n_bits_total, false); }
int tx_data_fn(struct l1sched_lchan_state *lchan, @@ -120,20 +119,19 @@ }
/* Check the prim payload length */ - if (lchan->prim->payload_len != GSM_MACBLOCK_LEN) { + if (msgb_l2len(lchan->prim) != GSM_MACBLOCK_LEN) { LOGP_LCHAND(lchan, LOGL_ERROR, - "Primitive has odd length %zu (expected %u), so dropping...\n", - lchan->prim->payload_len, GSM_MACBLOCK_LEN); + "Primitive has odd length %u (expected %u), so dropping...\n", + msgb_l2len(lchan->prim), GSM_MACBLOCK_LEN); l1sched_lchan_prim_drop(lchan); return -EINVAL; }
/* Encode payload */ - rc = gsm0503_xcch_encode(buffer, lchan->prim->payload); + rc = gsm0503_xcch_encode(buffer, msgb_l2(lchan->prim)); if (rc) { - LOGP_LCHAND(lchan, LOGL_ERROR, "Failed to encode L2 payload (len=%zu): %s\n", - lchan->prim->payload_len, osmo_hexdump(lchan->prim->payload, - lchan->prim->payload_len)); + LOGP_LCHAND(lchan, LOGL_ERROR, "Failed to encode L2 payload (len=%u): %s\n", + msgb_l2len(lchan->prim), msgb_hexdump_l2(lchan->prim)); l1sched_lchan_prim_drop(lchan); return -EINVAL; } @@ -160,11 +158,8 @@
/* If we have sent the last (4/4) burst */ if ((*mask & 0x0f) == 0x0f) { - /* Confirm data sending */ - l1sched_handle_data_cnf(lchan, br->fn, L1SCHED_DT_SIGNALING); - - /* Forget processed primitive */ - l1sched_lchan_prim_drop(lchan); + /* Confirm data sending (pass ownership of the prim) */ + l1sched_lchan_emit_data_cnf(lchan, br->fn);
/* Reset mask */ *mask = 0x00; diff --git a/src/host/trxcon/src/sched_prim.c b/src/host/trxcon/src/sched_prim.c index b7ebdeb..5f0ee29 100644 --- a/src/host/trxcon/src/sched_prim.c +++ b/src/host/trxcon/src/sched_prim.c @@ -3,7 +3,7 @@ * TDMA scheduler: primitive management * * (C) 2017-2022 by Vadim Yanitskiy axilirator@gmail.com - * Contributions by sysmocom - s.f.m.c. GmbH + * (C) 2023 by sysmocom - s.f.m.c. GmbH info@sysmocom.de * * All Rights Reserved * @@ -25,6 +25,8 @@ #include <talloc.h>
#include <osmocom/core/msgb.h> +#include <osmocom/core/prim.h> +#include <osmocom/core/utils.h> #include <osmocom/core/logging.h> #include <osmocom/core/linuxlist.h>
@@ -33,86 +35,45 @@ #include <osmocom/bb/l1sched/l1sched.h> #include <osmocom/bb/l1sched/logging.h>
-/** - * Initializes a new primitive by allocating memory - * and filling some meta-information (e.g. lchan type). - * - * @param ctx parent talloc context - * @param pl_len prim payload length - * @param type prim payload type - * @param chan_nr RSL channel description (used to set a proper chan) - * @param link_id RSL link description (used to set a proper chan) - * @return allocated primitive or NULL - */ -static struct l1sched_ts_prim *prim_alloc(void *ctx, size_t pl_len, - enum l1sched_ts_prim_type type, - uint8_t chan_nr, uint8_t link_id) +#define L1SCHED_PRIM_HEADROOM 128 + +osmo_static_assert(sizeof(struct l1sched_prim) <= L1SCHED_PRIM_HEADROOM, l1sched_prim_size); + +const struct value_string l1sched_prim_type_names[] = { + { L1SCHED_PRIM_T_DATA, "DATA" }, + { L1SCHED_PRIM_T_RACH, "RACH" }, + { L1SCHED_PRIM_T_SCH, "SCH" }, + { L1SCHED_PRIM_T_PCHAN_COMB, "PCHAN_COMB" }, + { 0, NULL }, +}; + +void l1sched_prim_init(struct msgb *msg, + enum l1sched_prim_type type, + enum osmo_prim_operation op) { - enum l1sched_lchan_type lchan_type; - struct l1sched_ts_prim *prim; + struct l1sched_prim *prim;
- /* Determine lchan type */ - lchan_type = l1sched_chan_nr2lchan_type(chan_nr, link_id); - if (!lchan_type) { - /* TODO: use proper logging context */ - LOGP(DLGLOBAL, LOGL_ERROR, "Couldn't determine lchan type " - "for chan_nr=%02x and link_id=%02x\n", chan_nr, link_id); - return NULL; - } + msg->l2h = msg->data; + msg->l1h = msgb_push(msg, sizeof(*prim));
- /* Allocate a new primitive */ - prim = talloc_zero_size(ctx, sizeof(*prim) + pl_len); - if (prim == NULL) - return NULL; - - /* Init primitive header */ - prim->payload_len = pl_len; - prim->chan = lchan_type; - prim->type = type; - - return prim; + prim = l1sched_prim_from_msgb(msg); + osmo_prim_init(&prim->oph, 0, type, op, msg); }
-/** - * Adds a primitive to the end of transmit queue of a particular - * timeslot, whose index is parsed from chan_nr. - * - * @param sched scheduler instance - * @param chan_nr RSL channel description - * @param link_id RSL link description - * @param pl Payload data - * @param pl_len Payload length - * @return queued primitive or NULL - */ -struct l1sched_ts_prim *l1sched_prim_push(struct l1sched_state *sched, - enum l1sched_ts_prim_type type, - uint8_t chan_nr, uint8_t link_id, - const uint8_t *pl, size_t pl_len) +struct msgb *l1sched_prim_alloc(enum l1sched_prim_type type, + enum osmo_prim_operation op, + size_t extra_size) { - struct l1sched_ts_prim *prim; - struct l1sched_ts *ts; - uint8_t tn; + struct msgb *msg;
- /* Determine TS index */ - tn = chan_nr & 0x7; - - /* Check whether required timeslot is allocated and configured */ - ts = sched->ts[tn]; - if (ts == NULL || ts->mf_layout == NULL) { - LOGP_SCHEDC(sched, LOGL_ERROR, "Timeslot %u isn't configured\n", tn); - return NULL; - } - - prim = prim_alloc(ts, pl_len, type, chan_nr, link_id); - if (prim == NULL) + msg = msgb_alloc_headroom(L1SCHED_PRIM_HEADROOM + extra_size, + L1SCHED_PRIM_HEADROOM, "l1sched_prim"); + if (msg == NULL) return NULL;
- memcpy(&prim->payload[0], pl, pl_len); + l1sched_prim_init(msg, type, op);
- /* Add primitive to TS transmit queue */ - llist_add_tail(&prim->list, &ts->tx_prims); - - return prim; + return msg; }
/** @@ -121,16 +82,21 @@ * @param lchan lchan to assign a primitive * @return SACCH primitive to be transmitted */ -static struct l1sched_ts_prim *prim_compose_mr(struct l1sched_lchan_state *lchan) +static struct msgb *prim_compose_mr(struct l1sched_lchan_state *lchan) { - struct l1sched_ts_prim *prim; + struct l1sched_prim *prim; + struct msgb *msg; bool cached;
/* Allocate a new primitive */ - prim = prim_alloc(lchan, GSM_MACBLOCK_LEN, L1SCHED_PRIM_DATA, - l1sched_lchan_desc[lchan->type].chan_nr, - L1SCHED_CH_LID_SACCH); - OSMO_ASSERT(prim != NULL); + msg = l1sched_prim_alloc(L1SCHED_PRIM_T_DATA, PRIM_OP_REQUEST, GSM_MACBLOCK_LEN); + OSMO_ASSERT(msg != NULL); + + prim = l1sched_prim_from_msgb(msg); + prim->data_req = (struct l1sched_prim_chdr) { + .chan_nr = l1sched_lchan_desc[lchan->type].chan_nr, + .link_id = L1SCHED_CH_LID_SACCH, + };
/* Check if the MR cache is populated (verify LAPDm header) */ cached = (lchan->sacch.mr_cache[2] != 0x00 @@ -143,7 +109,9 @@ }
/* Compose a new Measurement Report primitive */ - memcpy(&prim->payload[0], &lchan->sacch.mr_cache[0], GSM_MACBLOCK_LEN); + memcpy(msgb_put(msg, GSM_MACBLOCK_LEN), + &lchan->sacch.mr_cache[0], + GSM_MACBLOCK_LEN);
/* Inform about the cache usage count */ if (++lchan->sacch.mr_cache_usage > 5) { @@ -155,7 +123,7 @@
LOGP_LCHAND(lchan, LOGL_NOTICE, "Using cached Measurement Report\n");
- return prim; + return msg; }
/** @@ -180,140 +148,101 @@ * between two successive measurement result messages * shall not exceed one L2 frame. * - * @param queue transmit queue to take a prim from * @param lchan lchan to assign a primitive * @return SACCH primitive to be transmitted */ -static struct l1sched_ts_prim *prim_dequeue_sacch(struct llist_head *queue, - struct l1sched_lchan_state *lchan) +static struct msgb *prim_dequeue_sacch(struct l1sched_lchan_state *lchan) { - struct l1sched_ts_prim *prim_nmr = NULL; - struct l1sched_ts_prim *prim_mr = NULL; - struct l1sched_ts_prim *prim; + struct msgb *msg_nmr = NULL; + struct msgb *msg_mr = NULL; + struct msgb *msg; bool mr_now;
/* Shall we transmit MR now? */ mr_now = !lchan->sacch.mr_tx_last;
-#define PRIM_IS_MR(prim) \ - (prim->payload[5] == GSM48_PDISC_RR \ - && prim->payload[6] == GSM48_MT_RR_MEAS_REP) +#define PRIM_MSGB_IS_MR(msg) \ + (l1sched_prim_data_from_msgb(msg)[5] == GSM48_PDISC_RR && \ + l1sched_prim_data_from_msgb(msg)[6] == GSM48_MT_RR_MEAS_REP)
/* Iterate over all primitives in the queue */ - llist_for_each_entry(prim, queue, list) { - /* We are looking for particular channel */ - if (prim->chan != lchan->type) - continue; - + llist_for_each_entry(msg, &lchan->tx_prims, list) { /* Look for a Measurement Report */ - if (!prim_mr && PRIM_IS_MR(prim)) - prim_mr = prim; + if (!msg_mr && PRIM_MSGB_IS_MR(msg)) + msg_mr = msg;
/* Look for anything else */ - if (!prim_nmr && !PRIM_IS_MR(prim)) - prim_nmr = prim; + if (!msg_nmr && !PRIM_MSGB_IS_MR(msg)) + msg_nmr = msg;
/* Should we look further? */ - if (mr_now && prim_mr) + if (mr_now && msg_mr) break; /* MR was found */ - else if (!mr_now && prim_nmr) + else if (!mr_now && msg_nmr) break; /* something else was found */ }
LOGP_LCHAND(lchan, LOGL_DEBUG, - "SACCH MR selection: mr_tx_last=%d prim_mr=%p prim_nmr=%p\n", - lchan->sacch.mr_tx_last, prim_mr, prim_nmr); + "SACCH MR selection: mr_tx_last=%d msg_mr=%p msg_nmr=%p\n", + lchan->sacch.mr_tx_last, msg_mr, msg_nmr);
/* Prioritize non-MR prim if possible */ - if (mr_now && prim_mr) - prim = prim_mr; - else if (!mr_now && prim_nmr) - prim = prim_nmr; - else if (!mr_now && prim_mr) - prim = prim_mr; + if (mr_now && msg_mr) + msg = msg_mr; + else if (!mr_now && msg_nmr) + msg = msg_nmr; + else if (!mr_now && msg_mr) + msg = msg_mr; else /* Nothing was found */ - prim = NULL; + msg = NULL;
/* Have we found what we were looking for? */ - if (prim) /* Dequeue if so */ - llist_del(&prim->list); + if (msg) /* Dequeue if so */ + llist_del(&msg->list); else /* Otherwise compose a new MR */ - prim = prim_compose_mr(lchan); + msg = prim_compose_mr(lchan);
/* Update the cached report */ - if (prim == prim_mr) { - memcpy(lchan->sacch.mr_cache, - prim->payload, GSM_MACBLOCK_LEN); + if (msg == msg_mr) { + memcpy(lchan->sacch.mr_cache, msgb_l2(msg), GSM_MACBLOCK_LEN); lchan->sacch.mr_cache_usage = 0;
LOGP_LCHAND(lchan, LOGL_DEBUG, "SACCH MR cache has been updated\n"); }
/* Update the MR transmission state */ - lchan->sacch.mr_tx_last = PRIM_IS_MR(prim); + lchan->sacch.mr_tx_last = PRIM_MSGB_IS_MR(msg);
LOGP_LCHAND(lchan, LOGL_DEBUG, "SACCH decision: %s\n", - PRIM_IS_MR(prim) ? "Measurement Report" : "data frame"); + PRIM_MSGB_IS_MR(msg) ? "Measurement Report" : "data frame");
- return prim; -} - -/* Dequeues a primitive of a given channel type */ -static struct l1sched_ts_prim *prim_dequeue_one(struct llist_head *queue, - enum l1sched_lchan_type lchan_type) -{ - struct l1sched_ts_prim *prim; - - /** - * There is no need to use the 'safe' list iteration here - * as an item removal is immediately followed by return. - */ - llist_for_each_entry(prim, queue, list) { - if (prim->chan == lchan_type) { - llist_del(&prim->list); - return prim; - } - } - - return NULL; + return msg; }
/** * Dequeues either a FACCH, or a speech TCH primitive * of a given channel type (Lm or Bm). * - * Note: we could avoid 'lchan_type' parameter and just - * check the prim's channel type using L1SCHED_CHAN_IS_TCH(), - * but the current approach is a bit more flexible, - * and allows one to have both sub-slots of TCH/H - * enabled on same timeslot e.g. for testing... - * - * @param queue transmit queue to take a prim from - * @param lchan_type required channel type of a primitive, - * e.g. L1SCHED_TCHF, L1SCHED_TCHH_0, or L1SCHED_TCHH_1 + * @param lchan logical channel state * @param facch FACCH (true) or speech (false) prim? * @return either a FACCH, or a TCH primitive if found, * otherwise NULL */ -static struct l1sched_ts_prim *prim_dequeue_tch(struct llist_head *queue, - enum l1sched_lchan_type lchan_type, bool facch) +static struct msgb *prim_dequeue_tch(struct l1sched_lchan_state *lchan, bool facch) { - struct l1sched_ts_prim *prim; + struct msgb *msg;
/** * There is no need to use the 'safe' list iteration here * as an item removal is immediately followed by return. */ - llist_for_each_entry(prim, queue, list) { - if (prim->chan != lchan_type) + llist_for_each_entry(msg, &lchan->tx_prims, list) { + bool is_facch = msgb_l2len(msg) == GSM_MACBLOCK_LEN; + if (is_facch != facch) continue;
- /* Either FACCH, or not FACCH */ - if (L1SCHED_PRIM_IS_FACCH(prim) != facch) - continue; - - llist_del(&prim->list); - return prim; + llist_del(&msg->list); + return msg; }
return NULL; @@ -324,30 +253,30 @@ * If a FACCH/F prim is found, one TCH/F prim is being * dropped (i.e. replaced). * - * @param queue a transmit queue to take a prim from + * @param lchan logical channel state * @return either a FACCH/F, or a TCH/F primitive, * otherwise NULL */ -static struct l1sched_ts_prim *prim_dequeue_tch_f(struct llist_head *queue) +static struct msgb *prim_dequeue_tch_f(struct l1sched_lchan_state *lchan) { - struct l1sched_ts_prim *facch; - struct l1sched_ts_prim *tch; + struct msgb *facch; + struct msgb *tch;
/* Attempt to find a pair of both FACCH/F and TCH/F frames */ - facch = prim_dequeue_tch(queue, L1SCHED_TCHF, true); - tch = prim_dequeue_tch(queue, L1SCHED_TCHF, false); + facch = prim_dequeue_tch(lchan, true); + tch = prim_dequeue_tch(lchan, false);
/* Prioritize FACCH/F, if found */ if (facch) { /* One TCH/F prim is replaced */ if (tch) - talloc_free(tch); + msgb_free(tch); return facch; } else if (tch) { /* Only TCH/F prim was found */ return tch; } else { - /* Nothing was found, e.g. when only SACCH frames are in queue */ + /* Nothing was found */ return NULL; } } @@ -368,96 +297,95 @@ * * where the numbers within brackets are fn % 26. * - * @param queue transmit queue to take a prim from + * @param lchan logical channel state * @param fn the current frame number - * @param lchan_type required channel type of a primitive, * @return either a FACCH/H, or a TCH/H primitive, * otherwise NULL */ -static struct l1sched_ts_prim *prim_dequeue_tch_h(struct llist_head *queue, - uint32_t fn, enum l1sched_lchan_type lchan_type) +static struct msgb *prim_dequeue_tch_h(struct l1sched_lchan_state *lchan, uint32_t fn) { - struct l1sched_ts_prim *facch; - struct l1sched_ts_prim *tch; + struct msgb *facch; + struct msgb *tch; bool facch_now;
/* May we initiate an UL FACCH/H frame transmission now? */ - facch_now = l1sched_tchh_facch_start(lchan_type, fn, true); + facch_now = l1sched_tchh_facch_start(lchan->type, fn, true); if (!facch_now) /* Just dequeue a TCH/H prim */ goto no_facch;
/* If there are no FACCH/H prims in the queue */ - facch = prim_dequeue_tch(queue, lchan_type, true); + facch = prim_dequeue_tch(lchan, true); if (!facch) /* Just dequeue a TCH/H prim */ goto no_facch;
/* FACCH/H prim replaces two TCH/F prims */ - tch = prim_dequeue_tch(queue, lchan_type, false); + tch = prim_dequeue_tch(lchan, false); if (tch) { /* At least one TCH/H prim is dropped */ - talloc_free(tch); + msgb_free(tch);
/* Attempt to find another */ - tch = prim_dequeue_tch(queue, lchan_type, false); + tch = prim_dequeue_tch(lchan, false); if (tch) /* Drop the second TCH/H prim */ - talloc_free(tch); + msgb_free(tch); }
return facch;
no_facch: - return prim_dequeue_tch(queue, lchan_type, false); + return prim_dequeue_tch(lchan, false); }
/** - * Dequeues a single primitive of required type - * from a specified transmit queue. + * Dequeues a primitive from the Tx queue of the given lchan. * - * @param queue a transmit queue to take a prim from - * @param fn the current frame number (used for FACCH/H) * @param lchan logical channel state + * @param fn the current frame number (used for FACCH/H) * @return a primitive or NULL if not found */ -struct l1sched_ts_prim *l1sched_prim_dequeue(struct llist_head *queue, - uint32_t fn, struct l1sched_lchan_state *lchan) +struct msgb *l1sched_lchan_prim_dequeue(struct l1sched_lchan_state *lchan, uint32_t fn) { - struct l1sched_ts_prim *prim; - /* SACCH is unorthodox, see 3GPP TS 04.08, section 3.4.1 */ if (L1SCHED_CHAN_IS_SACCH(lchan->type)) - return prim_dequeue_sacch(queue, lchan); + return prim_dequeue_sacch(lchan);
/* There is nothing to dequeue */ - if (llist_empty(queue)) + if (llist_empty(&lchan->tx_prims)) return NULL;
switch (lchan->type) { /* TCH/F requires FACCH/F prioritization */ case L1SCHED_TCHF: - return prim_dequeue_tch_f(queue); + return prim_dequeue_tch_f(lchan);
/* FACCH/H prioritization is a bit more complex */ case L1SCHED_TCHH_0: case L1SCHED_TCHH_1: - return prim_dequeue_tch_h(queue, fn, lchan->type); + return prim_dequeue_tch_h(lchan, fn);
/* PDCH is timing critical, we need to check TDMA Fn */ case L1SCHED_PDTCH: case L1SCHED_PTCCH: - prim = prim_dequeue_one(queue, lchan->type); - if (prim == NULL) + { + struct msgb *msg = msgb_dequeue(&lchan->tx_prims); + const struct l1sched_prim *prim; + + if (msg == NULL) return NULL; - if (OSMO_LIKELY(prim->fn == fn)) - return prim; + prim = l1sched_prim_from_msgb(msg); + + if (OSMO_LIKELY(prim->data_req.frame_nr == fn)) + return msg; LOGP_LCHAND(lchan, LOGL_ERROR, "%s(): dropping Tx primitive (current Fn=%u, prim Fn=%u)\n", - __func__, fn, prim->fn); - talloc_free(prim); + __func__, fn, prim->data_req.frame_nr); + msgb_free(msg); return NULL; + }
/* Other kinds of logical channels */ default: - return prim_dequeue_one(queue, lchan->type); + return msgb_dequeue(&lchan->tx_prims); } }
@@ -468,7 +396,7 @@ */ void l1sched_lchan_prim_drop(struct l1sched_lchan_state *lchan) { - talloc_free(lchan->prim); + msgb_free(lchan->prim); lchan->prim = NULL; }
@@ -480,11 +408,13 @@ * @param lchan lchan to assign a primitive * @return zero in case of success, otherwise a error code */ -int l1sched_prim_dummy(struct l1sched_lchan_state *lchan) +void l1sched_lchan_prim_assign_dummy(struct l1sched_lchan_state *lchan) { + const struct l1sched_lchan_desc *lchan_desc; enum l1sched_lchan_type chan = lchan->type; uint8_t tch_mode = lchan->tch_mode; - struct l1sched_ts_prim *prim; + struct l1sched_prim *prim; + struct msgb *msg; uint8_t prim_buffer[40]; size_t prim_len = 0; int i; @@ -504,6 +434,8 @@ /* Not applicable for SACCH! */ OSMO_ASSERT(!L1SCHED_CHAN_IS_SACCH(lchan->type));
+ lchan_desc = &l1sched_lchan_desc[lchan->type]; + /** * Determine what actually should be generated: * TCH in GSM48_CMODE_SIGN: LAPDm fill frame; @@ -515,7 +447,7 @@ prim_len = l1sched_bad_frame_ind(prim_buffer, lchan); } else if (L1SCHED_CHAN_IS_TCH(chan) && L1SCHED_TCH_MODE_IS_DATA(tch_mode)) { /* FIXME: should we do anything for CSD? */ - return 0; + return; } else { /* Copy LAPDm fill frame's header */ memcpy(prim_buffer, lapdm_fill_frame, sizeof(lapdm_fill_frame)); @@ -535,39 +467,136 @@
/* Nothing to allocate / assign */ if (!prim_len) - return 0; + return;
- /* Allocate a new primitive */ - prim = talloc_zero_size(lchan, sizeof(struct l1sched_ts_prim) + prim_len); - if (prim == NULL) - return -ENOMEM; + msg = l1sched_prim_alloc(L1SCHED_PRIM_T_DATA, PRIM_OP_REQUEST, prim_len); + OSMO_ASSERT(msg != NULL);
- /* Init primitive header */ - prim->payload_len = prim_len; - prim->chan = lchan->type; + prim = l1sched_prim_from_msgb(msg); + prim->data_req = (struct l1sched_prim_chdr) { + .chan_nr = lchan_desc->chan_nr | lchan->ts->index, + .link_id = lchan_desc->link_id, + };
- /* Fill in the payload */ - memcpy(prim->payload, prim_buffer, prim_len); + memcpy(msgb_put(msg, prim_len), &prim_buffer[0], prim_len);
/* Assign the current prim */ - lchan->prim = prim; + lchan->prim = msg;
LOGP_LCHAND(lchan, LOGL_DEBUG, "Transmitting a dummy / silence frame\n"); +}
+int l1sched_lchan_emit_data_ind(struct l1sched_lchan_state *lchan, + const uint8_t *data, size_t data_len, + int n_errors, int n_bits_total, + bool traffic) +{ + const struct l1sched_meas_set *meas = &lchan->meas_avg; + const struct l1sched_lchan_desc *lchan_desc; + struct l1sched_prim *prim; + struct msgb *msg; + + lchan_desc = &l1sched_lchan_desc[lchan->type]; + + msg = l1sched_prim_alloc(L1SCHED_PRIM_T_DATA, PRIM_OP_INDICATION, data_len); + OSMO_ASSERT(msg != NULL); + + prim = l1sched_prim_from_msgb(msg); + prim->data_ind = (struct l1sched_prim_data_ind) { + .chdr = { + .frame_nr = meas->fn, + .chan_nr = lchan_desc->chan_nr | lchan->ts->index, + .link_id = lchan_desc->link_id, + .traffic = traffic, + }, + .toa256 = meas->toa256, + .rssi = meas->rssi, + .n_errors = n_errors, + .n_bits_total = n_bits_total, + }; + + if (data_len > 0) + memcpy(msgb_put(msg, data_len), data, data_len); + + return l1sched_prim_to_user(lchan->ts->sched, msg); +} + +int l1sched_lchan_emit_data_cnf(struct l1sched_lchan_state *lchan, uint32_t fn) +{ + struct l1sched_prim *prim; + struct msgb *msg; + + /* take ownership of the prim */ + OSMO_ASSERT(lchan->prim != NULL); + msg = lchan->prim; + lchan->prim = NULL; + + /* convert from DATA.req to DATA.cnf */ + prim = l1sched_prim_from_msgb(msg); + prim->oph.operation = PRIM_OP_CONFIRM; + + switch (prim->oph.primitive) { + case L1SCHED_PRIM_T_DATA: + prim->data_cnf.frame_nr = fn; + break; + case L1SCHED_PRIM_T_RACH: + prim->rach_cnf.chdr.frame_nr = fn; + break; + default: + /* shall not happen */ + OSMO_ASSERT(0); + } + + return l1sched_prim_to_user(lchan->ts->sched, msg); +} + +static int prim_enqeue(struct l1sched_state *sched, struct msgb *msg, + const struct l1sched_prim_chdr *chdr) +{ + const struct l1sched_prim *prim = l1sched_prim_from_msgb(msg); + struct l1sched_lchan_state *lchan; + + lchan = l1sched_find_lchan_by_chan_nr(sched, chdr->chan_nr, chdr->link_id); + if (OSMO_UNLIKELY(lchan == NULL || !lchan->active)) { + LOGP_SCHEDD(sched, LOGL_ERROR, + "No [active] lchan for primitive " L1SCHED_PRIM_STR_FMT " " + "(chan_nr=%02x, link_id=%02x, len=%u): %s\n", + L1SCHED_PRIM_STR_ARGS(prim), + chdr->chan_nr, chdr->link_id, + msgb_l2len(msg), msgb_hexdump_l2(msg)); + msgb_free(msg); + return -ENODEV; + } + + LOGP_LCHAND(lchan, LOGL_DEBUG, + "Enqueue primitive " L1SCHED_PRIM_STR_FMT " " + "(chan_nr=%02x, link_id=%02x, len=%u): %s\n", + L1SCHED_PRIM_STR_ARGS(prim), + chdr->chan_nr, chdr->link_id, + msgb_l2len(msg), msgb_hexdump_l2(msg)); + + msgb_enqueue(&lchan->tx_prims, msg); return 0; }
-/** - * Flushes a queue of primitives - * - * @param list list of prims going to be flushed - */ -void l1sched_prim_flush_queue(struct llist_head *list) +int l1sched_prim_from_user(struct l1sched_state *sched, struct msgb *msg) { - struct l1sched_ts_prim *prim, *prim_next; + const struct l1sched_prim *prim = l1sched_prim_from_msgb(msg);
- llist_for_each_entry_safe(prim, prim_next, list, list) { - llist_del(&prim->list); - talloc_free(prim); + LOGP_SCHEDD(sched, LOGL_DEBUG, + "%s(): Rx " L1SCHED_PRIM_STR_FMT "\n", + __func__, L1SCHED_PRIM_STR_ARGS(prim)); + + switch (OSMO_PRIM_HDR(&prim->oph)) { + case OSMO_PRIM(L1SCHED_PRIM_T_DATA, PRIM_OP_REQUEST): + return prim_enqeue(sched, msg, &prim->data_req); + case OSMO_PRIM(L1SCHED_PRIM_T_RACH, PRIM_OP_REQUEST): + return prim_enqeue(sched, msg, &prim->rach_req.chdr); + default: + LOGP_SCHEDD(sched, LOGL_ERROR, + "%s(): Unhandled primitive " L1SCHED_PRIM_STR_FMT "\n", + __func__, L1SCHED_PRIM_STR_ARGS(prim)); + msgb_free(msg); + return -ENOTSUP; } } diff --git a/src/host/trxcon/src/sched_trx.c b/src/host/trxcon/src/sched_trx.c index 376fec1..acf060e 100644 --- a/src/host/trxcon/src/sched_trx.c +++ b/src/host/trxcon/src/sched_trx.c @@ -68,18 +68,20 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
-static int l1sched_cfg_pchan_comb_req(struct l1sched_state *sched, +static int l1sched_cfg_pchan_comb_ind(struct l1sched_state *sched, uint8_t tn, enum gsm_phys_chan_config pchan) { - const struct l1sched_config_req cr = { - .type = L1SCHED_CFG_PCHAN_COMB, - .pchan_comb = { - .tn = tn, - .pchan = pchan, - }, - }; + struct l1sched_prim *prim; + struct msgb *msg;
- return l1sched_handle_config_req(sched, &cr); + msg = l1sched_prim_alloc(L1SCHED_PRIM_T_PCHAN_COMB, PRIM_OP_INDICATION, 0); + OSMO_ASSERT(msg != NULL); + + prim = l1sched_prim_from_msgb(msg); + prim->pchan_comb_ind.tn = tn; + prim->pchan_comb_ind.pchan = pchan; + + return l1sched_prim_to_user(sched, msg); }
static void l1sched_a5_burst_enc(struct l1sched_lchan_state *lchan, @@ -121,11 +123,11 @@
/* If no primitive is being processed, try obtaining one from Tx queue */ if (lchan->prim == NULL) - lchan->prim = l1sched_prim_dequeue(&ts->tx_prims, br->fn, lchan); + lchan->prim = l1sched_lchan_prim_dequeue(lchan, br->fn); if (lchan->prim == NULL) { /* If CBTX (Continuous Burst Transmission) is required */ if (l1sched_lchan_desc[chan].flags & L1SCHED_CH_FLAG_CBTX) - l1sched_prim_dummy(lchan); + l1sched_lchan_prim_assign_dummy(lchan); if (lchan->prim == NULL) return; } @@ -134,7 +136,8 @@
/* Handover RACH needs to be handled regardless of the * current channel type and the associated handler. */ - if (L1SCHED_PRIM_IS_RACH(lchan->prim) && lchan->prim->chan != L1SCHED_RACH) + if (l1sched_prim_type_from_msgb(lchan->prim) == L1SCHED_PRIM_T_RACH && + lchan->type != L1SCHED_RACH) handler = l1sched_lchan_desc[L1SCHED_RACH].tx_fn;
/* Poke lchan handler */ @@ -272,15 +275,12 @@ talloc_free(lchan); }
- /* Flush queue primitives for TX */ - l1sched_prim_flush_queue(&ts->tx_prims); - /* Remove ts from list and free memory */ sched->ts[tn] = NULL; talloc_free(ts);
/* Notify transceiver about that */ - l1sched_cfg_pchan_comb_req(sched, tn, GSM_PCHAN_NONE); + l1sched_cfg_pchan_comb_ind(sched, tn, GSM_PCHAN_NONE); }
#define LAYOUT_HAS_LCHAN(layout, lchan) \ @@ -316,8 +316,6 @@ "(Re)configure TDMA timeslot #%u as %s\n", tn, ts->mf_layout->name);
- /* Init queue primitives for TX */ - INIT_LLIST_HEAD(&ts->tx_prims); /* Init logical channels list */ INIT_LLIST_HEAD(&ts->lchans);
@@ -337,6 +335,9 @@ /* Set channel type */ lchan->type = type;
+ /* Init the Tx queue */ + INIT_LLIST_HEAD(&lchan->tx_prims); + /* Add to the list of channel states */ llist_add_tail(&lchan->list, &ts->lchans);
@@ -346,7 +347,7 @@ }
/* Notify transceiver about TS activation */ - l1sched_cfg_pchan_comb_req(sched, tn, config); + l1sched_cfg_pchan_comb_ind(sched, tn, config);
return 0; } @@ -364,9 +365,6 @@ /* Undefine multiframe layout */ ts->mf_layout = NULL;
- /* Flush queue primitives for TX */ - l1sched_prim_flush_queue(&ts->tx_prims); - /* Deactivate all logical channels */ l1sched_deactivate_all_lchans(ts);
@@ -377,7 +375,7 @@ }
/* Notify transceiver about that */ - l1sched_cfg_pchan_comb_req(sched, tn, GSM_PCHAN_NONE); + l1sched_cfg_pchan_comb_ind(sched, tn, GSM_PCHAN_NONE);
return 0; } @@ -541,6 +539,8 @@
static void l1sched_reset_lchan(struct l1sched_lchan_state *lchan) { + struct msgb *msg; + /* Prevent NULL-pointer deference */ OSMO_ASSERT(lchan != NULL);
@@ -568,6 +568,10 @@ /* Forget the current prim */ l1sched_lchan_prim_drop(lchan);
+ /* Flush the queue of pending Tx prims */ + while ((msg = msgb_dequeue(&lchan->tx_prims)) != NULL) + msgb_free(msg); + /* Channel specific stuff */ if (L1SCHED_CHAN_IS_TCH(lchan->type)) { lchan->dl_ongoing_facch = 0; @@ -657,20 +661,6 @@ return GSM_PCHAN_NONE; }
-enum l1sched_lchan_type l1sched_chan_nr2lchan_type(uint8_t chan_nr, - uint8_t link_id) -{ - int i; - - /* Iterate over all known lchan types */ - for (i = 0; i < _L1SCHED_CHAN_MAX; i++) - if (l1sched_lchan_desc[i].chan_nr == (chan_nr & RSL_CHAN_NR_MASK)) - if (l1sched_lchan_desc[i].link_id == link_id) - return i; - - return L1SCHED_IDLE; -} - static void l1sched_a5_burst_dec(struct l1sched_lchan_state *lchan, struct l1sched_burst_ind *bi) { diff --git a/src/host/trxcon/src/trxcon_fsm.c b/src/host/trxcon/src/trxcon_fsm.c index 91c807a..219f0c0 100644 --- a/src/host/trxcon/src/trxcon_fsm.c +++ b/src/host/trxcon/src/trxcon_fsm.c @@ -283,21 +283,25 @@ const struct trxcon_param_tx_access_burst_req *req) { struct trxcon_inst *trxcon = fi->priv; - enum l1sched_ts_prim_type prim_type; - const struct l1sched_ts_prim *prim; + struct l1sched_prim *prim; + struct msgb *msg;
- const struct l1sched_ts_prim_rach rach = { + msg = l1sched_prim_alloc(L1SCHED_PRIM_T_RACH, PRIM_OP_REQUEST, 0); + OSMO_ASSERT(msg != NULL); + + prim = l1sched_prim_from_msgb(msg); + prim->rach_req = (struct l1sched_prim_rach) { + .chdr = { + .chan_nr = req->chan_nr, + .link_id = req->link_id, + }, .synch_seq = req->synch_seq, .offset = req->offset, + .is_11bit = req->is_11bit, .ra = req->ra, };
- prim_type = req->is_11bit ? L1SCHED_PRIM_RACH11 : L1SCHED_PRIM_RACH8; - prim = l1sched_prim_push(trxcon->sched, prim_type, - req->chan_nr, req->link_id, - (const uint8_t *)&rach, sizeof(rach)); - if (prim == NULL) - LOGPFSML(fi, LOGL_ERROR, "Failed to enqueue a prim\n"); + l1sched_prim_from_user(trxcon->sched, msg); }
static void handle_dch_est_req(struct osmo_fsm_inst *fi, @@ -485,15 +489,21 @@ case TRXCON_EV_TX_DATA_REQ: { const struct trxcon_param_tx_data_req *req = data; - struct l1sched_ts_prim *prim; + struct l1sched_prim *prim; + struct msgb *msg;
- prim = l1sched_prim_push(trxcon->sched, L1SCHED_PRIM_DATA, - req->chan_nr, req->link_id, - req->data, req->data_len); - if (prim == NULL) { - LOGPFSML(fi, LOGL_ERROR, "Failed to enqueue a prim\n"); - return; - } + msg = l1sched_prim_alloc(L1SCHED_PRIM_T_DATA, PRIM_OP_REQUEST, req->data_len); + OSMO_ASSERT(msg != NULL); + + prim = l1sched_prim_from_msgb(msg); + prim->data_req = (struct l1sched_prim_chdr) { + .chan_nr = req->chan_nr, + .link_id = req->link_id, + .traffic = req->traffic, + }; + + memcpy(msgb_put(msg, req->data_len), req->data, req->data_len); + l1sched_prim_from_user(trxcon->sched, msg); break; } case TRXCON_EV_TX_DATA_CNF: @@ -547,21 +557,24 @@ case TRXCON_EV_GPRS_UL_BLOCK_REQ: { struct l1gprs_prim_ul_block_req block_req; - const struct msgb *msg = data; - struct l1sched_ts_prim *prim; + struct l1sched_prim *prim; + struct msgb *msg = data;
if (l1gprs_handle_ul_block_req(trxcon->gprs, &block_req, msg) != 0) return;
- prim = l1sched_prim_push(trxcon->sched, L1SCHED_PRIM_DATA, - RSL_CHAN_OSMO_PDCH | block_req.hdr.tn, 0x00, - block_req.data, block_req.data_len); - if (prim == NULL) { - LOGPFSML(fi, LOGL_ERROR, "Failed to enqueue a prim\n"); - return; - } + msg = l1sched_prim_alloc(L1SCHED_PRIM_T_DATA, PRIM_OP_REQUEST, block_req.data_len); + OSMO_ASSERT(msg != NULL);
- prim->fn = block_req.hdr.fn; + prim = l1sched_prim_from_msgb(msg); + prim->data_req = (struct l1sched_prim_chdr) { + .frame_nr = block_req.hdr.fn, + .chan_nr = RSL_CHAN_OSMO_PDCH | block_req.hdr.tn, + .link_id = 0x00, + }; + + memcpy(msgb_put(msg, block_req.data_len), block_req.data, block_req.data_len); + l1sched_prim_from_user(trxcon->sched, msg); break; } case TRXCON_EV_RX_DATA_IND: diff --git a/src/host/trxcon/src/trxcon_shim.c b/src/host/trxcon/src/trxcon_shim.c index de3de91..4f56d85 100644 --- a/src/host/trxcon/src/trxcon_shim.c +++ b/src/host/trxcon/src/trxcon_shim.c @@ -1,7 +1,7 @@ /* * OsmocomBB <-> SDR connection bridge * - * (C) 2022 by sysmocom - s.f.m.c. GmbH info@sysmocom.de + * (C) 2022-2023 by sysmocom - s.f.m.c. GmbH info@sysmocom.de * Author: Vadim Yanitskiy vyanitskiy@sysmocom.de * * All Rights Reserved @@ -24,52 +24,33 @@ #include <osmocom/core/fsm.h> #include <osmocom/core/gsmtap_util.h> #include <osmocom/core/gsmtap.h> +#include <osmocom/gsm/rsl.h>
#include <osmocom/bb/trxcon/trxcon.h> #include <osmocom/bb/trxcon/trxcon_fsm.h> #include <osmocom/bb/trxcon/phyif.h> #include <osmocom/bb/l1sched/l1sched.h>
-static void trxcon_gsmtap_send(struct gsmtap_inst *gi, uint8_t chan_type, - uint32_t fn, uint8_t tn, uint8_t ss, - uint16_t band_arfcn, - int8_t signal_dbm, uint8_t snr, - const uint8_t *data, size_t data_len) +static void trxcon_gsmtap_send(struct trxcon_inst *trxcon, + const struct l1sched_prim_chdr *chdr, + const uint8_t *data, size_t data_len, + int8_t signal_dbm, uint8_t snr, bool uplink) { - /* Omit frames with unknown channel type */ - if (chan_type == GSMTAP_CHANNEL_UNKNOWN) - return; + uint16_t band_arfcn = trxcon->l1p.band_arfcn; + uint8_t chan_type, ss, tn;
- /* TODO: distinguish GSMTAP_CHANNEL_PCH and GSMTAP_CHANNEL_AGCH */ - gsmtap_send(gi, band_arfcn, tn, chan_type, ss, fn, signal_dbm, snr, data, data_len); + if (uplink) + band_arfcn |= ARFCN_UPLINK; + if (rsl_dec_chan_nr(chdr->chan_nr, &chan_type, &ss, &tn) != 0) + return; + chan_type = chantype_rsl2gsmtap2(chan_type, chdr->link_id, chdr->traffic); + + gsmtap_send(trxcon->gsmtap, band_arfcn, tn, chan_type, ss, + chdr->frame_nr, signal_dbm, snr, + data, data_len); }
/* External L1 API for the scheduler */ -int l1sched_handle_config_req(struct l1sched_state *sched, - const struct l1sched_config_req *cr) -{ - struct trxcon_inst *trxcon = sched->priv; - - switch (cr->type) { - case L1SCHED_CFG_PCHAN_COMB: - { - struct trxcon_param_set_phy_config_req req = { - .type = TRXCON_PHY_CFGT_PCHAN_COMB, - .pchan_comb = { - .tn = cr->pchan_comb.tn, - .pchan = cr->pchan_comb.pchan, - }, - }; - - return osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_SET_PHY_CONFIG_REQ, &req); - } - default: - LOGPFSML(trxcon->fi, LOGL_ERROR, - "Unhandled config request (type 0x%02x)\n", cr->type); - return -ENODEV; - } -} - int l1sched_handle_burst_req(struct l1sched_state *sched, const struct l1sched_burst_req *br) { @@ -86,137 +67,122 @@ }
/* External L2 API for the scheduler */ -int l1sched_handle_data_ind(struct l1sched_lchan_state *lchan, - const uint8_t *data, size_t data_len, - int n_errors, int n_bits_total, - enum l1sched_data_type dt) +static int handle_prim_data_ind(struct trxcon_inst *trxcon, struct msgb *msg) { - const struct l1sched_meas_set *meas = &lchan->meas_avg; - const struct l1sched_lchan_desc *lchan_desc; - struct l1sched_state *sched = lchan->ts->sched; - struct trxcon_inst *trxcon = sched->priv; - int rc; - - lchan_desc = &l1sched_lchan_desc[lchan->type]; - + const struct l1sched_prim *prim = l1sched_prim_from_msgb(msg); struct trxcon_param_rx_data_ind ind = { - /* .traffic is set below */ - .chan_nr = lchan_desc->chan_nr | lchan->ts->index, - .link_id = lchan_desc->link_id, + .traffic = prim->data_ind.chdr.traffic, + .chan_nr = prim->data_ind.chdr.chan_nr, + .link_id = prim->data_ind.chdr.link_id, .band_arfcn = trxcon->l1p.band_arfcn, - .frame_nr = meas->fn, - .toa256 = meas->toa256, - .rssi = meas->rssi, - .n_errors = n_errors, - .n_bits_total = n_bits_total, - .data_len = data_len, - .data = data, + .frame_nr = prim->data_ind.chdr.frame_nr, + .toa256 = prim->data_ind.toa256, + .rssi = prim->data_ind.rssi, + .n_errors = prim->data_ind.n_errors, + .n_bits_total = prim->data_ind.n_bits_total, + .data_len = msgb_l2len(msg), + .data = msgb_l2(msg), };
- switch (dt) { - case L1SCHED_DT_PACKET_DATA: - case L1SCHED_DT_TRAFFIC: - ind.traffic = true; - /* fall-through */ - case L1SCHED_DT_SIGNALING: - rc = osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_RX_DATA_IND, &ind); - break; - case L1SCHED_DT_OTHER: - if (lchan->type == L1SCHED_SCH) { - if (trxcon->fi->state != TRXCON_ST_FBSB_SEARCH) - return 0; - rc = osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_FBSB_SEARCH_RES, NULL); - break; - } - /* fall through */ - default: - LOGPFSML(trxcon->fi, LOGL_ERROR, - "Unhandled L2 DATA.ind (type 0x%02x)\n", dt); - return -ENODEV; + if (trxcon->gsmtap != NULL && ind.data_len > 0) { + trxcon_gsmtap_send(trxcon, &prim->data_ind.chdr, + ind.data, ind.data_len, + ind.rssi, 0, false); }
- if (trxcon->gsmtap != NULL && data != NULL && data_len > 0) { - trxcon_gsmtap_send(trxcon->gsmtap, lchan_desc->gsmtap_chan_type, - meas->fn, lchan->ts->index, lchan_desc->ss_nr, - trxcon->l1p.band_arfcn, meas->rssi, 0, - data, data_len); - } - - return rc; + return osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_RX_DATA_IND, &ind); }
-int l1sched_handle_data_cnf(struct l1sched_lchan_state *lchan, - uint32_t fn, enum l1sched_data_type dt) +static int handle_prim_data_cnf(struct trxcon_inst *trxcon, struct msgb *msg) { - const struct l1sched_lchan_desc *lchan_desc; - struct l1sched_state *sched = lchan->ts->sched; - struct trxcon_inst *trxcon = sched->priv; - const uint8_t *data; - uint8_t ra_buf[2]; - size_t data_len; - int rc; - - lchan_desc = &l1sched_lchan_desc[lchan->type]; - - switch (dt) { - case L1SCHED_DT_PACKET_DATA: - data_len = lchan->prim->payload_len; - data = lchan->prim->payload; - rc = 0; - break; /* do not send DATA.cnf */ - case L1SCHED_DT_SIGNALING: - case L1SCHED_DT_TRAFFIC: - { - struct trxcon_param_tx_data_cnf cnf = { - .traffic = (dt == L1SCHED_DT_TRAFFIC), - .chan_nr = lchan_desc->chan_nr | lchan->ts->index, - .link_id = lchan_desc->link_id, - .band_arfcn = trxcon->l1p.band_arfcn, - .frame_nr = fn, - }; - - rc = osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_TX_DATA_CNF, &cnf); - data_len = lchan->prim->payload_len; - data = lchan->prim->payload; - break; - } - case L1SCHED_DT_OTHER: - if (L1SCHED_PRIM_IS_RACH(lchan->prim)) { - const struct l1sched_ts_prim_rach *rach; - struct trxcon_param_tx_access_burst_cnf cnf = { - .band_arfcn = trxcon->l1p.band_arfcn, - .frame_nr = fn, - }; - - rc = osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_TX_ACCESS_BURST_CNF, &cnf); - - rach = (struct l1sched_ts_prim_rach *)lchan->prim->payload; - if (lchan->prim->type == L1SCHED_PRIM_RACH11) { - ra_buf[0] = (uint8_t)(rach->ra >> 3); - ra_buf[1] = (uint8_t)(rach->ra & 0x07); - data = &ra_buf[0]; - data_len = 2; - } else { - ra_buf[0] = (uint8_t)(rach->ra); - data = &ra_buf[0]; - data_len = 1; - } - break; - } - /* fall through */ - default: - LOGPFSML(trxcon->fi, LOGL_ERROR, - "Unhandled L2 DATA.cnf (type 0x%02x)\n", dt); - return -ENODEV; - } + const struct l1sched_prim *prim = l1sched_prim_from_msgb(msg); + struct trxcon_param_tx_data_cnf cnf = { + .traffic = prim->data_cnf.traffic, + .chan_nr = prim->data_cnf.chan_nr, + .link_id = prim->data_cnf.link_id, + .band_arfcn = trxcon->l1p.band_arfcn, + .frame_nr = prim->data_cnf.frame_nr, + };
if (trxcon->gsmtap != NULL) { - trxcon_gsmtap_send(trxcon->gsmtap, lchan_desc->gsmtap_chan_type, - fn, lchan->ts->index, lchan_desc->ss_nr, - trxcon->l1p.band_arfcn | ARFCN_UPLINK, - 0, 0, data, data_len); + trxcon_gsmtap_send(trxcon, &prim->data_cnf, + msgb_l2(msg), msgb_l2len(msg), + 0, 0, true); }
+ /* XXX: do not send for L1SCHED_DT_PACKET_DATA */ + return osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_TX_DATA_CNF, &cnf); +} + +static int handle_prim_rach_cnf(struct trxcon_inst *trxcon, struct msgb *msg) +{ + const struct l1sched_prim *prim = l1sched_prim_from_msgb(msg); + struct trxcon_param_tx_access_burst_cnf cnf = { + .band_arfcn = trxcon->l1p.band_arfcn, + .frame_nr = prim->rach_cnf.chdr.frame_nr, + }; + + if (trxcon->gsmtap != NULL) { + if (prim->rach_cnf.is_11bit) { + msgb_put_u8(msg, (uint8_t)(prim->rach_cnf.ra >> 3)); + msgb_put_u8(msg, (uint8_t)(prim->rach_cnf.ra & 0x07)); + } else { + msgb_put_u8(msg, (uint8_t)(prim->rach_cnf.ra)); + } + + trxcon_gsmtap_send(trxcon, &prim->rach_cnf.chdr, + msgb_l2(msg), msgb_l2len(msg), + 0, 0, true); + } + + return osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_TX_ACCESS_BURST_CNF, &cnf); +} + +int l1sched_prim_to_user(struct l1sched_state *sched, struct msgb *msg) +{ + const struct l1sched_prim *prim = l1sched_prim_from_msgb(msg); + struct trxcon_inst *trxcon = sched->priv; + int rc = 0; + + LOGPFSML(trxcon->fi, LOGL_DEBUG, + "%s(): Rx " L1SCHED_PRIM_STR_FMT "\n", + __func__, L1SCHED_PRIM_STR_ARGS(prim)); + + switch (OSMO_PRIM_HDR(&prim->oph)) { + case OSMO_PRIM(L1SCHED_PRIM_T_DATA, PRIM_OP_INDICATION): + rc = handle_prim_data_ind(trxcon, msg); + break; + case OSMO_PRIM(L1SCHED_PRIM_T_DATA, PRIM_OP_CONFIRM): + rc = handle_prim_data_cnf(trxcon, msg); + break; + case OSMO_PRIM(L1SCHED_PRIM_T_RACH, PRIM_OP_CONFIRM): + rc = handle_prim_rach_cnf(trxcon, msg); + break; + case OSMO_PRIM(L1SCHED_PRIM_T_SCH, PRIM_OP_INDICATION): + if (trxcon->fi->state == TRXCON_ST_FBSB_SEARCH) + rc = osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_FBSB_SEARCH_RES, NULL); + break; + case OSMO_PRIM(L1SCHED_PRIM_T_PCHAN_COMB, PRIM_OP_INDICATION): + { + struct trxcon_param_set_phy_config_req req = { + .type = TRXCON_PHY_CFGT_PCHAN_COMB, + .pchan_comb = { + .tn = prim->pchan_comb_ind.tn, + .pchan = prim->pchan_comb_ind.pchan, + }, + }; + + rc = osmo_fsm_inst_dispatch(trxcon->fi, TRXCON_EV_SET_PHY_CONFIG_REQ, &req); + break; + } + default: + LOGPFSML(trxcon->fi, LOGL_ERROR, + "%s(): Unhandled primitive " L1SCHED_PRIM_STR_FMT "\n", + __func__, L1SCHED_PRIM_STR_ARGS(prim)); + rc = -ENOTSUP; + } + + msgb_free(msg); return rc; }