fixeria submitted this change.

View Change

Approvals: Jenkins Builder: Verified fixeria: Looks good to me, approved
trxcon: group Rx burst params into struct l1sched_burst_ind

Change-Id: I3363c38a43d2f54f846527b70cedac8fa57bcb27
Related: OS#5599
---
M src/host/trxcon/include/osmocom/bb/l1sched/l1sched.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_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_trx.c
M src/host/trxcon/src/trxcon_shim.c
9 files changed, 122 insertions(+), 101 deletions(-)

diff --git a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
index 31d4b64..5202e5e 100644
--- a/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
+++ b/src/host/trxcon/include/osmocom/bb/l1sched/l1sched.h
@@ -145,9 +145,25 @@
size_t burst_len;
};

+/* Represents a received burst */
+struct l1sched_burst_ind {
+ uint32_t fn;
+ uint8_t tn;
+
+ /*! ToA256 (Timing of Arrival, 1/256 of a symbol) */
+ int16_t toa256;
+ /*! RSSI (Received Signal Strength Indication) */
+ int8_t rssi;
+
+ /* Internally used by the scheduler */
+ uint8_t bid;
+
+ sbit_t burst[EDGE_BURST_LEN];
+ size_t burst_len;
+};
+
typedef int l1sched_lchan_rx_func(struct l1sched_lchan_state *lchan,
- uint32_t fn, uint8_t bid, const sbit_t *bits,
- const struct l1sched_meas_set *meas);
+ const struct l1sched_burst_ind *bi);

typedef int l1sched_lchan_tx_func(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);
@@ -459,9 +475,8 @@
void l1sched_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, uint8_t tn,
- uint32_t fn, sbit_t *bits, uint16_t nbits,
- const struct l1sched_meas_set *meas);
+int l1sched_handle_rx_burst(struct l1sched_state *sched,
+ struct l1sched_burst_ind *bi);

/* Shared declarations for lchan handlers */
extern const uint8_t l1sched_nb_training_bits[8][26];
@@ -484,7 +499,8 @@
l1sched_tchh_block_map_fn(chan, fn, ul, 1, 0)

/* Measurement history */
-void l1sched_lchan_meas_push(struct l1sched_lchan_state *lchan, const struct l1sched_meas_set *meas);
+void l1sched_lchan_meas_push(struct l1sched_lchan_state *lchan,
+ const struct l1sched_burst_ind *bi);
void l1sched_lchan_meas_avg(struct l1sched_lchan_state *lchan, unsigned int n);

/* Clock and Downlink scheduling trigger */
diff --git a/src/host/trxcon/src/sched_lchan_desc.c b/src/host/trxcon/src/sched_lchan_desc.c
index 54635ba..cb1a431 100644
--- a/src/host/trxcon/src/sched_lchan_desc.c
+++ b/src/host/trxcon/src/sched_lchan_desc.c
@@ -31,36 +31,31 @@

/* Forward declaration of handlers */
int rx_data_fn(struct l1sched_lchan_state *lchan,
- uint32_t fn, uint8_t bid, const sbit_t *bits,
- const struct l1sched_meas_set *meas);
+ const struct l1sched_burst_ind *bi);

int tx_data_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);

int rx_sch_fn(struct l1sched_lchan_state *lchan,
- uint32_t fn, uint8_t bid, const sbit_t *bits,
- const struct l1sched_meas_set *meas);
+ const struct l1sched_burst_ind *bi);

int tx_rach_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);

int rx_tchf_fn(struct l1sched_lchan_state *lchan,
- uint32_t fn, uint8_t bid, const sbit_t *bits,
- const struct l1sched_meas_set *meas);
+ const struct l1sched_burst_ind *bi);

int tx_tchf_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);

int rx_tchh_fn(struct l1sched_lchan_state *lchan,
- uint32_t fn, uint8_t bid, const sbit_t *bits,
- const struct l1sched_meas_set *meas);
+ const struct l1sched_burst_ind *bi);

int tx_tchh_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);

int rx_pdtch_fn(struct l1sched_lchan_state *lchan,
- uint32_t fn, uint8_t bid, const sbit_t *bits,
- const struct l1sched_meas_set *meas);
+ const struct l1sched_burst_ind *bi);

int tx_pdtch_fn(struct l1sched_lchan_state *lchan,
struct l1sched_burst_req *br);
diff --git a/src/host/trxcon/src/sched_lchan_pdtch.c b/src/host/trxcon/src/sched_lchan_pdtch.c
index 0ef4573..2951c86 100644
--- a/src/host/trxcon/src/sched_lchan_pdtch.c
+++ b/src/host/trxcon/src/sched_lchan_pdtch.c
@@ -34,8 +34,7 @@
#include <osmocom/bb/l1sched/logging.h>

int rx_pdtch_fn(struct l1sched_lchan_state *lchan,
- uint32_t fn, uint8_t bid, const sbit_t *bits,
- const struct l1sched_meas_set *meas)
+ const struct l1sched_burst_ind *bi)
{
uint8_t l2[GPRS_L2_MAX_LEN], *mask;
int n_errors, n_bits_total, rc;
@@ -46,25 +45,26 @@
mask = &lchan->rx_burst_mask;
buffer = lchan->rx_bursts;

- LOGP_LCHAND(lchan, LOGL_DEBUG, "Packet data received: fn=%u bid=%u\n", fn, bid);
+ LOGP_LCHAND(lchan, LOGL_DEBUG,
+ "Packet data received: fn=%u bid=%u\n", bi->fn, bi->bid);

/* Align to the first burst of a block */
- if (*mask == 0x00 && bid != 0)
+ if (*mask == 0x00 && bi->bid != 0)
return 0;

/* Update mask */
- *mask |= (1 << bid);
+ *mask |= (1 << bi->bid);

/* Store the measurements */
- l1sched_lchan_meas_push(lchan, meas);
+ l1sched_lchan_meas_push(lchan, bi);

/* Copy burst to buffer of 4 bursts */
- offset = buffer + bid * 116;
- memcpy(offset, bits + 3, 58);
- memcpy(offset + 58, bits + 87, 58);
+ offset = buffer + bi->bid * 116;
+ memcpy(offset, bi->burst + 3, 58);
+ memcpy(offset + 58, bi->burst + 87, 58);

/* Wait until complete set of bursts */
- if (bid != 3)
+ if (bi->bid != 3)
return 0;

/* Calculate AVG of the measurements */
diff --git a/src/host/trxcon/src/sched_lchan_sch.c b/src/host/trxcon/src/sched_lchan_sch.c
index d943ae8..de665cb 100644
--- a/src/host/trxcon/src/sched_lchan_sch.c
+++ b/src/host/trxcon/src/sched_lchan_sch.c
@@ -62,8 +62,7 @@
}

int rx_sch_fn(struct l1sched_lchan_state *lchan,
- uint32_t fn, uint8_t bid, const sbit_t *bits,
- const struct l1sched_meas_set *meas)
+ const struct l1sched_burst_ind *bi)
{
sbit_t payload[2 * 39];
struct gsm_time time;
@@ -72,13 +71,14 @@
int rc;

/* Obtain payload from burst */
- memcpy(payload, bits + 3, 39);
- memcpy(payload + 39, bits + 3 + 39 + 64, 39);
+ memcpy(payload, bi->burst + 3, 39);
+ memcpy(payload + 39, bi->burst + 3 + 39 + 64, 39);

/* Attempt to decode */
rc = gsm0503_sch_decode(sb_info, payload);
if (rc) {
- LOGP_LCHAND(lchan, LOGL_ERROR, "Received bad SCH burst at fn=%u\n", fn);
+ LOGP_LCHAND(lchan, LOGL_ERROR,
+ "Received bad SCH burst at fn=%u\n", bi->fn);
return rc;
}

@@ -87,13 +87,13 @@

LOGP_LCHAND(lchan, LOGL_DEBUG,
"Received SCH: bsic=%u, fn=%u, sched_fn=%u\n",
- bsic, time.fn, fn);
+ bsic, time.fn, bi->fn);

/* Check if decoded frame number matches */
- if (time.fn != fn) {
+ if (time.fn != bi->fn) {
LOGP_LCHAND(lchan, LOGL_ERROR,
"Decoded fn=%u does not match sched_fn=%u\n",
- time.fn, fn);
+ time.fn, bi->fn);
return -EINVAL;
}

diff --git a/src/host/trxcon/src/sched_lchan_tchf.c b/src/host/trxcon/src/sched_lchan_tchf.c
index ec87220..eed1c8a 100644
--- a/src/host/trxcon/src/sched_lchan_tchf.c
+++ b/src/host/trxcon/src/sched_lchan_tchf.c
@@ -58,8 +58,7 @@
};

int rx_tchf_fn(struct l1sched_lchan_state *lchan,
- uint32_t fn, uint8_t bid, const sbit_t *bits,
- const struct l1sched_meas_set *meas)
+ const struct l1sched_burst_ind *bi)
{
int n_errors = -1, n_bits_total = 0, rc;
sbit_t *buffer, *offset;
@@ -73,25 +72,26 @@
mask = &lchan->rx_burst_mask;
buffer = lchan->rx_bursts;

- LOGP_LCHAND(lchan, LOGL_DEBUG, "Traffic received: fn=%u bid=%u\n", fn, bid);
+ LOGP_LCHAND(lchan, LOGL_DEBUG,
+ "Traffic received: fn=%u bid=%u\n", bi->fn, bi->bid);

/* Align to the first burst of a block */
- if (*mask == 0x00 && bid != 0)
+ if (*mask == 0x00 && bi->bid != 0)
return 0;

/* Update mask */
- *mask |= (1 << bid);
+ *mask |= (1 << bi->bid);

/* Store the measurements */
- l1sched_lchan_meas_push(lchan, meas);
+ l1sched_lchan_meas_push(lchan, bi);

/* Copy burst to end of buffer of 8 bursts */
- offset = buffer + bid * 116 + 464;
- memcpy(offset, bits + 3, 58);
- memcpy(offset + 58, bits + 87, 58);
+ offset = buffer + bi->bid * 116 + 464;
+ memcpy(offset, bi->burst + 3, 58);
+ memcpy(offset + 58, bi->burst + 87, 58);

/* Wait until complete set of bursts */
- if (bid != 3)
+ if (bi->bid != 3)
return 0;

/* Calculate AVG of the measurements */
@@ -126,7 +126,7 @@
* the first FN 0,8,17 defines that CMR/CMC is included in frame.
* NOTE: A frame ends 7 FN after start.
*/
- amr_is_cmr = !sched_tchf_dl_amr_cmi_map[fn % 26];
+ amr_is_cmr = !sched_tchf_dl_amr_cmi_map[bi->fn % 26];

/* we store tch_data + 2 header bytes, the amr variable set to
* 2 will allow us to skip the first 2 bytes in case we did
diff --git a/src/host/trxcon/src/sched_lchan_tchh.c b/src/host/trxcon/src/sched_lchan_tchh.c
index be59010..963b2d4 100644
--- a/src/host/trxcon/src/sched_lchan_tchh.c
+++ b/src/host/trxcon/src/sched_lchan_tchh.c
@@ -235,8 +235,7 @@
}

int rx_tchh_fn(struct l1sched_lchan_state *lchan,
- uint32_t fn, uint8_t bid, const sbit_t *bits,
- const struct l1sched_meas_set *meas)
+ const struct l1sched_burst_ind *bi)
{
int n_errors = -1, n_bits_total = 0, rc;
sbit_t *buffer, *offset;
@@ -250,36 +249,37 @@
mask = &lchan->rx_burst_mask;
buffer = lchan->rx_bursts;

- LOGP_LCHAND(lchan, LOGL_DEBUG, "Traffic received: fn=%u bid=%u\n", fn, bid);
+ LOGP_LCHAND(lchan, LOGL_DEBUG,
+ "Traffic received: fn=%u bid=%u\n", bi->fn, bi->bid);

if (*mask == 0x00) {
/* Align to the first burst */
- if (bid > 0)
+ if (bi->bid > 0)
return 0;

/* Align reception of the first FACCH/H frame */
if (lchan->tch_mode == GSM48_CMODE_SIGN) {
- if (!l1sched_tchh_facch_start(lchan->type, fn, 0))
+ if (!l1sched_tchh_facch_start(lchan->type, bi->fn, 0))
return 0;
} else { /* or TCH/H traffic frame */
- if (!l1sched_tchh_traffic_start(lchan->type, fn, 0))
+ if (!l1sched_tchh_traffic_start(lchan->type, bi->fn, 0))
return 0;
}
}

/* Update mask */
- *mask |= (1 << bid);
+ *mask |= (1 << bi->bid);

/* Store the measurements */
- l1sched_lchan_meas_push(lchan, meas);
+ l1sched_lchan_meas_push(lchan, bi);

/* Copy burst to the end of buffer of 6 bursts */
- offset = buffer + bid * 116 + 464;
- memcpy(offset, bits + 3, 58);
- memcpy(offset + 58, bits + 87, 58);
+ offset = buffer + bi->bid * 116 + 464;
+ memcpy(offset, bi->burst + 3, 58);
+ memcpy(offset + 58, bi->burst + 87, 58);

/* Wait until the second burst */
- if (bid != 1)
+ if (bi->bid != 1)
return 0;

/* Wait for complete set of bursts */
@@ -303,19 +303,19 @@
case GSM48_CMODE_SIGN:
case GSM48_CMODE_SPEECH_V1: /* HR */
rc = gsm0503_tch_hr_decode(l2, buffer,
- !l1sched_tchh_facch_end(lchan->type, fn, 0),
+ !l1sched_tchh_facch_end(lchan->type, bi->fn, 0),
&n_errors, &n_bits_total);
break;
case GSM48_CMODE_SPEECH_AMR: /* AMR */
/* the first FN FN 4,13,21 or 5,14,22 defines that CMI is
* included in frame, the first FN FN 0,8,17 or 1,9,18 defines
* that CMR/CMC is included in frame. */
- fn_is_cmi = sched_tchh_dl_amr_cmi_map[fn % 26];
+ fn_is_cmi = sched_tchh_dl_amr_cmi_map[bi->fn % 26];

/* See comment in function rx_tchf_fn() */
amr = 2;
rc = gsm0503_tch_ahs_decode_dtx(l2 + amr, buffer,
- !sched_tchh_dl_facch_map[fn % 26],
+ !sched_tchh_dl_facch_map[bi->fn % 26],
!fn_is_cmi, lchan->amr.codec, lchan->amr.codecs, &lchan->amr.dl_ft,
&lchan->amr.dl_cmr, &n_errors, &n_bits_total, &lchan->amr.last_dtx);

@@ -398,7 +398,7 @@
/* Didn't try to decode, fake measurements */
if (n_errors < 0) {
lchan->meas_avg = (struct l1sched_meas_set) {
- .fn = tchh_block_dl_first_fn(lchan, fn, false),
+ .fn = tchh_block_dl_first_fn(lchan, bi->fn, false),
.toa256 = 0,
.rssi = -110,
};
diff --git a/src/host/trxcon/src/sched_lchan_xcch.c b/src/host/trxcon/src/sched_lchan_xcch.c
index 0d24866..aff4220 100644
--- a/src/host/trxcon/src/sched_lchan_xcch.c
+++ b/src/host/trxcon/src/sched_lchan_xcch.c
@@ -34,8 +34,7 @@
#include <osmocom/bb/l1sched/logging.h>

int rx_data_fn(struct l1sched_lchan_state *lchan,
- uint32_t fn, uint8_t bid, const sbit_t *bits,
- const struct l1sched_meas_set *meas)
+ const struct l1sched_burst_ind *bi)
{
uint8_t l2[GSM_MACBLOCK_LEN], *mask;
int n_errors, n_bits_total, rc;
@@ -45,25 +44,26 @@
mask = &lchan->rx_burst_mask;
buffer = lchan->rx_bursts;

- LOGP_LCHAND(lchan, LOGL_DEBUG, "Data received: fn=%u bid=%u\n", fn, bid);
+ LOGP_LCHAND(lchan, LOGL_DEBUG,
+ "Data received: fn=%u bid=%u\n", bi->fn, bi->bid);

/* Align to the first burst of a block */
- if (*mask == 0x00 && bid != 0)
+ if (*mask == 0x00 && bi->bid != 0)
return 0;

/* Update mask */
- *mask |= (1 << bid);
+ *mask |= (1 << bi->bid);

/* Store the measurements */
- l1sched_lchan_meas_push(lchan, meas);
+ l1sched_lchan_meas_push(lchan, bi);

/* Copy burst to buffer of 4 bursts */
- offset = buffer + bid * 116;
- memcpy(offset, bits + 3, 58);
- memcpy(offset + 58, bits + 87, 58);
+ offset = buffer + bi->bid * 116;
+ memcpy(offset, bi->burst + 3, 58);
+ memcpy(offset + 58, bi->burst + 87, 58);

/* Wait until complete set of bursts */
- if (bid != 3)
+ if (bi->bid != 3)
return 0;

/* Calculate AVG of the measurements */
diff --git a/src/host/trxcon/src/sched_trx.c b/src/host/trxcon/src/sched_trx.c
index 92f8bf2..b7d7854 100644
--- a/src/host/trxcon/src/sched_trx.c
+++ b/src/host/trxcon/src/sched_trx.c
@@ -703,27 +703,29 @@
return -EIO;
}

- static const sbit_t bits[148] = { 0 };
- struct l1sched_meas_set fake_meas = {
+ struct l1sched_burst_ind bi = {
.fn = lchan->tdma.last_proc,
- .rssi = -120,
+ .tn = lchan->ts->index,
.toa256 = 0,
+ .rssi = -120,
+ .burst = { 0 },
+ .burst_len = GSM_BURST_LEN,
};

/* Traverse from fp till the current frame */
for (i = 0; i < elapsed - 1; i++) {
- fp = &mf->frames[GSM_TDMA_FN_INC(fake_meas.fn) % mf->period];
+ fp = &mf->frames[GSM_TDMA_FN_INC(bi.fn) % mf->period];
if (fp->dl_chan != lchan->type)
continue;

LOGP_LCHANC(lchan, LOGL_NOTICE,
- "Substituting lost TDMA frame fn=%u\n",
- fake_meas.fn);
+ "Substituting lost TDMA frame fn=%u\n", bi.fn);

- handler(lchan, fake_meas.fn, fp->dl_bid, bits, &fake_meas);
+ bi.bid = fp->dl_bid;
+ handler(lchan, &bi);

/* Update TDMA frame statistics */
- lchan->tdma.last_proc = fake_meas.fn;
+ lchan->tdma.last_proc = bi.fn;
lchan->tdma.num_proc++;
lchan->tdma.num_lost++;
}
@@ -731,33 +733,31 @@
return 0;
}

-int l1sched_handle_rx_burst(struct l1sched_state *sched, uint8_t tn,
- uint32_t fn, sbit_t *bits, uint16_t nbits,
- const struct l1sched_meas_set *meas)
+int l1sched_handle_rx_burst(struct l1sched_state *sched,
+ struct l1sched_burst_ind *bi)
{
struct l1sched_lchan_state *lchan;
const struct l1sched_tdma_frame *frame;
- struct l1sched_ts *ts;
+ struct l1sched_ts *ts = sched->ts[bi->tn];

l1sched_lchan_rx_func *handler;
enum l1sched_lchan_type chan;
- uint8_t offset, bid;
+ uint8_t offset;
int rc;

/* Check whether required timeslot is allocated and configured */
- ts = sched->ts[tn];
if (ts == NULL || ts->mf_layout == NULL) {
LOGP_SCHEDD(sched, LOGL_DEBUG,
- "Timeslot #%u isn't configured, ignoring burst...\n", tn);
+ "Timeslot #%u isn't configured, ignoring burst...\n", bi->tn);
return -EINVAL;
}

/* Get frame from multiframe */
- offset = fn % ts->mf_layout->period;
+ offset = bi->fn % ts->mf_layout->period;
frame = ts->mf_layout->frames + offset;

/* Get required info from frame */
- bid = frame->dl_bid;
+ bi->bid = frame->dl_bid;
chan = frame->dl_chan;
handler = l1sched_lchan_desc[chan].rx_fn;

@@ -776,19 +776,19 @@
return 0;

/* Compensate lost TDMA frames (if any) */
- rc = subst_frame_loss(lchan, handler, fn);
+ rc = subst_frame_loss(lchan, handler, bi->fn);
if (rc == -EALREADY)
return rc;

/* Perform A5/X decryption if required */
if (lchan->a5.algo)
- l1sched_a5_burst_dec(lchan, fn, bits);
+ l1sched_a5_burst_dec(lchan, bi->fn, &bi->burst[0]);

/* Put burst to handler */
- handler(lchan, fn, bid, bits, meas);
+ handler(lchan, bi);

/* Update TDMA frame statistics */
- lchan->tdma.last_proc = fn;
+ lchan->tdma.last_proc = bi->fn;

if (++lchan->tdma.num_proc == 0) {
/* Theoretically, we may have an integer overflow of num_proc counter.
@@ -810,7 +810,8 @@
(MEAS_HIST_FIRST(hist) + ARRAY_SIZE(hist->buf) - 1)

/* Add a new set of measurements to the history */
-void l1sched_lchan_meas_push(struct l1sched_lchan_state *lchan, const struct l1sched_meas_set *meas)
+void l1sched_lchan_meas_push(struct l1sched_lchan_state *lchan,
+ const struct l1sched_burst_ind *bi)
{
struct l1sched_lchan_meas_hist *hist = &lchan->meas_hist;

@@ -820,7 +821,11 @@
else
hist->head++;

- *hist->head = *meas;
+ *hist->head = (struct l1sched_meas_set) {
+ .fn = bi->fn,
+ .toa256 = bi->toa256,
+ .rssi = bi->rssi,
+ };
}

/* Calculate the AVG of n measurements from the history */
diff --git a/src/host/trxcon/src/trxcon_shim.c b/src/host/trxcon/src/trxcon_shim.c
index 5329539..ee51036 100644
--- a/src/host/trxcon/src/trxcon_shim.c
+++ b/src/host/trxcon/src/trxcon_shim.c
@@ -220,18 +220,23 @@
}

/* External L1 API for the PHYIF */
-int trxcon_phyif_handle_burst_ind(void *priv, const struct trxcon_phyif_burst_ind *bi)
+int trxcon_phyif_handle_burst_ind(void *priv, const struct trxcon_phyif_burst_ind *phybi)
{
struct trxcon_inst *trxcon = priv;
- const struct l1sched_meas_set meas = {
- .fn = bi->fn,
- .toa256 = bi->toa256,
- .rssi = bi->rssi,
+ struct l1sched_burst_ind bi = {
+ .fn = phybi->fn,
+ .tn = phybi->tn,
+ .toa256 = phybi->toa256,
+ .rssi = phybi->rssi,
+ /* .burst[] is populated below */
+ .burst_len = phybi->burst_len,
};

+ OSMO_ASSERT(phybi->burst_len <= sizeof(bi.burst));
+ memcpy(&bi.burst[0], phybi->burst, phybi->burst_len);
+
/* Poke scheduler */
- return l1sched_handle_rx_burst(trxcon->sched, bi->tn, bi->fn,
- bi->burst, bi->burst_len, &meas);
+ return l1sched_handle_rx_burst(trxcon->sched, &bi);
}

int trxcon_phyif_handle_clock_ind(void *priv, uint32_t fn)

To view, visit change 30253. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: I3363c38a43d2f54f846527b70cedac8fa57bcb27
Gerrit-Change-Number: 30253
Gerrit-PatchSet: 4
Gerrit-Owner: fixeria <vyanitskiy@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de>
Gerrit-Reviewer: osmith <osmith@sysmocom.de>
Gerrit-Reviewer: pespin <pespin@sysmocom.de>
Gerrit-MessageType: merged