]>
Commit | Line | Data |
---|---|---|
dad0d04f FF |
1 | /** |
2 | * Copyright (c) 2014 Redpine Signals Inc. | |
3 | * | |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | */ | |
16 | ||
17 | #include <linux/etherdevice.h> | |
18 | #include "rsi_debugfs.h" | |
19 | #include "rsi_mgmt.h" | |
20 | #include "rsi_common.h" | |
21 | ||
22 | static const struct ieee80211_channel rsi_2ghz_channels[] = { | |
23 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2412, | |
24 | .hw_value = 1 }, /* Channel 1 */ | |
25 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2417, | |
26 | .hw_value = 2 }, /* Channel 2 */ | |
27 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2422, | |
28 | .hw_value = 3 }, /* Channel 3 */ | |
29 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2427, | |
30 | .hw_value = 4 }, /* Channel 4 */ | |
31 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2432, | |
32 | .hw_value = 5 }, /* Channel 5 */ | |
33 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2437, | |
34 | .hw_value = 6 }, /* Channel 6 */ | |
35 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2442, | |
36 | .hw_value = 7 }, /* Channel 7 */ | |
37 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2447, | |
38 | .hw_value = 8 }, /* Channel 8 */ | |
39 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2452, | |
40 | .hw_value = 9 }, /* Channel 9 */ | |
41 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2457, | |
42 | .hw_value = 10 }, /* Channel 10 */ | |
43 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2462, | |
44 | .hw_value = 11 }, /* Channel 11 */ | |
45 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2467, | |
46 | .hw_value = 12 }, /* Channel 12 */ | |
47 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2472, | |
48 | .hw_value = 13 }, /* Channel 13 */ | |
49 | { .band = IEEE80211_BAND_2GHZ, .center_freq = 2484, | |
50 | .hw_value = 14 }, /* Channel 14 */ | |
51 | }; | |
52 | ||
53 | static const struct ieee80211_channel rsi_5ghz_channels[] = { | |
54 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5180, | |
55 | .hw_value = 36, }, /* Channel 36 */ | |
56 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5200, | |
57 | .hw_value = 40, }, /* Channel 40 */ | |
58 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5220, | |
59 | .hw_value = 44, }, /* Channel 44 */ | |
60 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5240, | |
61 | .hw_value = 48, }, /* Channel 48 */ | |
62 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5260, | |
63 | .hw_value = 52, }, /* Channel 52 */ | |
64 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5280, | |
65 | .hw_value = 56, }, /* Channel 56 */ | |
66 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5300, | |
67 | .hw_value = 60, }, /* Channel 60 */ | |
68 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5320, | |
69 | .hw_value = 64, }, /* Channel 64 */ | |
70 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5500, | |
71 | .hw_value = 100, }, /* Channel 100 */ | |
72 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5520, | |
73 | .hw_value = 104, }, /* Channel 104 */ | |
74 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5540, | |
75 | .hw_value = 108, }, /* Channel 108 */ | |
76 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5560, | |
77 | .hw_value = 112, }, /* Channel 112 */ | |
78 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5580, | |
79 | .hw_value = 116, }, /* Channel 116 */ | |
80 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5600, | |
81 | .hw_value = 120, }, /* Channel 120 */ | |
82 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5620, | |
83 | .hw_value = 124, }, /* Channel 124 */ | |
84 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5640, | |
85 | .hw_value = 128, }, /* Channel 128 */ | |
86 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5660, | |
87 | .hw_value = 132, }, /* Channel 132 */ | |
88 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5680, | |
89 | .hw_value = 136, }, /* Channel 136 */ | |
90 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5700, | |
91 | .hw_value = 140, }, /* Channel 140 */ | |
92 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5745, | |
93 | .hw_value = 149, }, /* Channel 149 */ | |
94 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5765, | |
95 | .hw_value = 153, }, /* Channel 153 */ | |
96 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5785, | |
97 | .hw_value = 157, }, /* Channel 157 */ | |
98 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5805, | |
99 | .hw_value = 161, }, /* Channel 161 */ | |
100 | { .band = IEEE80211_BAND_5GHZ, .center_freq = 5825, | |
101 | .hw_value = 165, }, /* Channel 165 */ | |
102 | }; | |
103 | ||
104 | struct ieee80211_rate rsi_rates[12] = { | |
105 | { .bitrate = STD_RATE_01 * 5, .hw_value = RSI_RATE_1 }, | |
106 | { .bitrate = STD_RATE_02 * 5, .hw_value = RSI_RATE_2 }, | |
107 | { .bitrate = STD_RATE_5_5 * 5, .hw_value = RSI_RATE_5_5 }, | |
108 | { .bitrate = STD_RATE_11 * 5, .hw_value = RSI_RATE_11 }, | |
109 | { .bitrate = STD_RATE_06 * 5, .hw_value = RSI_RATE_6 }, | |
110 | { .bitrate = STD_RATE_09 * 5, .hw_value = RSI_RATE_9 }, | |
111 | { .bitrate = STD_RATE_12 * 5, .hw_value = RSI_RATE_12 }, | |
112 | { .bitrate = STD_RATE_18 * 5, .hw_value = RSI_RATE_18 }, | |
113 | { .bitrate = STD_RATE_24 * 5, .hw_value = RSI_RATE_24 }, | |
114 | { .bitrate = STD_RATE_36 * 5, .hw_value = RSI_RATE_36 }, | |
115 | { .bitrate = STD_RATE_48 * 5, .hw_value = RSI_RATE_48 }, | |
116 | { .bitrate = STD_RATE_54 * 5, .hw_value = RSI_RATE_54 }, | |
117 | }; | |
118 | ||
119 | const u16 rsi_mcsrates[8] = { | |
120 | RSI_RATE_MCS0, RSI_RATE_MCS1, RSI_RATE_MCS2, RSI_RATE_MCS3, | |
121 | RSI_RATE_MCS4, RSI_RATE_MCS5, RSI_RATE_MCS6, RSI_RATE_MCS7 | |
122 | }; | |
123 | ||
124 | /** | |
125 | * rsi_is_cipher_wep() - This function determines if the cipher is WEP or not. | |
126 | * @common: Pointer to the driver private structure. | |
127 | * | |
128 | * Return: If cipher type is WEP, a value of 1 is returned, else 0. | |
129 | */ | |
130 | ||
131 | bool rsi_is_cipher_wep(struct rsi_common *common) | |
132 | { | |
133 | if (((common->secinfo.gtk_cipher == WLAN_CIPHER_SUITE_WEP104) || | |
134 | (common->secinfo.gtk_cipher == WLAN_CIPHER_SUITE_WEP40)) && | |
135 | (!common->secinfo.ptk_cipher)) | |
136 | return true; | |
137 | else | |
138 | return false; | |
139 | } | |
140 | ||
141 | /** | |
142 | * rsi_register_rates_channels() - This function registers channels and rates. | |
143 | * @adapter: Pointer to the adapter structure. | |
144 | * @band: Operating band to be set. | |
145 | * | |
146 | * Return: None. | |
147 | */ | |
148 | static void rsi_register_rates_channels(struct rsi_hw *adapter, int band) | |
149 | { | |
150 | struct ieee80211_supported_band *sbands = &adapter->sbands[band]; | |
151 | void *channels = NULL; | |
152 | ||
153 | if (band == IEEE80211_BAND_2GHZ) { | |
154 | channels = kmalloc(sizeof(rsi_2ghz_channels), GFP_KERNEL); | |
155 | memcpy(channels, | |
156 | rsi_2ghz_channels, | |
157 | sizeof(rsi_2ghz_channels)); | |
158 | sbands->band = IEEE80211_BAND_2GHZ; | |
159 | sbands->n_channels = ARRAY_SIZE(rsi_2ghz_channels); | |
160 | sbands->bitrates = rsi_rates; | |
161 | sbands->n_bitrates = ARRAY_SIZE(rsi_rates); | |
162 | } else { | |
163 | channels = kmalloc(sizeof(rsi_5ghz_channels), GFP_KERNEL); | |
164 | memcpy(channels, | |
165 | rsi_5ghz_channels, | |
166 | sizeof(rsi_5ghz_channels)); | |
167 | sbands->band = IEEE80211_BAND_5GHZ; | |
168 | sbands->n_channels = ARRAY_SIZE(rsi_5ghz_channels); | |
169 | sbands->bitrates = &rsi_rates[4]; | |
170 | sbands->n_bitrates = ARRAY_SIZE(rsi_rates) - 4; | |
171 | } | |
172 | ||
173 | sbands->channels = channels; | |
174 | ||
175 | memset(&sbands->ht_cap, 0, sizeof(struct ieee80211_sta_ht_cap)); | |
176 | sbands->ht_cap.ht_supported = true; | |
177 | sbands->ht_cap.cap = (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | | |
178 | IEEE80211_HT_CAP_SGI_20 | | |
179 | IEEE80211_HT_CAP_SGI_40); | |
180 | sbands->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K; | |
181 | sbands->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; | |
182 | sbands->ht_cap.mcs.rx_mask[0] = 0xff; | |
183 | sbands->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; | |
184 | /* sbands->ht_cap.mcs.rx_highest = 0x82; */ | |
185 | } | |
186 | ||
187 | /** | |
19d2e619 | 188 | * rsi_mac80211_detach() - This function is used to de-initialize the |
dad0d04f FF |
189 | * Mac80211 stack. |
190 | * @adapter: Pointer to the adapter structure. | |
191 | * | |
192 | * Return: None. | |
193 | */ | |
194 | void rsi_mac80211_detach(struct rsi_hw *adapter) | |
195 | { | |
196 | struct ieee80211_hw *hw = adapter->hw; | |
197 | ||
198 | if (hw) { | |
199 | ieee80211_stop_queues(hw); | |
200 | ieee80211_unregister_hw(hw); | |
201 | ieee80211_free_hw(hw); | |
202 | } | |
203 | ||
204 | rsi_remove_dbgfs(adapter); | |
205 | } | |
206 | EXPORT_SYMBOL_GPL(rsi_mac80211_detach); | |
207 | ||
208 | /** | |
209 | * rsi_indicate_tx_status() - This function indicates the transmit status. | |
210 | * @adapter: Pointer to the adapter structure. | |
211 | * @skb: Pointer to the socket buffer structure. | |
212 | * @status: Status | |
213 | * | |
214 | * Return: None. | |
215 | */ | |
216 | void rsi_indicate_tx_status(struct rsi_hw *adapter, | |
217 | struct sk_buff *skb, | |
218 | int status) | |
219 | { | |
220 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | |
221 | ||
222 | memset(info->driver_data, 0, IEEE80211_TX_INFO_DRIVER_DATA_SIZE); | |
223 | ||
224 | if (!status) | |
225 | info->flags |= IEEE80211_TX_STAT_ACK; | |
226 | ||
227 | ieee80211_tx_status_irqsafe(adapter->hw, skb); | |
228 | } | |
229 | ||
230 | /** | |
231 | * rsi_mac80211_tx() - This is the handler that 802.11 module calls for each | |
232 | * transmitted frame.SKB contains the buffer starting | |
233 | * from the IEEE 802.11 header. | |
234 | * @hw: Pointer to the ieee80211_hw structure. | |
235 | * @control: Pointer to the ieee80211_tx_control structure | |
236 | * @skb: Pointer to the socket buffer structure. | |
237 | * | |
238 | * Return: None | |
239 | */ | |
240 | static void rsi_mac80211_tx(struct ieee80211_hw *hw, | |
241 | struct ieee80211_tx_control *control, | |
242 | struct sk_buff *skb) | |
243 | { | |
244 | struct rsi_hw *adapter = hw->priv; | |
245 | struct rsi_common *common = adapter->priv; | |
246 | ||
247 | rsi_core_xmit(common, skb); | |
248 | } | |
249 | ||
250 | /** | |
251 | * rsi_mac80211_start() - This is first handler that 802.11 module calls, since | |
252 | * the driver init is complete by then, just | |
253 | * returns success. | |
254 | * @hw: Pointer to the ieee80211_hw structure. | |
255 | * | |
256 | * Return: 0 as success. | |
257 | */ | |
258 | static int rsi_mac80211_start(struct ieee80211_hw *hw) | |
259 | { | |
260 | struct rsi_hw *adapter = hw->priv; | |
261 | struct rsi_common *common = adapter->priv; | |
262 | ||
263 | mutex_lock(&common->mutex); | |
264 | common->iface_down = false; | |
265 | mutex_unlock(&common->mutex); | |
266 | ||
267 | return 0; | |
268 | } | |
269 | ||
270 | /** | |
271 | * rsi_mac80211_stop() - This is the last handler that 802.11 module calls. | |
272 | * @hw: Pointer to the ieee80211_hw structure. | |
273 | * | |
274 | * Return: None. | |
275 | */ | |
276 | static void rsi_mac80211_stop(struct ieee80211_hw *hw) | |
277 | { | |
278 | struct rsi_hw *adapter = hw->priv; | |
279 | struct rsi_common *common = adapter->priv; | |
280 | ||
281 | mutex_lock(&common->mutex); | |
282 | common->iface_down = true; | |
283 | mutex_unlock(&common->mutex); | |
284 | } | |
285 | ||
286 | /** | |
287 | * rsi_mac80211_add_interface() - This function is called when a netdevice | |
288 | * attached to the hardware is enabled. | |
289 | * @hw: Pointer to the ieee80211_hw structure. | |
290 | * @vif: Pointer to the ieee80211_vif structure. | |
291 | * | |
292 | * Return: ret: 0 on success, negative error code on failure. | |
293 | */ | |
294 | static int rsi_mac80211_add_interface(struct ieee80211_hw *hw, | |
295 | struct ieee80211_vif *vif) | |
296 | { | |
297 | struct rsi_hw *adapter = hw->priv; | |
298 | struct rsi_common *common = adapter->priv; | |
299 | int ret = -EOPNOTSUPP; | |
300 | ||
301 | mutex_lock(&common->mutex); | |
302 | switch (vif->type) { | |
303 | case NL80211_IFTYPE_STATION: | |
304 | if (!adapter->sc_nvifs) { | |
305 | ++adapter->sc_nvifs; | |
306 | adapter->vifs[0] = vif; | |
307 | ret = rsi_set_vap_capabilities(common, STA_OPMODE); | |
308 | } | |
309 | break; | |
310 | default: | |
311 | rsi_dbg(ERR_ZONE, | |
312 | "%s: Interface type %d not supported\n", __func__, | |
313 | vif->type); | |
314 | } | |
315 | mutex_unlock(&common->mutex); | |
316 | ||
317 | return ret; | |
318 | } | |
319 | ||
320 | /** | |
321 | * rsi_mac80211_remove_interface() - This function notifies driver that an | |
322 | * interface is going down. | |
323 | * @hw: Pointer to the ieee80211_hw structure. | |
324 | * @vif: Pointer to the ieee80211_vif structure. | |
325 | * | |
326 | * Return: None. | |
327 | */ | |
328 | static void rsi_mac80211_remove_interface(struct ieee80211_hw *hw, | |
329 | struct ieee80211_vif *vif) | |
330 | { | |
331 | struct rsi_hw *adapter = hw->priv; | |
332 | struct rsi_common *common = adapter->priv; | |
333 | ||
334 | mutex_lock(&common->mutex); | |
335 | if (vif->type == NL80211_IFTYPE_STATION) | |
336 | adapter->sc_nvifs--; | |
337 | ||
338 | if (!memcmp(adapter->vifs[0], vif, sizeof(struct ieee80211_vif))) | |
339 | adapter->vifs[0] = NULL; | |
340 | mutex_unlock(&common->mutex); | |
341 | } | |
342 | ||
343 | /** | |
344 | * rsi_mac80211_config() - This function is a handler for configuration | |
345 | * requests. The stack calls this function to | |
346 | * change hardware configuration, e.g., channel. | |
347 | * @hw: Pointer to the ieee80211_hw structure. | |
348 | * @changed: Changed flags set. | |
349 | * | |
350 | * Return: 0 on success, negative error code on failure. | |
351 | */ | |
352 | static int rsi_mac80211_config(struct ieee80211_hw *hw, | |
353 | u32 changed) | |
354 | { | |
355 | struct rsi_hw *adapter = hw->priv; | |
356 | struct rsi_common *common = adapter->priv; | |
357 | int status = -EOPNOTSUPP; | |
358 | ||
359 | mutex_lock(&common->mutex); | |
360 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | |
361 | struct ieee80211_channel *curchan = hw->conf.chandef.chan; | |
362 | u16 channel = curchan->hw_value; | |
363 | ||
364 | rsi_dbg(INFO_ZONE, | |
365 | "%s: Set channel: %d MHz type: %d channel_no %d\n", | |
366 | __func__, curchan->center_freq, | |
367 | curchan->flags, channel); | |
368 | common->band = curchan->band; | |
369 | status = rsi_set_channel(adapter->priv, channel); | |
370 | } | |
371 | mutex_unlock(&common->mutex); | |
372 | ||
373 | return status; | |
374 | } | |
375 | ||
376 | /** | |
377 | * rsi_get_connected_channel() - This function is used to get the current | |
378 | * connected channel number. | |
379 | * @adapter: Pointer to the adapter structure. | |
380 | * | |
381 | * Return: Current connected AP's channel number is returned. | |
382 | */ | |
383 | u16 rsi_get_connected_channel(struct rsi_hw *adapter) | |
384 | { | |
385 | struct ieee80211_vif *vif = adapter->vifs[0]; | |
386 | if (vif) { | |
387 | struct ieee80211_bss_conf *bss = &vif->bss_conf; | |
388 | struct ieee80211_channel *channel = bss->chandef.chan; | |
389 | return channel->hw_value; | |
390 | } | |
391 | ||
392 | return 0; | |
393 | } | |
394 | ||
395 | /** | |
396 | * rsi_mac80211_bss_info_changed() - This function is a handler for config | |
397 | * requests related to BSS parameters that | |
398 | * may vary during BSS's lifespan. | |
399 | * @hw: Pointer to the ieee80211_hw structure. | |
400 | * @vif: Pointer to the ieee80211_vif structure. | |
401 | * @bss_conf: Pointer to the ieee80211_bss_conf structure. | |
402 | * @changed: Changed flags set. | |
403 | * | |
404 | * Return: None. | |
405 | */ | |
406 | static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, | |
407 | struct ieee80211_vif *vif, | |
408 | struct ieee80211_bss_conf *bss_conf, | |
409 | u32 changed) | |
410 | { | |
411 | struct rsi_hw *adapter = hw->priv; | |
412 | struct rsi_common *common = adapter->priv; | |
413 | ||
414 | mutex_lock(&common->mutex); | |
415 | if (changed & BSS_CHANGED_ASSOC) { | |
416 | rsi_dbg(INFO_ZONE, "%s: Changed Association status: %d\n", | |
417 | __func__, bss_conf->assoc); | |
418 | rsi_inform_bss_status(common, | |
419 | bss_conf->assoc, | |
420 | bss_conf->bssid, | |
421 | bss_conf->qos, | |
422 | bss_conf->aid); | |
423 | } | |
424 | mutex_unlock(&common->mutex); | |
425 | } | |
426 | ||
427 | /** | |
428 | * rsi_mac80211_conf_filter() - This function configure the device's RX filter. | |
429 | * @hw: Pointer to the ieee80211_hw structure. | |
430 | * @changed: Changed flags set. | |
431 | * @total_flags: Total initial flags set. | |
432 | * @multicast: Multicast. | |
433 | * | |
434 | * Return: None. | |
435 | */ | |
436 | static void rsi_mac80211_conf_filter(struct ieee80211_hw *hw, | |
437 | u32 changed_flags, | |
438 | u32 *total_flags, | |
439 | u64 multicast) | |
440 | { | |
441 | /* Not doing much here as of now */ | |
442 | *total_flags &= RSI_SUPP_FILTERS; | |
443 | } | |
444 | ||
445 | /** | |
446 | * rsi_mac80211_conf_tx() - This function configures TX queue parameters | |
447 | * (EDCF (aifs, cw_min, cw_max), bursting) | |
448 | * for a hardware TX queue. | |
449 | * @hw: Pointer to the ieee80211_hw structure | |
450 | * @vif: Pointer to the ieee80211_vif structure. | |
451 | * @queue: Queue number. | |
452 | * @params: Pointer to ieee80211_tx_queue_params structure. | |
453 | * | |
454 | * Return: 0 on success, negative error code on failure. | |
455 | */ | |
456 | static int rsi_mac80211_conf_tx(struct ieee80211_hw *hw, | |
457 | struct ieee80211_vif *vif, u16 queue, | |
458 | const struct ieee80211_tx_queue_params *params) | |
459 | { | |
460 | struct rsi_hw *adapter = hw->priv; | |
461 | struct rsi_common *common = adapter->priv; | |
462 | u8 idx = 0; | |
463 | ||
464 | if (queue >= IEEE80211_NUM_ACS) | |
465 | return 0; | |
466 | ||
467 | rsi_dbg(INFO_ZONE, | |
468 | "%s: Conf queue %d, aifs: %d, cwmin: %d cwmax: %d, txop: %d\n", | |
469 | __func__, queue, params->aifs, | |
470 | params->cw_min, params->cw_max, params->txop); | |
471 | ||
472 | mutex_lock(&common->mutex); | |
473 | /* Map into the way the f/w expects */ | |
474 | switch (queue) { | |
475 | case IEEE80211_AC_VO: | |
476 | idx = VO_Q; | |
477 | break; | |
478 | case IEEE80211_AC_VI: | |
479 | idx = VI_Q; | |
480 | break; | |
481 | case IEEE80211_AC_BE: | |
482 | idx = BE_Q; | |
483 | break; | |
484 | case IEEE80211_AC_BK: | |
485 | idx = BK_Q; | |
486 | break; | |
487 | default: | |
488 | idx = BE_Q; | |
489 | break; | |
490 | } | |
491 | ||
492 | memcpy(&common->edca_params[idx], | |
493 | params, | |
494 | sizeof(struct ieee80211_tx_queue_params)); | |
495 | mutex_unlock(&common->mutex); | |
496 | ||
497 | return 0; | |
498 | } | |
499 | ||
500 | /** | |
501 | * rsi_hal_key_config() - This function loads the keys into the firmware. | |
502 | * @hw: Pointer to the ieee80211_hw structure. | |
503 | * @vif: Pointer to the ieee80211_vif structure. | |
504 | * @key: Pointer to the ieee80211_key_conf structure. | |
505 | * | |
506 | * Return: status: 0 on success, -1 on failure. | |
507 | */ | |
508 | static int rsi_hal_key_config(struct ieee80211_hw *hw, | |
509 | struct ieee80211_vif *vif, | |
510 | struct ieee80211_key_conf *key) | |
511 | { | |
512 | struct rsi_hw *adapter = hw->priv; | |
513 | int status; | |
514 | u8 key_type; | |
515 | ||
516 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) | |
517 | key_type = RSI_PAIRWISE_KEY; | |
518 | else | |
519 | key_type = RSI_GROUP_KEY; | |
520 | ||
521 | rsi_dbg(ERR_ZONE, "%s: Cipher 0x%x key_type: %d key_len: %d\n", | |
522 | __func__, key->cipher, key_type, key->keylen); | |
523 | ||
524 | if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || | |
525 | (key->cipher == WLAN_CIPHER_SUITE_WEP40)) { | |
526 | status = rsi_hal_load_key(adapter->priv, | |
527 | key->key, | |
528 | key->keylen, | |
529 | RSI_PAIRWISE_KEY, | |
530 | key->keyidx, | |
531 | key->cipher); | |
532 | if (status) | |
533 | return status; | |
534 | } | |
535 | return rsi_hal_load_key(adapter->priv, | |
536 | key->key, | |
537 | key->keylen, | |
538 | key_type, | |
539 | key->keyidx, | |
540 | key->cipher); | |
541 | } | |
542 | ||
543 | /** | |
544 | * rsi_mac80211_set_key() - This function sets type of key to be loaded. | |
545 | * @hw: Pointer to the ieee80211_hw structure. | |
546 | * @cmd: enum set_key_cmd. | |
547 | * @vif: Pointer to the ieee80211_vif structure. | |
548 | * @sta: Pointer to the ieee80211_sta structure. | |
549 | * @key: Pointer to the ieee80211_key_conf structure. | |
550 | * | |
551 | * Return: status: 0 on success, negative error code on failure. | |
552 | */ | |
553 | static int rsi_mac80211_set_key(struct ieee80211_hw *hw, | |
554 | enum set_key_cmd cmd, | |
555 | struct ieee80211_vif *vif, | |
556 | struct ieee80211_sta *sta, | |
557 | struct ieee80211_key_conf *key) | |
558 | { | |
559 | struct rsi_hw *adapter = hw->priv; | |
560 | struct rsi_common *common = adapter->priv; | |
561 | struct security_info *secinfo = &common->secinfo; | |
562 | int status; | |
563 | ||
564 | mutex_lock(&common->mutex); | |
565 | switch (cmd) { | |
566 | case SET_KEY: | |
567 | secinfo->security_enable = true; | |
568 | status = rsi_hal_key_config(hw, vif, key); | |
569 | if (status) { | |
570 | mutex_unlock(&common->mutex); | |
571 | return status; | |
572 | } | |
573 | ||
574 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) | |
575 | secinfo->ptk_cipher = key->cipher; | |
576 | else | |
577 | secinfo->gtk_cipher = key->cipher; | |
578 | ||
579 | key->hw_key_idx = key->keyidx; | |
580 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | |
581 | ||
582 | rsi_dbg(ERR_ZONE, "%s: RSI set_key\n", __func__); | |
583 | break; | |
584 | ||
585 | case DISABLE_KEY: | |
586 | secinfo->security_enable = false; | |
587 | rsi_dbg(ERR_ZONE, "%s: RSI del key\n", __func__); | |
588 | memset(key, 0, sizeof(struct ieee80211_key_conf)); | |
589 | status = rsi_hal_key_config(hw, vif, key); | |
590 | break; | |
591 | ||
592 | default: | |
593 | status = -EOPNOTSUPP; | |
594 | break; | |
595 | } | |
596 | ||
597 | mutex_unlock(&common->mutex); | |
598 | return status; | |
599 | } | |
600 | ||
601 | /** | |
602 | * rsi_mac80211_ampdu_action() - This function selects the AMPDU action for | |
603 | * the corresponding mlme_action flag and | |
604 | * informs the f/w regarding this. | |
605 | * @hw: Pointer to the ieee80211_hw structure. | |
606 | * @vif: Pointer to the ieee80211_vif structure. | |
607 | * @action: ieee80211_ampdu_mlme_action enum. | |
608 | * @sta: Pointer to the ieee80211_sta structure. | |
609 | * @tid: Traffic identifier. | |
610 | * @ssn: Pointer to ssn value. | |
611 | * @buf_size: Buffer size (for kernel version > 2.6.38). | |
612 | * | |
613 | * Return: status: 0 on success, negative error code on failure. | |
614 | */ | |
615 | static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, | |
616 | struct ieee80211_vif *vif, | |
617 | enum ieee80211_ampdu_mlme_action action, | |
618 | struct ieee80211_sta *sta, | |
619 | unsigned short tid, | |
620 | unsigned short *ssn, | |
621 | unsigned char buf_size) | |
622 | { | |
623 | int status = -EOPNOTSUPP; | |
624 | struct rsi_hw *adapter = hw->priv; | |
625 | struct rsi_common *common = adapter->priv; | |
626 | u16 seq_no = 0; | |
627 | u8 ii = 0; | |
628 | ||
629 | for (ii = 0; ii < RSI_MAX_VIFS; ii++) { | |
630 | if (vif == adapter->vifs[ii]) | |
631 | break; | |
632 | } | |
633 | ||
634 | mutex_lock(&common->mutex); | |
635 | rsi_dbg(INFO_ZONE, "%s: AMPDU action %d called\n", __func__, action); | |
636 | if (ssn != NULL) | |
637 | seq_no = *ssn; | |
638 | ||
639 | switch (action) { | |
640 | case IEEE80211_AMPDU_RX_START: | |
641 | status = rsi_send_aggregation_params_frame(common, | |
642 | tid, | |
643 | seq_no, | |
644 | buf_size, | |
645 | STA_RX_ADDBA_DONE); | |
646 | break; | |
647 | ||
648 | case IEEE80211_AMPDU_RX_STOP: | |
649 | status = rsi_send_aggregation_params_frame(common, | |
650 | tid, | |
651 | 0, | |
652 | buf_size, | |
653 | STA_RX_DELBA); | |
654 | break; | |
655 | ||
656 | case IEEE80211_AMPDU_TX_START: | |
657 | common->vif_info[ii].seq_start = seq_no; | |
658 | ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | |
5f407acb | 659 | status = 0; |
dad0d04f FF |
660 | break; |
661 | ||
662 | case IEEE80211_AMPDU_TX_STOP_CONT: | |
663 | case IEEE80211_AMPDU_TX_STOP_FLUSH: | |
664 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: | |
665 | status = rsi_send_aggregation_params_frame(common, | |
666 | tid, | |
667 | seq_no, | |
668 | buf_size, | |
669 | STA_TX_DELBA); | |
670 | if (!status) | |
671 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | |
672 | break; | |
673 | ||
674 | case IEEE80211_AMPDU_TX_OPERATIONAL: | |
675 | status = rsi_send_aggregation_params_frame(common, | |
676 | tid, | |
677 | common->vif_info[ii] | |
678 | .seq_start, | |
679 | buf_size, | |
680 | STA_TX_ADDBA_DONE); | |
681 | break; | |
682 | ||
683 | default: | |
684 | rsi_dbg(ERR_ZONE, "%s: Uknown AMPDU action\n", __func__); | |
685 | break; | |
686 | } | |
687 | ||
688 | mutex_unlock(&common->mutex); | |
689 | return status; | |
690 | } | |
691 | ||
692 | /** | |
693 | * rsi_mac80211_set_rts_threshold() - This function sets rts threshold value. | |
694 | * @hw: Pointer to the ieee80211_hw structure. | |
695 | * @value: Rts threshold value. | |
696 | * | |
697 | * Return: 0 on success. | |
698 | */ | |
699 | static int rsi_mac80211_set_rts_threshold(struct ieee80211_hw *hw, | |
700 | u32 value) | |
701 | { | |
702 | struct rsi_hw *adapter = hw->priv; | |
703 | struct rsi_common *common = adapter->priv; | |
704 | ||
705 | mutex_lock(&common->mutex); | |
706 | common->rts_threshold = value; | |
707 | mutex_unlock(&common->mutex); | |
708 | ||
709 | return 0; | |
710 | } | |
711 | ||
712 | /** | |
713 | * rsi_mac80211_set_rate_mask() - This function sets bitrate_mask to be used. | |
714 | * @hw: Pointer to the ieee80211_hw structure | |
715 | * @vif: Pointer to the ieee80211_vif structure. | |
716 | * @mask: Pointer to the cfg80211_bitrate_mask structure. | |
717 | * | |
718 | * Return: 0 on success. | |
719 | */ | |
720 | static int rsi_mac80211_set_rate_mask(struct ieee80211_hw *hw, | |
721 | struct ieee80211_vif *vif, | |
722 | const struct cfg80211_bitrate_mask *mask) | |
723 | { | |
724 | struct rsi_hw *adapter = hw->priv; | |
725 | struct rsi_common *common = adapter->priv; | |
726 | ||
727 | mutex_lock(&common->mutex); | |
728 | ||
729 | common->fixedrate_mask[IEEE80211_BAND_2GHZ] = 0; | |
730 | ||
731 | if (mask->control[IEEE80211_BAND_2GHZ].legacy == 0xfff) { | |
732 | common->fixedrate_mask[IEEE80211_BAND_2GHZ] = | |
733 | (mask->control[IEEE80211_BAND_2GHZ].ht_mcs[0] << 12); | |
734 | } else { | |
735 | common->fixedrate_mask[IEEE80211_BAND_2GHZ] = | |
736 | mask->control[IEEE80211_BAND_2GHZ].legacy; | |
737 | } | |
738 | mutex_unlock(&common->mutex); | |
739 | ||
740 | return 0; | |
741 | } | |
742 | ||
743 | /** | |
744 | * rsi_fill_rx_status() - This function fills rx status in | |
745 | * ieee80211_rx_status structure. | |
746 | * @hw: Pointer to the ieee80211_hw structure. | |
747 | * @skb: Pointer to the socket buffer structure. | |
748 | * @common: Pointer to the driver private structure. | |
749 | * @rxs: Pointer to the ieee80211_rx_status structure. | |
750 | * | |
751 | * Return: None. | |
752 | */ | |
753 | static void rsi_fill_rx_status(struct ieee80211_hw *hw, | |
754 | struct sk_buff *skb, | |
755 | struct rsi_common *common, | |
756 | struct ieee80211_rx_status *rxs) | |
757 | { | |
758 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | |
759 | struct skb_info *rx_params = (struct skb_info *)info->driver_data; | |
760 | struct ieee80211_hdr *hdr; | |
761 | char rssi = rx_params->rssi; | |
762 | u8 hdrlen = 0; | |
763 | u8 channel = rx_params->channel; | |
764 | s32 freq; | |
765 | ||
766 | hdr = ((struct ieee80211_hdr *)(skb->data)); | |
767 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | |
768 | ||
769 | memset(info, 0, sizeof(struct ieee80211_tx_info)); | |
770 | ||
771 | rxs->signal = -(rssi); | |
772 | ||
773 | if (channel <= 14) | |
774 | rxs->band = IEEE80211_BAND_2GHZ; | |
775 | else | |
776 | rxs->band = IEEE80211_BAND_5GHZ; | |
777 | ||
778 | freq = ieee80211_channel_to_frequency(channel, rxs->band); | |
779 | ||
780 | if (freq) | |
781 | rxs->freq = freq; | |
782 | ||
783 | if (ieee80211_has_protected(hdr->frame_control)) { | |
784 | if (rsi_is_cipher_wep(common)) { | |
785 | memmove(skb->data + 4, skb->data, hdrlen); | |
786 | skb_pull(skb, 4); | |
787 | } else { | |
788 | memmove(skb->data + 8, skb->data, hdrlen); | |
789 | skb_pull(skb, 8); | |
790 | rxs->flag |= RX_FLAG_MMIC_STRIPPED; | |
791 | } | |
792 | rxs->flag |= RX_FLAG_DECRYPTED; | |
793 | rxs->flag |= RX_FLAG_IV_STRIPPED; | |
794 | } | |
795 | } | |
796 | ||
797 | /** | |
798 | * rsi_indicate_pkt_to_os() - This function sends recieved packet to mac80211. | |
799 | * @common: Pointer to the driver private structure. | |
800 | * @skb: Pointer to the socket buffer structure. | |
801 | * | |
802 | * Return: None. | |
803 | */ | |
804 | void rsi_indicate_pkt_to_os(struct rsi_common *common, | |
805 | struct sk_buff *skb) | |
806 | { | |
807 | struct rsi_hw *adapter = common->priv; | |
808 | struct ieee80211_hw *hw = adapter->hw; | |
809 | struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); | |
810 | ||
811 | if ((common->iface_down) || (!adapter->sc_nvifs)) { | |
812 | dev_kfree_skb(skb); | |
813 | return; | |
814 | } | |
815 | ||
816 | /* filling in the ieee80211_rx_status flags */ | |
817 | rsi_fill_rx_status(hw, skb, common, rx_status); | |
818 | ||
819 | ieee80211_rx_irqsafe(hw, skb); | |
820 | } | |
821 | ||
822 | static void rsi_set_min_rate(struct ieee80211_hw *hw, | |
823 | struct ieee80211_sta *sta, | |
824 | struct rsi_common *common) | |
825 | { | |
826 | u8 band = hw->conf.chandef.chan->band; | |
827 | u8 ii; | |
828 | u32 rate_bitmap; | |
829 | bool matched = false; | |
830 | ||
831 | common->bitrate_mask[band] = sta->supp_rates[band]; | |
832 | ||
833 | rate_bitmap = (common->fixedrate_mask[band] & sta->supp_rates[band]); | |
834 | ||
835 | if (rate_bitmap & 0xfff) { | |
836 | /* Find out the min rate */ | |
837 | for (ii = 0; ii < ARRAY_SIZE(rsi_rates); ii++) { | |
838 | if (rate_bitmap & BIT(ii)) { | |
839 | common->min_rate = rsi_rates[ii].hw_value; | |
840 | matched = true; | |
841 | break; | |
842 | } | |
843 | } | |
844 | } | |
845 | ||
846 | common->vif_info[0].is_ht = sta->ht_cap.ht_supported; | |
847 | ||
848 | if ((common->vif_info[0].is_ht) && (rate_bitmap >> 12)) { | |
849 | for (ii = 0; ii < ARRAY_SIZE(rsi_mcsrates); ii++) { | |
850 | if ((rate_bitmap >> 12) & BIT(ii)) { | |
851 | common->min_rate = rsi_mcsrates[ii]; | |
852 | matched = true; | |
853 | break; | |
854 | } | |
855 | } | |
856 | } | |
857 | ||
858 | if (!matched) | |
859 | common->min_rate = 0xffff; | |
860 | } | |
861 | ||
862 | /** | |
863 | * rsi_mac80211_sta_add() - This function notifies driver about a peer getting | |
864 | * connected. | |
865 | * @hw: pointer to the ieee80211_hw structure. | |
866 | * @vif: Pointer to the ieee80211_vif structure. | |
867 | * @sta: Pointer to the ieee80211_sta structure. | |
868 | * | |
869 | * Return: 0 on success, -1 on failure. | |
870 | */ | |
871 | static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, | |
872 | struct ieee80211_vif *vif, | |
873 | struct ieee80211_sta *sta) | |
874 | { | |
875 | struct rsi_hw *adapter = hw->priv; | |
876 | struct rsi_common *common = adapter->priv; | |
877 | ||
878 | mutex_lock(&common->mutex); | |
879 | ||
880 | rsi_set_min_rate(hw, sta, common); | |
881 | ||
882 | if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) || | |
883 | (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) { | |
884 | common->vif_info[0].sgi = true; | |
885 | } | |
886 | ||
887 | if (sta->ht_cap.ht_supported) | |
888 | ieee80211_start_tx_ba_session(sta, 0, 0); | |
889 | ||
890 | mutex_unlock(&common->mutex); | |
891 | ||
892 | return 0; | |
893 | } | |
894 | ||
895 | /** | |
896 | * rsi_mac80211_sta_remove() - This function notifies driver about a peer | |
897 | * getting disconnected. | |
898 | * @hw: Pointer to the ieee80211_hw structure. | |
899 | * @vif: Pointer to the ieee80211_vif structure. | |
900 | * @sta: Pointer to the ieee80211_sta structure. | |
901 | * | |
902 | * Return: 0 on success, -1 on failure. | |
903 | */ | |
904 | static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, | |
905 | struct ieee80211_vif *vif, | |
906 | struct ieee80211_sta *sta) | |
907 | { | |
908 | struct rsi_hw *adapter = hw->priv; | |
909 | struct rsi_common *common = adapter->priv; | |
910 | ||
911 | mutex_lock(&common->mutex); | |
912 | /* Resetting all the fields to default values */ | |
913 | common->bitrate_mask[IEEE80211_BAND_2GHZ] = 0; | |
914 | common->bitrate_mask[IEEE80211_BAND_5GHZ] = 0; | |
915 | common->min_rate = 0xffff; | |
916 | common->vif_info[0].is_ht = false; | |
917 | common->vif_info[0].sgi = false; | |
918 | common->vif_info[0].seq_start = 0; | |
919 | common->secinfo.ptk_cipher = 0; | |
920 | common->secinfo.gtk_cipher = 0; | |
921 | mutex_unlock(&common->mutex); | |
922 | ||
923 | return 0; | |
924 | } | |
925 | ||
926 | static struct ieee80211_ops mac80211_ops = { | |
927 | .tx = rsi_mac80211_tx, | |
928 | .start = rsi_mac80211_start, | |
929 | .stop = rsi_mac80211_stop, | |
930 | .add_interface = rsi_mac80211_add_interface, | |
931 | .remove_interface = rsi_mac80211_remove_interface, | |
932 | .config = rsi_mac80211_config, | |
933 | .bss_info_changed = rsi_mac80211_bss_info_changed, | |
934 | .conf_tx = rsi_mac80211_conf_tx, | |
935 | .configure_filter = rsi_mac80211_conf_filter, | |
936 | .set_key = rsi_mac80211_set_key, | |
937 | .set_rts_threshold = rsi_mac80211_set_rts_threshold, | |
938 | .set_bitrate_mask = rsi_mac80211_set_rate_mask, | |
939 | .ampdu_action = rsi_mac80211_ampdu_action, | |
940 | .sta_add = rsi_mac80211_sta_add, | |
941 | .sta_remove = rsi_mac80211_sta_remove, | |
942 | }; | |
943 | ||
944 | /** | |
945 | * rsi_mac80211_attach() - This function is used to initialize Mac80211 stack. | |
946 | * @common: Pointer to the driver private structure. | |
947 | * | |
948 | * Return: 0 on success, -1 on failure. | |
949 | */ | |
950 | int rsi_mac80211_attach(struct rsi_common *common) | |
951 | { | |
952 | int status = 0; | |
953 | struct ieee80211_hw *hw = NULL; | |
954 | struct wiphy *wiphy = NULL; | |
955 | struct rsi_hw *adapter = common->priv; | |
956 | u8 addr_mask[ETH_ALEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x3}; | |
957 | ||
958 | rsi_dbg(INIT_ZONE, "%s: Performing mac80211 attach\n", __func__); | |
959 | ||
960 | hw = ieee80211_alloc_hw(sizeof(struct rsi_hw), &mac80211_ops); | |
961 | if (!hw) { | |
962 | rsi_dbg(ERR_ZONE, "%s: ieee80211 hw alloc failed\n", __func__); | |
963 | return -ENOMEM; | |
964 | } | |
965 | ||
966 | wiphy = hw->wiphy; | |
967 | ||
968 | SET_IEEE80211_DEV(hw, adapter->device); | |
969 | ||
970 | hw->priv = adapter; | |
971 | adapter->hw = hw; | |
972 | ||
973 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | |
974 | IEEE80211_HW_HAS_RATE_CONTROL | | |
975 | IEEE80211_HW_AMPDU_AGGREGATION | | |
976 | 0; | |
977 | ||
978 | hw->queues = MAX_HW_QUEUES; | |
979 | hw->extra_tx_headroom = RSI_NEEDED_HEADROOM; | |
980 | ||
981 | hw->max_rates = 1; | |
982 | hw->max_rate_tries = MAX_RETRIES; | |
983 | ||
984 | hw->max_tx_aggregation_subframes = 6; | |
985 | rsi_register_rates_channels(adapter, IEEE80211_BAND_2GHZ); | |
986 | hw->rate_control_algorithm = "AARF"; | |
987 | ||
988 | SET_IEEE80211_PERM_ADDR(hw, common->mac_addr); | |
989 | ether_addr_copy(hw->wiphy->addr_mask, addr_mask); | |
990 | ||
991 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | |
992 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | |
993 | wiphy->retry_short = RETRY_SHORT; | |
994 | wiphy->retry_long = RETRY_LONG; | |
995 | wiphy->frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD; | |
996 | wiphy->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; | |
997 | wiphy->flags = 0; | |
998 | ||
999 | wiphy->available_antennas_rx = 1; | |
1000 | wiphy->available_antennas_tx = 1; | |
1001 | wiphy->bands[IEEE80211_BAND_2GHZ] = | |
1002 | &adapter->sbands[IEEE80211_BAND_2GHZ]; | |
1003 | ||
1004 | status = ieee80211_register_hw(hw); | |
1005 | if (status) | |
1006 | return status; | |
1007 | ||
1008 | return rsi_init_dbgfs(adapter); | |
1009 | } |