summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2018-03-03 12:30:01 +0100
committerHarald Welte <laforge@gnumonks.org>2018-03-03 22:38:01 +0100
commitfabf8091adc0e60019c795e035131d87399ace7d (patch)
treeeb93961f82d9a06d3efd426b967966e75150419b
parent8b9d3170ff265c934f6271bd445ff5a6788ffffb (diff)
WIP: virtphy: Add L1CTL_DATA_ABS_REQ supportlaforge/virtphy-gprs
L1CTL_DATA_ABS_REQ is used for transmitting single uplink blocks at pre-determined frame numbers. This is required as part of the "polling" procedure for UL ACK of DL control blocks, which works irrespective of any USF. Change-Id: I77b168791cf972d8e625df54c4653b23f4abcb82
-rw-r--r--include/l1ctl_proto.h20
-rw-r--r--src/host/virt_phy/include/virtphy/virt_l1_model.h2
-rw-r--r--src/host/virt_phy/src/gsmtapl1_if.c47
-rw-r--r--src/host/virt_phy/src/l1ctl_sap.c45
4 files changed, 113 insertions, 1 deletions
diff --git a/include/l1ctl_proto.h b/include/l1ctl_proto.h
index 17065349..a3bd5463 100644
--- a/include/l1ctl_proto.h
+++ b/include/l1ctl_proto.h
@@ -1,6 +1,6 @@
/* Messages to be sent between the different layers */
-/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
+/* (C) 2010-2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by Holger Hans Peter Freyther
*
* All Rights Reserved
@@ -64,6 +64,7 @@ enum {
L1CTL_DATA_TBF_REQ,
L1CTL_DATA_TBF_CONF,
+ L1CTL_DATA_ABS_REQ,
};
enum ccch_mode {
@@ -186,6 +187,23 @@ struct l1ctl_info_ul_tbf {
uint8_t payload[0];
} __attribute__((packed));
+/* (E)GPRS uplink block at user-specified absolute frame number */
+struct l1ctl_info_ul_abs {
+ /* references l1ctl_tbf_cfg_req.tbf_nr */
+ uint8_t tbf_nr;
+ /* timeslot number on which to transmit */
+ uint8_t coding_scheme;
+ uint8_t ts_nr;
+ uint8_t padding[1];
+ /* frame number on which to transmit (first of 4 blocks) */
+ uint32_t fn;
+ /* ARFCN on which to transmit */
+ uint16_t arfcn;
+ uint8_t padding2[2];
+ /* RLC/MAC block */
+ uint8_t payload[0];
+} __attribute__((packed));
+
/*
* msg for FBSB_REQ
* the l1_info_ul header is in front
diff --git a/src/host/virt_phy/include/virtphy/virt_l1_model.h b/src/host/virt_phy/include/virtphy/virt_l1_model.h
index 67c24bb6..d774756a 100644
--- a/src/host/virt_phy/include/virtphy/virt_l1_model.h
+++ b/src/host/virt_phy/include/virtphy/virt_l1_model.h
@@ -84,6 +84,8 @@ struct l1_state_ms {
uint8_t tfi[8];
} dl;
} tbf;
+ /* PS related transmit requests with absolute frame number */
+ struct llist_head tx_queue_abs;
/* fbsb state */
struct {
diff --git a/src/host/virt_phy/src/gsmtapl1_if.c b/src/host/virt_phy/src/gsmtapl1_if.c
index 2cf9d2dc..8fcccbbb 100644
--- a/src/host/virt_phy/src/gsmtapl1_if.c
+++ b/src/host/virt_phy/src/gsmtapl1_if.c
@@ -70,6 +70,7 @@ void gsmtapl1_tx_to_virt_um_inst(struct l1_model_ms *ms, uint32_t fn, uint8_t tn
switch (l1h->msg_type) {
case L1CTL_DATA_TBF_REQ:
+ case L1CTL_DATA_ABS_REQ:
ul = NULL;
rsl_chantype = RSL_CHAN_OSMO_PDCH;
timeslot = tn;
@@ -166,12 +167,58 @@ static uint8_t get_usf_from_block(struct msgb *msg)
return msg->data[0] & 0x7;
}
+/* get first message in queue, but don't de-queue */
+static struct msgb *my_msgb_queue_peek(struct llist_head *queue)
+{
+ struct llist_head *lh;
+
+ if (llist_empty(queue))
+ return NULL;
+
+ lh = queue->next;
+ if (!lh)
+ return NULL;
+
+ return llist_entry(lh, struct msgb, list);
+}
+
+/* Check if we have any uplink transfer queued for this frame number. If so, transmit */
+static bool ms_ul_abs_may_transmit(struct l1_model_ms *ms, uint32_t fn)
+{
+ struct llist_head *queue = &ms->state.tx_queue_abs;
+ struct msgb *msg;
+
+ /* First check if we have any pending uplink blocks for this absolute FN */
+ msg = my_msgb_queue_peek(queue);
+ if (msg) {
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_info_ul_abs *abs = (struct l1ctl_info_ul_abs *) l1h->data;
+ if (abs->fn < fn) {
+ printf("----Dropping UL ABS, %u < %u\n", abs->fn, fn);
+ LOGPMS(DVIRPHY, LOGL_ERROR, ms, "Dropping UL ABS, %u < %u\n", abs->fn, fn);
+ OSMO_ASSERT(msgb_dequeue(queue) == msg);
+ msgb_free(msg);
+ } else if (abs->fn == fn) {
+ printf("----dequeueing abs for fn %u tn %u\n", abs->fn, abs->ts_nr);
+ OSMO_ASSERT(msgb_dequeue(queue) == msg);
+ gsmtapl1_tx_to_virt_um_inst(ms, fn, abs->ts_nr, msg);
+ return true;
+ }
+ }
+ /* TODO: what in case we have multiple for same FN but different TN? */
+ return false;
+}
+
/* MS is authorized to transmit a block in uplink for given USF on timeslot+arfcn at FN */
static void ms_ul_tbf_may_transmit(struct l1_model_ms *ms, uint16_t arfcn, uint8_t timeslot,
uint32_t fn, uint8_t usf)
{
struct msgb *msg;
+ /* If we have any ABS uplink transmit queued, this has higher precedence than USF */
+ if (ms_ul_abs_may_transmit(ms, fn))
+ return;
+
/* If USF is not for us, bail out */
if (!usf_matches_ms(ms, usf, timeslot))
return;
diff --git a/src/host/virt_phy/src/l1ctl_sap.c b/src/host/virt_phy/src/l1ctl_sap.c
index aac49bf0..276d7f5b 100644
--- a/src/host/virt_phy/src/l1ctl_sap.c
+++ b/src/host/virt_phy/src/l1ctl_sap.c
@@ -42,6 +42,7 @@
static void l1ctl_rx_tbf_cfg_req(struct l1_model_ms *ms, struct msgb *msg);
static void l1ctl_rx_data_tbf_req(struct l1_model_ms *ms, struct msgb *msg);
+static void l1ctl_rx_data_abs_req(struct l1_model_ms *ms, struct msgb *msg);
static void l1_model_tch_mode_set(struct l1_model_ms *ms, uint8_t tch_mode)
{
@@ -60,6 +61,7 @@ void l1ctl_sap_init(struct l1_model_ms *model)
{
INIT_LLIST_HEAD(&model->state.sched.mframe_items);
INIT_LLIST_HEAD(&model->state.tbf.ul.tx_queue);
+ INIT_LLIST_HEAD(&model->state.tx_queue_abs);
prim_pm_init(model);
}
@@ -252,6 +254,9 @@ void l1ctl_sap_handler(struct l1_model_ms *ms, struct msgb *msg)
case L1CTL_DATA_TBF_REQ:
l1ctl_rx_data_tbf_req(ms, msg);
goto exit_nofree;
+ case L1CTL_DATA_ABS_REQ:
+ l1ctl_rx_data_abs_req(ms, msg);
+ goto exit_nofree;
}
exit_msgbfree:
@@ -662,6 +667,46 @@ static void l1ctl_rx_data_tbf_req(struct l1_model_ms *ms, struct msgb *msg)
msgb_enqueue(&ms->state.tbf.ul.tx_queue, msg);
}
+static void l1ctl_rx_data_abs_req(struct l1_model_ms *ms, struct msgb *msg)
+{
+ struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
+ struct l1ctl_info_ul_abs *udt = (struct l1ctl_info_ul_abs *) l1h->data;
+ enum osmo_gprs_cs osmo_cs;
+ int block_size;
+
+ msg->l2h = udt->payload;
+
+ LOGPMS(DL1P, LOGL_ERROR, ms, "Rx L1CTL_DATA_ABS_REQ (tbf_id=%d, ts=%u, fn=%u, data=%s)\n",
+ udt->tbf_nr, udt->ts_nr, udt->fn, osmo_hexdump(msg->l2h, msgb_l2len(msg)));
+ if (udt->tbf_nr != 0) {
+ LOGPMS(DL1C, LOGL_ERROR, ms, "TBF_NR != 0 not supported yet!\n");
+ return;
+ }
+
+ if (ms->state.state != MS_STATE_TBF) {
+ LOGPMS(DL1P, LOGL_ERROR, ms, "DATA_ABS_REQ in state != TBF\n");
+ return;
+ }
+
+ osmo_cs = get_l1ctl_cs_by_osmo(udt->coding_scheme);
+ if (osmo_cs < 0) {
+ LOGPMS(DL1P, LOGL_ERROR, ms, "DATA_RBF_REQ with invalid CS\n");
+ return;
+ }
+ block_size = osmo_gprs_ul_block_size_bytes(osmo_cs);
+
+ if (msgb_l2len(msg) < block_size) {
+ int pad_len = block_size - msgb_l2len(msg);
+ uint8_t *pad = msgb_put(msg, pad_len);
+ memset(pad, GSM_MACBLOCK_PADDING, pad_len);
+ }
+
+ printf("----enqueueing abs for fn %u, ts %u: %s\n", udt->fn, udt->ts_nr, msgb_hexdump(msg));
+ /* FIXME: ordered insert? But then, the L1CTL_DATA_ABS_REQ should already
+ * arrive in ordered fashion */
+ msgb_enqueue(&ms->state.tx_queue_abs, msg);
+}
+
/***************************************************************
* L1CTL TX ROUTINES *******************************************
* For more routines check the respective handler classes ******