diff options
author | Vadim Yanitskiy <axilirator@gmail.com> | 2018-08-14 04:46:48 +0700 |
---|---|---|
committer | Vadim Yanitskiy <axilirator@gmail.com> | 2018-08-14 05:46:59 +0700 |
commit | 799f26c07534e9ad5b002650d2db50bdbc2016bf (patch) | |
tree | 8817b3f4d349171dc02cb5f2b72736b3632bd9d6 /src/host/trxcon | |
parent | 8ae0c13fa93ef19a2b1a683f390427b7411aa0e0 (diff) |
trxcon/sched_prim.c: refactor prim dequeuing logic
The previous primitive dequeuing logic (especially for TCH/F
channels) was a bit complicated, and it could not be possible
to reuse the existing code parts in the upcoming implementation
of both TCH/H and FACCH/H channels without changing anything.
In particular, this change introduces two internal functions:
- prim_dequeue_one(), which merely dequeues a primitive
of a given channel type (e.g. TRXC_SDCCH4_0);
- prim_dequeue_tch(), which dequeues either a FACCH,
or a speech TCH primitive of a given channel
type (Lm or Bm).
So the logic of the TCH/F prim dequeuing function has become
cleaner, and the upcoming TCH/H prim dequeuing function, where
FACCH/H prioritization is more complex than FACCH/F, will
reuse the introduced functions.
Change-Id: Ib82ad2480ab1bc6b1df9576eb2bf5acbd398bf66
Diffstat (limited to 'src/host/trxcon')
-rw-r--r-- | src/host/trxcon/sched_prim.c | 138 |
1 files changed, 83 insertions, 55 deletions
diff --git a/src/host/trxcon/sched_prim.c b/src/host/trxcon/sched_prim.c index 2ee06d73..49873798 100644 --- a/src/host/trxcon/sched_prim.c +++ b/src/host/trxcon/sched_prim.c @@ -128,61 +128,98 @@ int sched_prim_push(struct trx_instance *trx, return 0; } +/* Dequeues a primitive of a given channel type */ +static struct trx_ts_prim *prim_dequeue_one(struct llist_head *queue, + enum trx_lchan_type lchan_type) +{ + struct trx_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; +} + /** - * Dequeues a TCH or FACCH frame, prioritizing the second. - * In case if a FACCH frame is found, a TCH frame is being - * dropped (i.e. replaced). + * Dequeues either a FACCH, or a speech TCH primitive + * of a given channel type (Lm or Bm). * - * @param queue a transmit queue to take a prim from - * @return a FACCH or TCH primitive, otherwise NULL + * Note: we could avoid 'lchan_type' parameter and just + * check the prim's channel type using 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. TRXC_TCHF, TRXC_TCHH_0, or TRXC_TCHH_1 + * @param facch FACCH (true) or speech (false) prim? + * @return either a FACCH, or a TCH primitive if found, + * otherwise NULL */ -static struct trx_ts_prim *sched_prim_dequeue_tch(struct llist_head *queue) +static struct trx_ts_prim *prim_dequeue_tch(struct llist_head *queue, + enum trx_lchan_type lchan_type, bool facch) { - struct trx_ts_prim *facch = NULL; - struct trx_ts_prim *tch = NULL; - struct trx_ts_prim *i; - - /* Attempt to find a pair of FACCH and TCH frames */ - llist_for_each_entry(i, queue, list) { - /* Find one FACCH frame */ - if (!facch && PRIM_IS_FACCH(i)) - facch = i; - - /* Find one TCH frame */ - if (!tch && PRIM_IS_TCH(i)) - tch = i; - - /* If both are found */ - if (facch && tch) - break; - } + struct trx_ts_prim *prim; - /* Prioritize FACCH */ - if (facch && tch) { - /* We found a pair, dequeue both */ - llist_del(&facch->list); - llist_del(&tch->list); + /** + * 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) + continue; - /* Drop TCH */ - talloc_free(tch); + /* Either FACCH, or not FACCH */ + if (PRIM_IS_FACCH(prim) != facch) + continue; - /* FACCH replaces TCH */ - return facch; - } else if (facch) { - /* Only FACCH was found */ - llist_del(&facch->list); + llist_del(&prim->list); + return prim; + } + + return NULL; +} + +/** + * 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 queue a transmit queue to take a prim from + * @return either a FACCH/F, or a TCH/F primitive, + * otherwise NULL + */ +static struct trx_ts_prim *prim_dequeue_tch_f(struct llist_head *queue) +{ + struct trx_ts_prim *facch; + struct trx_ts_prim *tch; + + /* Attempt to find a pair of both FACCH/F and TCH/F frames */ + facch = prim_dequeue_tch(queue, TRXC_TCHF, true); + tch = prim_dequeue_tch(queue, TRXC_TCHF, false); + + /* Prioritize FACCH/F, if found */ + if (facch) { + /* One TCH/F prim is replaced */ + if (tch) + talloc_free(tch); return facch; } else if (tch) { - /* Only TCH was found */ - llist_del(&tch->list); + /* Only TCH/F prim was found */ return tch; + } else { + /* Nothing was found, e.g. when only SACCH frames are in queue */ + return NULL; } - - /** - * Nothing was found, - * e.g. only SACCH frames are in queue - */ - return NULL; } /** @@ -196,24 +233,15 @@ static struct trx_ts_prim *sched_prim_dequeue_tch(struct llist_head *queue) struct trx_ts_prim *sched_prim_dequeue(struct llist_head *queue, enum trx_lchan_type lchan_type) { - struct trx_ts_prim *prim; - /* There is nothing to dequeue */ if (llist_empty(queue)) return NULL; /* TCH requires FACCH prioritization, so handle it separately */ if (CHAN_IS_TCH(lchan_type)) - return sched_prim_dequeue_tch(queue); + return prim_dequeue_tch_f(queue); - llist_for_each_entry(prim, queue, list) { - if (prim->chan == lchan_type) { - llist_del(&prim->list); - return prim; - } - } - - return NULL; + return prim_dequeue_one(queue, lchan_type); } /** |