From: Sam Chapman mmrc_feedback() walks the returned retry chain using the total attempt count and unconditionally credits one success to the rate the walk ends on. A frame that exhausted the whole chain without being acknowledged is therefore recorded as a success on its final rate, inflating the success probability of fallback rates and leads to misinformed future rate selections. To fix, make sure we only count a success if the frame was acked to prevent failing rates from being picked when they shouldn't be. Signed-off-by: Sam Chapman Signed-off-by: Lachlan Hodges --- drivers/net/wireless/morsemicro/mm81x/mmrc.c | 47 ++++++++++---------- drivers/net/wireless/morsemicro/mm81x/mmrc.h | 2 +- drivers/net/wireless/morsemicro/mm81x/rc.c | 14 +++--- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/morsemicro/mm81x/mmrc.c b/drivers/net/wireless/morsemicro/mm81x/mmrc.c index 6bedcdbcb61f..3f87b50ce391 100644 --- a/drivers/net/wireless/morsemicro/mm81x/mmrc.c +++ b/drivers/net/wireless/morsemicro/mm81x/mmrc.c @@ -1212,37 +1212,38 @@ void mmrc_update(struct mmrc_table *tb) } void mmrc_feedback(struct mmrc_table *tb, struct mmrc_rate_table *rates, - s32 retry_count, bool was_aggregated) + bool was_aggregated, bool was_acked) { - s32 ind = retry_count; + s32 last_index = -1; u32 i; + /* + * Every attempt reported by the firmware is accounted as sent. Only + * the final attempt of an acknowledged frame counts as a success; a + * frame that exhausted its retry chain must not credit the last rate. + */ for (i = 0; i < MMRC_MAX_CHAIN_LENGTH; i++) { + if (!rates->rates[i].attempts) + break; + rate_update_index(tb, &rates->rates[i]); tb->table[rates->rates[i].index].have_sent_ampdus |= was_aggregated; - - if ((s32)rates->rates[i].attempts < ind) { - ind = ind - rates->rates[i].attempts; - tb->table[rates->rates[i].index].sent += + tb->table[rates->rates[i].index].sent += + rates->rates[i].attempts; + if (was_aggregated) + tb->table[rates->rates[i].index].back_mpdu_failure += rates->rates[i].attempts; - if (was_aggregated) { - tb->table[rates->rates[i].index] - .back_mpdu_failure += - rates->rates[i].attempts; - } - } else { - tb->table[rates->rates[i].index].sent += ind; - tb->table[rates->rates[i].index].sent_success += 1; - if (was_aggregated) { - tb->table[rates->rates[i].index] - .back_mpdu_success += 1; - tb->table[rates->rates[i].index] - .back_mpdu_failure += - ind > 1 ? ind - 1 : 0; - } - return; - } + last_index = i; + } + + if (last_index < 0 || !was_acked) + return; + + tb->table[rates->rates[last_index].index].sent_success += 1; + if (was_aggregated) { + tb->table[rates->rates[last_index].index].back_mpdu_success += 1; + tb->table[rates->rates[last_index].index].back_mpdu_failure -= 1; } } diff --git a/drivers/net/wireless/morsemicro/mm81x/mmrc.h b/drivers/net/wireless/morsemicro/mm81x/mmrc.h index a4c7d941ad55..f4a90a50e4bf 100644 --- a/drivers/net/wireless/morsemicro/mm81x/mmrc.h +++ b/drivers/net/wireless/morsemicro/mm81x/mmrc.h @@ -184,7 +184,7 @@ size_t mmrc_memory_required_for_caps(struct mmrc_sta_capabilities *caps); void mmrc_get_rates(struct mmrc_table *tb, struct mmrc_rate_table *out, size_t size); void mmrc_feedback(struct mmrc_table *tb, struct mmrc_rate_table *rates, - s32 retry_count, bool was_aggregated); + bool was_aggregated, bool was_acked); void mmrc_update(struct mmrc_table *tb); bool mmrc_set_fixed_rate(struct mmrc_table *tb, struct mmrc_rate fixed_rate); u32 mmrc_calculate_theoretical_throughput(struct mmrc_rate rate); diff --git a/drivers/net/wireless/morsemicro/mm81x/rc.c b/drivers/net/wireless/morsemicro/mm81x/rc.c index 28dd293df966..c1a334f7846c 100644 --- a/drivers/net/wireless/morsemicro/mm81x/rc.c +++ b/drivers/net/wireless/morsemicro/mm81x/rc.c @@ -341,8 +341,8 @@ void mm81x_rc_sta_fill_tx_rates(struct mm81x *mors, } static void mm81x_rc_sta_set_rates(struct mm81x *mors, struct mm81x_sta *msta, - struct mmrc_rate_table *rates, int attempts, - bool was_aggregated) + struct mmrc_rate_table *rates, + bool was_aggregated, bool was_acked) { struct list_head *pos; @@ -352,8 +352,8 @@ static void mm81x_rc_sta_set_rates(struct mm81x *mors, struct mm81x_sta *msta, list_entry(pos, struct mm81x_rc_sta, list); if (&msta->rc == mrc_sta) { - mmrc_feedback(msta->rc.tb, rates, attempts, - was_aggregated); + mmrc_feedback(msta->rc.tb, rates, was_aggregated, + was_acked); break; } } @@ -410,9 +410,11 @@ void mm81x_rc_sta_feedback_rates(struct mm81x *mors, struct sk_buff *skb, msta->last_sta_tx_rate.guard = rates.rates[0].guard; } - mm81x_rc_sta_set_rates(mors, msta, &rates, attempts, + mm81x_rc_sta_set_rates(mors, msta, &rates, !!(le32_to_cpu(tx_sts->flags) & - MM81X_TX_STATUS_WAS_AGGREGATED)); + MM81X_TX_STATUS_WAS_AGGREGATED), + !(le32_to_cpu(tx_sts->flags) & + MM81X_TX_STATUS_FLAGS_NO_ACK)); ieee80211_sta_register_airtime(sta, tx_sts->tid, tx_airtime, 0); -- 2.43.0