diff options
author | Larry Finger <Larry.Finger@lwfinger.net> | 2010-12-08 12:12:31 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-12-15 16:17:49 -0500 |
commit | 0c8173385e549f95cd80c3fff5aab87b4f881d8d (patch) | |
tree | eb818f70ed027eecbc5e170b046aa0d785168d43 /drivers/net/wireless/rtlwifi/rc.c | |
parent | 412b31334b831a8c2909afaca017c5a236ac2dd0 (diff) |
rtl8192ce: Add new driver
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rtlwifi/rc.c')
-rw-r--r-- | drivers/net/wireless/rtlwifi/rc.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c new file mode 100644 index 00000000000..904b8fd01f6 --- /dev/null +++ b/drivers/net/wireless/rtlwifi/rc.c | |||
@@ -0,0 +1,329 @@ | |||
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 sk_buff *skb, bool not_data) | ||
42 | { | ||
43 | struct rtl_mac *rtlmac = rtl_mac(rtlpriv); | ||
44 | |||
45 | /* | ||
46 | *mgt use 1M, although we have check it | ||
47 | *before this function use rate_control_send_low, | ||
48 | *we still check it here | ||
49 | */ | ||
50 | if (not_data) | ||
51 | return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; | ||
52 | |||
53 | /* | ||
54 | *this rate is no use for true rate, firmware | ||
55 | *will control rate at all it just used for | ||
56 | *1.show in iwconfig in B/G mode | ||
57 | *2.in rtl_get_tcb_desc when we check rate is | ||
58 | * 1M we will not use FW rate but user rate. | ||
59 | */ | ||
60 | if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true)) { | ||
61 | return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; | ||
62 | } else { | ||
63 | if (rtlmac->mode == WIRELESS_MODE_B) | ||
64 | return rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]; | ||
65 | else | ||
66 | return rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, | ||
71 | struct ieee80211_tx_rate *rate, | ||
72 | struct ieee80211_tx_rate_control *txrc, | ||
73 | u8 tries, u8 rix, int rtsctsenable, | ||
74 | bool not_data) | ||
75 | { | ||
76 | struct rtl_mac *mac = rtl_mac(rtlpriv); | ||
77 | |||
78 | rate->count = tries; | ||
79 | rate->idx = (rix > 0x2) ? rix : 0x2; | ||
80 | |||
81 | if (!not_data) { | ||
82 | if (txrc->short_preamble) | ||
83 | rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; | ||
84 | if (mac->bw_40) | ||
85 | rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
86 | if (mac->sgi_20 || mac->sgi_40) | ||
87 | rate->flags |= IEEE80211_TX_RC_SHORT_GI; | ||
88 | if (mac->ht_enable) | ||
89 | rate->flags |= IEEE80211_TX_RC_MCS; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta, | ||
94 | void *priv_sta, struct ieee80211_tx_rate_control *txrc) | ||
95 | { | ||
96 | struct rtl_priv *rtlpriv = ppriv; | ||
97 | struct sk_buff *skb = txrc->skb; | ||
98 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||
99 | struct ieee80211_tx_rate *rates = tx_info->control.rates; | ||
100 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
101 | __le16 fc = hdr->frame_control; | ||
102 | u8 try_per_rate, i, rix; | ||
103 | bool not_data = !ieee80211_is_data(fc); | ||
104 | |||
105 | if (rate_control_send_low(sta, priv_sta, txrc)) | ||
106 | return; | ||
107 | |||
108 | rix = _rtl_rc_get_highest_rix(rtlpriv, skb, not_data); | ||
109 | |||
110 | try_per_rate = 1; | ||
111 | _rtl_rc_rate_set_series(rtlpriv, &rates[0], txrc, | ||
112 | try_per_rate, rix, 1, not_data); | ||
113 | |||
114 | if (!not_data) { | ||
115 | for (i = 1; i < 4; i++) | ||
116 | _rtl_rc_rate_set_series(rtlpriv, &rates[i], | ||
117 | txrc, i, (rix - i), 1, | ||
118 | not_data); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, u16 tid) | ||
123 | { | ||
124 | struct rtl_mac *mac = rtl_mac(rtlpriv); | ||
125 | |||
126 | if (mac->act_scanning) | ||
127 | return false; | ||
128 | |||
129 | if (mac->cnt_after_linked < 3) | ||
130 | return false; | ||
131 | |||
132 | if (mac->tids[tid].agg.agg_state == RTL_AGG_OFF) | ||
133 | return true; | ||
134 | |||
135 | return false; | ||
136 | } | ||
137 | |||
138 | /*mac80211 Rate Control callbacks*/ | ||
139 | static void rtl_tx_status(void *ppriv, | ||
140 | struct ieee80211_supported_band *sband, | ||
141 | struct ieee80211_sta *sta, void *priv_sta, | ||
142 | struct sk_buff *skb) | ||
143 | { | ||
144 | struct rtl_priv *rtlpriv = ppriv; | ||
145 | struct rtl_mac *mac = rtl_mac(rtlpriv); | ||
146 | struct ieee80211_hdr *hdr; | ||
147 | __le16 fc; | ||
148 | |||
149 | hdr = (struct ieee80211_hdr *)skb->data; | ||
150 | fc = hdr->frame_control; | ||
151 | |||
152 | if (!priv_sta || !ieee80211_is_data(fc)) | ||
153 | return; | ||
154 | |||
155 | if (rtl_is_special_data(mac->hw, skb, true)) | ||
156 | return; | ||
157 | |||
158 | if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) | ||
159 | || is_broadcast_ether_addr(ieee80211_get_DA(hdr))) | ||
160 | return; | ||
161 | |||
162 | /* Check if aggregation has to be enabled for this tid */ | ||
163 | if (conf_is_ht(&mac->hw->conf) && | ||
164 | !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { | ||
165 | if (ieee80211_is_data_qos(fc)) { | ||
166 | u8 *qc, tid; | ||
167 | |||
168 | qc = ieee80211_get_qos_ctl(hdr); | ||
169 | tid = qc[0] & 0xf; | ||
170 | |||
171 | if (_rtl_tx_aggr_check(rtlpriv, tid)) | ||
172 | ieee80211_start_tx_ba_session(sta, tid); | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | |||
177 | static void rtl_rate_init(void *ppriv, | ||
178 | struct ieee80211_supported_band *sband, | ||
179 | struct ieee80211_sta *sta, void *priv_sta) | ||
180 | { | ||
181 | struct rtl_priv *rtlpriv = ppriv; | ||
182 | struct rtl_mac *mac = rtl_mac(rtlpriv); | ||
183 | u8 is_ht = conf_is_ht(&mac->hw->conf); | ||
184 | |||
185 | if ((mac->opmode == NL80211_IFTYPE_STATION) || | ||
186 | (mac->opmode == NL80211_IFTYPE_MESH_POINT) || | ||
187 | (mac->opmode == NL80211_IFTYPE_ADHOC)) { | ||
188 | |||
189 | switch (sband->band) { | ||
190 | case IEEE80211_BAND_2GHZ: | ||
191 | rtlpriv->rate_priv->cur_ratetab_idx = | ||
192 | RATR_INX_WIRELESS_G; | ||
193 | if (is_ht) | ||
194 | rtlpriv->rate_priv->cur_ratetab_idx = | ||
195 | RATR_INX_WIRELESS_NGB; | ||
196 | break; | ||
197 | case IEEE80211_BAND_5GHZ: | ||
198 | rtlpriv->rate_priv->cur_ratetab_idx = | ||
199 | RATR_INX_WIRELESS_A; | ||
200 | if (is_ht) | ||
201 | rtlpriv->rate_priv->cur_ratetab_idx = | ||
202 | RATR_INX_WIRELESS_NGB; | ||
203 | break; | ||
204 | default: | ||
205 | RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, | ||
206 | ("Invalid band\n")); | ||
207 | rtlpriv->rate_priv->cur_ratetab_idx = | ||
208 | RATR_INX_WIRELESS_NGB; | ||
209 | break; | ||
210 | } | ||
211 | |||
212 | RT_TRACE(rtlpriv, COMP_RATE, DBG_DMESG, | ||
213 | ("Choosing rate table index: %d\n", | ||
214 | rtlpriv->rate_priv->cur_ratetab_idx)); | ||
215 | |||
216 | } | ||
217 | |||
218 | } | ||
219 | |||
220 | static void rtl_rate_update(void *ppriv, | ||
221 | struct ieee80211_supported_band *sband, | ||
222 | struct ieee80211_sta *sta, void *priv_sta, | ||
223 | u32 changed, | ||
224 | enum nl80211_channel_type oper_chan_type) | ||
225 | { | ||
226 | struct rtl_priv *rtlpriv = ppriv; | ||
227 | struct rtl_mac *mac = rtl_mac(rtlpriv); | ||
228 | struct rtl_hal *rtlhal = rtl_hal(rtlpriv); | ||
229 | bool oper_cw40 = false, oper_sgi40; | ||
230 | bool local_cw40 = mac->bw_40; | ||
231 | bool local_sgi40 = mac->sgi_40; | ||
232 | u8 is_ht = conf_is_ht(&mac->hw->conf); | ||
233 | |||
234 | if (changed & IEEE80211_RC_HT_CHANGED) { | ||
235 | if (mac->opmode != NL80211_IFTYPE_STATION) | ||
236 | return; | ||
237 | |||
238 | if (rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40MINUS || | ||
239 | rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40PLUS) | ||
240 | oper_cw40 = true; | ||
241 | |||
242 | oper_sgi40 = mac->sgi_40; | ||
243 | |||
244 | if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) { | ||
245 | switch (sband->band) { | ||
246 | case IEEE80211_BAND_2GHZ: | ||
247 | rtlpriv->rate_priv->cur_ratetab_idx = | ||
248 | RATR_INX_WIRELESS_G; | ||
249 | if (is_ht) | ||
250 | rtlpriv->rate_priv->cur_ratetab_idx = | ||
251 | RATR_INX_WIRELESS_NGB; | ||
252 | break; | ||
253 | case IEEE80211_BAND_5GHZ: | ||
254 | rtlpriv->rate_priv->cur_ratetab_idx = | ||
255 | RATR_INX_WIRELESS_A; | ||
256 | if (is_ht) | ||
257 | rtlpriv->rate_priv->cur_ratetab_idx = | ||
258 | RATR_INX_WIRELESS_NGB; | ||
259 | break; | ||
260 | default: | ||
261 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | ||
262 | ("Invalid band\n")); | ||
263 | rtlpriv->rate_priv->cur_ratetab_idx = | ||
264 | RATR_INX_WIRELESS_NGB; | ||
265 | break; | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | |||
271 | static void *rtl_rate_alloc(struct ieee80211_hw *hw, | ||
272 | struct dentry *debugfsdir) | ||
273 | { | ||
274 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
275 | return rtlpriv; | ||
276 | } | ||
277 | |||
278 | static void rtl_rate_free(void *rtlpriv) | ||
279 | { | ||
280 | return; | ||
281 | } | ||
282 | |||
283 | static void *rtl_rate_alloc_sta(void *ppriv, | ||
284 | struct ieee80211_sta *sta, gfp_t gfp) | ||
285 | { | ||
286 | struct rtl_priv *rtlpriv = ppriv; | ||
287 | struct rtl_rate_priv *rate_priv; | ||
288 | |||
289 | rate_priv = kzalloc(sizeof(struct rtl_rate_priv), gfp); | ||
290 | if (!rate_priv) { | ||
291 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | ||
292 | ("Unable to allocate private rc structure\n")); | ||
293 | return NULL; | ||
294 | } | ||
295 | |||
296 | rtlpriv->rate_priv = rate_priv; | ||
297 | |||
298 | return rate_priv; | ||
299 | } | ||
300 | |||
301 | static void rtl_rate_free_sta(void *rtlpriv, | ||
302 | struct ieee80211_sta *sta, void *priv_sta) | ||
303 | { | ||
304 | struct rtl_rate_priv *rate_priv = priv_sta; | ||
305 | kfree(rate_priv); | ||
306 | } | ||
307 | |||
308 | static struct rate_control_ops rtl_rate_ops = { | ||
309 | .module = NULL, | ||
310 | .name = "rtl_rc", | ||
311 | .alloc = rtl_rate_alloc, | ||
312 | .free = rtl_rate_free, | ||
313 | .alloc_sta = rtl_rate_alloc_sta, | ||
314 | .free_sta = rtl_rate_free_sta, | ||
315 | .rate_init = rtl_rate_init, | ||
316 | .rate_update = rtl_rate_update, | ||
317 | .tx_status = rtl_tx_status, | ||
318 | .get_rate = rtl_get_rate, | ||
319 | }; | ||
320 | |||
321 | int rtl_rate_control_register(void) | ||
322 | { | ||
323 | return ieee80211_rate_control_register(&rtl_rate_ops); | ||
324 | } | ||
325 | |||
326 | void rtl_rate_control_unregister(void) | ||
327 | { | ||
328 | ieee80211_rate_control_unregister(&rtl_rate_ops); | ||
329 | } | ||