pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmo-gprs/+/31751 )
Change subject: rlcmac: ul_tbf: Implement support for TBF Starting Time ......................................................................
rlcmac: ul_tbf: Implement support for TBF Starting Time
While reworking tbf_ul_ass_fsm, avoid being in "ASSIGN" state while waiting to send Pkt Ctrl Ack. The PCU is free to ask the TBF to transmit data before receiving Pkt Ctrl Ack; the time where it can start transmitting data is actually controlled by TBF Starting Time.
Change-Id: Id81f16743f2c464e01caf27ba2eb8c0fc715fe8a --- M include/osmocom/gprs/rlcmac/rlcmac_dec.h M include/osmocom/gprs/rlcmac/rlcmac_private.h M include/osmocom/gprs/rlcmac/sched.h M include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h M src/rlcmac/pdch_ul_controller.c M src/rlcmac/rlcmac.c M src/rlcmac/rlcmac_dec.c M src/rlcmac/rlcmac_prim.c M src/rlcmac/sched.c M src/rlcmac/tbf_ul_ass_fsm.c M tests/rlcmac/rlcmac_prim_test.err 11 files changed, 239 insertions(+), 53 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-gprs refs/changes/51/31751/1
diff --git a/include/osmocom/gprs/rlcmac/rlcmac_dec.h b/include/osmocom/gprs/rlcmac/rlcmac_dec.h index ea92a0f..fc082f6 100644 --- a/include/osmocom/gprs/rlcmac/rlcmac_dec.h +++ b/include/osmocom/gprs/rlcmac/rlcmac_dec.h @@ -5,10 +5,13 @@ #include <stdint.h> #include <osmocom/core/msgb.h> #include <osmocom/core/bitvec.h> +#include <osmocom/gsm/gsm0502.h> +#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gprs/rlcmac/csn1_defs.h> #include <osmocom/gprs/rlcmac/rlc.h> #include <osmocom/gprs/rlcmac/coding_scheme.h> +#include <osmocom/gprs/rlcmac/sched.h>
struct gprs_rlcmac_rlc_ul_window;
@@ -46,3 +49,7 @@ int gprs_rlcmac_decode_gprs_acknack_bits(const Ack_Nack_Description_t *desc, struct bitvec *bits, int *bsn_begin, int *bsn_end, struct gprs_rlcmac_rlc_ul_window *ulw); + +uint32_t TBF_StartingTime_to_fn(const StartingTime_t *tbf_start_time, uint32_t curr_fn); +uint32_t TBF_Starting_Frame_Number_to_fn(const Starting_Frame_Number_t *tbf_start_fn, uint32_t curr_fn); + diff --git a/include/osmocom/gprs/rlcmac/rlcmac_private.h b/include/osmocom/gprs/rlcmac/rlcmac_private.h index e2d2494..cd03066 100644 --- a/include/osmocom/gprs/rlcmac/rlcmac_private.h +++ b/include/osmocom/gprs/rlcmac/rlcmac_private.h @@ -88,7 +88,7 @@ struct gprs_rlcmac_entity *gprs_rlcmac_find_entity_by_tlli(uint32_t tlli); struct gprs_rlcmac_dl_tbf *gprs_rlcmac_find_dl_tbf_by_tfi(uint8_t dl_tfi); struct gprs_rlcmac_ul_tbf *gprs_rlcmac_find_ul_tbf_by_tfi(uint8_t ul_tfi); -int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia); +int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia, uint32_t fn); int gprs_rlcmac_handle_bcch_si13(const struct gsm48_system_information_type_13 *si13); int gprs_rlcmac_handle_gprs_dl_block(const struct osmo_gprs_rlcmac_prim *rlcmac_prim, enum gprs_rlcmac_coding_scheme cs); diff --git a/include/osmocom/gprs/rlcmac/sched.h b/include/osmocom/gprs/rlcmac/sched.h index c7fa82a..18fbe7d 100644 --- a/include/osmocom/gprs/rlcmac/sched.h +++ b/include/osmocom/gprs/rlcmac/sched.h @@ -12,3 +12,23 @@ uint32_t rrbp2fn(uint32_t cur_fn, uint8_t rrbp);
int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_rts_block_ind *bi); + +static inline bool fn_valid(uint32_t fn) +{ + uint32_t f = fn % 13; + return f == 0 || f == 4 || f == 8; +} + +#define GSM_MAX_FN_THRESH (GSM_MAX_FN >> 1) +/* 0: equal, -1: fn1 BEFORE fn2, 1: fn1 AFTER fn2 */ +static inline int fn_cmp(uint32_t fn1, uint32_t fn2) +{ + if (fn1 == fn2) + return 0; + /* FN1 goes before FN2: */ + if ((fn1 < fn2 && (fn2 - fn1) < GSM_MAX_FN_THRESH) || + (fn1 > fn2 && (fn1 - fn2) > GSM_MAX_FN_THRESH)) + return -1; + /* FN1 goes after FN2: */ + return 1; +} diff --git a/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h b/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h index c5a785d..9026459 100644 --- a/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h +++ b/include/osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h @@ -20,9 +20,10 @@ enum gprs_rlcmac_tbf_ul_ass_fsm_states { GPRS_RLCMAC_TBF_UL_ASS_ST_IDLE = 0, /* new created TBF */ GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_CCCH_IMM_ASS, /* wait for Immediate Assignment */ + GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1, /* Wait for Tbf Starting Time (1phase) */ GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ, /* wait PDCH sched (USF) */ GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_PKT_UL_ASS, /* Wait for PCU to send the new assignment */ - GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK, /* Wait for scheduler to send PKT CTRL ACK */ + GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2, /* Wait for Tbf Starting Time (2phase) */ GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL, /* Completed, will update TBF and return to IDLE state */ };
@@ -37,6 +38,8 @@ uint8_t rach_req_ra; struct gprs_rlcmac_ul_tbf_allocation phase1_alloc; struct gprs_rlcmac_ul_tbf_allocation phase2_alloc; + bool tbf_starting_time_exists; + uint32_t tbf_starting_time; /* Number of packet resource request transmitted (T3168) */ unsigned int pkt_res_req_proc_attempts; }; @@ -46,12 +49,14 @@ GPRS_RLCMAC_TBF_UL_ASS_EV_START_DIRECT_2PHASE, /* Start Uplink assignment directly into 2phase from an older UL TBF */ GPRS_RLCMAC_TBF_UL_ASS_EV_START_FROM_DL_TBF, /* Uplink assignment requested by DL TBF ACK/NACK, wait to receive Pkt Ul Ass on its PACCH */ GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS, /* (data: struct tbf_ul_ass_ev_rx_ccch_imm_ass_ctx *) */ + GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME, /* Scheduler ticking reaches TBF Starting Time */ GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG, /* Generate RLC/MAC block (data: struct tbf_ul_ass_ev_create_rlcmac_msg_ctx) */ GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS, /* (data: struct tbf_ul_ass_ev_create_rlcmac_msg_ctx) */ };
struct tbf_ul_ass_ev_rx_ccch_imm_ass_ctx { uint8_t ts_nr; + uint32_t fn; const struct gsm48_imm_ass *ia; const IA_RestOctets_t *iaro; }; @@ -80,6 +85,8 @@
bool gprs_rlcmac_tbf_ul_ass_pending(struct gprs_rlcmac_ul_tbf *ul_tbf); bool gprs_rlcmac_tbf_ul_ass_match_rach_req(struct gprs_rlcmac_ul_tbf *ul_tbf, uint8_t ra); +bool gprs_rlcmac_tbf_ul_ass_waiting_tbf_starting_time(const struct gprs_rlcmac_ul_tbf *ul_tbf); +void gprs_rlcmac_tbf_ul_ass_fn_tick(const struct gprs_rlcmac_ul_tbf *ul_tbf, uint32_t fn, uint8_t ts_nr); bool gprs_rlcmac_tbf_ul_ass_rts(const struct gprs_rlcmac_ul_tbf *ul_tbf, const struct gprs_rlcmac_rts_block_ind *bi); struct msgb *gprs_rlcmac_tbf_ul_ass_create_rlcmac_msg(const struct gprs_rlcmac_ul_tbf *ul_tbf, const struct gprs_rlcmac_rts_block_ind *bi); diff --git a/src/rlcmac/pdch_ul_controller.c b/src/rlcmac/pdch_ul_controller.c index 7a3b753..731caf0 100644 --- a/src/rlcmac/pdch_ul_controller.c +++ b/src/rlcmac/pdch_ul_controller.c @@ -26,6 +26,7 @@ #include <osmocom/gprs/rlcmac/pdch_ul_controller.h> #include <osmocom/gprs/rlcmac/rlcmac_private.h> #include <osmocom/gprs/rlcmac/types_private.h> +#include <osmocom/gprs/rlcmac/sched.h>
/* TS 44.060 Table 10.4.5.1 states maximum RRBP is N + 26. Give extra space for time diff between Tx and Rx? */ #define MAX_FN_RESERVED (27 + 50) @@ -39,20 +40,6 @@ { 0, NULL } };
-#define GSM_MAX_FN_THRESH (GSM_MAX_FN >> 1) -/* 0: equal, -1: fn1 BEFORE fn2, 1: fn1 AFTER fn2 */ -static inline int fn_cmp(uint32_t fn1, uint32_t fn2) -{ - if (fn1 == fn2) - return 0; - /* FN1 goes before FN2: */ - if ((fn1 < fn2 && (fn2 - fn1) < GSM_MAX_FN_THRESH) || - (fn1 > fn2 && (fn1 - fn2) > GSM_MAX_FN_THRESH)) - return -1; - /* FN1 goes after FN2: */ - return 1; -} - struct gprs_rlcmac_pdch_ulc *gprs_rlcmac_pdch_ulc_alloc(void *ctx, uint8_t ts_nr) { struct gprs_rlcmac_pdch_ulc *ulc; diff --git a/src/rlcmac/rlcmac.c b/src/rlcmac/rlcmac.c index 3b30fb6..4647fff 100644 --- a/src/rlcmac/rlcmac.c +++ b/src/rlcmac/rlcmac.c @@ -165,12 +165,13 @@ return NULL; }
-static int gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(uint8_t ts_nr, const struct gsm48_imm_ass *ia, const IA_RestOctets_t *iaro) +static int gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(uint8_t ts_nr, uint32_t fn, const struct gsm48_imm_ass *ia, const IA_RestOctets_t *iaro) { int rc = -ENOENT; struct gprs_rlcmac_entity *gre; struct gprs_rlcmac_ul_tbf *ul_tbf; struct tbf_ul_ass_ev_rx_ccch_imm_ass_ctx d = { + .fn = fn, .ts_nr = ts_nr, .ia = ia, .iaro = iaro @@ -190,7 +191,7 @@ return rc; }
-static int gprs_rlcmac_handle_ccch_imm_ass_dl_tbf(uint8_t ts_nr, const struct gsm48_imm_ass *ia, const IA_RestOctets_t *iaro) +static int gprs_rlcmac_handle_ccch_imm_ass_dl_tbf(uint8_t ts_nr, uint32_t fn, const struct gsm48_imm_ass *ia, const IA_RestOctets_t *iaro) { int rc; struct gprs_rlcmac_entity *gre; @@ -224,7 +225,7 @@ return rc; }
-int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia) +int gprs_rlcmac_handle_ccch_imm_ass(const struct gsm48_imm_ass *ia, uint32_t fn) { int rc; uint8_t ch_type, ch_subch, ch_ts; @@ -253,10 +254,10 @@ case 1: /* iaro.u.lh.* (IA_RestOctetsLH_t) */ switch (iaro.u.lh.lh0x.UnionType) { case 0: /* iaro.u.ll.lh0x.EGPRS_PktUlAss.* (IA_EGPRS_PktUlAss_t) */ - rc = gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(ch_ts, ia, &iaro); + rc = gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(ch_ts, fn, ia, &iaro); break; case 1: /* iaro.u.ll.lh0x.MultiBlock_PktDlAss.* (IA_MultiBlock_PktDlAss_t) */ - rc = gprs_rlcmac_handle_ccch_imm_ass_dl_tbf(ch_ts, ia, &iaro); + rc = gprs_rlcmac_handle_ccch_imm_ass_dl_tbf(ch_ts, fn, ia, &iaro); break; } /* TODO: iaro.u.lh.AdditionsR13.* (IA_AdditionsR13_t) */ @@ -279,17 +280,17 @@ case 1: /* iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.* (GPRS_DynamicOrFixedAllocation_t) */ switch (iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.UnionType) { case 0: /* iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.Allocation.DynamicAllocation (DynamicAllocation_t) */ - rc = gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(ch_ts, ia, &iaro); + rc = gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(ch_ts, fn, ia, &iaro); break; case 1: /* iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.Allocation.FixedAllocationDummy (guint8) */ - rc = gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(ch_ts, ia, &iaro); + rc = gprs_rlcmac_handle_ccch_imm_ass_ul_tbf(ch_ts, fn, ia, &iaro); break; } break; } break; case 1: /* iaro.u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Downlink_ImmAssignment* (Packet_Downlink_ImmAssignment_t) */ - rc = gprs_rlcmac_handle_ccch_imm_ass_dl_tbf(ch_ts, ia, &iaro); + rc = gprs_rlcmac_handle_ccch_imm_ass_dl_tbf(ch_ts, fn, ia, &iaro); break; } break; diff --git a/src/rlcmac/rlcmac_dec.c b/src/rlcmac/rlcmac_dec.c index fa88c26..2978400 100644 --- a/src/rlcmac/rlcmac_dec.c +++ b/src/rlcmac/rlcmac_dec.c @@ -422,3 +422,47 @@
return num_blocks; } + +/* 12.21 Starting Frame Number Description */ +uint32_t TBF_StartingTime_to_fn(const StartingTime_t *tbf_start_time, uint32_t curr_fn) +{ + const struct gsm_time g_time = { + .t1 = tbf_start_time->N32, + .t2 = tbf_start_time->N51, + .t3 = tbf_start_time->N26 + }; + return gsm_gsmtime2fn(&g_time); + +} + +/* 12.21.2 Relative Frame Number Encoding */ +static uint32_t k_to_fn(uint16_t k, uint32_t curr_fn) +{ + uint32_t fn = 0; + + switch (k % 3) { + case 0: + case 1: + fn = GSM_TDMA_FN_SUM(curr_fn, 4 + 4 * k + (k / 3)); + if (!fn_valid(fn)) + GSM_TDMA_FN_INC(fn); + break; + case 2: + fn = GSM_TDMA_FN_SUM(curr_fn, 5 + 4 * k + (k / 3)); + break; + } + OSMO_ASSERT(fn_valid(fn)); + return fn; +} + +uint32_t TBF_Starting_Frame_Number_to_fn(const Starting_Frame_Number_t *tbf_start_fn, uint32_t curr_fn) +{ + switch (tbf_start_fn->UnionType) { + case 0: /* 12.21.1 Absolute Frame Number Encoding */ + return TBF_StartingTime_to_fn(&tbf_start_fn->u.StartingTime, curr_fn); + case 1: /* 12.21.2 Relative Frame Number Encoding */ + return k_to_fn(tbf_start_fn->u.k, curr_fn); + default: + OSMO_ASSERT(0); + } +} diff --git a/src/rlcmac/rlcmac_prim.c b/src/rlcmac/rlcmac_prim.c index 621b6dc..daf022a 100644 --- a/src/rlcmac/rlcmac_prim.c +++ b/src/rlcmac/rlcmac_prim.c @@ -504,7 +504,8 @@
switch (rlcmac_prim->l1ctl.ccch_data_ind.data[2]) { case GSM48_MT_RR_IMM_ASS: - rc = gprs_rlcmac_handle_ccch_imm_ass((struct gsm48_imm_ass *)rlcmac_prim->l1ctl.ccch_data_ind.data); + rc = gprs_rlcmac_handle_ccch_imm_ass((struct gsm48_imm_ass *)rlcmac_prim->l1ctl.ccch_data_ind.data, + rlcmac_prim->l1ctl.ccch_data_ind.fn); break; case GSM48_MT_RR_SYSINFO_13: rc = gprs_rlcmac_handle_bcch_si13((struct gsm48_system_information_type_13 *)rlcmac_prim->l1ctl.ccch_data_ind.data); diff --git a/src/rlcmac/sched.c b/src/rlcmac/sched.c index 6ec76c7..0431631 100644 --- a/src/rlcmac/sched.c +++ b/src/rlcmac/sched.c @@ -41,12 +41,6 @@ struct gprs_rlcmac_ul_tbf *ul_ass; /* PCU grants USF/SBA: transmit Pkt Res Req (2phase access)*/ };
-static inline bool fn_valid(uint32_t fn) -{ - uint32_t f = fn % 13; - return f == 0 || f == 4 || f == 8; -} - uint32_t rrbp2fn(uint32_t cur_fn, uint8_t rrbp) { uint32_t poll_fn; @@ -210,7 +204,7 @@ return msg; } if (tbfs->poll_ul_ass) { - msg = gprs_rlcmac_tbf_ul_ass_create_rlcmac_msg(tbfs->poll_ul_ass, bi); + msg = gprs_rlcmac_ul_tbf_create_pkt_ctrl_ack(tbfs->poll_ul_ass); if (msg) return msg; } @@ -260,6 +254,15 @@ return gprs_rlcmac_ul_tbf_dummy_create(ul_tbf); }
+static void rts_tick(const struct gprs_rlcmac_rts_block_ind *bi) +{ + struct gprs_rlcmac_entity *gre; + llist_for_each_entry(gre, &g_ctx->gre_list, entry) { + if (gre->ul_tbf && gprs_rlcmac_tbf_ul_ass_waiting_tbf_starting_time(gre->ul_tbf)) + gprs_rlcmac_tbf_ul_ass_fn_tick(gre->ul_tbf, bi->fn, bi->ts); + } +} + int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_rts_block_ind *bi) { struct msgb *msg = NULL; @@ -267,6 +270,8 @@ struct osmo_gprs_rlcmac_prim *rlcmac_prim_tx; int rc = 0;
+ rts_tick(bi); + get_ctrl_msg_tbf_candidates(bi, &tbf_cand);
if ((msg = sched_select_ctrl_msg(bi, &tbf_cand))) diff --git a/src/rlcmac/tbf_ul_ass_fsm.c b/src/rlcmac/tbf_ul_ass_fsm.c index e2775be..48c1bf8 100644 --- a/src/rlcmac/tbf_ul_ass_fsm.c +++ b/src/rlcmac/tbf_ul_ass_fsm.c @@ -24,6 +24,8 @@ #include <osmocom/core/tdef.h> #include <osmocom/core/fsm.h> #include <osmocom/core/bitvec.h> +#include <osmocom/gsm/gsm_utils.h> +#include <osmocom/gsm/gsm0502.h>
#include <osmocom/gprs/rlcmac/types.h> #include <osmocom/gprs/rlcmac/tbf_ul_ass_fsm.h> @@ -32,6 +34,7 @@ #include <osmocom/gprs/rlcmac/sched.h> #include <osmocom/gprs/rlcmac/csn1_defs.h> #include <osmocom/gprs/rlcmac/rlcmac_enc.h> +#include <osmocom/gprs/rlcmac/rlcmac_dec.h> #include <osmocom/gprs/rlcmac/pdch_ul_controller.h>
#define X(s) (1 << (s)) @@ -39,8 +42,9 @@ static const struct value_string tbf_ul_ass_fsm_event_names[] = { { GPRS_RLCMAC_TBF_UL_ASS_EV_START, "START" }, { GPRS_RLCMAC_TBF_UL_ASS_EV_START_DIRECT_2PHASE, "START_DIRECT_2PHASE" }, - { GPRS_RLCMAC_TBF_UL_ASS_EV_START_FROM_DL_TBF, "START_FROM_DL_TBF" }, + { GPRS_RLCMAC_TBF_UL_ASS_EV_START_FROM_DL_TBF, "START_FROM_DL_TBF" }, { GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS, "RX_CCCH_IMM_ASS" }, + { GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME, "TBF_STARTING_TIME" }, { GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG, "CREATE_RLCMAC_MSG" }, { GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS, "RX_PKT_UL_ASS" }, { 0, NULL } @@ -49,9 +53,10 @@ static const struct osmo_tdef_state_timeout tbf_ul_ass_fsm_timeouts[32] = { [GPRS_RLCMAC_TBF_UL_ASS_ST_IDLE] = { }, [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_CCCH_IMM_ASS] = { }, + [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1] = { }, [GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ] = { }, [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_PKT_UL_ASS] = { .T = 3168 }, - [GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK] = { }, + [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2] = { }, [GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL] = { }, };
@@ -141,6 +146,10 @@ return -ENOTSUP; case 1: /* d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.* (GPRS_DynamicOrFixedAllocation_t) */ ctx->ul_tbf->tx_cs = d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.CHANNEL_CODING_COMMAND + 1; + ctx->tbf_starting_time_exists = d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.Exist_TBF_STARTING_TIME; + if (ctx->tbf_starting_time_exists) + ctx->tbf_starting_time = TBF_StartingTime_to_fn(&d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.TBF_STARTING_TIME, + d->fn); LOGPFSML(ctx->fi, LOGL_INFO, "ImmAss initial CS=%s\n", gprs_rlcmac_mcs_name(ctx->ul_tbf->tx_cs)); switch (d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.UnionType) { case 0: /* d->iaro->u.hh.u.UplinkDownlinkAssignment.ul_dl.Packet_Uplink_ImmAssignment.Access.DynamicOrFixedAllocation.Allocation.DynamicAllocation (DynamicAllocation_t) */ @@ -181,7 +190,11 @@ case 1: /* Dynamic Allocation (Dynamic_Allocation_t) */ if (ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.Exist_UPLINK_TFI_ASSIGNMENT) ctx->phase2_alloc.ul_tfi = ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.UPLINK_TFI_ASSIGNMENT; - /* TODO: P0, PR_MODE, USF_GRANULARITY, RLC_DATA_BLOCKS_GRANTED, TBF_Starting_Time */ + /* TODO: P0, PR_MODE, USF_GRANULARITY, RLC_DATA_BLOCKS_GRANTED */ + ctx->tbf_starting_time_exists = ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.Exist_TBF_Starting_Time; + if (ctx->tbf_starting_time_exists) + ctx->tbf_starting_time = TBF_Starting_Frame_Number_to_fn(&ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.TBF_Starting_Time, + d->fn); switch (ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.UnionType) { case 0: /* Timeslot_Allocation_t */ ts_alloc = &ulass->u.PUA_GPRS_Struct.u.Dynamic_Allocation.u.Timeslot_Allocation[0]; @@ -271,6 +284,42 @@ ev_rx_ccch_imm_ass_ctx = data; if (handle_imm_ass(ctx, ev_rx_ccch_imm_ass_ctx) < 0) return; + if (ctx->tbf_starting_time_exists && + fn_cmp(ctx->tbf_starting_time, ev_rx_ccch_imm_ass_ctx->fn) > 0) { + tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1); + return; + } + if (ctx->ass_type == GPRS_RLCMAC_TBF_UL_ASS_TYPE_1PHASE) + tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL); + else + tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ); + break; + default: + OSMO_ASSERT(0); + } +} + +static void st_wait_tbf_starting_time1(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *)fi->priv; + const struct tbf_ul_ass_ev_rx_ccch_imm_ass_ctx *ev_rx_ccch_imm_ass_ctx; + + switch (event) { + case GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS: + ev_rx_ccch_imm_ass_ctx = data; + if (handle_imm_ass(ctx, ev_rx_ccch_imm_ass_ctx) < 0) + return; + if (ctx->tbf_starting_time_exists && + fn_cmp(ctx->tbf_starting_time, ev_rx_ccch_imm_ass_ctx->fn) > 0) { + tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1); + return; + } + if (ctx->ass_type == GPRS_RLCMAC_TBF_UL_ASS_TYPE_1PHASE) + tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL); + else + tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ); + break; + case GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME: if (ctx->ass_type == GPRS_RLCMAC_TBF_UL_ASS_TYPE_1PHASE) tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL); else @@ -317,7 +366,11 @@ gprs_rlcmac_pdch_ulc_reserve(g_ctx->sched.ulc[d->ts_nr], poll_fn, GPRS_RLCMAC_PDCH_ULC_POLL_UL_ASS, ul_tbf_as_tbf(ctx->ul_tbf)); - tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK); + } + + if (ctx->tbf_starting_time_exists && + fn_cmp(ctx->tbf_starting_time, d->fn) > 0) { + tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2); } else { tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL); } @@ -327,17 +380,34 @@ } }
-static void st_sched_pkt_ctrl_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data) +static void st_wait_tbf_starting_time2(struct osmo_fsm_inst *fi, uint32_t event, void *data) { struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = (struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *)fi->priv; - struct tbf_ul_ass_ev_create_rlcmac_msg_ctx *data_ctx; + struct tbf_ul_ass_ev_rx_pkt_ul_ass_ctx *d; + int rc;
switch (event) { - case GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG: - data_ctx = (struct tbf_ul_ass_ev_create_rlcmac_msg_ctx *)data; - data_ctx->msg = gprs_rlcmac_ul_tbf_create_pkt_ctrl_ack(ctx->ul_tbf); - if (!data_ctx->msg) - return; + case GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS: + d = data; + rc = handle_pkt_ul_ass(ctx, d); + if (rc < 0) + LOGPFSML(fi, LOGL_ERROR, "Rx Pkt Ul Ass: failed to parse!\n"); + // TODO: what to do if Pkt_ul_ass is "reject"? need to check spec, depending on cause. + /* If RRBP contains valid data, schedule a response (PKT CONTROL ACK or PKT RESOURCE REQ). */ + if (d->dl_block->SP) { + uint32_t poll_fn = rrbp2fn(d->fn, d->dl_block->RRBP); + gprs_rlcmac_pdch_ulc_reserve(g_ctx->sched.ulc[d->ts_nr], poll_fn, + GPRS_RLCMAC_PDCH_ULC_POLL_UL_ASS, + ul_tbf_as_tbf(ctx->ul_tbf)); + } + + if (ctx->tbf_starting_time_exists && + fn_cmp(ctx->tbf_starting_time, d->fn) > 0) { + tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2); + } else { + tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL); + } + case GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME: tbf_ul_ass_fsm_state_chg(fi, GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL); break; default: @@ -378,11 +448,23 @@ .in_event_mask = X(GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS), .out_state_mask = + X(GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1) | X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ) | X(GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL), .name = "WAIT_CCCH_IMM_ASS", .action = st_wait_ccch_imm_ass, }, + [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1] = { + .in_event_mask = + X(GPRS_RLCMAC_TBF_UL_ASS_EV_RX_CCCH_IMM_ASS) | + X(GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME), + .out_state_mask = + X(GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1) | + X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ) | + X(GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL), + .name = "WAIT_TBF_STARTING_TIME1", + .action = st_wait_tbf_starting_time1, + }, [GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ] = { .in_event_mask = X(GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG), @@ -396,18 +478,21 @@ X(GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS), .out_state_mask = X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ) | - X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK) | + X(GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2) | X(GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL), .name = "WAIT_PKT_UL_ASS", .action = st_wait_pkt_ul_ass, }, - [GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_CTRL_ACK] = { + [GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2] = { .in_event_mask = - X(GPRS_RLCMAC_TBF_UL_ASS_EV_CREATE_RLCMAC_MSG), + X(GPRS_RLCMAC_TBF_UL_ASS_EV_RX_PKT_UL_ASS) | + X(GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME), .out_state_mask = + X(GPRS_RLCMAC_TBF_UL_ASS_ST_SCHED_PKT_RES_REQ) | + X(GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2) | X(GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL), - .name = "SCHED_PKT_CTRL_ACK", - .action = st_sched_pkt_ctrl_ack, + .name = "WAIT_TBF_STARTING_TIME2", + .action = st_wait_tbf_starting_time2, }, [GPRS_RLCMAC_TBF_UL_ASS_ST_COMPL] = { .in_event_mask = 0, @@ -539,6 +624,23 @@ ul_tbf->ul_ass_fsm.rach_req_ra == ra; }
+bool gprs_rlcmac_tbf_ul_ass_waiting_tbf_starting_time(const struct gprs_rlcmac_ul_tbf *ul_tbf) +{ + return ul_tbf->ul_ass_fsm.fi->state == GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME1 || + ul_tbf->ul_ass_fsm.fi->state == GPRS_RLCMAC_TBF_UL_ASS_ST_WAIT_TBF_STARTING_TIME2; +} + +/* The scheduled ticks the new FN, which may trigger changes internally if TBF Starting Time is reached */ +void gprs_rlcmac_tbf_ul_ass_fn_tick(const struct gprs_rlcmac_ul_tbf *ul_tbf, uint32_t fn, uint8_t ts_nr) +{ + OSMO_ASSERT(gprs_rlcmac_tbf_ul_ass_waiting_tbf_starting_time(ul_tbf)); + OSMO_ASSERT(ul_tbf->ul_ass_fsm.tbf_starting_time_exists); + if (fn != ul_tbf->ul_ass_fsm.tbf_starting_time) + return; + + osmo_fsm_inst_dispatch(ul_tbf->ul_ass_fsm.fi, GPRS_RLCMAC_TBF_UL_ASS_EV_TBF_STARTING_TIME, NULL); +} + enum gprs_rlcmac_tbf_ul_ass_fsm_states gprs_rlcmac_tbf_ul_ass_state(const struct gprs_rlcmac_ul_tbf *ul_tbf) { const struct gprs_rlcmac_tbf_ul_ass_fsm_ctx *ctx = &ul_tbf->ul_ass_fsm; diff --git a/tests/rlcmac/rlcmac_prim_test.err b/tests/rlcmac/rlcmac_prim_test.err index af14349..5d997dd 100644 --- a/tests/rlcmac/rlcmac_prim_test.err +++ b/tests/rlcmac/rlcmac_prim_test.err @@ -659,16 +659,14 @@ DLGLOBAL INFO TS=7 FN=26 Rx Pkt UL ASS DLGLOBAL INFO UL_TBF_ASS{WAIT_PKT_UL_ASS}: Received Event RX_PKT_UL_ASS DLGLOBAL DEBUG Register POLL (TS=7 FN=43, reason=UL_ASS) -DLGLOBAL INFO UL_TBF_ASS{WAIT_PKT_UL_ASS}: state_chg to SCHED_PKT_CTRL_ACK -DLGLOBAL DEBUG Rx from lower layers: L1CTL-PDCH_RTS.indication -DLGLOBAL INFO UL_TBF_ASS{SCHED_PKT_CTRL_ACK}: Received Event CREATE_RLCMAC_MSG -DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) Tx Packet Control Ack -DLGLOBAL INFO UL_TBF_ASS{SCHED_PKT_CTRL_ACK}: state_chg to COMPLETED +DLGLOBAL INFO UL_TBF_ASS{WAIT_PKT_UL_ASS}: state_chg to COMPLETED DLGLOBAL INFO UL_TBF{ASSIGN}: Received Event UL_ASS_COMPL DLGLOBAL INFO UL_TBF{ASSIGN}: Send L1CTL-CF_UL_TBF.req ul_slotmask=0xc0 DLGLOBAL INFO UL_TBF{ASSIGN}: state_chg to FLOW DLGLOBAL INFO UL_TBF_ASS{COMPLETED}: state_chg to IDLE DLGLOBAL DEBUG Rx from lower layers: L1CTL-PDCH_RTS.indication +DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) Tx Packet Control Ack +DLGLOBAL DEBUG Rx from lower layers: L1CTL-PDCH_RTS.indication DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) Sending new block at BSN 0, CS=CS-2 DLGLOBAL DEBUG TBF(UL:NR-0:TLLI-00000001) Dequeue next LLC (len=14) DLGLOBAL DEBUG -- Chunk with length 14 is less than remaining space (30): add length header to delimit LLC frame