18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 2009-2012 Realtek Corporation.*/ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "wifi.h" 58c2ecf20Sopenharmony_ci#include "base.h" 68c2ecf20Sopenharmony_ci#include "rc.h" 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci *Finds the highest rate index we can use 108c2ecf20Sopenharmony_ci *if skb is special data like DHCP/EAPOL, we set should 118c2ecf20Sopenharmony_ci *it to lowest rate CCK_1M, otherwise we set rate to 128c2ecf20Sopenharmony_ci *highest rate based on wireless mode used for iwconfig 138c2ecf20Sopenharmony_ci *show Tx rate. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_cistatic u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, 168c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 178c2ecf20Sopenharmony_ci struct sk_buff *skb, bool not_data) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct rtl_hal *rtlhal = rtl_hal(rtlpriv); 208c2ecf20Sopenharmony_ci struct rtl_phy *rtlphy = &(rtlpriv->phy); 218c2ecf20Sopenharmony_ci struct rtl_sta_info *sta_entry = NULL; 228c2ecf20Sopenharmony_ci u16 wireless_mode = 0; 238c2ecf20Sopenharmony_ci u8 nss; 248c2ecf20Sopenharmony_ci struct ieee80211_tx_rate rate; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci switch (get_rf_type(rtlphy)) { 278c2ecf20Sopenharmony_ci case RF_4T4R: 288c2ecf20Sopenharmony_ci nss = 4; 298c2ecf20Sopenharmony_ci break; 308c2ecf20Sopenharmony_ci case RF_3T3R: 318c2ecf20Sopenharmony_ci nss = 3; 328c2ecf20Sopenharmony_ci break; 338c2ecf20Sopenharmony_ci case RF_2T2R: 348c2ecf20Sopenharmony_ci nss = 2; 358c2ecf20Sopenharmony_ci break; 368c2ecf20Sopenharmony_ci default: 378c2ecf20Sopenharmony_ci nss = 1; 388c2ecf20Sopenharmony_ci break; 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* 428c2ecf20Sopenharmony_ci *this rate is no use for true rate, firmware 438c2ecf20Sopenharmony_ci *will control rate at all it just used for 448c2ecf20Sopenharmony_ci *1.show in iwconfig in B/G mode 458c2ecf20Sopenharmony_ci *2.in rtl_get_tcb_desc when we check rate is 468c2ecf20Sopenharmony_ci * 1M we will not use FW rate but user rate. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (sta) { 508c2ecf20Sopenharmony_ci sta_entry = (struct rtl_sta_info *)sta->drv_priv; 518c2ecf20Sopenharmony_ci wireless_mode = sta_entry->wireless_mode; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true, false) || 558c2ecf20Sopenharmony_ci not_data) { 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci } else { 588c2ecf20Sopenharmony_ci if (rtlhal->current_bandtype == BAND_ON_2_4G) { 598c2ecf20Sopenharmony_ci if (wireless_mode == WIRELESS_MODE_B) { 608c2ecf20Sopenharmony_ci return B_MODE_MAX_RIX; 618c2ecf20Sopenharmony_ci } else if (wireless_mode == WIRELESS_MODE_G) { 628c2ecf20Sopenharmony_ci return G_MODE_MAX_RIX; 638c2ecf20Sopenharmony_ci } else if (wireless_mode == WIRELESS_MODE_N_24G) { 648c2ecf20Sopenharmony_ci if (nss == 1) 658c2ecf20Sopenharmony_ci return N_MODE_MCS7_RIX; 668c2ecf20Sopenharmony_ci else 678c2ecf20Sopenharmony_ci return N_MODE_MCS15_RIX; 688c2ecf20Sopenharmony_ci } else if (wireless_mode == WIRELESS_MODE_AC_24G) { 698c2ecf20Sopenharmony_ci if (sta->bandwidth == IEEE80211_STA_RX_BW_20) { 708c2ecf20Sopenharmony_ci ieee80211_rate_set_vht(&rate, 718c2ecf20Sopenharmony_ci AC_MODE_MCS8_RIX, 728c2ecf20Sopenharmony_ci nss); 738c2ecf20Sopenharmony_ci goto out; 748c2ecf20Sopenharmony_ci } else { 758c2ecf20Sopenharmony_ci ieee80211_rate_set_vht(&rate, 768c2ecf20Sopenharmony_ci AC_MODE_MCS9_RIX, 778c2ecf20Sopenharmony_ci nss); 788c2ecf20Sopenharmony_ci goto out; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci } else { 838c2ecf20Sopenharmony_ci if (wireless_mode == WIRELESS_MODE_A) { 848c2ecf20Sopenharmony_ci return A_MODE_MAX_RIX; 858c2ecf20Sopenharmony_ci } else if (wireless_mode == WIRELESS_MODE_N_5G) { 868c2ecf20Sopenharmony_ci if (nss == 1) 878c2ecf20Sopenharmony_ci return N_MODE_MCS7_RIX; 888c2ecf20Sopenharmony_ci else 898c2ecf20Sopenharmony_ci return N_MODE_MCS15_RIX; 908c2ecf20Sopenharmony_ci } else if (wireless_mode == WIRELESS_MODE_AC_5G) { 918c2ecf20Sopenharmony_ci if (sta->bandwidth == IEEE80211_STA_RX_BW_20) { 928c2ecf20Sopenharmony_ci ieee80211_rate_set_vht(&rate, 938c2ecf20Sopenharmony_ci AC_MODE_MCS8_RIX, 948c2ecf20Sopenharmony_ci nss); 958c2ecf20Sopenharmony_ci goto out; 968c2ecf20Sopenharmony_ci } else { 978c2ecf20Sopenharmony_ci ieee80211_rate_set_vht(&rate, 988c2ecf20Sopenharmony_ci AC_MODE_MCS9_RIX, 998c2ecf20Sopenharmony_ci nss); 1008c2ecf20Sopenharmony_ci goto out; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ciout: 1088c2ecf20Sopenharmony_ci return rate.idx; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, 1128c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 1138c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rate, 1148c2ecf20Sopenharmony_ci struct ieee80211_tx_rate_control *txrc, 1158c2ecf20Sopenharmony_ci u8 tries, s8 rix, int rtsctsenable, 1168c2ecf20Sopenharmony_ci bool not_data) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct rtl_mac *mac = rtl_mac(rtlpriv); 1198c2ecf20Sopenharmony_ci struct rtl_sta_info *sta_entry = NULL; 1208c2ecf20Sopenharmony_ci u16 wireless_mode = 0; 1218c2ecf20Sopenharmony_ci u8 sgi_20 = 0, sgi_40 = 0, sgi_80 = 0; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (sta) { 1248c2ecf20Sopenharmony_ci sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; 1258c2ecf20Sopenharmony_ci sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; 1268c2ecf20Sopenharmony_ci sgi_80 = sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80; 1278c2ecf20Sopenharmony_ci sta_entry = (struct rtl_sta_info *)sta->drv_priv; 1288c2ecf20Sopenharmony_ci wireless_mode = sta_entry->wireless_mode; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci rate->count = tries; 1318c2ecf20Sopenharmony_ci rate->idx = rix >= 0x00 ? rix : 0x00; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (!not_data) { 1348c2ecf20Sopenharmony_ci if (txrc->short_preamble) 1358c2ecf20Sopenharmony_ci rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; 1368c2ecf20Sopenharmony_ci if (mac->opmode == NL80211_IFTYPE_AP || 1378c2ecf20Sopenharmony_ci mac->opmode == NL80211_IFTYPE_ADHOC) { 1388c2ecf20Sopenharmony_ci if (sta && (sta->ht_cap.cap & 1398c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_SUP_WIDTH_20_40)) 1408c2ecf20Sopenharmony_ci rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; 1418c2ecf20Sopenharmony_ci if (sta && sta->vht_cap.vht_supported) 1428c2ecf20Sopenharmony_ci rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; 1438c2ecf20Sopenharmony_ci } else { 1448c2ecf20Sopenharmony_ci if (mac->bw_80) 1458c2ecf20Sopenharmony_ci rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; 1468c2ecf20Sopenharmony_ci else if (mac->bw_40) 1478c2ecf20Sopenharmony_ci rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (sgi_20 || sgi_40 || sgi_80) 1518c2ecf20Sopenharmony_ci rate->flags |= IEEE80211_TX_RC_SHORT_GI; 1528c2ecf20Sopenharmony_ci if (sta && sta->ht_cap.ht_supported && 1538c2ecf20Sopenharmony_ci (wireless_mode == WIRELESS_MODE_N_5G || 1548c2ecf20Sopenharmony_ci wireless_mode == WIRELESS_MODE_N_24G)) 1558c2ecf20Sopenharmony_ci rate->flags |= IEEE80211_TX_RC_MCS; 1568c2ecf20Sopenharmony_ci if (sta && sta->vht_cap.vht_supported && 1578c2ecf20Sopenharmony_ci (wireless_mode == WIRELESS_MODE_AC_5G || 1588c2ecf20Sopenharmony_ci wireless_mode == WIRELESS_MODE_AC_24G || 1598c2ecf20Sopenharmony_ci wireless_mode == WIRELESS_MODE_AC_ONLY)) 1608c2ecf20Sopenharmony_ci rate->flags |= IEEE80211_TX_RC_VHT_MCS; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta, 1658c2ecf20Sopenharmony_ci void *priv_sta, 1668c2ecf20Sopenharmony_ci struct ieee80211_tx_rate_control *txrc) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = ppriv; 1698c2ecf20Sopenharmony_ci struct sk_buff *skb = txrc->skb; 1708c2ecf20Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 1718c2ecf20Sopenharmony_ci struct ieee80211_tx_rate *rates = tx_info->control.rates; 1728c2ecf20Sopenharmony_ci __le16 fc = rtl_get_fc(skb); 1738c2ecf20Sopenharmony_ci u8 try_per_rate, i, rix; 1748c2ecf20Sopenharmony_ci bool not_data = !ieee80211_is_data(fc); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data); 1778c2ecf20Sopenharmony_ci try_per_rate = 1; 1788c2ecf20Sopenharmony_ci _rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc, 1798c2ecf20Sopenharmony_ci try_per_rate, rix, 1, not_data); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (!not_data) { 1828c2ecf20Sopenharmony_ci for (i = 1; i < 4; i++) 1838c2ecf20Sopenharmony_ci _rtl_rc_rate_set_series(rtlpriv, sta, &rates[i], 1848c2ecf20Sopenharmony_ci txrc, i, (rix - i), 1, 1858c2ecf20Sopenharmony_ci not_data); 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, 1908c2ecf20Sopenharmony_ci struct rtl_sta_info *sta_entry, u16 tid) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct rtl_mac *mac = rtl_mac(rtlpriv); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (mac->act_scanning) 1958c2ecf20Sopenharmony_ci return false; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (mac->opmode == NL80211_IFTYPE_STATION && 1988c2ecf20Sopenharmony_ci mac->cnt_after_linked < 3) 1998c2ecf20Sopenharmony_ci return false; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP) 2028c2ecf20Sopenharmony_ci return true; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return false; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/*mac80211 Rate Control callbacks*/ 2088c2ecf20Sopenharmony_cistatic void rtl_tx_status(void *ppriv, 2098c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband, 2108c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, void *priv_sta, 2118c2ecf20Sopenharmony_ci struct sk_buff *skb) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = ppriv; 2148c2ecf20Sopenharmony_ci struct rtl_mac *mac = rtl_mac(rtlpriv); 2158c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = rtl_get_hdr(skb); 2168c2ecf20Sopenharmony_ci __le16 fc = rtl_get_fc(skb); 2178c2ecf20Sopenharmony_ci struct rtl_sta_info *sta_entry; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (!priv_sta || !ieee80211_is_data(fc)) 2208c2ecf20Sopenharmony_ci return; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (rtl_is_special_data(mac->hw, skb, true, true)) 2238c2ecf20Sopenharmony_ci return; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || 2268c2ecf20Sopenharmony_ci is_broadcast_ether_addr(ieee80211_get_DA(hdr))) 2278c2ecf20Sopenharmony_ci return; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (sta) { 2308c2ecf20Sopenharmony_ci /* Check if aggregation has to be enabled for this tid */ 2318c2ecf20Sopenharmony_ci sta_entry = (struct rtl_sta_info *)sta->drv_priv; 2328c2ecf20Sopenharmony_ci if (sta->ht_cap.ht_supported && 2338c2ecf20Sopenharmony_ci !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { 2348c2ecf20Sopenharmony_ci if (ieee80211_is_data_qos(fc)) { 2358c2ecf20Sopenharmony_ci u8 tid = rtl_get_tid(skb); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (_rtl_tx_aggr_check(rtlpriv, sta_entry, 2388c2ecf20Sopenharmony_ci tid)) { 2398c2ecf20Sopenharmony_ci sta_entry->tids[tid].agg.agg_state = 2408c2ecf20Sopenharmony_ci RTL_AGG_PROGRESS; 2418c2ecf20Sopenharmony_ci ieee80211_start_tx_ba_session(sta, tid, 2428c2ecf20Sopenharmony_ci 5000); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic void rtl_rate_init(void *ppriv, 2508c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband, 2518c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef, 2528c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, void *priv_sta) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic void rtl_rate_update(void *ppriv, 2578c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband, 2588c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef, 2598c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, void *priv_sta, 2608c2ecf20Sopenharmony_ci u32 changed) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic void *rtl_rate_alloc(struct ieee80211_hw *hw) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = rtl_priv(hw); 2678c2ecf20Sopenharmony_ci return rtlpriv; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void rtl_rate_free(void *rtlpriv) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci return; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void *rtl_rate_alloc_sta(void *ppriv, 2768c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, gfp_t gfp) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct rtl_priv *rtlpriv = ppriv; 2798c2ecf20Sopenharmony_ci struct rtl_rate_priv *rate_priv; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci rate_priv = kzalloc(sizeof(*rate_priv), gfp); 2828c2ecf20Sopenharmony_ci if (!rate_priv) 2838c2ecf20Sopenharmony_ci return NULL; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci rtlpriv->rate_priv = rate_priv; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return rate_priv; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void rtl_rate_free_sta(void *rtlpriv, 2918c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, void *priv_sta) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct rtl_rate_priv *rate_priv = priv_sta; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci kfree(rate_priv); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic const struct rate_control_ops rtl_rate_ops = { 2998c2ecf20Sopenharmony_ci .name = "rtl_rc", 3008c2ecf20Sopenharmony_ci .alloc = rtl_rate_alloc, 3018c2ecf20Sopenharmony_ci .free = rtl_rate_free, 3028c2ecf20Sopenharmony_ci .alloc_sta = rtl_rate_alloc_sta, 3038c2ecf20Sopenharmony_ci .free_sta = rtl_rate_free_sta, 3048c2ecf20Sopenharmony_ci .rate_init = rtl_rate_init, 3058c2ecf20Sopenharmony_ci .rate_update = rtl_rate_update, 3068c2ecf20Sopenharmony_ci .tx_status = rtl_tx_status, 3078c2ecf20Sopenharmony_ci .get_rate = rtl_get_rate, 3088c2ecf20Sopenharmony_ci}; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ciint rtl_rate_control_register(void) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci return ieee80211_rate_control_register(&rtl_rate_ops); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_civoid rtl_rate_control_unregister(void) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci ieee80211_rate_control_unregister(&rtl_rate_ops); 3188c2ecf20Sopenharmony_ci} 319