diff options
author | Vadim Yanitskiy <vyanitskiy@sysmocom.de> | 2023-07-09 05:37:47 +0700 |
---|---|---|
committer | Vadim Yanitskiy <vyanitskiy@sysmocom.de> | 2023-07-12 03:52:34 +0700 |
commit | a22acea3a9db44d891080caaed8619114386afff (patch) | |
tree | d52fae704258f6e5f5ba8f6d2b537ab448905bf6 | |
parent | 58bd4e712a98d10e3c5104c83ea095553c8bae19 (diff) |
trxcon/l1sched: rework dequeueing of Tx prims
Centralized dequeueing of Tx prims in l1sched_pull_burst() is a working
approach, but doing this in each logical channel handler individually
is a lot more flexible. This is how it's done in osmo-bts-trx, and
this allows implementing FACCH support for CSD channels.
Change-Id: I3d6c2136ff1855ab0aa9062b20b2a64fd0e5fe28
Related: OS#4396, OS#1572
-rw-r--r-- | src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h | 2 | ||||
-rw-r--r-- | src/host/trxcon/include/osmocom/bb/l1sched/prim.h | 5 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_desc.c | 30 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_pdtch.c | 32 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_rach.c | 5 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_tchf.c | 36 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_tchh.c | 46 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_lchan_xcch.c | 43 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_prim.c | 166 | ||||
-rw-r--r-- | src/host/trxcon/src/sched_trx.c | 21 |
10 files changed, 159 insertions, 227 deletions
diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h index 715b9a04..cee26600 100644 --- a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h +++ b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h @@ -30,8 +30,6 @@ #define L1SCHED_CH_FLAG_PDCH (1 << 0) /* Should a channel be activated automatically */ #define L1SCHED_CH_FLAG_AUTO (1 << 1) -/* Is continuous burst transmission assumed */ -#define L1SCHED_CH_FLAG_CBTX (1 << 2) #define MAX_A5_KEY_LEN (128 / 8) #define TRX_TS_COUNT 8 diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/prim.h b/src/host/trxcon/include/osmocom/bb/l1sched/prim.h index 0575ad80..c0e6af60 100644 --- a/src/host/trxcon/include/osmocom/bb/l1sched/prim.h +++ b/src/host/trxcon/include/osmocom/bb/l1sched/prim.h @@ -116,8 +116,9 @@ void l1sched_prim_init(struct msgb *msg, struct msgb *l1sched_prim_alloc(enum l1sched_prim_type type, enum osmo_prim_operation op); -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); +struct msgb *l1sched_lchan_prim_dequeue_sacch(struct l1sched_lchan_state *lchan); +struct msgb *l1sched_lchan_prim_dequeue_tch(struct l1sched_lchan_state *lchan, bool facch); +struct msgb *l1sched_lchan_prim_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, diff --git a/src/host/trxcon/src/sched_lchan_desc.c b/src/host/trxcon/src/sched_lchan_desc.c index 3b37c575..4943a713 100644 --- a/src/host/trxcon/src/sched_lchan_desc.c +++ b/src/host/trxcon/src/sched_lchan_desc.c @@ -131,7 +131,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { * The MS shall continuously transmit bursts, even if there is nothing * to send, unless DTX (Discontinuous Transmission) is used. */ .burst_buf_size = 8 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_tchf_fn, .tx_fn = tx_tchf_fn, }, @@ -158,7 +157,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { * The MS shall continuously transmit bursts, even if there is nothing * to send, unless DTX (Discontinuous Transmission) is used. */ .burst_buf_size = 6 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_tchh_fn, .tx_fn = tx_tchh_fn, }, @@ -170,7 +168,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_TCHH_0, see above. */ .burst_buf_size = 6 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_tchh_fn, .tx_fn = tx_tchh_fn, }, @@ -182,7 +179,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -194,7 +190,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -206,7 +201,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -218,7 +212,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -230,7 +223,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -242,7 +234,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -254,7 +245,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -266,7 +256,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -278,7 +267,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -290,7 +278,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -302,7 +289,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -314,7 +300,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -326,7 +311,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -338,7 +322,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -350,7 +333,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -362,7 +344,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -374,7 +355,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -386,7 +366,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -398,7 +377,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH4_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -410,7 +388,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -422,7 +399,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -434,7 +410,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -446,7 +421,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -458,7 +432,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -470,7 +443,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -482,7 +454,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, @@ -494,7 +465,6 @@ const struct l1sched_lchan_desc l1sched_lchan_desc[_L1SCHED_CHAN_MAX] = { /* Same as for L1SCHED_BCCH and L1SCHED_SDCCH8_* (xCCH), see above. */ .burst_buf_size = 4 * GSM_NBITS_NB_GMSK_PAYLOAD, - .flags = L1SCHED_CH_FLAG_CBTX, .rx_fn = rx_data_fn, .tx_fn = tx_data_fn, }, diff --git a/src/host/trxcon/src/sched_lchan_pdtch.c b/src/host/trxcon/src/sched_lchan_pdtch.c index 4b5ffdf5..03d43ce2 100644 --- a/src/host/trxcon/src/sched_lchan_pdtch.c +++ b/src/host/trxcon/src/sched_lchan_pdtch.c @@ -101,6 +101,24 @@ int rx_pdtch_fn(struct l1sched_lchan_state *lchan, return 0; } +static struct msgb *prim_dequeue_pdtch(struct l1sched_lchan_state *lchan, uint32_t fn) +{ + const struct l1sched_prim *prim; + struct msgb *msg; + + msg = msgb_dequeue(&lchan->tx_prims); + if (msg == NULL) + return NULL; + 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->data_req.frame_nr); + msgb_free(msg); + return NULL; +} int tx_pdtch_fn(struct l1sched_lchan_state *lchan, struct l1sched_burst_req *br) @@ -114,8 +132,17 @@ int tx_pdtch_fn(struct l1sched_lchan_state *lchan, mask = &lchan->tx_burst_mask; bursts_p = lchan->tx_bursts; - if (br->bid > 0) + if (br->bid > 0) { + if ((*mask & 0x01) != 0x01) + return -ENOENT; goto send_burst; + } + + *mask = *mask << 4; + + lchan->prim = prim_dequeue_pdtch(lchan, br->fn); + if (lchan->prim == NULL) + return -ENOENT; /* Encode payload */ rc = gsm0503_pdtch_encode(bursts_p, msgb_l2(lchan->prim), msgb_l2len(lchan->prim)); @@ -150,9 +177,6 @@ send_burst: if ((*mask & 0x0f) == 0x0f) { /* Confirm data / traffic sending (pass ownership of the prim) */ l1sched_lchan_emit_data_cnf(lchan, br->fn); - - /* Reset mask */ - *mask = 0x00; } return 0; diff --git a/src/host/trxcon/src/sched_lchan_rach.c b/src/host/trxcon/src/sched_lchan_rach.c index 109d1001..8df7fa25 100644 --- a/src/host/trxcon/src/sched_lchan_rach.c +++ b/src/host/trxcon/src/sched_lchan_rach.c @@ -78,6 +78,11 @@ int tx_rach_fn(struct l1sched_lchan_state *lchan, uint8_t payload[36]; int i, rc; + if (lchan->prim == NULL) { + lchan->prim = msgb_dequeue(&lchan->tx_prims); + if (lchan->prim == NULL) + return 0; + } prim = l1sched_prim_from_msgb(lchan->prim); /* Delay sending according to offset value */ diff --git a/src/host/trxcon/src/sched_lchan_tchf.c b/src/host/trxcon/src/sched_lchan_tchf.c index 9e8256fc..6d48fc77 100644 --- a/src/host/trxcon/src/sched_lchan_tchf.c +++ b/src/host/trxcon/src/sched_lchan_tchf.c @@ -213,6 +213,30 @@ bfi: n_errors, n_bits_total, true); } +static struct msgb *prim_dequeue_tchf(struct l1sched_lchan_state *lchan) +{ + struct msgb *facch; + struct msgb *tch; + + /* Attempt to find a pair of FACCH/F and TCH/F frames */ + facch = l1sched_lchan_prim_dequeue_tch(lchan, true); + tch = l1sched_lchan_prim_dequeue_tch(lchan, false); + + /* Prioritize FACCH/F, if found */ + if (facch) { + /* One TCH/F prim is replaced */ + if (tch) + msgb_free(tch); + return facch; + } else if (tch) { + /* Only TCH/F prim was found */ + return tch; + } else { + /* Nothing was found */ + return NULL; + } +} + int tx_tchf_fn(struct l1sched_lchan_state *lchan, struct l1sched_burst_req *br) { @@ -225,14 +249,24 @@ int tx_tchf_fn(struct l1sched_lchan_state *lchan, mask = &lchan->tx_burst_mask; bursts_p = lchan->tx_bursts; - if (br->bid > 0) + if (br->bid > 0) { + if ((*mask & 0x01) != 0x01) + return -ENOENT; goto send_burst; + } /* Shift the burst buffer by 4 bursts leftwards for interleaving */ memcpy(&bursts_p[0], &bursts_p[464], 464); memset(&bursts_p[464], 0, 464); *mask = *mask << 4; + lchan->prim = prim_dequeue_tchf(lchan); + if (lchan->prim == NULL) { + lchan->prim = l1sched_lchan_prim_dummy(lchan); + if (lchan->prim == NULL) + return -ENOENT; + } + /* populate the buffer with bursts */ switch (lchan->tch_mode) { case GSM48_CMODE_SIGN: diff --git a/src/host/trxcon/src/sched_lchan_tchh.c b/src/host/trxcon/src/sched_lchan_tchh.c index 6973f919..6affbc5d 100644 --- a/src/host/trxcon/src/sched_lchan_tchh.c +++ b/src/host/trxcon/src/sched_lchan_tchh.c @@ -412,6 +412,40 @@ bfi: n_errors, n_bits_total, true); } +static struct msgb *prim_dequeue_tchh(struct l1sched_lchan_state *lchan, uint32_t fn) +{ + struct msgb *facch; + struct msgb *tch; + bool facch_now; + + /* Can we initiate an UL FACCH/H frame transmission at this Fn? */ + facch_now = l1sched_tchh_facch_start(lchan->type, fn, true); + if (!facch_now) + goto no_facch; + + /* If there are no FACCH/H prims in the queue */ + facch = l1sched_lchan_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 = l1sched_lchan_prim_dequeue_tch(lchan, false); + if (tch) { + /* At least one TCH/H prim is dropped */ + msgb_free(tch); + + /* Attempt to find another */ + tch = l1sched_lchan_prim_dequeue_tch(lchan, false); + if (tch) /* Drop the second TCH/H prim */ + msgb_free(tch); + } + + return facch; + +no_facch: + return l1sched_lchan_prim_dequeue_tch(lchan, false); +} + int tx_tchh_fn(struct l1sched_lchan_state *lchan, struct l1sched_burst_req *br) { @@ -424,8 +458,11 @@ int tx_tchh_fn(struct l1sched_lchan_state *lchan, mask = &lchan->tx_burst_mask; bursts_p = lchan->tx_bursts; - if (br->bid > 0) + if (br->bid > 0) { + if ((*mask & 0x01) != 0x01) + return -ENOENT; goto send_burst; + } if (*mask == 0x00) { /* Align transmission of the first FACCH/H frame */ @@ -444,6 +481,13 @@ int tx_tchh_fn(struct l1sched_lchan_state *lchan, if (lchan->ul_facch_blocks > 2) goto send_burst; + lchan->prim = prim_dequeue_tchh(lchan, br->fn); + if (lchan->prim == NULL) { + lchan->prim = l1sched_lchan_prim_dummy(lchan); + if (lchan->prim == NULL) + return -ENOENT; + } + if (msgb_l2len(lchan->prim) == GSM_MACBLOCK_LEN) lchan->ul_facch_blocks = 6; diff --git a/src/host/trxcon/src/sched_lchan_xcch.c b/src/host/trxcon/src/sched_lchan_xcch.c index f76d518d..7f1dd11a 100644 --- a/src/host/trxcon/src/sched_lchan_xcch.c +++ b/src/host/trxcon/src/sched_lchan_xcch.c @@ -98,6 +98,27 @@ int rx_data_fn(struct l1sched_lchan_state *lchan, n_errors, n_bits_total, false); } +static struct msgb *prim_dequeue_xcch(struct l1sched_lchan_state *lchan) +{ + struct msgb *msg; + + if (L1SCHED_CHAN_IS_SACCH(lchan->type)) + return l1sched_lchan_prim_dequeue_sacch(lchan); + if ((msg = msgb_dequeue(&lchan->tx_prims)) == NULL) + return NULL; + + /* Check the prim payload length */ + if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) { + LOGP_LCHAND(lchan, LOGL_ERROR, + "Primitive has odd length %u (expected %u), so dropping...\n", + msgb_l2len(msg), GSM_MACBLOCK_LEN); + msgb_free(msg); + return NULL; + } + + return msg; +} + int tx_data_fn(struct l1sched_lchan_state *lchan, struct l1sched_burst_req *br) { @@ -110,18 +131,19 @@ int tx_data_fn(struct l1sched_lchan_state *lchan, mask = &lchan->tx_burst_mask; bursts_p = lchan->tx_bursts; - if (br->bid > 0) + if (br->bid > 0) { + if ((*mask & 0x01) != 0x01) + return -ENOENT; goto send_burst; - - /* Check the prim payload length */ - if (msgb_l2len(lchan->prim) != GSM_MACBLOCK_LEN) { - LOGP_LCHAND(lchan, LOGL_ERROR, - "Primitive has odd length %u (expected %u), so dropping...\n", - msgb_l2len(lchan->prim), GSM_MACBLOCK_LEN); - l1sched_lchan_prim_drop(lchan); - return -EINVAL; } + *mask = *mask << 4; + + lchan->prim = prim_dequeue_xcch(lchan); + if (lchan->prim == NULL) + lchan->prim = l1sched_lchan_prim_dummy(lchan); + OSMO_ASSERT(lchan->prim != NULL); + /* Encode payload */ rc = gsm0503_xcch_encode(bursts_p, msgb_l2(lchan->prim)); if (rc) { @@ -155,9 +177,6 @@ send_burst: if ((*mask & 0x0f) == 0x0f) { /* Confirm data sending (pass ownership of the prim) */ l1sched_lchan_emit_data_cnf(lchan, br->fn); - - /* Reset mask */ - *mask = 0x00; } return 0; diff --git a/src/host/trxcon/src/sched_prim.c b/src/host/trxcon/src/sched_prim.c index 44cfd37e..3301df4d 100644 --- a/src/host/trxcon/src/sched_prim.c +++ b/src/host/trxcon/src/sched_prim.c @@ -151,7 +151,7 @@ static struct msgb *prim_compose_mr(struct l1sched_lchan_state *lchan) * @param lchan lchan to assign a primitive * @return SACCH primitive to be transmitted */ -static struct msgb *prim_dequeue_sacch(struct l1sched_lchan_state *lchan) +struct msgb *l1sched_lchan_prim_dequeue_sacch(struct l1sched_lchan_state *lchan) { struct msgb *msg_nmr = NULL; struct msgb *msg_mr = NULL; @@ -228,7 +228,7 @@ static struct msgb *prim_dequeue_sacch(struct l1sched_lchan_state *lchan) * @return either a FACCH, or a TCH primitive if found, * otherwise NULL */ -static struct msgb *prim_dequeue_tch(struct l1sched_lchan_state *lchan, bool facch) +struct msgb *l1sched_lchan_prim_dequeue_tch(struct l1sched_lchan_state *lchan, bool facch) { struct msgb *msg; @@ -249,146 +249,6 @@ static struct msgb *prim_dequeue_tch(struct l1sched_lchan_state *lchan, bool fac } /** - * Dequeues either a TCH/F, or a FACCH/F prim (preferred). - * If a FACCH/F prim is found, one TCH/F prim is being - * dropped (i.e. replaced). - * - * @param lchan logical channel state - * @return either a FACCH/F, or a TCH/F primitive, - * otherwise NULL - */ -static struct msgb *prim_dequeue_tch_f(struct l1sched_lchan_state *lchan) -{ - struct msgb *facch; - struct msgb *tch; - - /* Attempt to find a pair of both FACCH/F and TCH/F frames */ - 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) - msgb_free(tch); - return facch; - } else if (tch) { - /* Only TCH/F prim was found */ - return tch; - } else { - /* Nothing was found */ - return NULL; - } -} - -/** - * Dequeues either a TCH/H, or a FACCH/H prim (preferred). - * If a FACCH/H prim is found, two TCH/H prims are being - * dropped (i.e. replaced). - * - * According to GSM 05.02, the following blocks can be used - * to carry FACCH/H data (see clause 7, table 1 of 9): - * - * UL FACCH/H0: - * B0(0,2,4,6,8,10), B1(8,10,13,15,17,19), B2(17,19,21,23,0,2) - * - * UL FACCH/H1: - * B0(1,3,5,7,9,11), B1(9,11,14,16,18,20), B2(18,20,22,24,1,3) - * - * where the numbers within brackets are fn % 26. - * - * @param lchan logical channel state - * @param fn the current frame number - * @return either a FACCH/H, or a TCH/H primitive, - * otherwise NULL - */ -static struct msgb *prim_dequeue_tch_h(struct l1sched_lchan_state *lchan, uint32_t fn) -{ - 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); - 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(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(lchan, false); - if (tch) { - /* At least one TCH/H prim is dropped */ - msgb_free(tch); - - /* Attempt to find another */ - tch = prim_dequeue_tch(lchan, false); - if (tch) /* Drop the second TCH/H prim */ - msgb_free(tch); - } - - return facch; - -no_facch: - return prim_dequeue_tch(lchan, false); -} - -/** - * Dequeues a primitive from the Tx queue of the given lchan. - * - * @param lchan logical channel state - * @param fn the current frame number (used for FACCH/H) - * @return a primitive or NULL if not found - */ -struct msgb *l1sched_lchan_prim_dequeue(struct l1sched_lchan_state *lchan, uint32_t fn) -{ - /* SACCH is unorthodox, see 3GPP TS 04.08, section 3.4.1 */ - if (L1SCHED_CHAN_IS_SACCH(lchan->type)) - return prim_dequeue_sacch(lchan); - - /* There is nothing to dequeue */ - 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(lchan); - - /* FACCH/H prioritization is a bit more complex */ - case L1SCHED_TCHH_0: - case L1SCHED_TCHH_1: - return prim_dequeue_tch_h(lchan, fn); - - /* PDCH is timing critical, we need to check TDMA Fn */ - case L1SCHED_PDTCH: - { - struct msgb *msg = msgb_dequeue(&lchan->tx_prims); - const struct l1sched_prim *prim; - - if (msg == NULL) - return NULL; - 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->data_req.frame_nr); - msgb_free(msg); - return NULL; - } - - /* Other kinds of logical channels */ - default: - return msgb_dequeue(&lchan->tx_prims); - } -} - -/** * Drops the current primitive of specified logical channel * * @param lchan a logical channel to drop prim from @@ -400,14 +260,13 @@ void l1sched_lchan_prim_drop(struct l1sched_lchan_state *lchan) } /** - * Assigns a dummy primitive to a lchan depending on its type. - * Could be used when there is nothing to transmit, but - * CBTX (Continuous Burst Transmission) is assumed. + * Allocate a dummy DATA.req for the given logical channel. + * To be used when no suitable DATA.req is present in the Tx queue. * - * @param lchan lchan to assign a primitive - * @return zero in case of success, otherwise a error code + * @param lchan lchan to allocate a dummy primitive for + * @return an msgb with DATA.req primitive, or NULL */ -void l1sched_lchan_prim_assign_dummy(struct l1sched_lchan_state *lchan) +struct msgb *l1sched_lchan_prim_dummy(struct l1sched_lchan_state *lchan) { const struct l1sched_lchan_desc *lchan_desc; enum l1sched_lchan_type chan = lchan->type; @@ -428,8 +287,6 @@ void l1sched_lchan_prim_assign_dummy(struct l1sched_lchan_state *lchan) /* Pending part is to be randomized */ }; - /* Make sure that there is no existing primitive */ - OSMO_ASSERT(lchan->prim == NULL); /* Not applicable for SACCH! */ OSMO_ASSERT(!L1SCHED_CHAN_IS_SACCH(lchan->type)); @@ -446,7 +303,7 @@ void l1sched_lchan_prim_assign_dummy(struct l1sched_lchan_state *lchan) 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; + return NULL; } else { /* Copy LAPDm fill frame's header */ memcpy(prim_buffer, lapdm_fill_frame, sizeof(lapdm_fill_frame)); @@ -466,7 +323,7 @@ void l1sched_lchan_prim_assign_dummy(struct l1sched_lchan_state *lchan) /* Nothing to allocate / assign */ if (!prim_len) - return; + return NULL; msg = l1sched_prim_alloc(L1SCHED_PRIM_T_DATA, PRIM_OP_REQUEST); OSMO_ASSERT(msg != NULL); @@ -479,10 +336,7 @@ void l1sched_lchan_prim_assign_dummy(struct l1sched_lchan_state *lchan) memcpy(msgb_put(msg, prim_len), &prim_buffer[0], prim_len); - /* Assign the current prim */ - lchan->prim = msg; - - LOGP_LCHAND(lchan, LOGL_DEBUG, "Transmitting a dummy / silence frame\n"); + return msg; } int l1sched_lchan_emit_data_ind(struct l1sched_lchan_state *lchan, diff --git a/src/host/trxcon/src/sched_trx.c b/src/host/trxcon/src/sched_trx.c index 3b452b16..cac3a219 100644 --- a/src/host/trxcon/src/sched_trx.c +++ b/src/host/trxcon/src/sched_trx.c @@ -121,27 +121,10 @@ void l1sched_pull_burst(struct l1sched_state *sched, struct l1sched_burst_req *b if (lchan == NULL || !lchan->active) return; - /* If no primitive is being processed, try obtaining one from Tx queue */ - if (lchan->prim == NULL) { - /* Align to the first burst of a block */ - if (frame->ul_bid != 0) - return; - 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_lchan_prim_assign_dummy(lchan); - if (lchan->prim == NULL) - return; - } - } - - /* TODO: report TX buffers health to the higher layers */ - /* Handover RACH needs to be handled regardless of the * current channel type and the associated handler. */ - if (l1sched_prim_type_from_msgb(lchan->prim) == L1SCHED_PRIM_T_RACH && - lchan->type != L1SCHED_RACH) + struct msgb *msg = llist_first_entry_or_null(&lchan->tx_prims, struct msgb, list); + if (msg && l1sched_prim_type_from_msgb(msg) == L1SCHED_PRIM_T_RACH) handler = l1sched_lchan_desc[L1SCHED_RACH].tx_fn; /* Poke lchan handler */ |