summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVadim Yanitskiy <vyanitskiy@sysmocom.de>2023-07-09 05:37:47 +0700
committerVadim Yanitskiy <vyanitskiy@sysmocom.de>2023-07-12 03:52:34 +0700
commita22acea3a9db44d891080caaed8619114386afff (patch)
treed52fae704258f6e5f5ba8f6d2b537ab448905bf6
parent58bd4e712a98d10e3c5104c83ea095553c8bae19 (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.h2
-rw-r--r--src/host/trxcon/include/osmocom/bb/l1sched/prim.h5
-rw-r--r--src/host/trxcon/src/sched_lchan_desc.c30
-rw-r--r--src/host/trxcon/src/sched_lchan_pdtch.c32
-rw-r--r--src/host/trxcon/src/sched_lchan_rach.c5
-rw-r--r--src/host/trxcon/src/sched_lchan_tchf.c36
-rw-r--r--src/host/trxcon/src/sched_lchan_tchh.c46
-rw-r--r--src/host/trxcon/src/sched_lchan_xcch.c43
-rw-r--r--src/host/trxcon/src/sched_prim.c166
-rw-r--r--src/host/trxcon/src/sched_trx.c21
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 */