Implement downgrade to DL MCS1-4 when USF for GPRS_only MS

In previous status, if USF for GPRS-only MS was selected, then EGPRS
TBFs were skipped and either a GPRS TBF was selected or a Dummy Block
was sent. That means the behavior was unfair towards EGPRS TBFs, because
sometimes they were skipped in favor of GPRS ones.
This patch imporves the situation in the above mentioned USF scenario, by
first, under specific conditions, allowing selection of an EGPRS TBF and
then forcing it to transmit in EGPRS-GMSK (MCS1-4) so that the
USF-targeted MS can still decode the USF, while at the same time
providing more fairness by allowing the EGPRS TBF to transmit data.

The specific conditions mentioned above are, mainly, related to the fact
that once a DL data block has been sent, and hence a BSN was assigned to
it, it cannot be retransmitted later using another MCS, since lower
MCS1-4 wouldn't be able to contain higher MCS RLC payload.

The set of conditions could be expanded in the future by also selecting
the EGPRS TBF if retransmition is required and the block to be
retransmitted was originally transmitted as MCS1-4.

Related: OS#4544
Change-Id: I9af23e175435fe9ae7b0e4119ad52fcd4707b9ca
This commit is contained in:
Pau Espin 2020-11-16 18:49:39 +01:00 committed by laforge
parent 7fd9a29eba
commit 022f9e56e5
6 changed files with 463 additions and 431 deletions

View File

@ -1123,6 +1123,17 @@ void BTS::set_max_mcs_ul(uint8_t mcs_ul)
m_max_mcs_ul = mcs_ul;
}
bool BTS::cs_dl_is_supported(CodingScheme cs)
{
OSMO_ASSERT(mcs_is_valid(cs));
uint8_t num = mcs_chan_code(cs);
if (mcs_is_gprs(cs)) {
return (max_cs_dl() >= num) && (m_bts.cs_mask & (1U << num));
} else {
return (max_mcs_dl() >= num) && (m_bts.mcs_mask & (1U << num));
}
}
GprsMs *BTS::ms_alloc(uint8_t ms_class, uint8_t egprs_ms_class)
{
GprsMs *ms;

View File

@ -339,6 +339,7 @@ public:
void set_max_cs_ul(uint8_t cs_ul);
void set_max_mcs_dl(uint8_t mcs_dl);
void set_max_mcs_ul(uint8_t mcs_ul);
bool cs_dl_is_supported(CodingScheme cs);
GprsMsStorage &ms_store();
GprsMs *ms_by_tlli(uint32_t tlli, uint32_t old_tlli = GSM_RESERVED_TMSI);

View File

@ -305,9 +305,6 @@ static struct msgb *sched_select_downlink(struct gprs_rlcmac_bts *bts,
/* If a GPRS (CS1-4) Dl block is required, skip EGPRS(_GSMK) tbfs: */
if (req_mcs_kind == GPRS && tbf->is_egprs_enabled())
continue;
/* TODO: If a GPRS (CS1-4/MCS1-4) Dl block is required, downgrade MCS below instead of skipping */
if (req_mcs_kind == EGPRS_GMSK && (tbf->is_egprs_enabled() || tbf->ms()->mode() != GPRS))
continue;
age = tbf->frames_since_last_poll(fn);
@ -316,6 +313,15 @@ static struct msgb *sched_select_downlink(struct gprs_rlcmac_bts *bts,
if (prio == DL_PRIO_NONE)
continue;
/* If a GPRS (CS1-4/MCS1-4) Dl block is required, downgrade MCS
* below instead of skipping. However, downgrade can only be
* done on new data BSNs (not yet sent) and control blocks. */
if (req_mcs_kind == EGPRS_GMSK && tbf->is_egprs_enabled() &&
(prio !=DL_PRIO_CONTROL && prio != DL_PRIO_NEW_DATA)) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Cannot downgrade EGPRS TBF with prio %d\n", prio);
continue;
}
/* get the TBF with the highest priority */
if (prio > max_prio) {
prio_tfi = tfi;
@ -326,12 +332,12 @@ static struct msgb *sched_select_downlink(struct gprs_rlcmac_bts *bts,
if (prio_tbf) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling data message at "
"RTS for DL TFI=%d (TRX=%d, TS=%d) prio=%d\n",
prio_tfi, trx, ts, max_prio);
"RTS for DL TFI=%d (TRX=%d, TS=%d) prio=%d mcs_mode_restrict=%s\n",
prio_tfi, trx, ts, max_prio, mode_name(req_mcs_kind));
/* next TBF to handle resource is the next one */
pdch->next_dl_tfi = (prio_tfi + 1) & 31;
/* generate DL data block */
msg = prio_tbf->create_dl_acked_block(fn, ts);
msg = prio_tbf->create_dl_acked_block(fn, ts, req_mcs_kind);
*is_egprs = prio_tbf->ms()->mode() != GPRS;
}

View File

@ -442,7 +442,7 @@ bool gprs_rlcmac_dl_tbf::restart_bsn_cycle()
}
int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
int previous_bsn, bool *may_combine)
int previous_bsn, enum mcs_kind req_mcs_kind, bool *may_combine)
{
int bsn;
int data_len2, force_data_len = -1;
@ -456,6 +456,19 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
if (!mcs_is_edge(force_cs))
return -1;
force_data_len = m_rlc.block(previous_bsn)->len;
} else if (bsn < 0 && is_egprs_enabled() && req_mcs_kind == EGPRS_GMSK) {
/* New data to be sent for EGPRS TBF but we are required to downgrade to
* MCS1-4, because USF for GPRS-only MS will be sent */
force_cs = m_ms->current_cs_dl();
if (force_cs > MCS4) {
force_cs = bts->cs_dl_is_supported(MCS4) ? MCS4 :
bts->cs_dl_is_supported(MCS3) ? MCS3 :
bts->cs_dl_is_supported(MCS2) ? MCS2 :
MCS1;
LOGPTBFDL(this, LOGL_DEBUG,
"Force downgrading DL %s -> %s due to USF for GPRS-only MS\n",
mcs_name(m_ms->current_cs_dl()), mcs_name(force_cs));
}
}
if (bsn >= 0) {
@ -510,7 +523,7 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
m_window.v_a());
bts->do_rate_ctr_inc(CTR_RLC_RESTARTED);
if (restart_bsn_cycle())
return take_next_bsn(fn, previous_bsn, may_combine);
return take_next_bsn(fn, previous_bsn, req_mcs_kind, may_combine);
} else if (dl_window_stalled()) {
/* There are no more packages to send, but the window is stalled.
* Restart the bsn_cycle to resend all unacked messages */
@ -519,14 +532,15 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
m_window.v_a());
bts->do_rate_ctr_inc(CTR_RLC_STALLED);
if (restart_bsn_cycle())
return take_next_bsn(fn, previous_bsn, may_combine);
return take_next_bsn(fn, previous_bsn, req_mcs_kind, may_combine);
} else if (have_data()) {
/* The window has space left, generate new bsn */
enum CodingScheme new_cs;
new_cs = force_cs ? force_cs : current_cs();
LOGPTBFDL(this, LOGL_DEBUG,
"Sending new block at BSN %d, CS=%s\n",
m_window.v_s(), mcs_name(new_cs));
"Sending new block at BSN %d, CS=%s%s\n",
m_window.v_s(), mcs_name(new_cs),
force_cs ? " (forced)" : "");
bsn = create_new_bsn(fn, new_cs);
} else if (bts->bts_data()->dl_tbf_preemptive_retransmission && !m_window.window_empty()) {
@ -537,7 +551,7 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
m_window.v_a());
bts->do_rate_ctr_inc(CTR_RLC_RESTARTED);
if (restart_bsn_cycle())
return take_next_bsn(fn, previous_bsn, may_combine);
return take_next_bsn(fn, previous_bsn, req_mcs_kind, may_combine);
} else {
/* Nothing left to send, create dummy LLC commands */
LOGPTBFDL(this, LOGL_DEBUG,
@ -565,20 +579,20 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
* Create DL data block
* The messages are fragmented and forwarded as data blocks.
*/
struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(uint32_t fn, uint8_t ts)
struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(uint32_t fn, uint8_t ts, enum mcs_kind req_mcs_kind)
{
int bsn, bsn2 = -1;
bool may_combine;
LOGPTBFDL(this, LOGL_DEBUG, "downlink (V(A)==%d .. V(S)==%d)\n",
m_window.v_a(), m_window.v_s());
LOGPTBFDL(this, LOGL_DEBUG, "downlink (V(A)==%d .. V(S)==%d) mcs_mode_restrict=%s\n",
m_window.v_a(), m_window.v_s(), mode_name(req_mcs_kind));
bsn = take_next_bsn(fn, -1, &may_combine);
bsn = take_next_bsn(fn, -1, req_mcs_kind, &may_combine);
if (bsn < 0)
return NULL;
if (may_combine)
bsn2 = take_next_bsn(fn, bsn, &may_combine);
bsn2 = take_next_bsn(fn, bsn, req_mcs_kind, &may_combine);
return create_dl_acked_block(fn, ts, bsn, bsn2);
}

View File

@ -54,7 +54,7 @@ struct gprs_rlcmac_dl_tbf : public gprs_rlcmac_tbf {
int rcvd_dl_ack(bool final, uint8_t ssn, uint8_t *rbb);
int rcvd_dl_ack(bool final_ack, unsigned first_bsn, struct bitvec *rbb);
struct msgb *create_dl_acked_block(uint32_t fn, uint8_t ts);
struct msgb *create_dl_acked_block(uint32_t fn, uint8_t ts, enum mcs_kind req_mcs_kind = EGPRS);
void trigger_ass(struct gprs_rlcmac_tbf *old_tbf);
bool handle_ack_nack();
@ -106,8 +106,8 @@ protected:
unsigned lost_bytes;
};
int take_next_bsn(uint32_t fn, int previous_bsn,
bool *may_combine);
int take_next_bsn(uint32_t fn, int previous_bsn, enum mcs_kind req_mcs_kind,
bool *may_combine);
bool restart_bsn_cycle();
int create_new_bsn(const uint32_t fn, enum CodingScheme cs);
struct msgb *create_dl_acked_block(const uint32_t fn, const uint8_t ts,

File diff suppressed because it is too large Load Diff