diff --git a/drivers/net/wireless/silabs/wfx/data_tx.c b/drivers/net/wireless/silabs/wfx/data_tx.c index 6a5e52a96d18..caa22226b01b 100644 --- a/drivers/net/wireless/silabs/wfx/data_tx.c +++ b/drivers/net/wireless/silabs/wfx/data_tx.c @@ -226,53 +226,40 @@ static u8 wfx_tx_get_link_id(struct wfx_vif *wvif, struct ieee80211_sta *sta, static void wfx_tx_fixup_rates(struct ieee80211_tx_rate *rates) { - int i; - bool finished; + bool has_rate0 = false; + int i, j; - /* Firmware is not able to mix rates with different flags */ - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI) - rates[i].flags |= IEEE80211_TX_RC_SHORT_GI; - if (!(rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) + for (i = 1, j = 1; j < IEEE80211_TX_MAX_RATES; j++) { + if (rates[j].idx == -1) + break; + /* The device use the rates in descending order, whatever the request from minstrel. + * We have to trade off here. Most important is to respect the primary rate + * requested by minstrel. So, we drops the entries with rate higher than the + * previous. + */ + if (rates[j].idx >= rates[i - 1].idx) { + rates[i - 1].count += rates[j].count; + rates[i - 1].count = min_t(u16, 15, rates[i - 1].count); + } else { + memcpy(rates + i, rates + j, sizeof(rates[i])); + if (rates[i].idx == 0) + has_rate0 = true; + /* The device apply Short GI only on the first rate */ rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; - if (!(rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)) - rates[i].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; - } - - /* Sort rates and remove duplicates */ - do { - finished = true; - for (i = 0; i < IEEE80211_TX_MAX_RATES - 1; i++) { - if (rates[i + 1].idx == rates[i].idx && - rates[i].idx != -1) { - rates[i].count += rates[i + 1].count; - if (rates[i].count > 15) - rates[i].count = 15; - rates[i + 1].idx = -1; - rates[i + 1].count = 0; - - finished = false; - } - if (rates[i + 1].idx > rates[i].idx) { - swap(rates[i + 1], rates[i]); - finished = false; - } + i++; } - } while (!finished); + } /* Ensure that MCS0 or 1Mbps is present at the end of the retry list */ - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - if (rates[i].idx == 0) - break; - if (rates[i].idx == -1) { - rates[i].idx = 0; - rates[i].count = 8; /* == hw->max_rate_tries */ - rates[i].flags = rates[i - 1].flags & IEEE80211_TX_RC_MCS; - break; - } + if (!has_rate0 && i < IEEE80211_TX_MAX_RATES) { + rates[i].idx = 0; + rates[i].count = 8; /* == hw->max_rate_tries */ + rates[i].flags = rates[0].flags & IEEE80211_TX_RC_MCS; + i++; + } + for (; i < IEEE80211_TX_MAX_RATES; i++) { + memset(rates + i, 0, sizeof(rates[i])); + rates[i].idx = -1; } - /* All retries use long GI */ - for (i = 1; i < IEEE80211_TX_MAX_RATES; i++) - rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; } static u8 wfx_tx_get_retry_policy_id(struct wfx_vif *wvif, struct ieee80211_tx_info *tx_info)