diff options
Diffstat (limited to 'drivers/net/wireless/rtlwifi/rc.c')
-rw-r--r-- | drivers/net/wireless/rtlwifi/rc.c | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c new file mode 100644 index 000000000000..30da68a77786 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rc.c | |||
@@ -0,0 +1,291 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2009-2010 Realtek Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of version 2 of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in the | ||
19 | * file called LICENSE. | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * wlanfae <wlanfae@realtek.com> | ||
23 | * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, | ||
24 | * Hsinchu 300, Taiwan. | ||
25 | * | ||
26 | * Larry Finger <Larry.Finger@lwfinger.net> | ||
27 | * | ||
28 | *****************************************************************************/ | ||
29 | |||
30 | #include "wifi.h" | ||
31 | #include "base.h" | ||
32 | #include "rc.h" | ||
33 | |||
34 | /* | ||
35 | *Finds the highest rate index we can use | ||
36 | *if skb is special data like DHCP/EAPOL, we set should | ||
37 | *it to lowest rate CCK_1M, otherwise we set rate to | ||
38 | *CCK11M or OFDM_54M based on wireless mode. | ||
39 | */ | ||
40 | static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, | ||
41 | struct ieee80211_sta *sta, | ||
42 | struct sk_buff *skb, bool not_data) | ||
43 | { | ||
44 | struct rtl_mac *rtlmac = rtl_mac(rtlpriv); | ||
45 | struct rtl_hal *rtlhal = rtl_hal(rtlpriv); | ||
46 | struct rtl_phy *rtlphy = &(rtlpriv->phy); | ||
47 | struct rtl_sta_info *sta_entry = NULL; | ||
48 | u8 wireless_mode = 0; | ||
49 | |||
50 | /* | ||
51 | *this rate is no use for true rate, firmware | ||
52 | *will control rate at all it just used for | ||
53 | *1.show in iwconfig in B/G mode | ||
54 | *2.in rtl_get_tcb_desc when we check rate is | ||
55 | * 1M we will not use FW rate but user rate. | ||
56 | */ | ||
57 | if (rtlmac->opmode == NL80211_IFTYPE_AP || | ||
58 | rtlmac->opmode == NL80211_IFTYPE_ADHOC) { | ||
59 | if (sta) { | ||
60 | sta_entry = (struct rtl_sta_info *) sta->drv_priv; | ||
61 | wireless_mode = sta_entry->wireless_mode; | ||
62 | } else { | ||
63 | return 0; | ||
64 | } | ||
65 | } else { | ||
66 | wireless_mode = rtlmac->mode; | ||
67 | } | ||
68 | |||
69 | if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true) || | ||
70 | not_data) { | ||
71 | return 0; | ||
72 | } else { | ||
73 | if (rtlhal->current_bandtype == BAND_ON_2_4G) { | ||
74 | if (wireless_mode == WIRELESS_MODE_B) { | ||
75 | return B_MODE_MAX_RIX; | ||
76 | } else if (wireless_mode == WIRELESS_MODE_G) { | ||
77 | return G_MODE_MAX_RIX; | ||
78 | } else { | ||
79 | if (get_rf_type(rtlphy) != RF_2T2R) | ||
80 | return N_MODE_MCS7_RIX; | ||
81 | else | ||
82 | return N_MODE_MCS15_RIX; | ||
83 | } | ||
84 | } else { | ||
85 | if (wireless_mode == WIRELESS_MODE_A) { | ||
86 | return A_MODE_MAX_RIX; | ||
87 | } else { | ||
88 | if (get_rf_type(rtlphy) != RF_2T2R) | ||
89 | return N_MODE_MCS7_RIX; | ||
90 | else | ||
91 | return N_MODE_MCS15_RIX; | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | |||
97 | static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, | ||
98 | struct ieee80211_sta *sta, | ||
99 | struct ieee80211_tx_rate *rate, | ||
100 | struct ieee80211_tx_rate_control *txrc, | ||
101 | u8 tries, char rix, int rtsctsenable, | ||
102 | bool not_data) | ||
103 | { | ||
104 | struct rtl_mac *mac = rtl_mac(rtlpriv); | ||
105 | u8 sgi_20 = 0, sgi_40 = 0; | ||
106 | |||
107 | if (sta) { | ||
108 | sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; | ||
109 | sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; | ||
110 | } | ||
111 | rate->count = tries; | ||
112 | rate->idx = rix >= 0x00 ? rix : 0x00; | ||
113 | |||
114 | if (!not_data) { | ||
115 | if (txrc->short_preamble) | ||
116 | rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; | ||
117 | if (mac->opmode == NL80211_IFTYPE_AP || | ||
118 | mac->opmode == NL80211_IFTYPE_ADHOC) { | ||
119 | if (sta && (sta->ht_cap.cap & | ||
120 | IEEE80211_HT_CAP_SUP_WIDTH_20_40)) | ||
121 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
122 | } else { | ||
123 | if (mac->bw_40) | ||
124 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
125 | } | ||
126 | if (sgi_20 || sgi_40) | ||
127 | rate->flags |= IEEE80211_TX_RC_SHORT_GI; | ||
128 | if (sta && sta->ht_cap.ht_supported) | ||
129 | rate->flags |= IEEE80211_TX_RC_MCS; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta, | ||
134 | void *priv_sta, struct ieee80211_tx_rate_control *txrc) | ||
135 | { | ||
136 | struct rtl_priv *rtlpriv = ppriv; | ||
137 | struct sk_buff *skb = txrc->skb; | ||
138 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||
139 | struct ieee80211_tx_rate *rates = tx_info->control.rates; | ||
140 | __le16 fc = rtl_get_fc(skb); | ||
141 | u8 try_per_rate, i, rix; | ||
142 | bool not_data = !ieee80211_is_data(fc); | ||
143 | |||
144 | if (rate_control_send_low(sta, priv_sta, txrc)) | ||
145 | return; | ||
146 | |||
147 | rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data); | ||
148 | try_per_rate = 1; | ||
149 | _rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc, | ||
150 | try_per_rate, rix, 1, not_data); | ||
151 | |||
152 | if (!not_data) { | ||
153 | for (i = 1; i < 4; i++) | ||
154 | _rtl_rc_rate_set_series(rtlpriv, sta, &rates[i], | ||
155 | txrc, i, (rix - i), 1, | ||
156 | not_data); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, | ||
161 | struct rtl_sta_info *sta_entry, u16 tid) | ||
162 | { | ||
163 | struct rtl_mac *mac = rtl_mac(rtlpriv); | ||
164 | |||
165 | if (mac->act_scanning) | ||
166 | return false; | ||
167 | |||
168 | if (mac->opmode == NL80211_IFTYPE_STATION && | ||
169 | mac->cnt_after_linked < 3) | ||
170 | return false; | ||
171 | |||
172 | if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP) | ||
173 | return true; | ||
174 | |||
175 | return false; | ||
176 | } | ||
177 | |||
178 | /*mac80211 Rate Control callbacks*/ | ||
179 | static void rtl_tx_status(void *ppriv, | ||
180 | struct ieee80211_supported_band *sband, | ||
181 | struct ieee80211_sta *sta, void *priv_sta, | ||
182 | struct sk_buff *skb) | ||
183 | { | ||
184 | struct rtl_priv *rtlpriv = ppriv; | ||
185 | struct rtl_mac *mac = rtl_mac(rtlpriv); | ||
186 | struct ieee80211_hdr *hdr = rtl_get_hdr(skb); | ||
187 | __le16 fc = rtl_get_fc(skb); | ||
188 | struct rtl_sta_info *sta_entry; | ||
189 | |||
190 | if (!priv_sta || !ieee80211_is_data(fc)) | ||
191 | return; | ||
192 | |||
193 | if (rtl_is_special_data(mac->hw, skb, true)) | ||
194 | return; | ||
195 | |||
196 | if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) | ||
197 | || is_broadcast_ether_addr(ieee80211_get_DA(hdr))) | ||
198 | return; | ||
199 | |||
200 | if (sta) { | ||
201 | /* Check if aggregation has to be enabled for this tid */ | ||
202 | sta_entry = (struct rtl_sta_info *) sta->drv_priv; | ||
203 | if ((sta->ht_cap.ht_supported == true) && | ||
204 | !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { | ||
205 | if (ieee80211_is_data_qos(fc)) { | ||
206 | u8 tid = rtl_get_tid(skb); | ||
207 | if (_rtl_tx_aggr_check(rtlpriv, sta_entry, | ||
208 | tid)) { | ||
209 | sta_entry->tids[tid].agg.agg_state = | ||
210 | RTL_AGG_PROGRESS; | ||
211 | ieee80211_start_tx_ba_session(sta, | ||
212 | tid, 5000); | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | |||
219 | static void rtl_rate_init(void *ppriv, | ||
220 | struct ieee80211_supported_band *sband, | ||
221 | struct ieee80211_sta *sta, void *priv_sta) | ||
222 | { | ||
223 | } | ||
224 | |||
225 | static void rtl_rate_update(void *ppriv, | ||
226 | struct ieee80211_supported_band *sband, | ||
227 | struct ieee80211_sta *sta, void *priv_sta, | ||
228 | u32 changed, | ||
229 | enum nl80211_channel_type oper_chan_type) | ||
230 | { | ||
231 | } | ||
232 | |||
233 | static void *rtl_rate_alloc(struct ieee80211_hw *hw, | ||
234 | struct dentry *debugfsdir) | ||
235 | { | ||
236 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
237 | return rtlpriv; | ||
238 | } | ||
239 | |||
240 | static void rtl_rate_free(void *rtlpriv) | ||
241 | { | ||
242 | return; | ||
243 | } | ||
244 | |||
245 | static void *rtl_rate_alloc_sta(void *ppriv, | ||
246 | struct ieee80211_sta *sta, gfp_t gfp) | ||
247 | { | ||
248 | struct rtl_priv *rtlpriv = ppriv; | ||
249 | struct rtl_rate_priv *rate_priv; | ||
250 | |||
251 | rate_priv = kzalloc(sizeof(struct rtl_rate_priv), gfp); | ||
252 | if (!rate_priv) { | ||
253 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | ||
254 | ("Unable to allocate private rc structure\n")); | ||
255 | return NULL; | ||
256 | } | ||
257 | |||
258 | rtlpriv->rate_priv = rate_priv; | ||
259 | |||
260 | return rate_priv; | ||
261 | } | ||
262 | |||
263 | static void rtl_rate_free_sta(void *rtlpriv, | ||
264 | struct ieee80211_sta *sta, void *priv_sta) | ||
265 | { | ||
266 | struct rtl_rate_priv *rate_priv = priv_sta; | ||
267 | kfree(rate_priv); | ||
268 | } | ||
269 | |||
270 | static struct rate_control_ops rtl_rate_ops = { | ||
271 | .module = NULL, | ||
272 | .name = "rtl_rc", | ||
273 | .alloc = rtl_rate_alloc, | ||
274 | .free = rtl_rate_free, | ||
275 | .alloc_sta = rtl_rate_alloc_sta, | ||
276 | .free_sta = rtl_rate_free_sta, | ||
277 | .rate_init = rtl_rate_init, | ||
278 | .rate_update = rtl_rate_update, | ||
279 | .tx_status = rtl_tx_status, | ||
280 | .get_rate = rtl_get_rate, | ||
281 | }; | ||
282 | |||
283 | int rtl_rate_control_register(void) | ||
284 | { | ||
285 | return ieee80211_rate_control_register(&rtl_rate_ops); | ||
286 | } | ||
287 | |||
288 | void rtl_rate_control_unregister(void) | ||
289 | { | ||
290 | ieee80211_rate_control_unregister(&rtl_rate_ops); | ||
291 | } | ||